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
parent
1e5bfb4252
commit
baba1d18b2
Binary file not shown.
|
@ -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.")
|
||||
|
|
Loading…
Reference in New Issue