hub/venv/lib/python3.7/site-packages/trimesh/path/curve.py

130 lines
3.7 KiB
Python

import numpy as np
from ..constants import res_path as res
from ..constants import tol_path as tol
def discretize_bezier(points,
count=None,
scale=1.0):
"""
Parameters
----------
points : (order, dimension) float
Control points of the bezier curve
For a 2D cubic bezier, order=3, dimension=2
count : int, or None
Number of segments
scale : float
Scale of curve
Returns
----------
discrete: (n, dimension) float
Points forming a a polyline representation
"""
# make sure we have a numpy array
points = np.asanyarray(points, dtype=np.float64)
if count is None:
# how much distance does a small percentage of the curve take
# this is so we can figure out how finely we have to sample t
norm = np.linalg.norm(np.diff(points, axis=0), axis=1).sum()
count = np.ceil(norm / (res.seg_frac * scale))
count = int(np.clip(count,
res.min_sections * len(points),
res.max_sections * len(points)))
count = int(count)
# parameterize incrementing 0.0 - 1.0
t = np.linspace(0.0, 1.0, count)
# decrementing 1.0-0.0
t_d = 1.0 - t
n = len(points) - 1
# binomial coefficients, i, and each point
iterable = zip(binomial(n), np.arange(len(points)), points)
# run the actual interpolation
stacked = [((t**i) * (t_d**(n - i))).reshape((-1, 1))
* p * c for c, i, p in iterable]
result = np.sum(stacked, axis=0)
# test to make sure end points are correct
test = np.sum((result[[0, -1]] - points[[0, -1]])**2, axis=1)
assert (test < tol.merge).all()
assert len(result) >= 2
return result
def discretize_bspline(control,
knots,
count=None,
scale=1.0):
"""
Given a B-Splines control points and knot vector, return
a sampled version of the curve.
Parameters
----------
control : (o, d) float
Control points of the b- spline
knots : (j,) float
B-spline knots
count : int
Number of line segments to discretize the spline
If not specified will be calculated as something reasonable
Returns
----------
discrete : (count, dimension) float
Points on a polyline version of the B-spline
"""
# evaluate the b-spline using scipy/fitpack
from scipy.interpolate import splev
# (n, d) control points where d is the dimension of vertices
control = np.asanyarray(control, dtype=np.float64)
degree = len(knots) - len(control) - 1
if count is None:
norm = np.linalg.norm(np.diff(control, axis=0), axis=1).sum()
count = int(np.clip(norm / (res.seg_frac * scale),
res.min_sections * len(control),
res.max_sections * len(control)))
ipl = np.linspace(knots[0], knots[-1], count)
discrete = splev(ipl, [knots, control.T, degree])
discrete = np.column_stack(discrete)
return discrete
def binomial(n):
"""
Return all binomial coefficients for a given order.
For n > 5, scipy.special.binom is used, below we hardcode
to avoid the scipy.special dependency.
Parameters
--------------
n : int
Order of binomial
Returns
---------------
binom : (n + 1,) int
Binomial coefficients of a given order
"""
if n == 1:
return [1, 1]
elif n == 2:
return [1, 2, 1]
elif n == 3:
return [1, 3, 3, 1]
elif n == 4:
return [1, 4, 6, 4, 1]
elif n == 5:
return [1, 5, 10, 10, 5, 1]
else:
from scipy.special import binom
return binom(n, np.arange(n + 1))