Skip to content

Commit

Permalink
Merge pull request #191 from tatarize/fastfail-intersection
Browse files Browse the repository at this point in the history
Fastfail Intersection
  • Loading branch information
mathandy authored Feb 4, 2023
2 parents d9515ea + 3eb2116 commit 2a1cb73
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
39 changes: 39 additions & 0 deletions svgpathtools/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,19 @@ def intersect(self, other_seg, tol=None):
Note: This will fail if the two segments coincide for more than a
finite collection of points.
tol is not used."""
if isinstance(other_seg, (Line, QuadraticBezier, CubicBezier)):
ob = [e.real for e in other_seg.bpoints()]
sb = [e.real for e in self.bpoints()]
if min(ob) > max(sb):
return []
if max(ob) < min(sb):
return []
ob = [e.imag for e in other_seg.bpoints()]
sb = [e.imag for e in self.bpoints()]
if min(ob) > max(sb):
return []
if max(ob) < min(sb):
return []
if isinstance(other_seg, Line):
assert other_seg.end != other_seg.start and self.end != self.start
assert self != other_seg
Expand Down Expand Up @@ -1038,6 +1051,19 @@ def intersect(self, other_seg, tol=1e-12):
self.point(t1) == other_seg.point(t2).
Note: This will fail if the two segments coincide for more than a
finite collection of points."""
if isinstance(other_seg, (Line, QuadraticBezier, CubicBezier)):
ob = [e.real for e in other_seg.bpoints()]
sb = [e.real for e in self.bpoints()]
if min(ob) > max(sb):
return []
if max(ob) < min(sb):
return []
ob = [e.imag for e in other_seg.bpoints()]
sb = [e.imag for e in self.bpoints()]
if min(ob) > max(sb):
return []
if max(ob) < min(sb):
return []
if isinstance(other_seg, Line):
return bezier_by_line_intersections(self, other_seg)
elif isinstance(other_seg, QuadraticBezier):
Expand Down Expand Up @@ -1298,6 +1324,19 @@ def intersect(self, other_seg, tol=1e-12):
This will fail if the two segments coincide for more than a
finite collection of points.
"""
if isinstance(other_seg, (Line, QuadraticBezier, CubicBezier)):
ob = [e.real for e in other_seg.bpoints()]
sb = [e.real for e in self.bpoints()]
if min(ob) > max(sb):
return []
if max(ob) < min(sb):
return []
ob = [e.imag for e in other_seg.bpoints()]
sb = [e.imag for e in self.bpoints()]
if min(ob) > max(sb):
return []
if max(ob) < min(sb):
return []
if isinstance(other_seg, Line):
return bezier_by_line_intersections(self, other_seg)
elif (isinstance(other_seg, QuadraticBezier) or
Expand Down
45 changes: 45 additions & 0 deletions test/test_path.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# External dependencies
from __future__ import division, absolute_import, print_function
import os
import time
from sys import version_info
import unittest
from math import sqrt, pi
Expand Down Expand Up @@ -1495,6 +1496,50 @@ def test_intersect(self):
self.assertTrue(len(yix) == 1)
###################################################################

def test_random_intersections(self):
from random import Random
r = Random()
distance = 100
distribution = 10000
count = 500

def random_complex(offset_x=0.0, offset_y=0.0):
return complex(r.random() * distance + offset_x, r.random() * distance + offset_y)

def random_line():
offset_x = r.random() * distribution
offset_y = r.random() * distribution
return Line(random_complex(offset_x, offset_y), random_complex(offset_x, offset_y))

def random_quad():
offset_x = r.random() * distribution
offset_y = r.random() * distribution
return QuadraticBezier(random_complex(offset_x, offset_y), random_complex(offset_x, offset_y), random_complex(offset_x, offset_y))

def random_cubic():
offset_x = r.random() * distribution
offset_y = r.random() * distribution
return CubicBezier(random_complex(offset_x, offset_y), random_complex(offset_x, offset_y), random_complex(offset_x, offset_y), random_complex(offset_x, offset_y))

def random_path():
path = Path()
for i in range(count):
type_segment = random.randint(0, 3)
if type_segment == 0:
path.append(random_line())
if type_segment == 1:
path.append(random_quad())
if type_segment == 2:
path.append(random_cubic())
return path

path1 = random_path()
path2 = random_path()
t = time.time()
intersections = path1.intersect(path2)
print("\nFound {} intersections in {} seconds.\n"
"".format(len(intersections), time.time() - t))

def test_line_line_0(self):
l0 = Line(start=(25.389999999999997+99.989999999999995j),
end=(25.389999999999997+90.484999999999999j))
Expand Down

0 comments on commit 2a1cb73

Please sign in to comment.