arc transform fixed (#98)

* arc transform fixed

* Update svgpathtools/path.py

Co-authored-by: Matthijs Kooijman <matthijs@stdin.nl>

* Fixed rotation bug in transformation of arcs

* Made compatible with python2.7

Changed the shorthand @ for np matrix multiplication to matmul

Co-authored-by: vrroom <vrroomc@github.com>
Co-authored-by: Matthijs Kooijman <matthijs@stdin.nl>
hashable-paths
Vrroom 2021-06-23 08:58:24 +05:30 committed by GitHub
parent 1e5bfb4252
commit baba1d18b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 8 deletions

Binary file not shown.

View File

@ -13,6 +13,7 @@ from warnings import warn
from operator import itemgetter
import numpy as np
from itertools import tee
from functools import reduce
# these imports were originally from math and cmath, now are from numpy
# in order to encourage code that generalizes to vector inputs
@ -288,7 +289,6 @@ def scale(curve, sx, sy=None, origin=0j):
raise TypeError("Input `curve` should be a Path, Line, "
"QuadraticBezier, CubicBezier, or Arc object.")
def transform(curve, tf):
"""Transforms the curve by the homogeneous transformation matrix tf"""
def to_point(p):
@ -310,13 +310,32 @@ def transform(curve, tf):
elif isinstance(curve, Arc):
new_start = to_complex(tf.dot(to_point(curve.start)))
new_end = to_complex(tf.dot(to_point(curve.end)))
new_radius = to_complex(tf.dot(to_vector(curve.radius)))
if tf[0][0] * tf[1][1] >= 0.0:
new_sweep = curve.sweep
# Based on https://math.stackexchange.com/questions/2349726/compute-the-major-and-minor-axis-of-an-ellipse-after-linearly-transforming-it
rx2 = curve.radius.real ** 2
ry2 = curve.radius.imag ** 2
Q = np.array([[1/rx2, 0], [0, 1/ry2]])
invT = np.linalg.inv(tf[:2,:2])
D = reduce(np.matmul, [invT.T, Q, invT])
eigvals, eigvecs = np.linalg.eig(D)
rx = 1 / np.sqrt(eigvals[0])
ry = 1 / np.sqrt(eigvals[1])
new_radius = complex(rx, ry)
xeigvec = eigvecs[:, 0]
rot = np.degrees(np.arccos(xeigvec[0]))
if new_radius.real == 0 or new_radius.imag == 0 :
return Line(new_start, new_end)
else :
new_sweep = not curve.sweep
return Arc(new_start, radius=new_radius, rotation=curve.rotation,
large_arc=curve.large_arc, sweep=new_sweep, end=new_end)
return Arc(new_start, radius=new_radius, rotation=curve.rotation + rot,
large_arc=curve.large_arc, sweep=curve.sweep, end=new_end,
autoscale_radius=False)
else:
raise TypeError("Input `curve` should be a Path, Line, "
"QuadraticBezier, CubicBezier, or Arc object.")