partially fixed scale fcn and improved tests
parent
f932036fb5
commit
fd95b5609f
|
@ -224,25 +224,25 @@ def scale(curve, sx, sy=None, origin=0j):
|
|||
else:
|
||||
isy = 1j*sy
|
||||
|
||||
def transform(z, sx=sx, sy=sy, origin=origin):
|
||||
def transform(z, origin=origin):
|
||||
zeta = z - origin
|
||||
return x*zeta.real + isy*zeta.imag + origin
|
||||
return sx*zeta.real + isy*zeta.imag + origin
|
||||
|
||||
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()])
|
||||
elif isinstance(curve, Arc):
|
||||
if y is None or y == x:
|
||||
if sy is None or sy == sx:
|
||||
return Arc(start=transform(curve.start),
|
||||
radius=transform(radius, origin=0),
|
||||
radius=transform(curve.radius, origin=0),
|
||||
rotation=curve.rotation,
|
||||
large_arc=curve.large_arc,
|
||||
sweep=curve.sweep,
|
||||
end=transform(curve.end))
|
||||
else:
|
||||
raise Excpetion("For `Arc` objects, only scale transforms "
|
||||
"with sx==sy are implemenented.")
|
||||
raise Exception("For `Arc` objects, only scale transforms "
|
||||
"with sx==sy are implemented.")
|
||||
else:
|
||||
raise TypeError("Input `curve` should be a Path, Line, "
|
||||
"QuadraticBezier, CubicBezier, or Arc object.")
|
||||
|
@ -2042,9 +2042,9 @@ class Path(MutableSequence):
|
|||
0) == previous.unit_tangent(1)
|
||||
|
||||
def T2t(self, T):
|
||||
"""returns the segment index, seg_idx, and segment parameter, t,
|
||||
corresponding to the path parameter T. In other words, this is the
|
||||
inverse of the Path.t2T() method."""
|
||||
"""returns the segment index, `seg_idx`, and segment parameter, `t`,
|
||||
corresponding to the path parameter `T`. In other words, this is the
|
||||
inverse of the `Path.t2T()` method."""
|
||||
if T == 1:
|
||||
return len(self)-1, 1
|
||||
if T == 0:
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import division, absolute_import, print_function
|
|||
import unittest
|
||||
from math import sqrt, pi
|
||||
from operator import itemgetter
|
||||
from numpy import poly1d, linspace
|
||||
import numpy as np
|
||||
|
||||
# Internal dependencies
|
||||
from svgpathtools import *
|
||||
|
@ -727,6 +727,7 @@ class TestPath(unittest.TestCase):
|
|||
p_open.cropped(1, 0)
|
||||
|
||||
def test_transform_scale(self):
|
||||
|
||||
line1 = Line(600.5 + 350.5j, 650.5 + 325.5j)
|
||||
arc1 = Arc(650 + 325j, 25 + 25j, -30, 0, 1, 700 + 300j)
|
||||
arc2 = Arc(650 + 325j, 30 + 25j, -30, 0, 0, 700 + 300j)
|
||||
|
@ -744,46 +745,107 @@ class TestPath(unittest.TestCase):
|
|||
cpath = Path(cub1)
|
||||
apath = Path(arc1, arc2)
|
||||
|
||||
test_curves = ([bezpath, bezpathz, path, pathz, lpath, qpath, cpath, apath] +
|
||||
[line1, arc1, arc2, cub1, cub2, quad3, linez])
|
||||
test_curves = [bezpath, bezpathz, path, pathz, lpath, qpath, cpath,
|
||||
apath, line1, arc1, arc2, cub1, cub2, quad3, linez]
|
||||
|
||||
for path_orig in test_curves:
|
||||
def scale_a_point(pt, sx, sy=None, origin=0j):
|
||||
|
||||
if sy is None:
|
||||
sy = sx
|
||||
|
||||
zeta = pt - origin
|
||||
pt_vec = [[zeta.real],
|
||||
[zeta.imag],
|
||||
[1]]
|
||||
transform = [[sx, 0, origin.real],
|
||||
[0, sy, origin.imag]]
|
||||
|
||||
return complex(*np.dot(transform, pt_vec).ravel())
|
||||
|
||||
for curve in test_curves:
|
||||
# generate a random point and a random scaling
|
||||
t = np.random.rand()
|
||||
pt = curve.point(t)
|
||||
|
||||
# random diagonal transformation
|
||||
sx = 2 * np.random.rand()
|
||||
sy = 2 * np.random.rand()
|
||||
|
||||
# random origin
|
||||
origin = (10 * (np.random.rand() - 0.5) +
|
||||
10j * (np.random.rand() - 0.5))
|
||||
|
||||
# Note: `sx != sy` cases are not implemented for `Arc` objects
|
||||
has_arc = (isinstance(curve, Arc) or
|
||||
isinstance(curve, Path) and
|
||||
any(isinstance(seg, Arc) for seg in curve))
|
||||
|
||||
# case where no `sy` and no `origin` given
|
||||
ans = scale_a_point(pt, sx, None)
|
||||
self.assertAlmostEqual(ans, curve.scaled(sx).point(t))
|
||||
|
||||
# case where no `sy` and random `origin` given
|
||||
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
|
||||
|
||||
# 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))
|
||||
else:
|
||||
self.assertAlmostEqual(ans, curve.scaled(sx, sy).point(t))
|
||||
|
||||
# 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))
|
||||
else:
|
||||
self.assertAlmostEqual(ans,
|
||||
curve.scaled(sx, sy, origin).point(t))
|
||||
|
||||
# more tests for scalar (i.e. `sx == sy`) case
|
||||
for curve in test_curves:
|
||||
# scale by 2 around (100, 100)
|
||||
path_trns = path_orig.scaled(2.0, complex(100, 100))
|
||||
scaled_curve = curve.scaled(2.0, complex(100, 100))
|
||||
|
||||
# expected length
|
||||
len_orig = path_orig.length()
|
||||
len_trns = path_trns.length()
|
||||
len_orig = curve.length()
|
||||
len_trns = scaled_curve.length()
|
||||
self.assertAlmostEqual(len_orig * 2.0, len_trns)
|
||||
|
||||
# expected positions
|
||||
for T in linspace(0.0, 1.0, num=100):
|
||||
pt_orig = path_orig.point(T)
|
||||
pt_trns = path_trns.point(T)
|
||||
for T in np.linspace(0.0, 1.0, num=100):
|
||||
pt_orig = curve.point(T)
|
||||
pt_trns = scaled_curve.point(T)
|
||||
pt_xpct = (pt_orig - complex(100, 100)) * 2.0 + complex(100, 100)
|
||||
self.assertAlmostEqual(pt_xpct, pt_trns)
|
||||
|
||||
for path_orig in test_curves:
|
||||
|
||||
# scale by 0.3 around (0, -100)
|
||||
# the 'almost equal' test fails at the 7th decimal place for
|
||||
# some length and position tests here.
|
||||
path_trns = path_orig.scaled(0.3, complex(0, -100))
|
||||
scaled_curve = curve.scaled(0.3, complex(0, -100))
|
||||
|
||||
# expected length
|
||||
len_orig = path_orig.length()
|
||||
len_trns = path_trns.length()
|
||||
len_orig = curve.length()
|
||||
len_trns = scaled_curve.length()
|
||||
self.assertAlmostEqual(len_orig * 0.3, len_trns, delta=0.000001)
|
||||
|
||||
# expected positions
|
||||
for T in linspace(0.0, 1.0, num=100):
|
||||
pt_orig = path_orig.point(T)
|
||||
pt_trns = path_trns.point(T)
|
||||
for T in np.linspace(0.0, 1.0, num=100):
|
||||
pt_orig = curve.point(T)
|
||||
pt_trns = scaled_curve.point(T)
|
||||
pt_xpct = (pt_orig - complex(0, -100)) * 0.3 + complex(0, -100)
|
||||
self.assertAlmostEqual(pt_xpct, pt_trns, delta=0.000001)
|
||||
|
||||
|
||||
|
||||
|
||||
class Test_ilength(unittest.TestCase):
|
||||
# See svgpathtools.notes.inv_arclength.py for information on how these
|
||||
# test values were generated (using the .length() method).
|
||||
|
@ -1136,10 +1198,10 @@ class TestPathTools(unittest.TestCase):
|
|||
|
||||
# Case: Line
|
||||
pcoeffs = [(-1.7-2j), (6+2j)]
|
||||
p = poly1d(pcoeffs)
|
||||
p = np.poly1d(pcoeffs)
|
||||
correct_bpoints = [(6+2j), (4.3+0j)]
|
||||
|
||||
# Input poly1d object
|
||||
# Input np.poly1d object
|
||||
bez = poly2bez(p)
|
||||
bpoints = bez.bpoints()
|
||||
self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
|
||||
|
@ -1150,10 +1212,10 @@ class TestPathTools(unittest.TestCase):
|
|||
|
||||
# Case: Quadratic
|
||||
pcoeffs = [(29.5+15.5j), (-31-19j), (7.5+5.5j)]
|
||||
p = poly1d(pcoeffs)
|
||||
p = np.poly1d(pcoeffs)
|
||||
correct_bpoints = [(7.5+5.5j), (-8-4j), (6+2j)]
|
||||
|
||||
# Input poly1d object
|
||||
# Input np.poly1d object
|
||||
bez = poly2bez(p)
|
||||
bpoints = bez.bpoints()
|
||||
self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
|
||||
|
@ -1164,10 +1226,10 @@ class TestPathTools(unittest.TestCase):
|
|||
|
||||
# Case: Cubic
|
||||
pcoeffs = [(-18.5-12.5j), (34.5+16.5j), (-18-6j), (6+2j)]
|
||||
p = poly1d(pcoeffs)
|
||||
p = np.poly1d(pcoeffs)
|
||||
correct_bpoints = [(6+2j), 0j, (5.5+3.5j), (4+0j)]
|
||||
|
||||
# Input poly1d object
|
||||
# Input np.poly1d object
|
||||
bez = poly2bez(p)
|
||||
bpoints = bez.bpoints()
|
||||
self.assertAlmostEqual(distfcn(bpoints, correct_bpoints), 0)
|
||||
|
|
Loading…
Reference in New Issue