446 lines
13 KiB
Plaintext
446 lines
13 KiB
Plaintext
Metadata-Version: 2.1
|
|
Name: svg.path
|
|
Version: 6.2
|
|
Summary: SVG path objects and parser
|
|
Home-page: https://github.com/regebro/svg.path
|
|
Author: Lennart Regebro
|
|
Author-email: regebro@gmail.com
|
|
License: MIT
|
|
Keywords: svg,path,maths
|
|
Platform: UNKNOWN
|
|
Classifier: Development Status :: 5 - Production/Stable
|
|
Classifier: Intended Audience :: Developers
|
|
Classifier: License :: OSI Approved :: MIT License
|
|
Classifier: Operating System :: OS Independent
|
|
Classifier: Programming Language :: Python
|
|
Classifier: Programming Language :: Python :: 3
|
|
Classifier: Programming Language :: Python :: 3.6
|
|
Classifier: Programming Language :: Python :: 3.7
|
|
Classifier: Programming Language :: Python :: 3.8
|
|
Classifier: Programming Language :: Python :: 3.9
|
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
Classifier: Topic :: Multimedia :: Graphics
|
|
Provides-Extra: test
|
|
Requires-Dist: Pillow ; extra == 'test'
|
|
Requires-Dist: pytest ; extra == 'test'
|
|
Requires-Dist: pytest-cov ; extra == 'test'
|
|
|
|
svg.path
|
|
========
|
|
|
|
svg.path is a collection of objects that implement the different path
|
|
commands in SVG, and a parser for SVG path definitions.
|
|
|
|
|
|
Usage
|
|
-----
|
|
|
|
There are four path segment objects, ``Line``, ``Arc``, ``CubicBezier`` and
|
|
``QuadraticBezier``.`There is also a ``Path`` object that acts as a
|
|
collection of the path segment objects.
|
|
|
|
All coordinate values for these classes are given as ``complex`` values,
|
|
where the ``.real`` part represents the X coordinate, and the ``.imag`` part
|
|
representes the Y coordinate::
|
|
|
|
>>> from svg.path import Path, Move, Line, Arc, CubicBezier, QuadraticBezier, Close
|
|
|
|
All of these objects have a ``.point()`` function which will return the
|
|
coordinates of a point on the path, where the point is given as a floating
|
|
point value where ``0.0`` is the start of the path and ``1.0`` is the end.
|
|
|
|
You can calculate the length of a Path or it's segments with the
|
|
``.length()`` function. For CubicBezier and Arc segments this is done by
|
|
geometric approximation and for this reason **may be very slow**. You can
|
|
make it faster by passing in an ``error`` option to the method. If you
|
|
don't pass in error, it defaults to ``1e-12``::
|
|
|
|
>>> CubicBezier(300+100j, 100+100j, 200+200j, 200+300j).length(error=1e-5)
|
|
297.2208145656899
|
|
|
|
CubicBezier and Arc also has a ``min_depth`` option that specifies the
|
|
minimum recursion depth. This is set to 5 by default, resulting in using a
|
|
minimum of 32 segments for the calculation. Setting it to 0 is a bad idea for
|
|
CubicBeziers, as they may become approximated to a straight line.
|
|
|
|
``Line.length()`` and ``QuadraticBezier.length()`` also takes these
|
|
parameters, but they are ignored.
|
|
|
|
CubicBezier and QuadraticBezier also has ``is_smooth_from(previous)``
|
|
methods, that check if the segment is a "smooth" segment compared to the
|
|
given segment.
|
|
|
|
There is also a ``parse_path()`` function that will take an SVG path definition
|
|
and return a ``Path`` object::
|
|
|
|
>>> from svg.path import parse_path
|
|
>>> parse_path('M 100 100 L 300 100')
|
|
Path(Move(to=(100+100j)), Line(start=(100+100j), end=(300+100j)))
|
|
|
|
|
|
Classes
|
|
.......
|
|
|
|
These are the SVG path segment classes. See the `SVG specifications
|
|
<http://www.w3.org/TR/SVG/paths.html>`_ for more information on what each
|
|
parameter means.
|
|
|
|
* ``Line(start, end)``
|
|
|
|
* ``Arc(start, radius, rotation, arc, sweep, end)``
|
|
|
|
* ``QuadraticBezier(start, control, end)``
|
|
|
|
* ``CubicBezier(start, control1, control2, end)``
|
|
|
|
In addition to that, there is the ``Path`` class, which is instantiated
|
|
with a sequence of path segments:
|
|
|
|
* ``Path(*segments)``
|
|
|
|
The ``Path`` class is a mutable sequence, so it behaves like a list.
|
|
You can add to it and replace path segments etc::
|
|
|
|
>>> path = Path(Move(200+100j), Line(200+100j,100+200j), Line(100+200j,300+100j))
|
|
>>> path.append(QuadraticBezier(300+100j, 200+200j, 200+300j))
|
|
>>> path[0] = Move(200+100j)
|
|
>>> del path[1]
|
|
|
|
The path object also has a ``d()`` method that will return the
|
|
SVG representation of the Path segments::
|
|
|
|
>>> path.d()
|
|
'M 200,100 L 300,100 Q 200,200 200,300'
|
|
|
|
Note that there currently is no internal consistency checks when you
|
|
manipulate lines this way. This path now has an internal representation that
|
|
it's different from it's d() path. Notice how the `Line()` segment starts in
|
|
a different location from where the `Move()` segments say. This **may**
|
|
change in future releases, and the Path manipulation methods **may** be
|
|
changed to ensure consistency.
|
|
|
|
>>> path
|
|
Path(Move(to=(200+100j)), Line(start=(100+200j), end=(300+100j)),
|
|
QuadraticBezier(start=(300+100j), control=(200+200j), end=(200+300j),
|
|
smooth=False))
|
|
|
|
|
|
Examples
|
|
........
|
|
|
|
This SVG path example draws a triangle::
|
|
|
|
|
|
>>> path1 = parse_path('M 100 100 L 300 100 L 200 300 z')
|
|
|
|
You can format SVG paths in many different ways, all valid paths should be
|
|
accepted::
|
|
|
|
>>> path2 = parse_path('M100,100L300,100L200,300z')
|
|
|
|
And these paths should be equal::
|
|
|
|
>>> path1 == path2
|
|
True
|
|
|
|
You can also build a path from objects::
|
|
|
|
>>> path3 = Path(Line(100+100j,300+100j), Line(300+100j, 200+300j), Line(200+300j, 100+100j))
|
|
|
|
And it should again be equal to the first path::
|
|
|
|
>>> path1 == path2
|
|
True
|
|
|
|
Paths are mutable sequences, you can slice and append::
|
|
|
|
>>> path1.append(QuadraticBezier(300+100j, 200+200j, 200+300j))
|
|
>>> len(path1[2:]) == 3
|
|
True
|
|
|
|
Note that there is no protection against you creating paths that are invalid.
|
|
You can for example have a Close command that doesn't end at the path start::
|
|
|
|
>>> wrong = Path(Line(100+100j,200+100j), Close(200+300j, 0))
|
|
|
|
|
|
Future features
|
|
---------------
|
|
|
|
* Reversing paths. They should then reasonably be drawn "backwards" meaning each
|
|
path segment also needs to be reversed.
|
|
|
|
* Mathematical transformations might make sense.
|
|
|
|
* Verifying that paths are correct, or protection against creating incorrect paths.
|
|
|
|
|
|
License
|
|
-------
|
|
|
|
This module is under a MIT License.
|
|
|
|
Contributors
|
|
============
|
|
|
|
Lennart Regebro <regebro@gmail.com>, Original Author
|
|
|
|
Justin Gruenberg implemented the Quadradic Bezier calculations and
|
|
provided suggestions and feedback about the d() function.
|
|
|
|
Michiel Schallig suggested calculating length by recursive straight-line
|
|
approximations, which enables you to choose between accuracy or speed.
|
|
Steve Schwarz added an error argument to make that choice an argument.
|
|
|
|
ClayJarCom speeded up `point()` calculations for paths.
|
|
|
|
Thanks also to bug fixers Martin R, abcjjy, Daniel Stender, MTician,
|
|
blokhin, Karthikeyan, jaraco and martinleopold.
|
|
|
|
Thanks to tatarize for help with investigating issues, and coming with
|
|
much feedback and ideas.
|
|
|
|
Samuel Carlsson [vidstige] provided the `tangent()` functions.
|
|
|
|
Lucas Simon discovered and fixed that not all path segments preserved
|
|
the relative setting when parsing.
|
|
|
|
Changelog
|
|
=========
|
|
|
|
|
|
6.2 (2022-06-17)
|
|
----------------
|
|
|
|
- Allow numbers with decimal point but no decimals, because other parsers do.
|
|
|
|
- Re-enabled the README.rst doctest, which got lost when switching to pytest
|
|
|
|
|
|
6.1 (2022-06-09)
|
|
----------------
|
|
|
|
- Not all path segments preserved the relative setting. [Lucas-C]
|
|
|
|
|
|
6.0 (2022-04-14)
|
|
----------------
|
|
|
|
- No functional changes from 6.0b1, only changes to tests.
|
|
|
|
|
|
6.0b1 (2022-04-02)
|
|
------------------
|
|
|
|
- Added new abstract base classes: PathSegment, and NonLinear. Also, Linear
|
|
is now derived from PathSegment, and may become abstract in the future.
|
|
|
|
- Added smooth support:
|
|
|
|
- CubicBezier and QuadraticBezier now has a "smooth" flag, that will be set
|
|
when parsing if the SVG path had a smooth segment.
|
|
|
|
- A path element will now only be designated as a smooth segment if it has
|
|
the smooth flag set. That means a path that *is* smooth but not parsed
|
|
from smooth (S and T) segments will not be represented as smooth.
|
|
The path segment must also be smooth, so if you parse a path with a
|
|
smooth segment, and modify it so it isn't smooth, it will not be
|
|
represented as smooth, regardless of the flag.
|
|
|
|
- CubicBezier and QuadraticBezier now has a "set_smooth_from" flag, that
|
|
will adjust the start point and first control point so that the curve is
|
|
smooth. It also sets the smooth flag.
|
|
|
|
- Added support to preserve vertical/horizontal commands.
|
|
|
|
- Refactored the generation of SVG path texts, each segment now generates its
|
|
own segment text, with a `_d(self, previous)` method.
|
|
|
|
|
|
5.1 (2022-03-23)
|
|
----------------
|
|
|
|
- Added SVG standard tests. [tatarize]
|
|
|
|
- Allow random characters to end parsing.
|
|
|
|
- #61: Fixed the length() calculations of nearly linear QuadradicBeziers.
|
|
[tatarize, regebro]
|
|
|
|
|
|
5.0.1 (2022-03-21)
|
|
------------------
|
|
|
|
- Two new test files were omitted from the distributions.
|
|
|
|
|
|
5.0.0 (2022-03-21)
|
|
------------------
|
|
|
|
- Drop Python 2 support, also 3.4 to 3.6. New minimum Python version is 3.7.
|
|
|
|
- New parser that solves the issue with Arc flags and whitespace.
|
|
See Issues #53 and #69.
|
|
|
|
- Fixed #60: Handle paths that are length 0 [Thanks to martinleopold and tatarize]
|
|
|
|
- New method on path objects: `.tangent(point)`, which returns a vector that is the
|
|
derivatative / tangent of the curve at that point. [vidstige]
|
|
|
|
- New graphical test. That test requires Pillow, so I stopped testing on PyPy, it
|
|
got too complicated to support. But it still works on PyPy.
|
|
|
|
|
|
4.1 (2021-02-16)
|
|
----------------
|
|
|
|
- Use collections.abc for ABC import to add Python 3.9 compatibility.
|
|
|
|
|
|
4.0.2 (2019-11-04)
|
|
------------------
|
|
|
|
- A solution for the setup.cfg [Alex Grönholm]
|
|
|
|
|
|
4.0.1 (2019-11-03)
|
|
------------------
|
|
else:
|
|
raise
|
|
|
|
- The pure setup.cfg config didn't work. All the tests pass fine,
|
|
but when installing the package somewhere else, nothing gets installed.
|
|
So I'm reverting that change for now.
|
|
|
|
|
|
4.0 (2019-11-02)
|
|
----------------
|
|
|
|
- Moved all the information from setup.py into setup.cfg.
|
|
|
|
- Added a Close() command which is different from a Line() command in
|
|
no way at all, to simplify the handling of closepath commands and subpaths.
|
|
|
|
- Path()'s no longer have a `closed` attribute.
|
|
|
|
- Now fully supports the SVG 1.1 "F.6.2 Out-of-range parameters" list.
|
|
|
|
- Uses circular maths to calculate the length of circular arcs,
|
|
more accurate and much faster.
|
|
|
|
|
|
3.1 (2019-10-25)
|
|
----------------
|
|
|
|
- The Move null command was not imported into ``__init__.py`` [blokhin]
|
|
- #41: Switched from ``pkg_resource``-style namespace
|
|
package for ``svg`` to a `pkgutil style
|
|
<https://packaging.python.org/guides/packaging-namespace-packages/#pkgutil-style-namespace-packages>`_
|
|
namespace package.
|
|
- A faster ``point()`` implementation for paths. [ClayJarCom]
|
|
- Dropped support for Python 2.6 and Python 3.3.
|
|
- Added support for Python 3.7 and 3.8.
|
|
|
|
|
|
3.0 (2018-08-14)
|
|
----------------
|
|
|
|
- Dropped support for Python 3.1 and 3.2. It still works, but it may stop.
|
|
Added support for Python 3.6. Dropped support for Jython, it's not
|
|
supported by Travis, and hasn't seen a release in over a year.
|
|
|
|
- #33: Move commands are now preserved when parsed.
|
|
|
|
- Subpaths are no longer merged even if they are joined.
|
|
|
|
- #30: Arcs where the endpoint is the same as the start point caused a crash.
|
|
The SVG specs say that it instead should be the equavalent of skipping
|
|
that section, which now is the case.
|
|
|
|
|
|
2.2 (2016-10-15)
|
|
----------------
|
|
|
|
- Don't add a line when closing a path if it's not needed.
|
|
|
|
|
|
2.1.1 (2016-02-28)
|
|
------------------
|
|
|
|
- #18: QuadraticBeziers could get a DivideByZero error under certain
|
|
circumstances. [MTician]
|
|
|
|
- Accept an error parameter to Path.point() to be able to
|
|
control error vs performance setting. [saschwarz]
|
|
|
|
- #25: Arc's could create a MathDomain error under certain circumstances.
|
|
|
|
- #17: Set last_command always.
|
|
|
|
|
|
2.0.1 (2015-10-17)
|
|
------------------
|
|
|
|
- #20: The doctext for the closed() setter was incorrect.
|
|
|
|
- #19: Fixed so tests didn't use relative paths. [danstender]
|
|
|
|
|
|
2.0 (2015-05-15)
|
|
----------------
|
|
|
|
- Nothing changed yet.
|
|
|
|
|
|
2.0b1 (2014-11-06)
|
|
------------------
|
|
|
|
- Added a Path.d() function to generate the Path's d attribute.
|
|
|
|
- Added is_smooth_from() on QubicBezier and QuadradicBezier.
|
|
|
|
- Path()'s now have a .closed property.
|
|
|
|
- Fixed the representation so it's parseable.
|
|
|
|
- The calculations for CubicBezier and Arc segments are now recursive,
|
|
and will end when a specific accuracy has been achieved.
|
|
This is somewhat faster for Arcs and somewhat slower for CubicBezier.
|
|
However, you can now specify an accuracy, so if you want faster but
|
|
looser calculations, you can have that.
|
|
|
|
- 't' segments (smooth, relative QuadraticBeziers) whose previous segment was
|
|
not a QuadraticBezier would get an incorrect control point.
|
|
|
|
|
|
1.2 (2014-11-01)
|
|
----------------
|
|
|
|
- New Quadradic Bezier implementation. [Justin Gruenberg]
|
|
|
|
- Solved issue #6: Z close path behavior. [abcjjy]
|
|
|
|
|
|
1.1 (2013-10-19)
|
|
----------------
|
|
|
|
- Floats with negative exponents work again.
|
|
|
|
- New tokenizer that is around 20 times faster.
|
|
|
|
|
|
1.0 (2013-05-28)
|
|
----------------
|
|
|
|
- Solved issue #2: Paths with negative values and no spaces didn't work.
|
|
[regebro]
|
|
|
|
|
|
1.0b1 (2013-02-03)
|
|
------------------
|
|
|
|
- Original release.
|
|
|
|
|