Fix merge conflicts with master
commit
88e21fcbc0
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue