Module sverchok.utils.curve.splprep
An interface to splprep
method from scipy.
Expand source code
# This file is part of project Sverchok. It's copyrighted by the contributors
# recorded in the version control history of the file, available from
# its original location https://github.com/nortikin/sverchok/commit/master
#
# SPDX-License-Identifier: GPL3
# License-Filename: LICENSE
"""
An interface to `splprep` method from scipy.
"""
import numpy as np
from sverchok.utils.curve.nurbs import SvNurbsCurve
from sverchok.utils.geom import Spline
from sverchok.dependencies import scipy
if scipy is not None:
from scipy import interpolate
def scipy_nurbs_approximate(points, weights=None, metric='DISTANCE', degree=3, filter_doubles = None, smoothing=None, is_cyclic=False):
"""
Approximate points by a NURBS curve by use of `splprep` method from scipy.
Args:
points: data points to be approximated. np.ndarray of shape (n, 3).
weights: point weights. np.ndarray of shape (n,) or None.
metric: metric to be used. See the list of supported metrics in `sverchok.utils.math.supported_metrics`.
degree: curve degree.
filter_doubles: if not None, this is the threshold for distance between
points, which are to be considered too close to one another; duplicates
are removed before approximation procedure. If None, duplicates
elimination is not performed.
smoothing: smoothing parameter to `splprep` method. None means scipy will decide on it's own.
is_cyclic: set to True if the curve must be closed.
Returns:
an instance of SvNurbsCurve.
"""
points = np.asarray(points)
if weights is not None and len(points) != len(weights):
raise Exception("Number of weights must be equal to number of points")
if filter_doubles is not None:
good = np.where(np.linalg.norm(np.diff(points, axis=0), axis=1) > filter_doubles)
points = np.r_[points[good], points[-1][np.newaxis]]
if weights is not None:
weights = np.r_[weights[good], weights[-1]]
if is_cyclic:
if (points[0] != points[-1]).any():
points = np.vstack((points, points[0]))
if weights is not None:
weights = np.insert(weights, -1, weights[0])
points_orig = points
points = points.T
kwargs = dict()
if weights is not None:
kwargs['w'] = np.asarray(weights)
if metric is not None:
tknots = Spline.create_knots(points.T, metric)
if len(tknots) != len(points.T):
raise Exception(f"Number of T knots ({len(tknots)}) is not equal to number of points ({len(points.T)})")
kwargs['u'] = tknots
if degree is not None:
kwargs['k'] = degree
if smoothing is not None:
kwargs['s'] = smoothing
if is_cyclic:
kwargs['per'] = 1
tck, u = interpolate.splprep(points, **kwargs)
knotvector = tck[0]
control_points = np.stack(tck[1]).T
degree = tck[2]
curve = SvNurbsCurve.build(SvNurbsCurve.NATIVE,
degree, knotvector,
control_points)
if is_cyclic:
curve = curve.cut_segment(0.0, 1.00)
#curve.u_bounds = (0.0, 1.0)
return curve
Functions
def scipy_nurbs_approximate(points, weights=None, metric='DISTANCE', degree=3, filter_doubles=None, smoothing=None, is_cyclic=False)
-
Approximate points by a NURBS curve by use of
splprep
method from scipy.Args
points
- data points to be approximated. np.ndarray of shape (n, 3).
weights
- point weights. np.ndarray of shape (n,) or None.
metric
- metric to be used. See the list of supported metrics in
sverchok.utils.math.supported_metrics
. degree
- curve degree.
filter_doubles
- if not None, this is the threshold for distance between points, which are to be considered too close to one another; duplicates are removed before approximation procedure. If None, duplicates elimination is not performed.
smoothing
- smoothing parameter to
splprep
method. None means scipy will decide on it's own. is_cyclic
- set to True if the curve must be closed.
Returns
an instance of SvNurbsCurve.
Expand source code
def scipy_nurbs_approximate(points, weights=None, metric='DISTANCE', degree=3, filter_doubles = None, smoothing=None, is_cyclic=False): """ Approximate points by a NURBS curve by use of `splprep` method from scipy. Args: points: data points to be approximated. np.ndarray of shape (n, 3). weights: point weights. np.ndarray of shape (n,) or None. metric: metric to be used. See the list of supported metrics in `sverchok.utils.math.supported_metrics`. degree: curve degree. filter_doubles: if not None, this is the threshold for distance between points, which are to be considered too close to one another; duplicates are removed before approximation procedure. If None, duplicates elimination is not performed. smoothing: smoothing parameter to `splprep` method. None means scipy will decide on it's own. is_cyclic: set to True if the curve must be closed. Returns: an instance of SvNurbsCurve. """ points = np.asarray(points) if weights is not None and len(points) != len(weights): raise Exception("Number of weights must be equal to number of points") if filter_doubles is not None: good = np.where(np.linalg.norm(np.diff(points, axis=0), axis=1) > filter_doubles) points = np.r_[points[good], points[-1][np.newaxis]] if weights is not None: weights = np.r_[weights[good], weights[-1]] if is_cyclic: if (points[0] != points[-1]).any(): points = np.vstack((points, points[0])) if weights is not None: weights = np.insert(weights, -1, weights[0]) points_orig = points points = points.T kwargs = dict() if weights is not None: kwargs['w'] = np.asarray(weights) if metric is not None: tknots = Spline.create_knots(points.T, metric) if len(tknots) != len(points.T): raise Exception(f"Number of T knots ({len(tknots)}) is not equal to number of points ({len(points.T)})") kwargs['u'] = tknots if degree is not None: kwargs['k'] = degree if smoothing is not None: kwargs['s'] = smoothing if is_cyclic: kwargs['per'] = 1 tck, u = interpolate.splprep(points, **kwargs) knotvector = tck[0] control_points = np.stack(tck[1]).T degree = tck[2] curve = SvNurbsCurve.build(SvNurbsCurve.NATIVE, degree, knotvector, control_points) if is_cyclic: curve = curve.cut_segment(0.0, 1.00) #curve.u_bounds = (0.0, 1.0) return curve