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

View File

@ -1,4 +1,3 @@
svgpathtools svgpathtools
============ ============
@ -29,7 +28,7 @@ Some included tools:
- find a **bounding box** for a path or segment - find a **bounding box** for a path or segment
- **reverse** segment/path orientation - **reverse** segment/path orientation
- **crop** and **split** paths and segments - **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) differentiable)
- **transition maps** from path domain to segment domain and back (T2t - **transition maps** from path domain to segment domain and back (T2t
and t2T) and t2T)
@ -47,6 +46,19 @@ Prerequisites
Setup 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 .. code:: bash
$ pip install svgpathtools $ pip install svgpathtools
@ -61,7 +73,7 @@ You can download the source from Github and install by using the command
$ python setup.py install $ 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) 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, on discontinuous Path objects. A simple workaround is provided, however,
by the ``Path.continuous_subpaths()`` method. `↩ <#a1>`__ by the ``Path.continuous_subpaths()`` method. `↩ <#a1>`__
.. code:: ipython2 .. code:: ipython3
from __future__ import division, print_function from __future__ import division, print_function
.. code:: ipython2 .. code:: ipython3
# Coordinates are given as points in the complex plane # Coordinates are given as points in the complex plane
from svgpathtools import Path, Line, QuadraticBezier, CubicBezier, Arc 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, list. So segments can **append**\ ed, **insert**\ ed, set by index,
**del**\ eted, **enumerate**\ d, **slice**\ d out, etc. **del**\ eted, **enumerate**\ d, **slice**\ d out, etc.
.. code:: ipython2 .. code:: ipython3
# Let's append another to the end of it # Let's append another to the end of it
path.append(CubicBezier(250+350j, 275+350j, 250+225j, 200+100j)) 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 | Note: Line, Polyline, Polygon, and Path SVG elements can all be
converted to Path objects using this function. 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 # Read SVG into a list of path objects and list of dictionaries of attributes
from svgpathtools import svg2paths, wsvg 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 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 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 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 automatically attempt to open the created svg file in your default SVG
viewer. viewer.
.. code:: ipython2 .. code:: ipython3
# Let's make a new SVG that's identical to the first # Let's make a new SVG that's identical to the first
wsvg(paths, attributes=attributes, svg_attributes=svg_attributes, filename='output1.svg') 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 :alt: output1.svg
output1.svg output1.svg
@ -268,14 +280,14 @@ over the domain 0 <= t <= 1.
| **Note:** In this document and in inline documentation and doctrings, | **Note:** In this document and in inline documentation and doctrings,
I use a capital ``T`` when referring to the parameterization of a Path I use a capital ``T`` when referring to the parameterization of a Path
object and a lower case ``t`` when referring speaking about 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). objects).
| Given a ``T`` value, the ``Path.T2t()`` method can be used to find the | Given a ``T`` value, the ``Path.T2t()`` method can be used to find the
corresponding segment index, ``k``, and segment parameter, ``t``, such corresponding segment index, ``k``, and segment parameter, ``t``, such
that ``path.point(T)=path[k].point(t)``. that ``path.point(T)=path[k].point(t)``.
| There is also a ``Path.t2T()`` method to solve the inverse problem. | There is also a ``Path.t2T()`` method to solve the inverse problem.
.. code:: ipython2 .. code:: ipython3
# Example: # Example:
@ -313,7 +325,7 @@ Bezier curves as NumPy polynomial objects
``numpy.poly1d`` objects. This is done easily using the ``numpy.poly1d`` objects. This is done easily using the
``Line.poly()``, ``QuadraticBezier.poly()`` and ``CubicBezier.poly()`` ``Line.poly()``, ``QuadraticBezier.poly()`` and ``CubicBezier.poly()``
methods. 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. submodule to convert polynomials back to Bezier curves.
**Note:** cubic Bezier curves are parameterized as **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 .. math:: \mathcal{B}(t) = c_0t^3 + c_1t^2 +c_2t+c3
where where
.. math:: .. math::
@ -344,7 +356,7 @@ form
``QuadraticBezier.poly()`` and ``Line.poly()`` are `defined ``QuadraticBezier.poly()`` and ``Line.poly()`` are `defined
similarly <https://en.wikipedia.org/wiki/B%C3%A9zier_curve#General_definition>`__. similarly <https://en.wikipedia.org/wiki/B%C3%A9zier_curve#General_definition>`__.
.. code:: ipython2 .. code:: ipython3
# Example: # Example:
b = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j) b = CubicBezier(300+100j, 100+100j, 200+200j, 200+300j)
@ -392,7 +404,7 @@ different ways.
Tangent vectors (and more on NumPy polynomials) Tangent vectors (and more on NumPy polynomials)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: ipython3
t = 0.5 t = 0.5
### Method 1: the easy way ### Method 1: the easy way
@ -434,7 +446,7 @@ Tangent vectors (and more on NumPy polynomials)
Translations (shifts), reversing orientation, and normal vectors Translations (shifts), reversing orientation, and normal vectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: ipython3
# Speaking of tangents, let's add a normal vector to the picture # Speaking of tangents, let's add a normal vector to the picture
n = b.normal(t) 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', '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]) 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 :alt: vectorframes.svg
vectorframes.svg vectorframes.svg
@ -464,7 +476,7 @@ Translations (shifts), reversing orientation, and normal vectors
Rotations and Translations Rotations and Translations
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: ipython3
# Let's take a Line and an Arc and make some pictures # 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) 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) decorated_ellipse = decorated_ellipse.translated(4+0j)
wsvg([top_half, midline, decorated_ellipse], filename='decorated_ellipse.svg') wsvg([top_half, midline, decorated_ellipse], filename='decorated_ellipse.svg')
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/decorated_ellipse.svg .. figure:: decorated_ellipse.svg
:alt: decorated\_ellipse.svg :alt: decorated_ellipse.svg
decorated\_ellipse.svg decorated_ellipse.svg
arc length and inverse arc length arc length and inverse arc length
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here we'll create an SVG that shows off the parametric and geometric Here well create an SVG that shows off the parametric and geometric
midpoints of the paths from ``test.svg``. We'll need to compute use the midpoints of the paths from ``test.svg``. Well need to compute use the
``Path.length()``, ``Line.length()``, ``QuadraticBezier.length()``, ``Path.length()``, ``Line.length()``, ``QuadraticBezier.length()``,
``CubicBezier.length()``, and ``Arc.length()`` methods, as well as the ``CubicBezier.length()``, and ``Arc.length()`` methods, as well as the
related inverse arc length methods ``.ilength()`` function to do this. 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 # First we'll load the path data from the file test.svg
paths, attributes = svg2paths('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, wsvg(paths, nodes=dots, node_colors=ncols, node_radii=nradii,
attributes=attributes, filename='output2.svg') attributes=attributes, filename='output2.svg')
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/output2.svg .. figure:: output2.svg
:alt: output2.svg :alt: output2.svg
output2.svg output2.svg
@ -539,7 +551,7 @@ related inverse arc length methods ``.ilength()`` function to do this.
Intersections between Bezier curves Intersections between Bezier curves
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: ipython3
# Let's find all intersections between redpath and the other # Let's find all intersections between redpath and the other
redpath = paths[0] redpath = paths[0]
@ -552,18 +564,18 @@ Intersections between Bezier curves
disvg(paths, filename='output_intersections.svg', attributes=attributes, disvg(paths, filename='output_intersections.svg', attributes=attributes,
nodes = intersections, node_radii = [5]*len(intersections)) nodes = intersections, node_radii = [5]*len(intersections))
.. figure:: https://cdn.rawgit.com/mathandy/svgpathtools/master/output_intersections.svg .. figure:: output_intersections.svg
:alt: output\_intersections.svg :alt: output_intersections.svg
output\_intersections.svg output_intersections.svg
An Advanced Application: Offsetting Paths 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. curve <https://en.wikipedia.org/wiki/Parallel_curve>`__ for a few paths.
.. code:: ipython2 .. code:: ipython3
from svgpathtools import parse_path, Line, Path, wsvg from svgpathtools import parse_path, Line, Path, wsvg
def offset_curve(path, offset_distance, steps=1000): 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.""" of the 'parallel' offset curve."""
nls = [] nls = []
for seg in path: for seg in path:
ct = 1
for k in range(steps): for k in range(steps):
t = k / float(steps) t = k / steps
offset_vector = offset_distance * seg.normal(t) offset_vector = offset_distance * seg.normal(t)
nl = Line(seg.point(t), seg.point(t) + offset_vector) nl = Line(seg.point(t), seg.point(t) + offset_vector)
nls.append(nl) nls.append(nl)
@ -595,21 +608,21 @@ curve <https://en.wikipedia.org/wiki/Parallel_curve>`__ for a few paths.
for distances in offset_distances: for distances in offset_distances:
offset_paths.append(offset_curve(path, 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') 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 .. figure:: offset_curves.svg
:alt: offset\_curves.svg :alt: offset_curves.svg
offset\_curves.svg offset_curves.svg
Compatibility Notes for users of svg.path (v2.0) 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), - 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 2 The behavior would be identical, but the string formatting used in
this method has been changed to use default format (instead of the this method has been changed to use default format (instead of the

Binary file not shown.

Binary file not shown.