From 316dc8bfe96f9443e11aab7b2b70951a35758282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Granskogen=20Bj=C3=B8rnstad?= Date: Fri, 10 Nov 2017 13:39:43 +0100 Subject: [PATCH 1/2] test_parsing.py: Add test_roundoff example This test currently fails due to math.acos(1.0000000000001) raising a ValueError. --- test/test_parsing.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/test_parsing.py b/test/test_parsing.py index c052ad8..3cdcfc2 100644 --- a/test/test_parsing.py +++ b/test/test_parsing.py @@ -137,3 +137,31 @@ class TestParser(unittest.TestCase): def test_errors(self): self.assertRaises(ValueError, parse_path, 'M 100 100 L 200 200 Z 100 200') + + def test_roundoff(self): + """Paths with arc segments may have floating point round-off issues""" + path1 = parse_path(""" + M160.172,102.95 + L159.922,102.95 + A0.025,0.025 0 0,1 159.897,102.925 + L159.897,102.675 + A0.025,0.025 0 0,1 159.922,102.65 + L160.172,102.65 + A0.025,0.025 0 0,1 160.197,102.675 + L160.197,102.925 + A0.025,0.025 0 0,1 160.172,102.95""") + + path2 = Path(Line(start=(160.172 + 102.95j), end=(159.922 + 102.95j)), + Arc(start=(159.922 + 102.95j), radius=(0.025 + 0.025j), rotation=0.0, + large_arc=False, sweep=True, end=(159.897 + 102.925j)), + Line(start=(159.897 + 102.925j), end=(159.897 + 102.675j)), + Arc(start=(159.897 + 102.675j), radius=(0.025 + 0.025j), rotation=0.0, + large_arc=False, sweep=True, end=(159.922 + 102.65j)), + Line(start=(159.922 + 102.65j), end=(160.172 + 102.65j)), + Arc(start=(160.172 + 102.65j), radius=(0.025 + 0.025j), rotation=0.0, + large_arc=False, sweep=True, end=(160.197 + 102.675j)), + Line(start=(160.197 + 102.675j), end=(160.197 + 102.925j)), + Arc(start=(160.197 + 102.925j), radius=(0.025 + 0.025j), rotation=0.0, + large_arc=False, sweep=True, end=(160.172 + 102.95j))) + + self.assertEqual(path1, path2) From ec63d0c312056545cce7450bfb9e91a7033dac58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Granskogen=20Bj=C3=B8rnstad?= Date: Fri, 10 Nov 2017 13:44:24 +0100 Subject: [PATCH 2/2] Arc: Handle round-off issue with acos() math.acos raises outside of valid range [-1, 1]. Handle round-off errors gracefully by using `round()` here too. --- svgpathtools/path.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/svgpathtools/path.py b/svgpathtools/path.py index 41989de..51378fd 100644 --- a/svgpathtools/path.py +++ b/svgpathtools/path.py @@ -1300,10 +1300,13 @@ class Arc(object): # delta is the angular distance of the arc (w.r.t the circle) # theta is the angle between the positive x'-axis and the start point # on the circle + u1_real_rounded = u1.real + if u1.real > 1 or u1.real < -1: + u1_real_rounded = round(u1.real) if u1.imag > 0: - self.theta = degrees(acos(u1.real)) + self.theta = degrees(acos(u1_real_rounded)) elif u1.imag < 0: - self.theta = -degrees(acos(u1.real)) + self.theta = -degrees(acos(u1_real_rounded)) else: if u1.real > 0: # start is on pos u_x axis self.theta = 0