From fd521748fa45a46aa82e63d5d1ce1c994af21df6 Mon Sep 17 00:00:00 2001 From: Andy Date: Fri, 6 Jul 2018 22:59:28 -0400 Subject: [PATCH] fixed scaled (before cleanup) --- disvg_output.svg | 8 ----- svgpathtools/path.py | 24 ++++++++----- test/test_path.py | 84 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 81 insertions(+), 35 deletions(-) delete mode 100644 disvg_output.svg diff --git a/disvg_output.svg b/disvg_output.svg deleted file mode 100644 index 280a4c8..0000000 --- a/disvg_output.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/svgpathtools/path.py b/svgpathtools/path.py index 547fca4..49fd4b7 100644 --- a/svgpathtools/path.py +++ b/svgpathtools/path.py @@ -225,25 +225,31 @@ def scale(curve, sx, sy=None, origin=0j): else: isy = 1j*sy - def transform(z, origin=origin): - zeta = z - origin - return sx*zeta.real + isy*zeta.imag + origin + def _scale(z): + if sy is None: + return sx*z + return sx*z.real + isy*z.imag + + def scale_bezier(bez): + p = [_scale(c) for c in bez2poly(bez)] + p[-1] += origin - _scale(origin) + return poly2bez(p) if isinstance(curve, Path): return Path(*[scale(seg, sx, sy, origin) for seg in curve]) elif is_bezier_segment(curve): - return bpoints2bezier([transform(z) for z in curve.bpoints()]) + return scale_bezier(curve) elif isinstance(curve, Arc): if sy is None or sy == sx: - return Arc(start=transform(curve.start), - radius=transform(curve.radius, origin=0), + return Arc(start=sx*(curve.start - origin) + origin, + radius=sx*curve.radius, rotation=curve.rotation, large_arc=curve.large_arc, sweep=curve.sweep, - end=transform(curve.end)) + end=sx*(curve.end - origin) + origin) else: - raise Exception("For `Arc` objects, only scale transforms " - "with sx==sy are implemented.") + raise Exception("\nFor `Arc` objects, only scale transforms " + "with sx==sy are implemented.\n") else: raise TypeError("Input `curve` should be a Path, Line, " "QuadraticBezier, CubicBezier, or Arc object.") diff --git a/test/test_path.py b/test/test_path.py index 8a9ab0f..254fa1f 100644 --- a/test/test_path.py +++ b/test/test_path.py @@ -7,6 +7,7 @@ import numpy as np # Internal dependencies from svgpathtools import * +from svgpathtools.path import _NotImplemented4ArcException # An important note for those doing any debugging: # ------------------------------------------------ @@ -780,39 +781,86 @@ class TestPath(unittest.TestCase): isinstance(curve, Path) and any(isinstance(seg, Arc) for seg in curve)) + # find seg which t lands on for failure reporting + seg = curve + if isinstance(curve, Path): + seg_idx, seg_t = curve.T2t(t) + seg = curve[seg_idx] + _fail_msg = "Failure!\nseg {}\n".format(seg) + # case where no `sy` and no `origin` given + curve_scaled = curve.scaled(sx) + # res = curve_scaled.point(t) + if isinstance(curve, Path): + res = curve_scaled[seg_idx].point(seg_t) + else: + res = curve_scaled.point(t) ans = scale_a_point(pt, sx, None) - self.assertAlmostEqual(ans, curve.scaled(sx).point(t)) + fail_msg = _fail_msg + ("curve.scaled({}, {}, {}) = \n{}\n" + "".format(sx, None, None, curve_scaled)) + # fail_msg += "curve.point({}) = {}".format(t, res) + fail_msg += "seg_scaled.point({}) = {}\n".format(seg_t, res) + fail_msg += "ans = {}".format(ans) + self.assertAlmostEqual(ans, res, places=4, msg=fail_msg) - # case where no `sy` and random `origin` given + # case where random `origin` given but no `sy` ans = scale_a_point(pt, sx, None, origin) - self.assertAlmostEqual(ans, - curve.scaled(sx, origin=origin).point(t)) - - # the cases with sx != sy are not yet imp - if isinstance(curve, Arc): - continue + curve_scaled = curve.scaled(sx, origin=origin) + # res = curve_scaled.point(t) + if isinstance(curve, Path): + res = curve_scaled[seg_idx].point(seg_t) + else: + res = curve_scaled.point(t) + fail_msg = _fail_msg + ("curve.scaled({}, {}, {}) = \n{}\n" + "".format(sx, None, origin, curve_scaled)) + # fail_msg += "curve.point({}) = {}\n".format(t, res) + fail_msg += "seg_scaled.point({}) = {}\n".format(seg_t, res) + fail_msg += "ans = {}".format(ans) + self.assertAlmostEqual(ans, res, places=4, msg=fail_msg) # case where `sx != sy`, and no `origin` given ans = scale_a_point(pt, sx, sy) - if has_arc: - self.assertRaises(Exception, curve.scaled(sx, sy).point(t)) + if has_arc: # the cases with sx != sy are not yet imp for arcs + with self.assertRaises(Exception): + curve.scaled(sx, sy).point(t) else: - self.assertAlmostEqual(ans, curve.scaled(sx, sy).point(t)) + curve_scaled = curve.scaled(sx, sy) + seg_scaled = seg.scaled(sx, sy) + # res = curve_scaled.point(t) + if isinstance(curve, Path): + res = curve_scaled[seg_idx].point(seg_t) + else: + res = curve_scaled.point(t) + fail_msg = _fail_msg + ("curve.scaled({}, {}, {}) = \n{}\n" + "".format(sx, sy, None, curve_scaled)) + # fail_msg += "curve.point({}) = {}\n".format(t, res) + fail_msg += "seg_scaled.point({}) = {}\n".format(seg_t, res) + fail_msg += "ans = {}".format(ans) + self.assertAlmostEqual(ans, res, places=4, msg=fail_msg) # case where `sx != sy`, and random `origin` given ans = scale_a_point(pt, sx, sy, origin) - if has_arc: - self.assertRaises(Exception, - curve.scaled(sx, sy, origin).point(t)) + if has_arc: # the cases with sx != sy are not yet imp for arcs + with self.assertRaises(Exception): + curve.scaled(sx, sy, origin).point(t) else: - self.assertAlmostEqual(ans, - curve.scaled(sx, sy, origin).point(t)) + curve_scaled = curve.scaled(sx, sy, origin) + # res = curve_scaled.point(t) + if isinstance(curve, Path): + res = curve_scaled[seg_idx].point(seg_t) + else: + res = curve_scaled.point(t) + fail_msg = _fail_msg + ("curve.scaled({}, {}, {}) = \n{}\n" + "".format(sx, sy, origin, curve_scaled)) + # fail_msg += "curve.point({}) = {}\n".format(t, res) + fail_msg += "seg_scaled.point({}) = {}\n".format(seg_t, res) + fail_msg += "ans = {}".format(ans) + self.assertAlmostEqual(ans, res, places=4, msg=fail_msg) # more tests for scalar (i.e. `sx == sy`) case for curve in test_curves: # scale by 2 around (100, 100) - scaled_curve = curve.scaled(2.0, complex(100, 100)) + scaled_curve = curve.scaled(2.0, origin=complex(100, 100)) # expected length len_orig = curve.length() @@ -829,7 +877,7 @@ class TestPath(unittest.TestCase): # scale by 0.3 around (0, -100) # the 'almost equal' test fails at the 7th decimal place for # some length and position tests here. - scaled_curve = curve.scaled(0.3, complex(0, -100)) + scaled_curve = curve.scaled(0.3, origin=complex(0, -100)) # expected length len_orig = curve.length()