Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mathandy/b4d2faf4ea3de7c0640126e2015c7484 to your computer and use it in GitHub Desktop.
Save mathandy/b4d2faf4ea3de7c0640126e2015c7484 to your computer and use it in GitHub Desktop.
An svgpathtools example: computing many points quickly with and numpy arrays
"""The goal of this gist is to show how to compute many points on a path
quickly using NumPy arrays. I.e. there's a much faster way than using, say
[some_path.point(t) for t in many_tvals]. The example below assumes the
`Path` object is composed entirely of `CubicBezier` objects, but this can
easily be generalized to paths containing `Line` and `QuadraticBezier` objects
also.
Note: The relevant matrix transformation for quadratics can be found in the
svgpathtools.bezier module."""
import numpy as np
from svgpathtools import *
class HigherOrderBezier:
def __init__(self, bpoints):
self.bpts = bpoints
def bpoints(self):
return self.bpts
def point(self, t):
return bezier_point(self.bpoints(), t)
def __repr__(self):
return str(self.bpts)
def random_bezier(degree):
if degree <= 3:
return bpoints2bezier(polynomial2bezier(np.random.rand(degree + 1)))
else:
return HigherOrderBezier(np.random.rand(degree + 1))
def points_in_each_seg_slow(path, tvals):
return [seg.poly()(tvals) for seg in path]
def points_in_each_seg(path, tvals):
"""Compute seg.point(t) for each seg in path and each t in tvals."""
A = np.matrix([[-1, 3, -3, 1], # transforms cubic bez to standard poly
[ 3, -6, 3, 0],
[-3, 3, 0, 0],
[ 1, 0, 0, 0]])
B = [seg.bpoints() for seg in path]
return np.dot(B, np.dot(A, np.power(tvals, [[3],[2],[1],[0]])))
if __name__ == '__main__':
num_segs = 1000
testpath = Path(*[random_bezier(3) for dummy in range(num_segs)])
tvals = np.linspace(0, 1, 10)
pts = points_in_each_seg(testpath, tvals)
pts_check = points_in_each_seg_slow(testpath, tvals)
print np.max(pts - pts_check)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment