I think I have found some errors in your code:
theta = degrees(acos(p / n)) if uy > 0: theta = -theta self.theta = theta % 360
The condition uy > 0
is wrong, correct is uy < 0
(the directed angle from (1, 0)
to (ux, uy)
is negative if uy < 0
):
theta = degrees(acos(p / n)) if uy < 0: theta = -theta self.theta = theta % 360
Then
if self.arc == self.sweep: angle = radians(self.theta - (self.delta * pos)) else: angle = radians(self.delta + (self.delta * pos))
And finally
x = sin(angle) * self.radius.real + self.center.real y = cos(angle) * self.radius.imag + self.center.imag
Here sin
and cos
are mixed up, correct is
x = cos(angle) * self.radius.real + self.center.real y = sin(angle) * self.radius.imag + self.center.imag
A collection of tools for manipulating and analyzing SVG Path objects and Bezier curves.,svgpathtools is a collection of tools for manipulating and analyzing SVG Path objects and Bézier curves.,Additionally, the submodule bezier.py contains tools for for working with general nth order Bezier curves stored as n-tuples.,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.
Setup
$ pip install svgpathtools
You can download the source from Github and install by using the command (from inside the folder containing setup.py):
$ python setup.py install
<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. ↩
from __future__
import division, print_function
The Path
class is a mutable sequence, so it behaves much like a list.
So segments can appended, inserted, set by index, deleted, enumerated, sliced out, etc.
# Let 's append another to the end of it path.append(CubicBezier(250 + 350 j, 275 + 350 j, 250 + 225 j, 200 + 100 j)) print(path) # Let 's replace the first segment with a Line object path[0] = Line(200 + 100 j, 200 + 300 j) print(path) # You may have noticed that this path is connected and now is also closed(i.e.path.start == path.end) print("path is continuous? ", path.iscontinuous()) print("path is closed? ", path.isclosed()) # The curve the path follows is not, however, smooth(differentiable) from svgpathtools import kinks, smoothed_path print("path contains non-differentiable points? ", len(kinks(path)) > 0) # If we want, we can smooth these out(Experimental and only for line / cubic paths) # Note: smoothing will always works(except on 180 degree turns), but you may want # to play with the maxjointsize and tightness parameters to get pleasing results # Note also: smoothing will increase the number of segments in a path spath = smoothed_path(path) print("spath contains non-differentiable points? ", len(kinks(spath)) > 0) print(spath) # Let 's take a quick look at the path and its smoothed relative # The following commands will open two browser windows to display path and spaths from svgpathtools import disvg from time import sleep disvg(path) sleep(1) # needed when not giving the SVGs unique names(or not using timestamp) disvg(spath) print("Notice that path contains {} segments and spath contains {} segments." "".format(len(path), len(spath)))
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.
Note: Line, Polyline, Polygon, and Path SVG elements can all be converted to Path objects using this function.
# Read SVG into a list of path objects and list of dictionaries of attributes from svgpathtools import svg2paths, wsvg paths, attributes = svg2paths('test.svg') # Update: You can now also extract the svg - attributes by setting # return_svg_attributes = True, or with the convenience function svg2paths2 from svgpathtools import svg2paths2 paths, attributes, svg_attributes = svg2paths2('test.svg') # Let 's print out the first path object and the color it was in the SVG # We 'll see it is composed of two CubicBezier objects and, in the SVG file it # came from, it was red redpath = paths[0] redpath_attribs = attributes[0] print(redpath) print(redpath_attribs['stroke'])
Last modified: Jun 8, 2022, by MDN contributors
M x y (or) m dx dy
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<path d="M10 10" />
<!-- Points -->
<circle cx="10" cy="10" r="2" fill="red" />
</svg>
L x y (or) l dx dy
H x (or) h dx V y (or) v dy
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<path d="M 10 10 H 90 V 90 H 10 L 10 10" />
<!-- Points -->
<circle cx="10" cy="10" r="2" fill="red" />
<circle cx="90" cy="90" r="2" fill="red" />
<circle cx="90" cy="10" r="2" fill="red" />
<circle cx="10" cy="90" r="2" fill="red" />
</svg>
Z (or) z
This chapter describes the syntax, behavior and DOM interfaces for SVG paths. Various implementation notes for SVG paths can be found in ‘path’ element implementation Notes., The Implementation Notes appendix has relevant formulae for software that needs to convert SVG arc notation to a format that uses center points and arc sweeps. ,Refer to the section on Out-of-range elliptical arc parameters for detailed implementation notes for the path data elliptical arc commands.,The value none indicates that there is no path data for the element. For ‘path’ elements, this means that the element does not render or contribute to the bounding box of ancestor container elements.
<?xml version="1.0" standalone="no"?>
<svg width="4cm" height="4cm" viewBox="0 0 400 400" xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example triangle01- simple example of a 'path'</title>
<desc>A path that draws a triangle</desc>
<rect x="1" y="1" width="398" height="398" fill="none" stroke="blue" />
<path d="M 100 100 L 300 100 L 200 300 z" fill="red" stroke="blue" stroke-width="3" />
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="5cm" height="4cm" viewBox="0 0 500 400"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example cubic01- cubic Bézier commands in path data</title>
<desc>Picture showing a simple example of path data
using both a "C" and an "S" command,
along with annotations showing the control points
and end points</desc>
<style type="text/css"><![CDATA[
.Border { fill:none; stroke:blue; stroke-width:1 }
.Connect { fill:none; stroke:#888888; stroke-width:2 }
.SamplePath { fill:none; stroke:red; stroke-width:5 }
.EndPoint { fill:none; stroke:#888888; stroke-width:2 }
.CtlPoint { fill:#888888; stroke:none }
.AutoCtlPoint { fill:none; stroke:blue; stroke-width:4 }
.Label { font-size:22; font-family:Verdana }
]]></style>
<rect class="Border" x="1" y="1" width="498" height="398" />
<polyline class="Connect" points="100,200 100,100" />
<polyline class="Connect" points="250,100 250,200" />
<polyline class="Connect" points="250,200 250,300" />
<polyline class="Connect" points="400,300 400,200" />
<path class="SamplePath" d="M100,200 C100,100 250,100 250,200
S400,300 400,200" />
<circle class="EndPoint" cx="100" cy="200" r="10" />
<circle class="EndPoint" cx="250" cy="200" r="10" />
<circle class="EndPoint" cx="400" cy="200" r="10" />
<circle class="CtlPoint" cx="100" cy="100" r="10" />
<circle class="CtlPoint" cx="250" cy="100" r="10" />
<circle class="CtlPoint" cx="400" cy="300" r="10" />
<circle class="AutoCtlPoint" cx="250" cy="300" r="9" />
<text class="Label" x="25" y="70">M100,200 C100,100 250,100 250,200</text>
<text class="Label" x="325" y="350"
style="text-anchor:middle">S400,300 400,200</text>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="12cm" height="6cm" viewBox="0 0 1200 600" xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example quad01 - quadratic Bézier commands in path data</title>
<desc>Picture showing a "Q" a "T" command,
along with annotations showing the control points
and end points</desc>
<rect x="1" y="1" width="1198" height="598" fill="none" stroke="blue" stroke-width="1" />
<path d="M200,300 Q400,50 600,300 T1000,300" fill="none" stroke="red" stroke-width="5" />
<!-- End points -->
<g fill="black">
<circle cx="200" cy="300" r="10" />
<circle cx="600" cy="300" r="10" />
<circle cx="1000" cy="300" r="10" />
</g>
<!-- Control points and lines from end points to control points -->
<g fill="#888888">
<circle cx="400" cy="50" r="10" />
<circle cx="800" cy="550" r="10" />
</g>
<path d="M200,300 L400,50 L600,300
L800,550 L1000,300" fill="none" stroke="#888888" stroke-width="2" />
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="12cm" height="5.25cm" viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example arcs01 - arc commands in path data</title>
<desc>Picture of a pie chart with two pie wedges and
a picture of a line with arc blips</desc>
<rect x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="1" />
<path d="M300,200 h-150 a150,150 0 1,0 150,-150 z" fill="red" stroke="blue" stroke-width="5" />
<path d="M275,175 v-150 a150,150 0 0,0 -150,150 z" fill="yellow" stroke="blue" stroke-width="5" />
<path d="M600,350 l 50,-25
a25,25 -30 0,1 50,-25 l 50,-25
a25,50 -30 0,1 50,-25 l 50,-25
a25,75 -30 0,1 50,-25 l 50,-25
a25,100 -30 0,1 50,-25 l 50,-25" fill="none" stroke="red" stroke-width="5" />
</svg>
An SVGPathElement object represents a ‘path’ in the DOM.
[Exposed = Window]
interface SVGPathElement: SVGGeometryElement {};
This example showcases the PathPatch object to create a Bezier polycurve path patch.,The use of the following functions, methods, classes and modules is shown in this example:, Demonstrates plotting contour (level) curves in 3D using the extend3d option , Demo of the histogram function's different histtype settings
import matplotlib.path as mpath
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
Path = mpath.Path
fig, ax = plt.subplots()
pp1 = mpatches.PathPatch(
Path([(0, 0), (1, 0), (1, 1), (0, 0)],
[Path.MOVETO, Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY]),
fc = "none", transform = ax.transData)
ax.add_patch(pp1)
ax.plot([0.75], [0.25], "ro")
ax.set_title('The red point should be on the path')
plt.show()