Updated with master
commit
30d511577b
|
@ -8,8 +8,8 @@ to make it easy to contribute.
|
|||
We need better automated testing coverage. Please, submit unittests! See the
|
||||
Testing Style section below for info.
|
||||
|
||||
Here's a list of things that need (more) unittests
|
||||
* OK, well... maybe you could help by filling out this list
|
||||
Here's a list of things that need (more) unittests:
|
||||
* TBA (feel free to help)
|
||||
|
||||
## Submitting Bugs
|
||||
If you find a bug, please submit an issue along with an **easily reproducible
|
||||
|
|
|
@ -766,7 +766,7 @@
|
|||
" for distances in offset_distances:\n",
|
||||
" offset_paths.append(offset_curve(path, distances))\n",
|
||||
"\n",
|
||||
"# Note: This will take a few moments\n",
|
||||
"# Let's take a look\n",
|
||||
"wsvg(paths + offset_paths, 'g'*len(paths) + 'r'*len(offset_paths), filename='offset_curves.svg')"
|
||||
]
|
||||
},
|
||||
|
@ -830,7 +830,7 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.13"
|
||||
"version": "2.7.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
|
|
@ -585,9 +585,8 @@ curve <https://en.wikipedia.org/wiki/Parallel_curve>`__ for a few paths.
|
|||
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)
|
||||
|
|
Binary file not shown.
Binary file not shown.
4
setup.py
4
setup.py
|
@ -3,7 +3,7 @@ import codecs
|
|||
import os
|
||||
|
||||
|
||||
VERSION = '1.3.2beta'
|
||||
VERSION = '1.3.2'
|
||||
AUTHOR_NAME = 'Andy Port'
|
||||
AUTHOR_EMAIL = 'AndyAPort@gmail.com'
|
||||
|
||||
|
@ -31,7 +31,7 @@ setup(name='svgpathtools',
|
|||
download_url = 'http://github.com/mathandy/svgpathtools/tarball/'+VERSION,
|
||||
license='MIT',
|
||||
|
||||
# install_requires=['numpy', 'svgwrite'],
|
||||
install_requires=['numpy', 'svgwrite'],
|
||||
platforms="OS Independent",
|
||||
# test_suite='tests',
|
||||
requires=['numpy', 'svgwrite'],
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
Metadata-Version: 1.1
|
||||
Name: svgpathtools
|
||||
Version: 1.3.1
|
||||
Version: 1.3.2
|
||||
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.1
|
||||
Description: svgpathtools
|
||||
Download-URL: http://github.com/mathandy/svgpathtools/tarball/1.3.2
|
||||
Description-Content-Type: UNKNOWN
|
||||
Description:
|
||||
svgpathtools
|
||||
============
|
||||
|
||||
svgpathtools is a collection of tools for manipulating and analyzing SVG
|
||||
|
@ -46,11 +48,6 @@ Description: svgpathtools
|
|||
- compute **inverse arc length**
|
||||
- convert RGB color tuples to hexadecimal color strings and back
|
||||
|
||||
Note on Python 3
|
||||
----------------
|
||||
While I am hopeful that this package entirely works with Python 3, it was born from a larger project coded in Python 2 and has not been thoroughly tested in
|
||||
Python 3. Please let me know if you find any incompatibilities.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
|
@ -94,8 +91,6 @@ Description: svgpathtools
|
|||
module <https://github.com/regebro/svg.path>`__. Interested svg.path
|
||||
users should see the compatibility notes at bottom of this readme.
|
||||
|
||||
Also, a big thanks to the author(s) of `A Primer on Bézier Curves <http://pomax.github.io/bezierinfo/>`_, an outstanding resource for learning about Bézier curves and Bézier curve-related algorithms.
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
|
@ -126,11 +121,11 @@ Description: svgpathtools
|
|||
on discontinuous Path objects. A simple workaround is provided, however,
|
||||
by the ``Path.continuous_subpaths()`` method. `↩ <#a1>`__
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from __future__ import division, print_function
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Coordinates are given as points in the complex plane
|
||||
from svgpathtools import Path, Line, QuadraticBezier, CubicBezier, Arc
|
||||
|
@ -167,7 +162,7 @@ Description: svgpathtools
|
|||
list. So segments can **append**\ ed, **insert**\ ed, set by index,
|
||||
**del**\ eted, **enumerate**\ d, **slice**\ d out, etc.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Let's append another to the end of it
|
||||
path.append(CubicBezier(250+350j, 275+350j, 250+225j, 200+100j))
|
||||
|
@ -234,7 +229,7 @@ Description: svgpathtools
|
|||
| Note: Line, Polyline, Polygon, and Path SVG elements can all be
|
||||
converted to Path objects using this function.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Read SVG into a list of path objects and list of dictionaries of attributes
|
||||
from svgpathtools import svg2paths, wsvg
|
||||
|
@ -271,7 +266,7 @@ Description: svgpathtools
|
|||
automatically attempt to open the created svg file in your default SVG
|
||||
viewer.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Let's make a new SVG that's identical to the first
|
||||
wsvg(paths, attributes=attributes, svg_attributes=svg_attributes, filename='output1.svg')
|
||||
|
@ -303,7 +298,7 @@ Description: svgpathtools
|
|||
that ``path.point(T)=path[k].point(t)``.
|
||||
| There is also a ``Path.t2T()`` method to solve the inverse problem.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Example:
|
||||
|
||||
|
@ -333,11 +328,11 @@ Description: svgpathtools
|
|||
True
|
||||
|
||||
|
||||
Tangent vectors and Bezier curves as numpy polynomial objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Bezier curves as NumPy polynomial objects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
| Another great way to work with the parameterizations for Line,
|
||||
QuadraticBezier, and CubicBezier objects is to convert them to
|
||||
| Another great way to work with the parameterizations for ``Line``,
|
||||
``QuadraticBezier``, and ``CubicBezier`` objects is to convert them to
|
||||
``numpy.poly1d`` objects. This is done easily using the
|
||||
``Line.poly()``, ``QuadraticBezier.poly()`` and ``CubicBezier.poly()``
|
||||
methods.
|
||||
|
@ -369,9 +364,10 @@ Description: svgpathtools
|
|||
\end{bmatrix}
|
||||
\begin{bmatrix}P_0\\P_1\\P_2\\P_3\end{bmatrix}
|
||||
|
||||
QuadraticBezier.poly() and Line.poly() are defined similarly.
|
||||
``QuadraticBezier.poly()`` and ``Line.poly()`` are `defined
|
||||
similarly <https://en.wikipedia.org/wiki/B%C3%A9zier_curve#General_definition>`__.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Example:
|
||||
b = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j)
|
||||
|
@ -401,15 +397,25 @@ Description: svgpathtools
|
|||
(-400 + -100j) t + (900 + 300j) t - 600 t + (300 + 100j)
|
||||
|
||||
|
||||
To illustrate the awesomeness of being able to convert our Bezier curve
|
||||
objects to numpy.poly1d objects and back, lets compute the unit tangent
|
||||
vector of the above CubicBezier object, b, at t=0.5 in four different
|
||||
ways.
|
||||
The ability to convert between Bezier objects to NumPy polynomial
|
||||
objects is very useful. For starters, we can take turn a list of Bézier
|
||||
segments into a NumPy array
|
||||
|
||||
Tangent vectors (and more on polynomials)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Numpy Array operations on Bézier path segments
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
`Example available
|
||||
here <https://github.com/mathandy/svgpathtools/blob/master/examples/compute-many-points-quickly-using-numpy-arrays.py>`__
|
||||
|
||||
To further illustrate the power of being able to convert our Bezier
|
||||
curve objects to numpy.poly1d objects and back, lets compute the unit
|
||||
tangent vector of the above CubicBezier object, b, at t=0.5 in four
|
||||
different ways.
|
||||
|
||||
Tangent vectors (and more on NumPy polynomials)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
t = 0.5
|
||||
### Method 1: the easy way
|
||||
|
@ -451,7 +457,7 @@ Description: svgpathtools
|
|||
Translations (shifts), reversing orientation, and normal vectors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Speaking of tangents, let's add a normal vector to the picture
|
||||
n = b.normal(t)
|
||||
|
@ -481,7 +487,7 @@ Description: svgpathtools
|
|||
Rotations and Translations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Let's take a Line and an Arc and make some pictures
|
||||
top_half = Arc(start=-1, radius=1+2j, rotation=0, large_arc=1, sweep=1, end=1)
|
||||
|
@ -514,7 +520,7 @@ Description: svgpathtools
|
|||
``CubicBezier.length()``, and ``Arc.length()`` methods, as well as the
|
||||
related inverse arc length methods ``.ilength()`` function to do this.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# First we'll load the path data from the file test.svg
|
||||
paths, attributes = svg2paths('test.svg')
|
||||
|
@ -556,7 +562,7 @@ Description: svgpathtools
|
|||
Intersections between Bezier curves
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# Let's find all intersections between redpath and the other
|
||||
redpath = paths[0]
|
||||
|
@ -580,7 +586,7 @@ Description: svgpathtools
|
|||
Here we'll find the `offset
|
||||
curve <https://en.wikipedia.org/wiki/Parallel_curve>`__ for a few paths.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from svgpathtools import parse_path, Line, Path, wsvg
|
||||
def offset_curve(path, offset_distance, steps=1000):
|
||||
|
@ -638,6 +644,7 @@ Description: svgpathtools
|
|||
|
||||
This module is under a MIT License.
|
||||
|
||||
|
||||
Keywords: svg,svg path,svg.path,bezier,parse svg path,display svg
|
||||
Platform: OS Independent
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
|
|
|
@ -15,23 +15,26 @@ test.svg
|
|||
vectorframes.svg
|
||||
svgpathtools/__init__.py
|
||||
svgpathtools/bezier.py
|
||||
svgpathtools/directional_field.py
|
||||
svgpathtools/misctools.py
|
||||
svgpathtools/parser.py
|
||||
svgpathtools/path.py
|
||||
svgpathtools/paths2svg.py
|
||||
svgpathtools/pathtools.py
|
||||
svgpathtools/polytools.py
|
||||
svgpathtools/smoothing.py
|
||||
svgpathtools/svg2paths.py
|
||||
svgpathtools.egg-info/PKG-INFO
|
||||
svgpathtools.egg-info/SOURCES.txt
|
||||
svgpathtools.egg-info/dependency_links.txt
|
||||
svgpathtools.egg-info/requires.txt
|
||||
svgpathtools.egg-info/top_level.txt
|
||||
test/circle.svg
|
||||
test/ellipse.svg
|
||||
test/polygons.svg
|
||||
test/rects.svg
|
||||
test/test.svg
|
||||
test/test_bezier.py
|
||||
test/test_generation.py
|
||||
test/test_parsing.py
|
||||
test/test_path.py
|
||||
test/test_pathtools.py
|
||||
test/test_polytools.py
|
||||
test/test_polytools.py
|
||||
test/test_svg2paths.py
|
|
@ -0,0 +1,2 @@
|
|||
numpy
|
||||
svgwrite
|
|
@ -572,7 +572,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]) -
|
||||
|
@ -1300,10 +1300,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
|
||||
|
@ -2060,7 +2063,7 @@ 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[
|
||||
|
|
|
@ -88,7 +88,7 @@ def disvg(paths=None, colors=None,
|
|||
openinbrowser=True, timestamp=False,
|
||||
margin_size=0.1, mindim=600, dimensions=None,
|
||||
viewbox=None, text=None, text_path=None, font_size=None,
|
||||
attributes=None, svg_attributes=None):
|
||||
attributes=None, svg_attributes=None, svgwrite_debug=False):
|
||||
"""Takes in a list of paths and creates an SVG file containing said paths.
|
||||
REQUIRED INPUTS:
|
||||
:param paths - a list of paths
|
||||
|
@ -152,14 +152,22 @@ 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 1: This will override any other conflicting settings.
|
||||
Note 2: Setting `svg_attributes={'debug': False}` may result in a
|
||||
significant increase in speed.
|
||||
|
||||
:param svgwrite_debug - This parameter turns on/off `svgwrite`'s
|
||||
debugging mode. By default svgwrite_debug=False. This increases
|
||||
speed and also prevents `svgwrite` from raising of an error when not
|
||||
all `svg_attributes` key-value pairs are understood.
|
||||
|
||||
NOTES:
|
||||
-The unit of length here is assumed to be pixels in all variables.
|
||||
* The `svg_attributes` parameter will override any other conflicting
|
||||
settings.
|
||||
|
||||
-If this function is used multiple times in quick succession to
|
||||
* Any `extra` parameters that `svgwrite.Drawing()` accepts can be
|
||||
controlled by passing them in through `svg_attributes`.
|
||||
|
||||
* The unit of length here is assumed to be pixels in all variables.
|
||||
|
||||
* If this function is used multiple times in quick succession to
|
||||
display multiple SVGs (all using the default filename), the
|
||||
svgviewer/browser will likely fail to load some of the SVGs in time.
|
||||
To fix this, use the timestamp attribute, or give the files unique
|
||||
|
@ -277,12 +285,15 @@ def disvg(paths=None, colors=None,
|
|||
szy = str(mindim) + 'px'
|
||||
|
||||
# Create an SVG file
|
||||
if svg_attributes:
|
||||
if svg_attributes is not None:
|
||||
szx = svg_attributes.get("width", szx)
|
||||
szy = svg_attributes.get("height", szy)
|
||||
dwg = Drawing(filename=filename, size=(szx, szy), **svg_attributes)
|
||||
debug = svg_attributes.get("debug", svgwrite_debug)
|
||||
dwg = Drawing(filename=filename, size=(szx, szy), debug=debug,
|
||||
**svg_attributes)
|
||||
else:
|
||||
dwg = Drawing(filename=filename, size=(szx, szy), viewBox=viewbox)
|
||||
dwg = Drawing(filename=filename, size=(szx, szy), debug=svgwrite_debug,
|
||||
viewBox=viewbox)
|
||||
|
||||
# add paths
|
||||
if paths:
|
||||
|
@ -377,7 +388,7 @@ def wsvg(paths=None, colors=None,
|
|||
openinbrowser=False, timestamp=False,
|
||||
margin_size=0.1, mindim=600, dimensions=None,
|
||||
viewbox=None, text=None, text_path=None, font_size=None,
|
||||
attributes=None, svg_attributes=None):
|
||||
attributes=None, svg_attributes=None, svgwrite_debug=False):
|
||||
"""Convenience function; identical to disvg() except that
|
||||
openinbrowser=False by default. See disvg() docstring for more info."""
|
||||
disvg(paths, colors=colors, filename=filename,
|
||||
|
@ -386,4 +397,5 @@ def wsvg(paths=None, colors=None,
|
|||
openinbrowser=openinbrowser, timestamp=timestamp,
|
||||
margin_size=margin_size, mindim=mindim, dimensions=dimensions,
|
||||
viewbox=viewbox, text=text, text_path=text_path, font_size=font_size,
|
||||
attributes=attributes, svg_attributes=svg_attributes)
|
||||
attributes=attributes, svg_attributes=svg_attributes,
|
||||
svgwrite_debug=svgwrite_debug)
|
||||
|
|
|
@ -10,6 +10,13 @@ import xml.etree.cElementTree as etree
|
|||
from .parser import parse_path
|
||||
|
||||
|
||||
COORD_PAIR_TMPLT = re.compile(
|
||||
r'([\+-]?\d*[\.\d]\d*[eE][\+-]?\d+|[\+-]?\d*[\.\d]\d*)' +
|
||||
r'(?:\s*,\s*|\s+|(?=-))' +
|
||||
r'([\+-]?\d*[\.\d]\d*[eE][\+-]?\d+|[\+-]?\d*[\.\d]\d*)'
|
||||
)
|
||||
|
||||
|
||||
def ellipse2pathd(ellipse):
|
||||
"""converts the parameters from an ellipse or a circle to a string
|
||||
for a Path object d-attribute"""
|
||||
|
@ -37,23 +44,21 @@ def ellipse2pathd(ellipse):
|
|||
return d
|
||||
|
||||
|
||||
def polyline2pathd(polyline_d):
|
||||
"""converts the string from a polyline points-attribute to a string
|
||||
for a Path object d-attribute"""
|
||||
try:
|
||||
points = polyline_d['points']
|
||||
except:
|
||||
pass
|
||||
points = polyline_d.replace(', ', ',')
|
||||
points = points.replace(' ,', ',')
|
||||
points = points.split()
|
||||
def polyline2pathd(polyline_d, is_polygon=False):
|
||||
"""converts the string from a polyline points-attribute to a string for a
|
||||
Path object d-attribute"""
|
||||
points = COORD_PAIR_TMPLT.findall(polyline_d)
|
||||
closed = (float(points[0][0]) == float(points[-1][0]) and
|
||||
float(points[0][1]) == float(points[-1][1]))
|
||||
|
||||
closed = points[0] == points[-1]
|
||||
# The `parse_path` call ignores redundant 'z' (closure) commands
|
||||
# e.g. `parse_path('M0 0L100 100Z') == parse_path('M0 0L100 100L0 0Z')`
|
||||
# This check ensures that an n-point polygon is converted to an n-Line path.
|
||||
if is_polygon and closed:
|
||||
points.append(points[0])
|
||||
|
||||
d = 'M' + points.pop(0).replace(',', ' ')
|
||||
for p in points:
|
||||
d += 'L' + p.replace(',', ' ')
|
||||
if closed:
|
||||
d = 'M' + 'L'.join('{0} {1}'.format(x,y) for x,y in points)
|
||||
if is_polygon or closed:
|
||||
d += 'z'
|
||||
return d
|
||||
|
||||
|
@ -62,31 +67,8 @@ def polygon2pathd(polyline_d):
|
|||
"""converts the string from a polygon points-attribute to a string
|
||||
for a Path object d-attribute.
|
||||
Note: For a polygon made from n points, the resulting path will be
|
||||
composed of n lines (even if some of these lines have length zero).
|
||||
"""
|
||||
try:
|
||||
points = polyline_d['points']
|
||||
except:
|
||||
pass
|
||||
points = polyline_d.replace(', ', ',')
|
||||
points = points.replace(' ,', ',')
|
||||
points = points.split()
|
||||
|
||||
reduntantly_closed = points[0] == points[-1]
|
||||
|
||||
d = 'M' + points[0].replace(',', ' ')
|
||||
for p in points[1:]:
|
||||
d += 'L' + p.replace(',', ' ')
|
||||
|
||||
# The `parse_path` call ignores redundant 'z' (closure) commands
|
||||
# e.g.
|
||||
# `parse_path('M0 0L100 100Z') == parse_path('M0 0L100 100L0 0Z')`
|
||||
# This check ensures that an n-point polygon is converted to an
|
||||
# n-Line path.
|
||||
if reduntantly_closed:
|
||||
d += 'L' + points[0].replace(',', ' ')
|
||||
|
||||
return d + 'z'
|
||||
composed of n lines (even if some of these lines have length zero)."""
|
||||
return polyline2pathd(polyline_d, True)
|
||||
|
||||
|
||||
def rect2pathd(rect):
|
||||
|
@ -104,9 +86,11 @@ def rect2pathd(rect):
|
|||
"".format(x0, y0, x1, y1, x2, y2, x3, y3))
|
||||
return d
|
||||
|
||||
|
||||
def line2pathd(l):
|
||||
return 'M' + l['x1'] + ' ' + l['y1'] + 'L' + l['x2'] + ' ' + l['y2']
|
||||
|
||||
|
||||
CONVERSIONS = {'circle': ellipse2pathd,
|
||||
'ellipse': ellipse2pathd,
|
||||
'line': line2pathd,
|
||||
|
@ -114,6 +98,7 @@ CONVERSIONS = {'circle': ellipse2pathd,
|
|||
'polygon': polygon2pathd,
|
||||
'rect': rect2pathd}
|
||||
|
||||
|
||||
def svg2paths(svg_file_location, return_svg_attributes=False,
|
||||
conversions=CONVERSIONS, return_tree=False):
|
||||
"""Converts SVG to list of Path objects and attribute dictionaries.
|
||||
|
@ -203,5 +188,3 @@ def svg2paths3(svg_file_location, return_svg_attributes=True,
|
|||
return svg2paths(svg_file_location=svg_file_location,
|
||||
return_svg_attributes=return_svg_attributes,
|
||||
conversions=conversions, return_tree=return_tree)
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" ?>
|
||||
<svg baseProfile="full" height="600px" version="1.1" viewBox="-10.05 -10.05 120.1 120.1" width="600px" xmlns="http://www.w3.org/2000/svg" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<polygon points="55.5,0 55.5, 50 105.5,50" style="stroke:purple;stroke-width:1"/>
|
||||
<polygon points="0,0 0,100 100,100 0,0" style="stroke:purple;stroke-width:1"/>
|
||||
<polygon points="0,0.0 0,-100 , 1.0e-1-1e2,0,0" style="stroke:purple;stroke-width:1"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 422 B After Width: | Height: | Size: 431 B |
|
@ -353,6 +353,18 @@ class QuadraticBezierTest(unittest.TestCase):
|
|||
|
||||
class ArcTest(unittest.TestCase):
|
||||
|
||||
def test_trusting_acos(self):
|
||||
"""`u1.real` is > 1 in this arc due to numerical error."""
|
||||
try:
|
||||
a1 = Arc(start=(160.197+102.925j),
|
||||
radius=(0.025+0.025j),
|
||||
rotation=0.0,
|
||||
large_arc=False,
|
||||
sweep=True,
|
||||
end=(160.172+102.95j))
|
||||
except ValueError:
|
||||
self.fail("Arc() raised ValueError unexpectedly!")
|
||||
|
||||
def test_points(self):
|
||||
arc1 = Arc(0j, 100 + 50j, 0, 0, 0, 100 + 50j)
|
||||
self.assertAlmostEqual(arc1.center, 100 + 0j)
|
||||
|
@ -979,6 +991,19 @@ class Test_intersect(unittest.TestCase):
|
|||
self.assertTrue(len(yix), 1)
|
||||
###################################################################
|
||||
|
||||
def test_line_line_0(self):
|
||||
l0 = Line(start=(25.389999999999997+99.989999999999995j), end=(25.389999999999997+90.484999999999999j))
|
||||
l1 = Line(start=(25.390000000000001+84.114999999999995j), end=(25.389999999999997+74.604202137430320j))
|
||||
i = l0.intersect(l1)
|
||||
assert(len(i)) == 0
|
||||
|
||||
def test_line_line_1(self):
|
||||
l0 = Line(start=(-124.705378549+327.696674827j), end=(12.4926214511+121.261674827j))
|
||||
l1 = Line(start=(-12.4926214511+121.261674827j), end=(124.705378549+327.696674827j))
|
||||
i = l0.intersect(l1)
|
||||
assert(len(i)) == 1
|
||||
assert(abs(l0.point(i[0][0])-l1.point(i[0][1])) < 1e-9)
|
||||
|
||||
|
||||
class TestPathTools(unittest.TestCase):
|
||||
# moved from test_pathtools.py
|
||||
|
|
|
@ -20,9 +20,9 @@ class TestSVG2Paths(unittest.TestCase):
|
|||
|
||||
# triangular quadrilateral (with a redundant 4th "closure" point)
|
||||
path = paths[1]
|
||||
path_correct = Path(Line(0+0j, 0+100j),
|
||||
Line(0+100j, 100+100j),
|
||||
Line(100+100j, 0+0j),
|
||||
path_correct = Path(Line(0+0j, 0-100j),
|
||||
Line(0-100j, 0.1-100j),
|
||||
Line(0.1-100j, 0+0j),
|
||||
Line(0+0j, 0+0j) # result of redundant point
|
||||
)
|
||||
self.assertTrue(path.isclosed())
|
||||
|
|
Loading…
Reference in New Issue