From c89c68f4218b1afc2bb0e71ea4ba9e007e092f27 Mon Sep 17 00:00:00 2001 From: Andy Port Date: Wed, 1 Jul 2020 22:31:57 -0700 Subject: [PATCH] speed up randialrange for Line objects --- svgpathtools/path.py | 40 +++++++++++++++++++++++++++++++++++----- test/test_path.py | 14 +++++++++++++- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/svgpathtools/path.py b/svgpathtools/path.py index 3cce50a..eca12f5 100644 --- a/svgpathtools/path.py +++ b/svgpathtools/path.py @@ -730,11 +730,41 @@ class Line(object): pt = self.point(t) return Line(self.start, pt), Line(pt, self.end) - def radialrange(self, origin, return_all_global_extrema=False): - """returns the tuples (d_min, t_min) and (d_max, t_max) which minimize - and maximize, respectively, the distance d = |self.point(t)-origin|.""" - return bezier_radialrange(self, origin, - return_all_global_extrema=return_all_global_extrema) + def radialrange(self, origin, **kwargs): + """compute points in self that are min and max distance to origin. + + Args: + origin (complex): the point extremize distance to + + Returns: + tuples (d_min, t_min) and (d_max, t_max) which minimize and + maximize, respectively, the distance d = |self.point(t)-origin|. + """ + + x, y = origin.real, origin.imag + p0, p1 = self.start, self.end + x0, y0, x1, y1 = p0.real, p0.imag, p1.real, p1.imag + + dx, dy = x1 - x0, y1 - y0 + numerator, denominator = dx * (x - x0) + dy * (y - y0), dx * dx + dy * dy + t = numerator / denominator + + if 0 < t < 1: + # get distance to origin at 0, 1, and t + d0, d1, dt = ( + abs(p0 - origin), + abs(p1 - origin), + abs(self.point(t) - origin) + ) + if d0 < d1: + return (dt, t), (d1, 1) + return (dt, t), (d0, 0) + else: + # get distance to origin at t = 0 and t = 1 + d0, d1 = abs(p0 - origin), abs(p1 - origin) + if d0 < d1: + return (d0, 0), (d1, 1) + return (d1, 1), (d0, 0) def rotated(self, degs, origin=None): """Returns a copy of self rotated by `degs` degrees (CCW) around the diff --git a/test/test_path.py b/test/test_path.py index b2cdbda..5c440fb 100644 --- a/test/test_path.py +++ b/test/test_path.py @@ -8,7 +8,7 @@ import random # Internal dependencies from svgpathtools import * -from svgpathtools.path import _NotImplemented4ArcException +from svgpathtools.path import _NotImplemented4ArcException, bezier_radialrange # An important note for those doing any debugging: # ------------------------------------------------ @@ -161,7 +161,19 @@ class LineTest(unittest.TestCase): computed_t = l.point_to_t(p) self.assertAlmostEqual(orig_t, computed_t) + def test_radialrange(self): + def crand(): + return 100*(np.random.rand() + np.random.rand()*1j) + for _ in range(100): + z = crand() + l = Line(crand(), crand()) + (min_da, min_ta), (max_da, max_ta) = l.radialrange(z) + (min_db, min_tb), (max_db, max_tb) = bezier_radialrange(l, z) + self.assertAlmostEqual(min_da, min_db) + self.assertAlmostEqual(min_ta, min_tb) + self.assertAlmostEqual(max_da, max_db) + self.assertAlmostEqual(max_ta, max_tb) class CubicBezierTest(unittest.TestCase):