"svgpathtools is a collection of tools for manipulating and analyzing SVG Path objects and Bézier curves.\n",
"\n",
"## Features\n",
"\n",
"svgpathtools contains functions designed to **easily read, write and display SVG files** as well as *a large selection of geometrically\\-oriented tools* to **transform and analyze path elements**.\n",
"\n",
"Additionally, the submodule *bezier.py* contains tools for for working with general **nth order Bezier curves stored as n-tuples**.\n",
"- convert Bézier path segments to **numpy.poly1d** (polynomial) objects\n",
"- convert polynomials (in standard form) to their Bézier form\n",
"- compute **tangent vectors** and (right-hand rule) **normal vectors**\n",
"- compute **curvature**\n",
"- break discontinuous paths into their **continuous subpaths**.\n",
"- efficiently compute **intersections** between paths and/or segments\n",
"- find a **bounding box** for a path or segment\n",
"- **reverse** segment/path orientation\n",
"- **crop** and **split** paths and segments\n",
"- **smooth** paths (i.e. smooth away kinks to make paths differentiable)\n",
"- **transition maps** from path domain to segment domain and back (T2t and t2T)\n",
"- compute **area** enclosed by a closed path\n",
"- compute **arc length**\n",
"- compute **inverse arc length**\n",
"- convert RGB color tuples to hexadecimal color strings and back\n",
"\n",
"## Prerequisites\n",
"- **numpy**\n",
"- **svgwrite**\n",
"\n",
"## Setup\n",
"\n",
"If not already installed, you can **install the prerequisites** using pip.\n",
"\n",
"```bash\n",
"$ pip install numpy\n",
"```\n",
"\n",
"```bash\n",
"$ pip install svgwrite\n",
"```\n",
"\n",
"Then **install svgpathtools**:\n",
"```bash\n",
"$ pip install svgpathtools\n",
"``` \n",
" \n",
"### Alternative Setup \n",
"You can download the source from Github and install by using the command (from inside the folder containing setup.py):\n",
"\n",
"```bash\n",
"$ python setup.py install\n",
"```\n",
"\n",
"## Credit where credit's due\n",
"Much of the core of this module was taken from [the svg.path (v2.0) module](https://github.com/regebro/svg.path). Interested svg.path users should see the compatibility notes at bottom of this readme.\n",
"\n",
"## Basic Usage\n",
"\n",
"### Classes\n",
"The svgpathtools module is primarily structured around four path segment classes: ``Line``, ``QuadraticBezier``, ``CubicBezier``, and ``Arc``. There is also a fifth class, ``Path``, whose objects are sequences of (connected or disconnected<sup id=\"a1\">[1](#f1)</sup>) path segment objects.\n",
"\n",
"* ``Line(start, end)``\n",
"\n",
"* ``Arc(start, radius, rotation, large_arc, sweep, end)`` Note: See docstring for a detailed explanation of these parameters\n",
"See the relevant docstrings in *path.py* or the [official SVG specifications](<http://www.w3.org/TR/SVG/paths.html>) for more information on what each parameter means.\n",
"\n",
"<u id=\"f1\">1</u> Warning: Some of the functionality in this library has not been tested on discontinuous Path objects. A simple workaround is provided, however, by the ``Path.continuous_subpaths()`` method. [↩](#a1)"
"# Let's take a quick look at the path and its smoothed relative\n",
"# The following commands will open two browser windows to display path and spaths\n",
"from svgpathtools import disvg\n",
"from time import sleep\n",
"disvg(path) \n",
"sleep(1) # needed when not giving the SVGs unique names (or not using timestamp)\n",
"disvg(spath)\n",
"print(\"Notice that path contains {} segments and spath contains {} segments.\"\n",
" \"\".format(len(path), len(spath)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Reading SVGSs\n",
"\n",
"The **svg2paths()** function converts an svgfile to a list of Path objects and a separate list of dictionaries containing the attributes of each said path. \n",
"Note: Line, Polyline, Polygon, and Path SVG elements can all be converted to Path objects using this function."
"# Let's print out the first path object and the color it was in the SVG\n",
"# We'll see it is composed of two CubicBezier objects and, in the SVG file it \n",
"# came from, it was red\n",
"redpath = paths[0]\n",
"redpath_attribs = attributes[0]\n",
"print(redpath)\n",
"print(redpath_attribs['stroke'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Writing SVGSs (and some geometric functions and methods)\n",
"\n",
"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.\n",
"Note: Use the convenience function **disvg()** (or set 'openinbrowser=True') to automatically attempt to open the created svg file in your default SVG viewer."
"There will be many more examples of writing and displaying path data below.\n",
"\n",
"### The .point() method and transitioning between path and path segment parameterizations\n",
"SVG Path elements and their segments have official parameterizations.\n",
"These parameterizations can be accessed using the ``Path.point()``, ``Line.point()``, ``QuadraticBezier.point()``, ``CubicBezier.point()``, and ``Arc.point()`` methods.\n",
"All these parameterizations are defined over the domain 0 <= t <= 1.\n",
"\n",
"**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 objects). \n",
"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)``. \n",
"There is also a ``Path.t2T()`` method to solve the inverse problem."
"### Tangent vectors and 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",
"There's also a ``polynomial2bezier()`` function in the pathtools.py submodule to convert polynomials back to Bezier curves. \n",
"\n",
"**Note:** cubic Bezier curves are parameterized as $$\\mathcal{B}(t) = P_0(1-t)^3 + 3P_1(1-t)^2t + 3P_2(1-t)t^2 + P_3t^3$$\n",
"where $P_0$, $P_1$, $P_2$, and $P_3$ are the control points ``start``, ``control1``, ``control2``, and ``end``, respectively, that svgpathtools uses to define a CubicBezier object. The ``CubicBezier.poly()`` method expands this polynomial to its standard form \n",
" \"can be rewritten in standard form as \\n\\n\" +\n",
" str(p).replace('x','t'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"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.\n",
"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 ``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."
"## Compatibility Notes for users of svg.path (v2.0)\n",
"\n",
"- renamed Arc.arc attribute as Arc.large_arc\n",
"\n",
"- Path.d() : For behavior similar<sup id=\"a2\">[2](#f2)</sup> to svg.path (v2.0), set both useSandT and use_closed_attrib to be True.\n",
"\n",
"<u id=\"f2\">2</u> The behavior would be identical, but the string formatting used in this method has been changed to use default format (instead of the General format, {:G}), for inceased precision. [↩](#a2)\n",