commit branch

pull/135/head
Andrew Port 2020-11-14 23:22:09 -08:00
parent d354b8ffe4
commit bdbd976e0a
4 changed files with 91 additions and 187 deletions

View File

@ -2,10 +2,7 @@
"cells": [
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"# svgpathtools\n",
"\n",
@ -91,9 +88,7 @@
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true,
"deletable": true,
"editable": true
"collapsed": true
},
"outputs": [],
"source": [
@ -103,11 +98,7 @@
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [
{
"name": "stdout",
@ -146,10 +137,7 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"The ``Path`` class is a mutable sequence, so it behaves much like a list.\n",
"So segments can **append**ed, **insert**ed, set by index, **del**eted, **enumerate**d, **slice**d out, etc."
@ -158,11 +146,7 @@
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [
{
"name": "stdout",
@ -226,10 +210,7 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### Reading SVGSs\n",
"\n",
@ -240,11 +221,7 @@
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [
{
"name": "stdout",
@ -277,10 +254,7 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### Writing SVGSs (and some geometric functions and methods)\n",
"\n",
@ -291,11 +265,7 @@
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [],
"source": [
"# Let's make a new SVG that's identical to the first\n",
@ -304,20 +274,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"![output1.svg](output1.svg)"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"There will be many more examples of writing and displaying path data below.\n",
"\n",
@ -334,11 +298,7 @@
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [
{
"name": "stdout",
@ -374,10 +334,7 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### Bezier curves as NumPy polynomial objects\n",
"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. \n",
@ -402,11 +359,7 @@
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [
{
"name": "stdout",
@ -442,10 +395,7 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"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 \n",
"\n",
@ -461,11 +411,7 @@
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [
{
"name": "stdout",
@ -510,10 +456,7 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### Translations (shifts), reversing orientation, and normal vectors"
]
@ -521,11 +464,7 @@
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [],
"source": [
"# Speaking of tangents, let's add a normal vector to the picture\n",
@ -551,20 +490,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"![vectorframes.svg](vectorframes.svg)"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### Rotations and Translations"
]
@ -572,11 +505,7 @@
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [],
"source": [
"# Let's take a Line and an Arc and make some pictures\n",
@ -599,20 +528,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"![decorated_ellipse.svg](decorated_ellipse.svg)"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### arc length and inverse arc length\n",
"\n",
@ -622,11 +545,7 @@
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [],
"source": [
"# First we'll load the path data from the file test.svg\n",
@ -664,20 +583,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"![output2.svg](output2.svg)"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### Intersections between Bezier curves"
]
@ -685,11 +598,7 @@
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [],
"source": [
"# Let's find all intersections between redpath and the other \n",
@ -706,20 +615,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"![output_intersections.svg](output_intersections.svg)"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"### An Advanced Application: Offsetting Paths\n",
"Here we'll find the [offset curve](https://en.wikipedia.org/wiki/Parallel_curve) for a few paths."
@ -728,11 +631,7 @@
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false,
"deletable": true,
"editable": true
},
"metadata": {},
"outputs": [],
"source": [
"from svgpathtools import parse_path, Line, Path, wsvg\n",
@ -772,20 +671,14 @@
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"![offset_curves.svg](offset_curves.svg)"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": true,
"editable": true
},
"metadata": {},
"source": [
"## Compatibility Notes for users of svg.path (v2.0)\n",
"\n",
@ -806,9 +699,7 @@
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true,
"deletable": true,
"editable": true
"collapsed": true
},
"outputs": [],
"source": []
@ -823,16 +714,16 @@
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.12"
"pygments_lexer": "ipython3",
"version": "3.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 0
"nbformat_minor": 1
}

View File

@ -1,4 +1,3 @@
svgpathtools
============
@ -29,7 +28,7 @@ Some included tools:
- find a **bounding box** for a path or segment
- **reverse** segment/path orientation
- **crop** and **split** paths and segments
- **smooth** paths (i.e. smooth away kinks to make paths
- **smooth** paths (i.e. smooth away kinks to make paths
differentiable)
- **transition maps** from path domain to segment domain and back (T2t
and t2T)
@ -47,6 +46,19 @@ Prerequisites
Setup
-----
If not already installed, you can **install the prerequisites** using
pip.
.. code:: bash
$ pip install numpy
.. code:: bash
$ pip install svgwrite
Then **install svgpathtools**:
.. code:: bash
$ pip install svgpathtools
@ -61,7 +73,7 @@ You can download the source from Github and install by using the command
$ python setup.py install
Credit where credit's due
Credit where credits due
-------------------------
Much of the core of this module was taken from `the svg.path (v2.0)
@ -98,11 +110,11 @@ information on what each parameter means.
on discontinuous Path objects. A simple workaround is provided, however,
by the ``Path.continuous_subpaths()`` method. `↩ <#a1>`__
.. code:: ipython2
.. code:: ipython3
from __future__ import division, print_function
.. code:: ipython2
.. code:: ipython3
# Coordinates are given as points in the complex plane
from svgpathtools import Path, Line, QuadraticBezier, CubicBezier, Arc
@ -139,7 +151,7 @@ The ``Path`` class is a mutable sequence, so it behaves much like a
list. So segments can **append**\ ed, **insert**\ ed, set by index,
**del**\ eted, **enumerate**\ d, **slice**\ d out, etc.
.. code:: ipython2
.. code:: ipython3
# Let's append another to the end of it
path.append(CubicBezier(250+350j, 275+350j, 250+225j, 200+100j))
@ -206,7 +218,7 @@ Reading SVGSs
| Note: Line, Polyline, Polygon, and Path SVG elements can all be
converted to Path objects using this function.
.. code:: ipython2
.. code:: ipython3
# Read SVG into a list of path objects and list of dictionaries of attributes
from svgpathtools import svg2paths, wsvg
@ -239,16 +251,16 @@ Writing SVGSs (and some geometric functions and methods)
The **wsvg()** function creates an SVG file from a list of path. This
function can do many things (see docstring in *paths2svg.py* for more
information) and is meant to be quick and easy to use. Note: Use the
convenience function **disvg()** (or set 'openinbrowser=True') to
convenience function **disvg()** (or set openinbrowser=True) to
automatically attempt to open the created svg file in your default SVG
viewer.
.. code:: ipython2
.. code:: ipython3
# Let's make a new SVG that's identical to the first
wsvg(paths, attributes=attributes, svg_attributes=svg_attributes, filename='output1.svg')
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/output1.svg
.. figure:: output1.svg
:alt: output1.svg
output1.svg
@ -268,14 +280,14 @@ over the domain 0 <= t <= 1.
| **Note:** In this document and in inline documentation and doctrings,
I use a capital ``T`` when referring to the parameterization of a Path
object and a lower case ``t`` when referring speaking about path
segment objects (i.e. Line, QaudraticBezier, CubicBezier, and Arc
segment objects (i.e. Line, QaudraticBezier, CubicBezier, and Arc
objects).
| Given a ``T`` value, the ``Path.T2t()`` method can be used to find the
corresponding segment index, ``k``, and segment parameter, ``t``, such
that ``path.point(T)=path[k].point(t)``.
| There is also a ``Path.t2T()`` method to solve the inverse problem.
.. code:: ipython2
.. code:: ipython3
# Example:
@ -313,7 +325,7 @@ Bezier curves as NumPy polynomial objects
``numpy.poly1d`` objects. This is done easily using the
``Line.poly()``, ``QuadraticBezier.poly()`` and ``CubicBezier.poly()``
methods.
| There's also a ``polynomial2bezier()`` function in the pathtools.py
| Theres also a ``polynomial2bezier()`` function in the pathtools.py
submodule to convert polynomials back to Bezier curves.
**Note:** cubic Bezier curves are parameterized as
@ -328,7 +340,7 @@ form
.. math:: \mathcal{B}(t) = c_0t^3 + c_1t^2 +c_2t+c3
where
where
.. math::
@ -344,7 +356,7 @@ form
``QuadraticBezier.poly()`` and ``Line.poly()`` are `defined
similarly <https://en.wikipedia.org/wiki/B%C3%A9zier_curve#General_definition>`__.
.. code:: ipython2
.. code:: ipython3
# Example:
b = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j)
@ -392,7 +404,7 @@ different ways.
Tangent vectors (and more on NumPy polynomials)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2
.. code:: ipython3
t = 0.5
### Method 1: the easy way
@ -434,7 +446,7 @@ Tangent vectors (and more on NumPy polynomials)
Translations (shifts), reversing orientation, and normal vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2
.. code:: ipython3
# Speaking of tangents, let's add a normal vector to the picture
n = b.normal(t)
@ -456,7 +468,7 @@ Translations (shifts), reversing orientation, and normal vectors
'bgpkgp', nodes=[b.point(t), br.point(t)], filename='vectorframes.svg',
text=["b's tangent", "br's tangent"], text_path=[tangent_line, tangent_line_r])
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/vectorframes.svg
.. figure:: vectorframes.svg
:alt: vectorframes.svg
vectorframes.svg
@ -464,7 +476,7 @@ Translations (shifts), reversing orientation, and normal vectors
Rotations and Translations
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2
.. code:: ipython3
# 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)
@ -483,21 +495,21 @@ Rotations and Translations
decorated_ellipse = decorated_ellipse.translated(4+0j)
wsvg([top_half, midline, decorated_ellipse], filename='decorated_ellipse.svg')
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/decorated_ellipse.svg
:alt: decorated\_ellipse.svg
.. figure:: decorated_ellipse.svg
:alt: decorated_ellipse.svg
decorated\_ellipse.svg
decorated_ellipse.svg
arc length and inverse arc length
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here we'll create an SVG that shows off the parametric and geometric
midpoints of the paths from ``test.svg``. We'll need to compute use the
Here well create an SVG that shows off the parametric and geometric
midpoints of the paths from ``test.svg``. Well need to compute use the
``Path.length()``, ``Line.length()``, ``QuadraticBezier.length()``,
``CubicBezier.length()``, and ``Arc.length()`` methods, as well as the
related inverse arc length methods ``.ilength()`` function to do this.
.. code:: ipython2
.. code:: ipython3
# First we'll load the path data from the file test.svg
paths, attributes = svg2paths('test.svg')
@ -531,7 +543,7 @@ related inverse arc length methods ``.ilength()`` function to do this.
wsvg(paths, nodes=dots, node_colors=ncols, node_radii=nradii,
attributes=attributes, filename='output2.svg')
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/output2.svg
.. figure:: output2.svg
:alt: output2.svg
output2.svg
@ -539,7 +551,7 @@ related inverse arc length methods ``.ilength()`` function to do this.
Intersections between Bezier curves
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2
.. code:: ipython3
# Let's find all intersections between redpath and the other
redpath = paths[0]
@ -552,18 +564,18 @@ Intersections between Bezier curves
disvg(paths, filename='output_intersections.svg', attributes=attributes,
nodes = intersections, node_radii = [5]*len(intersections))
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/output_intersections.svg
:alt: output\_intersections.svg
.. figure:: output_intersections.svg
:alt: output_intersections.svg
output\_intersections.svg
output_intersections.svg
An Advanced Application: Offsetting Paths
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here we'll find the `offset
Here well find the `offset
curve <https://en.wikipedia.org/wiki/Parallel_curve>`__ for a few paths.
.. code:: ipython2
.. code:: ipython3
from svgpathtools import parse_path, Line, Path, wsvg
def offset_curve(path, offset_distance, steps=1000):
@ -572,8 +584,9 @@ 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 / float(steps)
t = k / steps
offset_vector = offset_distance * seg.normal(t)
nl = Line(seg.point(t), seg.point(t) + offset_vector)
nls.append(nl)
@ -595,21 +608,21 @@ curve <https://en.wikipedia.org/wiki/Parallel_curve>`__ for a few paths.
for distances in offset_distances:
offset_paths.append(offset_curve(path, distances))
# Note: This will take a few moments
# Let's take a look
wsvg(paths + offset_paths, 'g'*len(paths) + 'r'*len(offset_paths), filename='offset_curves.svg')
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/offset_curves.svg
:alt: offset\_curves.svg
.. figure:: offset_curves.svg
:alt: offset_curves.svg
offset\_curves.svg
offset_curves.svg
Compatibility Notes for users of svg.path (v2.0)
------------------------------------------------
- renamed Arc.arc attribute as Arc.large\_arc
- renamed Arc.arc attribute as Arc.large_arc
- Path.d() : For behavior similar\ `2 <#f2>`__\ to svg.path (v2.0),
set both useSandT and use\_closed\_attrib to be True.
set both useSandT and use_closed_attrib to be True.
2 The behavior would be identical, but the string formatting used in
this method has been changed to use default format (instead of the

Binary file not shown.

Binary file not shown.