diff --git a/build/lib/svgpathtools/bezier.py b/build/lib/svgpathtools/bezier.py index b910863..1919e68 100644 --- a/build/lib/svgpathtools/bezier.py +++ b/build/lib/svgpathtools/bezier.py @@ -286,9 +286,9 @@ def bezier_intersections(bez1, bez2, longer_length, tol=1e-8, tol_deC=1e-8): tol - is the smallest distance that two solutions can differ by and still be considered distinct solutions. OUTPUT: a list of tuples (t,s) in [0,1]x[0,1] such that - bezier_point(cubs[0],t) - bezier_point(cubs[1],s) < tol_deC + abs(bezier_point(bez1[0],t) - bezier_point(bez2[1],s)) < tol_deC Note: This will return exactly one such tuple for each intersection - (assuming tol_deC is small enough)""" + (assuming tol_deC is small enough).""" maxits = int(ceil(1-log(tol_deC/longer_length)/log(2))) pair_list = [BPair(bez1, bez2, 0.5, 0.5)] intersection_list = [] diff --git a/build/lib/svgpathtools/path.py b/build/lib/svgpathtools/path.py index d026e3d..1484b5a 100644 --- a/build/lib/svgpathtools/path.py +++ b/build/lib/svgpathtools/path.py @@ -568,9 +568,11 @@ class Line(object): return [(t1, t2)] return [] elif isinstance(other_seg, QuadraticBezier): - return bezier_by_line_intersections(other_seg, self) + t2t1s = bezier_by_line_intersections(other_seg, self) + return [(t1, t2) for t2, t1 in t2t1s] elif isinstance(other_seg, CubicBezier): - return bezier_by_line_intersections(other_seg, self) + t2t1s = bezier_by_line_intersections(other_seg, self) + return [(t1, t2) for t2, t1 in t2t1s] elif isinstance(other_seg, Arc): t2t1s = other_seg.intersect(self) return [(t1, t2) for t2, t1 in t2t1s] @@ -820,8 +822,8 @@ class QuadraticBezier(object): longer_length=longer_length, tol=tol, tol_deC=tol) elif isinstance(other_seg, Arc): - t1 = other_seg.intersect(self) - return t1, t2 + t2t1s = other_seg.intersect(self) + return [(t1, t2) for t2, t1 in t2t1s] elif isinstance(other_seg, Path): raise TypeError( "other_seg must be a path segment, not a Path object, use " @@ -1113,7 +1115,8 @@ class Arc(object): Parameters ---------- start : complex - The start point of the large_arc. + The start point of the curve. Note: `start` and `end` cannot be the + same. To make a full ellipse or circle, use two `Arc` objects. radius : complex rx + 1j*ry, where rx and ry are the radii of the ellipse (also known as its semi-major and semi-minor axes, or vice-versa or if @@ -1128,43 +1131,36 @@ class Arc(object): This is the CCW angle (in degrees) from the positive x-axis of the current coordinate system to the x-axis of the ellipse. large_arc : bool - This is the large_arc flag. Given two points on an ellipse, - there are two elliptical arcs connecting those points, the first - going the short way around the ellipse, and the second going the - long way around the ellipse. If large_arc is 0, the shorter - elliptical large_arc will be used. If large_arc is 1, then longer - elliptical will be used. - In other words, it should be 0 for arcs spanning less than or - equal to 180 degrees and 1 for arcs spanning greater than 180 + Given two points on an ellipse, there are two elliptical arcs + connecting those points, the first going the short way around the + ellipse, and the second going the long way around the ellipse. If + `large_arc == False`, the shorter elliptical arc will be used. If + `large_arc == True`, then longer elliptical will be used. + In other words, `large_arc` should be 0 for arcs spanning less than + or equal to 180 degrees and 1 for arcs spanning greater than 180 degrees. sweep : bool - This is the sweep flag. For any acceptable parameters start, end, - rotation, and radius, there are two ellipses with the given major - and minor axes (radii) which connect start and end. One which - connects them in a CCW fashion and one which connected them in a - CW fashion. If sweep is 1, the CCW ellipse will be used. If - sweep is 0, the CW ellipse will be used. - + For any acceptable parameters `start`, `end`, `rotation`, and + `radius`, there are two ellipses with the given major and minor + axes (radii) which connect `start` and `end`. One which connects + them in a CCW fashion and one which connected them in a CW + fashion. If `sweep == True`, the CCW ellipse will be used. If + `sweep == False`, the CW ellipse will be used. See note on curve + orientation below. end : complex - The end point of the large_arc (must be distinct from start). - - Note on CW and CCW: The notions of CW and CCW are reversed in some - sense when viewing SVGs (as the y coordinate starts at the top of the - image and increases towards the bottom). - - Derived Parameters - ------------------ - self._parameterize() sets self.center, self.theta and self.delta - for use in self.point() and other methods. If - autoscale_radius == True, then this will also scale self.radius in the - case that no ellipse exists with the given parameters (see usage - below). + The end point of the curve. Note: `start` and `end` cannot be the + same. To make a full ellipse or circle, use two `Arc` objects. + autoscale_radius : bool + If `autoscale_radius == True`, then will also scale `self.radius` + in the case that no ellipse exists with the input parameters + (see inline comments for further explanation). + Derived Parameters/Attributes + ----------------------------- self.theta : float This is the phase (in degrees) of self.u1transform(self.start). It is $\theta_1$ in the official documentation and ranges from -180 to 180. - self.delta : float This is the angular distance (in degrees) between the start and end of the arc after the arc has been sent to the unit circle @@ -1172,10 +1168,23 @@ class Arc(object): It is $\Delta\theta$ in the official documentation and ranges from -360 to 360; being positive when the arc travels CCW and negative otherwise (i.e. is positive/negative when sweep == True/False). - self.center : complex This is the center of the arc's ellipse. + self.phi : float + The arc's rotation in radians, i.e. `radians(self.rotation)`. + self.rot_matrix : complex + Equal to `exp(1j * self.phi)` which is also equal to + `cos(self.phi) + 1j*sin(self.phi)`. + + + Note on curve orientation (CW vs CCW) + ------------------------------------- + The notions of clockwise (CW) and counter-clockwise (CCW) are reversed + in some sense when viewing SVGs (as the y coordinate starts at the top + of the image and increases towards the bottom). """ + assert start != end + assert radius.real != 0 and radius.imag != 0 self.start = start self.radius = abs(radius.real) + 1j*abs(radius.imag) @@ -1212,10 +1221,6 @@ class Arc(object): return not self == other def _parameterize(self): - # start cannot be the same as end as the ellipse would - # not be well defined - assert self.start != self.end - # See http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes # my notation roughly follows theirs rx = self.radius.real @@ -1497,7 +1502,12 @@ class Arc(object): returns a list of tuples (t1, t2) such that self.point(t1) == other_seg.point(t2). Note: This will fail if the two segments coincide for more than a - finite collection of points.""" + finite collection of points. + + Note: Arc related intersections are only partially supported, i.e. are + only half-heartedly implemented and not well tested. Please feel free + to let me know if you're interested in such a feature -- or even better + please submit an implementation if you want to code one.""" if is_bezier_segment(other_seg): u1poly = self.u1transform(other_seg.poly()) @@ -1506,6 +1516,7 @@ class Arc(object): t1s = [self.phase2t(phase(u1poly(t2))) for t2 in t2s] return zip(t1s, t2s) elif isinstance(other_seg, Arc): + assert other_seg != self # This could be made explicit to increase efficiency longer_length = max(self.length(), other_seg.length()) inters = bezier_intersections(self, other_seg, diff --git a/build/lib/svgpathtools/paths2svg.py b/build/lib/svgpathtools/paths2svg.py index a4ae48b..d09ff57 100644 --- a/build/lib/svgpathtools/paths2svg.py +++ b/build/lib/svgpathtools/paths2svg.py @@ -152,7 +152,9 @@ def disvg(paths=None, colors=None, paths. Note: This will override any other conflicting settings. :param svg_attributes - a dictionary of attributes for output svg. - Note: This will override any other conflicting settings. + Note 1: This will override any other conflicting settings. + Note 2: Setting `svg_attributes={'debug': False}` may result in a + significant increase in speed. NOTES: -The unit of length here is assumed to be pixels in all variables. diff --git a/dist/svgpathtools-1.2.6-py2.py3-none-any.whl b/dist/svgpathtools-1.2.6-py2.py3-none-any.whl new file mode 100644 index 0000000..1c129e0 Binary files /dev/null and b/dist/svgpathtools-1.2.6-py2.py3-none-any.whl differ diff --git a/dist/svgpathtools-1.2.6.tar.gz b/dist/svgpathtools-1.2.6.tar.gz new file mode 100644 index 0000000..8ad404b Binary files /dev/null and b/dist/svgpathtools-1.2.6.tar.gz differ diff --git a/svgpathtools.egg-info/PKG-INFO b/svgpathtools.egg-info/PKG-INFO index 823a378..2047ffe 100644 --- a/svgpathtools.egg-info/PKG-INFO +++ b/svgpathtools.egg-info/PKG-INFO @@ -1,12 +1,12 @@ Metadata-Version: 1.1 Name: svgpathtools -Version: 1.2.5 +Version: 1.2.6 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.2.5 +Download-URL: http://github.com/mathandy/svgpathtools/tarball/1.2.6 Description: svgpathtools ============