Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line-line intersection edge cases #3396

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions Lib/fontTools/misc/bezierTools.py
Expand Up @@ -1184,6 +1184,11 @@
if math.isclose(s1x, e1x) and math.isclose(s1y, e1y): # Line segment is tiny
return []
if math.isclose(e1x, s1x):
if math.isclose(e2x, s2x): # Same start
if math.isclose(s1y, s2y):
return [Intersection(pt=(s1x, s1y), t1=0, t2=0)]
# Degenerate coincident case
return []
x = s1x
slope34 = (e2y - s2y) / (e2x - s2x)
y = slope34 * (x - s2x) + s2y
Expand All @@ -1194,6 +1199,11 @@
)
]
if math.isclose(s2x, e2x):
if math.isclose(s1x, e1x):
if math.isclose(e1y, e2y): # Same end
return [Intersection(pt=(e1x, e1y), t1=1, t2=1)]

Check warning on line 1204 in Lib/fontTools/misc/bezierTools.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/misc/bezierTools.py#L1204

Added line #L1204 was not covered by tests
# Degenerate coincident case
return []

Check warning on line 1206 in Lib/fontTools/misc/bezierTools.py

View check run for this annotation

Codecov / codecov/patch

Lib/fontTools/misc/bezierTools.py#L1206

Added line #L1206 was not covered by tests
x = s2x
slope12 = (e1y - s1y) / (e1x - s1x)
y = slope12 * (x - s1x) + s1y
Expand Down
10 changes: 10 additions & 0 deletions Tests/misc/bezierTools_test.py
Expand Up @@ -5,6 +5,7 @@
calcCubicBounds,
curveLineIntersections,
curveCurveIntersections,
lineLineIntersections,
segmentPointAtT,
splitLine,
splitQuadratic,
Expand Down Expand Up @@ -197,3 +198,12 @@ def test_intersections_linelike():
seg2 = [(0.0, 0.5), (0.25, 0.5), (0.75, 0.5), (1.0, 0.5)]
pt = curveCurveIntersections(seg1, seg2)[0][0]
assert pt == (0.0, 0.5)


def test_intersections_samestart():
seg1 = [(250, 1000), (250, 810)]
seg2 = [(250, 1000), (250, 400)]
pt = lineLineIntersections(*seg1, *seg2)[0][0]
assert pt == (250.0, 1000.0)
seg3 = [(250, 810), (250, 500)]
assert lineLineIntersections(*seg1, *seg3) == []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't seg1 and seg3 intersect at (250, 810)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh sorry I see now (was typing from mobile), the segments actually are coincident, sitting on top of one another. In theory they intersect in all the points where they overlap, but since we need to return some finite results it's ok to return [] in this edge case

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait I'm still confused... I think you swapped the two cases.

all the three segments above seg1, seg2 and seg3 are parallel to one another and the Y axis, have the same x coordinate 250; seg1 and and seg2 are the ones that overlap one another, they also share the starting point but coincide for the entire length of seg1 (which is a subset of seg2). So I'd expect we would return [] in this case. Whereas you are returning (250.0, 1000.0) which is their starting point.

On the other hand, seg1 and seg2, while being parallel (x coordinates are all 250), they only touch where seg1 ends and seg3 starts, i.e. (250, 810) -- so I would expect the latter to be returned as their intersection, not []