updated for new PyPI release

pull/55/head 1.3.3
Andy 2018-07-06 23:04:23 -04:00
parent fb916596e2
commit 8d5023939e
4 changed files with 109 additions and 21 deletions

View File

@ -18,7 +18,8 @@ except:
# Internal dependencies
from .bezier import (bezier_intersections, bezier_bounding_box, split_bezier,
bezier_by_line_intersections, polynomial2bezier)
bezier_by_line_intersections, polynomial2bezier,
bezier2polynomial)
from .misctools import BugException
from .polytools import rational_limit, polyroots, polyroots01, imag, real
@ -97,6 +98,21 @@ def bbox2path(xmin, xmax, ymin, ymax):
return Path(b, r, t.reversed(), l.reversed())
def polyline(*points):
"""Converts a list of points to a Path composed of lines connecting those
points (i.e. a linear spline or polyline). See also `polygon()`."""
return Path(*[Line(points[i], points[i+1])
for i in range(len(points) - 1)])
def polygon(*points):
"""Converts a list of points to a Path composed of lines connecting those
points, then closes the path by connecting the last point to the first.
See also `polyline()`."""
return Path(*[Line(points[i], points[(i + 1) % len(points)])
for i in range(len(points))])
# Conversion###################################################################
def bpoints2bezier(bpoints):
@ -154,7 +170,7 @@ def rotate(curve, degs, origin=None):
def transform(z):
return exp(1j*radians(degs))*(z - origin) + origin
if origin == None:
if origin is None:
if isinstance(curve, Arc):
origin = curve.center
else:
@ -192,6 +208,53 @@ def translate(curve, z0):
"QuadraticBezier, CubicBezier, or Arc object.")
def scale(curve, sx, sy=None, origin=0j):
"""Scales `curve`, about `origin`, by diagonal matrix `[[sx,0],[0,sy]]`.
Notes:
------
* If `sy` is not specified, it is assumed to be equal to `sx` and
a scalar transformation of `curve` about `origin` will be returned.
I.e.
scale(curve, sx, origin).point(t) ==
((curve.point(t) - origin) * sx) + origin
"""
if sy is None:
isy = 1j*sx
else:
isy = 1j*sy
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 scale_bezier(curve)
elif isinstance(curve, Arc):
if sy is None or sy == sx:
return Arc(start=sx*(curve.start - origin) + origin,
radius=sx*curve.radius,
rotation=curve.rotation,
large_arc=curve.large_arc,
sweep=curve.sweep,
end=sx*(curve.end - origin) + origin)
else:
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.")
def bezier_unit_tangent(seg, t):
"""Returns the unit tangent of the segment at t.
@ -557,7 +620,7 @@ class Line(object):
d = (other_seg.start.imag, other_seg.end.imag)
denom = ((a[1] - a[0])*(d[0] - d[1]) -
(b[1] - b[0])*(c[0] - c[1]))
if denom == 0:
if np.isclose(denom, 0):
return []
t1 = (c[0]*(b[0] - d[1]) -
c[1]*(b[0] - d[0]) -
@ -622,6 +685,10 @@ class Line(object):
that self.translated(z0).point(t) = self.point(t) + z0 for any t."""
return translate(self, z0)
def scaled(self, sx, sy=None, origin=0j):
"""Scale transform. See `scale` function for further explanation."""
return scale(self, sx=sx, sy=sy, origin=origin)
class QuadraticBezier(object):
# For compatibility with old pickle files.
@ -866,6 +933,10 @@ class QuadraticBezier(object):
that self.translated(z0).point(t) = self.point(t) + z0 for any t."""
return translate(self, z0)
def scaled(self, sx, sy=None, origin=0j):
"""Scale transform. See `scale` function for further explanation."""
return scale(self, sx=sx, sy=sy, origin=origin)
class CubicBezier(object):
# For compatibility with old pickle files.
@ -1106,6 +1177,10 @@ class CubicBezier(object):
that self.translated(z0).point(t) = self.point(t) + z0 for any t."""
return translate(self, z0)
def scaled(self, sx, sy=None, origin=0j):
"""Scale transform. See `scale` function for further explanation."""
return scale(self, sx=sx, sy=sy, origin=origin)
class Arc(object):
def __init__(self, start, radius, rotation, large_arc, sweep, end,
@ -1285,10 +1360,13 @@ class Arc(object):
# delta is the angular distance of the arc (w.r.t the circle)
# theta is the angle between the positive x'-axis and the start point
# on the circle
u1_real_rounded = u1.real
if u1.real > 1 or u1.real < -1:
u1_real_rounded = round(u1.real)
if u1.imag > 0:
self.theta = degrees(acos(u1.real))
self.theta = degrees(acos(u1_real_rounded))
elif u1.imag < 0:
self.theta = -degrees(acos(u1.real))
self.theta = -degrees(acos(u1_real_rounded))
else:
if u1.real > 0: # start is on pos u_x axis
self.theta = 0
@ -1668,6 +1746,10 @@ class Arc(object):
that self.translated(z0).point(t) = self.point(t) + z0 for any t."""
return translate(self, z0)
def scaled(self, sx, sy=None, origin=0j):
"""Scale transform. See `scale` function for further explanation."""
return scale(self, sx=sx, sy=sy, origin=origin)
def is_bezier_segment(x):
return (isinstance(x, Line) or
@ -1967,9 +2049,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:
@ -2042,15 +2124,15 @@ class Path(MutableSequence):
if np.isclose(t, 0) and (seg_idx != 0 or self.end==self.start):
previous_seg_in_path = self._segments[
(seg_idx - 1) % len(self._segments)]
if not seg.joins_smoothl_with(previous_seg_in_path):
if not seg.joins_smoothly_with(previous_seg_in_path):
return float('inf')
elif np.isclose(t, 1) and (seg_idx != len(self) - 1 or self.end==self.start):
next_seg_in_path = self._segments[
(seg_idx + 1) % len(self._segments)]
if not next_seg_in_path.joins_smoothly_with(seg):
return float('inf')
dz = self.derivative(t)
ddz = self.derivative(t, n=2)
dz = self.derivative(T)
ddz = self.derivative(T, n=2)
dx, dy = dz.real, dz.imag
ddx, ddy = ddz.real, ddz.imag
return abs(dx*ddy - dy*ddx)/(dx*dx + dy*dy)**1.5
@ -2136,7 +2218,13 @@ class Path(MutableSequence):
def cropped(self, T0, T1):
"""returns a cropped copy of the path."""
assert 0 <= T0 <= 1 and 0 <= T1<= 1
assert T0 != T1
assert not (T0 == 1 and T1 == 0)
if T0 == 1 and 0 < T1 < 1 and self.isclosed():
return self.cropped(0, T1)
if T1 == 1:
seg1 = self[-1]
t_seg1 = 1
@ -2171,7 +2259,7 @@ class Path(MutableSequence):
# T1<T0 must cross discontinuity case
if T1 < T0:
if self.isclosed():
if not self.isclosed():
raise ValueError("This path is not closed, thus T0 must "
"be less than T1.")
else:
@ -2189,7 +2277,6 @@ class Path(MutableSequence):
new_path.append(seg1.cropped(0, t_seg1))
return new_path
def radialrange(self, origin, return_all_global_extrema=False):
"""returns the tuples (d_min, t_min, idx_min), (d_max, t_max, idx_max)
which minimize and maximize, respectively, the distance
@ -2218,3 +2305,7 @@ class Path(MutableSequence):
"""Returns a copy of self shifted by the complex quantity `z0` such
that self.translated(z0).point(t) = self.point(t) + z0 for any t."""
return translate(self, z0)
def scaled(self, sx, sy=None, origin=0j):
"""Scale transform. See `scale` function for further explanation."""
return scale(self, sx=sx, sy=sy, origin=origin)

View File

@ -3,7 +3,7 @@ import codecs
import os
VERSION = '1.3.2'
VERSION = '1.3.3'
AUTHOR_NAME = 'Andy Port'
AUTHOR_EMAIL = 'AndyAPort@gmail.com'

View File

@ -1,13 +1,12 @@
Metadata-Version: 1.1
Name: svgpathtools
Version: 1.3.2
Version: 1.3.3
Summary: A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves.
Home-page: https://github.com/mathandy/svgpathtools
Author: Andy Port
Author-email: AndyAPort@gmail.com
License: MIT
Download-URL: http://github.com/mathandy/svgpathtools/tarball/1.3.2
Description-Content-Type: UNKNOWN
Download-URL: http://github.com/mathandy/svgpathtools/tarball/1.3.3
Description:
svgpathtools
============
@ -595,9 +594,8 @@ Description:
of the 'parallel' offset curve."""
nls = []
for seg in path:
ct = 1
for k in range(steps):
t = k / steps
t = k / float(steps)
offset_vector = offset_distance * seg.normal(t)
nl = Line(seg.point(t), seg.point(t) + offset_vector)
nls.append(nl)

View File

@ -3,7 +3,6 @@ LICENSE2.txt
MANIFEST.in
README.rst
decorated_ellipse.svg
disvg_output.svg
offset_curves.svg
output1.svg
output2.svg
@ -21,7 +20,7 @@ svgpathtools/path.py
svgpathtools/paths2svg.py
svgpathtools/polytools.py
svgpathtools/smoothing.py
svgpathtools/svg2paths.py
svgpathtools/svg_to_paths.py
svgpathtools.egg-info/PKG-INFO
svgpathtools.egg-info/SOURCES.txt
svgpathtools.egg-info/dependency_links.txt