Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion svgpathtools/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ def to_complex(v):
invT = np.linalg.inv(tf[:2,:2])
D = reduce(np.matmul, [invT.T, Q, invT])

eigvals, eigvecs = np.linalg.eig(D)
eigvals, eigvecs = np.linalg.eigh(0.5*(D+D.T)) # symmetrized in case of floating point error; D already symmetric

rx = 1 / np.sqrt(eigvals[0])
ry = 1 / np.sqrt(eigvals[1])
Expand Down
52 changes: 51 additions & 1 deletion test/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
bpoints2bezier, closest_point_in_path, farthest_point_in_path,
is_bezier_segment, is_bezier_path, parse_path
)
from svgpathtools.path import bezier_radialrange
from svgpathtools.path import bezier_radialrange, transform

# An important note for those doing any debugging:
# ------------------------------------------------
Expand Down Expand Up @@ -724,6 +724,56 @@ def test_approx_cubic(self):
# Error less than 0.1% typically less than 0.001%
self.assertAlmostEqual(d, 0.0, delta=2)

def test_transform(self):
TOL = 1e-6

# Returns a 3x3 homogeneous rotation matrix of `angle_deg` degrees about the provided `center`
def R(angle_deg, center=(0, 0)):
radians = angle_deg * pi / 180
cos_a, sin_a = np.cos(radians), np.sin(radians)
x, y = center
print(angle_deg)

return np.array([
[cos_a, -sin_a, x - x * cos_a + y * sin_a],
[sin_a, cos_a, y - x * sin_a - y * cos_a],
[0, 0, 1]
])

# Define some vertices derived from a rounded rect
# <rect x="116.40955" y="202.60011"
# width="32" height="10"
# rx="5" ry="5"
# transform="rotate(-8)" />
rect_top_left = 116.40955+207.60011j
rect_top_right = 148.40955+207.60011j
rect_bottom_left = 121.40955+202.60011j
rect_bottom_right = 143.40955+212.60011j
radius = 5+5j

# Test Arcs w/ endpoints from the rectangle
test_paths = [
Arc(start=rect_bottom_right, radius=radius, rotation=0.0, large_arc=False, sweep=True, end=rect_top_right),
Arc(start=rect_top_right, radius=radius, rotation=0.0, large_arc=False, sweep=True, end=rect_bottom_right),
Arc(start=rect_bottom_left, radius=radius, rotation=0.0, large_arc=False, sweep=True, end=rect_top_left),
Arc(start=rect_top_left, radius=radius, rotation=0.0, large_arc=False, sweep=True, end=rect_bottom_left)
]

# Define several rotation matrices to transform these arcs (some with explicit centers)
xforms = [R(-152.62813), R(-48.851395), R(-45.851395), R(-40.851395),
R(-40.5511), R(-36.5511), R(-30), R(-26.5511), R(-25.851395),
R(-25),R(-23.5511), R(-20), R(-18), R(-15), R(-14), R(-12),
R(-8), R(-6), R(-5.8513953), R(0), R(5), R(10), R(12),
R(15), R(16.31965), R(18), R(20), R(25),
R(53.961757), R(60.737255), R(61.722145)]
xforms.extend([R(-20,(256,175)), R(12,(216,185)), R(15,(216,185))])

# Test transform function; rotation matrices should not affect lengths
for path in test_paths:
for tf in xforms:
transformed = transform(path, tf)
self.assertAlmostEqual(transformed.length(), path.length(), delta=TOL)


class TestPath(unittest.TestCase):

Expand Down
Loading