summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorPouleyKetchoupp <pouleyketchoup@gmail.com>2021-08-25 13:34:32 -0700
committerPouleyKetchoupp <pouleyketchoup@gmail.com>2021-08-25 18:17:52 -0700
commit511c80b2ec3c8d8eb8a71ddfab56b2c071b956d0 (patch)
treef5e82f280335152c9f2411cf2b91d4a704f4e9af /core
parent353bb45e21fadf8da1f6fbbaaf99b8ac8acafea9 (diff)
Fix segment intersection consistency in Geometry2D
Segment collision results could be different depending on the direction when they exactly touch (order of the points in segments). This was due to the way parallelism was checked, using different logic based on positive or negative sign of cross products. Now the results are the same whatever the direction, without changing the current design, which is that parallel or colinear segments are not considered colinear. Fixes inconsistencies with raycasts exactly on edges of convex shapes depending on the direction.
Diffstat (limited to 'core')
-rw-r--r--core/math/geometry_2d.h20
1 files changed, 17 insertions, 3 deletions
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index e1a5bfe6f2..8e5830f9b3 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -182,7 +182,15 @@ public:
C = Vector2(C.x * Bn.x + C.y * Bn.y, C.y * Bn.x - C.x * Bn.y);
D = Vector2(D.x * Bn.x + D.y * Bn.y, D.y * Bn.x - D.x * Bn.y);
- if ((C.y < 0 && D.y < 0) || (C.y >= 0 && D.y >= 0)) {
+ // Fail if C x B and D x B have the same sign (segments don't intersect).
+ // (equivalent to condition (C.y < 0 && D.y < CMP_EPSILON) || (C.y > 0 && D.y > CMP_EPSILON))
+ if (C.y * D.y > CMP_EPSILON) {
+ return false;
+ }
+
+ // Fail if segments are parallel or colinear.
+ // (when A x B == zero, i.e (C - D) x B == zero, i.e C x B == D x B)
+ if (Math::is_equal_approx(C.y, D.y)) {
return false;
}
@@ -193,7 +201,7 @@ public:
return false;
}
- // (4) Apply the discovered position to line A-B in the original coordinate system.
+ // Apply the discovered position to line A-B in the original coordinate system.
if (r_result) {
*r_result = p_from_a + B * ABpos;
}
@@ -353,8 +361,14 @@ public:
for (int i = 0; i < c; i++) {
const Vector2 &v1 = p[i];
const Vector2 &v2 = p[(i + 1) % c];
- if (segment_intersects_segment(v1, v2, p_point, further_away, nullptr)) {
+
+ Vector2 res;
+ if (segment_intersects_segment(v1, v2, p_point, further_away, &res)) {
intersections++;
+ if (res.is_equal_approx(p_point)) {
+ // Point is in one of the polygon edges.
+ return true;
+ }
}
}