|
|
@@ -33,17 +33,24 @@ namespace math {
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ enum orientation {
|
|
|
+ colinear = 0, clockwise = 1, anticlockwise = 2
|
|
|
+ };
|
|
|
+
|
|
|
+ orientation orient(dim2::point const & p, dim2::point const & q,
|
|
|
+ dim2::point const & r) {
|
|
|
+ float val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
|
|
|
+
|
|
|
+ if (val == 0) return colinear;
|
|
|
+ return (val > 0) ? clockwise : anticlockwise;
|
|
|
+ }
|
|
|
+
|
|
|
bool contains(dim2::line const & ln, dim2::point const & pt) {
|
|
|
- if (ln.first[0] == ln.second[0]) {
|
|
|
- return pt[0] == ln.first[0] && between(pt[1], ln.first[1], ln.second[1]);
|
|
|
- } else if (ln.first == pt || ln.second == pt) {
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- auto slope = dim2::line{ln.first, pt}.slope();
|
|
|
- return (slope == ln.slope() || slope == -1/ln.slope()) &&
|
|
|
- between(pt[0], ln.first[0], ln.second[0]) &&
|
|
|
- between(pt[1], ln.first[1], ln.second[1]);
|
|
|
- }
|
|
|
+ auto xs = std::minmax(ln.first[0], ln.second[0], lessinf());
|
|
|
+ auto ys = std::minmax(ln.first[1], ln.second[1], lessinf());
|
|
|
+ return orient(ln.first, ln.second, pt) == colinear &&
|
|
|
+ between(pt[0], xs.first, xs.second) &&
|
|
|
+ between(pt[1], ys.first, ys.second);
|
|
|
}
|
|
|
|
|
|
bool contains(dim2::circle const & shape, dim2::point const & pt) {
|
|
|
@@ -51,18 +58,17 @@ namespace math {
|
|
|
return delta.dot(delta) <= std::pow(shape.radius, 2);
|
|
|
}
|
|
|
|
|
|
- static dim2::line ray_x(dim2::point const & pt) {
|
|
|
- return {pt, {{std::numeric_limits<float>::infinity(), pt[1]}}};
|
|
|
+ static dim2::line ray_x(dim2::point const & pt, dim2::line const & l) {
|
|
|
+ auto x_inf = std::max({l.first[0], l.second[0], pt[0]});
|
|
|
+ return {pt, {{x_inf, pt[1]}}};
|
|
|
}
|
|
|
|
|
|
static bool contains(std::vector<dim2::line> const & segments,
|
|
|
dim2::point const & pt) {
|
|
|
- dim2::line const ray = ray_x(pt);
|
|
|
int hits = 0;
|
|
|
for (auto l : segments) {
|
|
|
- dim2::point const inter = lines::intersection(l, ray);
|
|
|
- if (inter == pt) return true;
|
|
|
- else if (contains(l, inter)) ++hits;
|
|
|
+ if (contains(l, pt)) return true;
|
|
|
+ else if (intersects(l, ray_x(pt, l))) ++hits;
|
|
|
}
|
|
|
return (hits & 1) == 1;
|
|
|
}
|
|
|
@@ -72,8 +78,28 @@ namespace math {
|
|
|
}
|
|
|
|
|
|
bool intersects(dim2::line const & lhs, dim2::line const & rhs) {
|
|
|
- dim2::point const inter = lines::intersection(lhs, rhs);
|
|
|
- return contains(rhs, inter);
|
|
|
+ // Find the four orientations needed for general and
|
|
|
+ // special cases
|
|
|
+ orientation o1 = orient(lhs.first, lhs.second, rhs.first);
|
|
|
+ orientation o2 = orient(lhs.first, lhs.second, rhs.second);
|
|
|
+ orientation o3 = orient(rhs.first, rhs.second, lhs.first);
|
|
|
+ orientation o4 = orient(rhs.first, rhs.second, lhs.second);
|
|
|
+
|
|
|
+ // General case
|
|
|
+ if (o1 != o2 && o3 != o4)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ // Special Cases
|
|
|
+ // p1, q1 and p2 are colinear and p2 lies on segment p1q1
|
|
|
+ if (o1 == colinear && contains(lhs, rhs.second)) { return true; }
|
|
|
+ // p1, q1 and q2 are colinear and q2 lies on segment p1q1
|
|
|
+ if (o2 == colinear && contains(lhs, rhs.second)) { return true; }
|
|
|
+ // p2, q2 and p1 are colinear and p1 lies on segment p2q2
|
|
|
+ if (o3 == colinear && contains(rhs, lhs.first)) { return true; }
|
|
|
+ // p2, q2 and q1 are colinear and q1 lies on segment p2q2
|
|
|
+ if (o4 == colinear && contains(rhs, lhs.second)) { return true; }
|
|
|
+
|
|
|
+ return false; // Doesn't fall in any of the above cases
|
|
|
}
|
|
|
|
|
|
bool intersects(dim2::line const & lhs, dim2::circle const & rhs) {
|