I'm using the excellent svgpathtools library in Python 3 to work with some paths in an SVG file, created in a vector drawing application.
I'd like to create detailed point arrays for each of the paths contained within the SVG, where the points are equidistant along the path. The following does just that but becomes unbearably slow if more than a few thousand samples are taken.
SAMPLES_PER_PX = 1
fname = "/path/to/file.svg"
paths, attributes = svg2paths(fname)
myPaths = {}
for path,attr in zip(paths, attributes):
myPathList = []
pathLength = path.length()
pathColour = attr['stroke']
numSamples = int(pathLength * SAMPLES_PER_PX)
for i in range(numSamples):
#parametric length = ilength(geometric length)
myPathList.append(path.point(path.ilength(pathLength * i / (numSamples-1))))
myPaths[pathColour] = np.array(myPathList)
I've always felt that my Python ain't very Pythonic. Is there a way I can take advantage of some Python-ness to speed this up?
I had the same problem. My solution was to sample N points using path.point and then interpolate those points using scipy spline and resample from the spline. Something like:
tck, _ = interpolate.splprep(pts, s=0)
result = interpolate.splev(np.linspace(0, 1, 1000), tck)
Where pts is a list of sampled points. The number N depends on how non-uniform the input curve is. Usually N=20 is sufficient for not too crazy cases:-)
You actually do not need to use the ilength method. What you are doing with myPathList.append(path.point(path.ilength(pathLength * i / (numSamples-1)))) is computing the position of the point you want on the geometric length of the path, but since you know you are taking numSamples points regularly spaced on the path, you will keep the same number of points regularly spaced in the parametric distance, so you can directly write myPathList.append(path.point(i / (numSamples-1))).
Hope this will help!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With