Module sverchok.utils.nurbs_common
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
import numpy as np
from math import sqrt
from sverchok.utils.math import binomial
from sverchok.utils.curve import knotvector as sv_knotvector
from sverchok.dependencies import geomdl
class SvNurbsMaths(object):
"""
This class allows modules such as curve.primitives and others to
create NURBS curves or surfaces without need to import curves.nurbs
or surfaces.nurbs. It is required to exclude such imports because
curves.nurbs and surfaces.nurbs require curves.primitives and several
other curves.* and surfaces.* modules.
"""
NATIVE = 'NATIVE'
GEOMDL = 'GEOMDL'
FREECAD = 'FREECAD'
# Classes by implementation
curve_classes = dict()
surface_classes = dict()
@staticmethod
def build_curve(implementation, degree, knotvector, control_points, weights=None, normalize_knots=False):
kv_error = sv_knotvector.check(degree, knotvector, len(control_points))
if kv_error is not None:
raise Exception(kv_error)
nurbs_class = SvNurbsMaths.curve_classes.get(implementation)
if nurbs_class is None and isinstance(implementation, type):
nurbs_class = implementation
if nurbs_class is None:
raise Exception(f"Unsupported NURBS Curve implementation: {implementation}")
else:
return nurbs_class.build(implementation, degree, knotvector, control_points, weights, normalize_knots)
@staticmethod
def build_surface(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights=None, normalize_knots=False):
kv_error = sv_knotvector.check(degree_u, knotvector_u, len(control_points))
if kv_error is not None:
raise Exception("U direction: " + kv_error)
kv_error = sv_knotvector.check(degree_v, knotvector_v, len(control_points[0]))
if kv_error is not None:
raise Exception("V direction: " + kv_error)
nurbs_class = SvNurbsMaths.surface_classes.get(implementation)
if nurbs_class is None:
raise Exception(f"Unsupported NURBS Surface implementation: {implementation}")
else:
return nurbs_class.build(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights)
@staticmethod
def interpolate_curve(implementation, degree, points, metric='DISTANCE', **kwargs):
nurbs_class = SvNurbsMaths.curve_classes.get(implementation)
if nurbs_class is None and isinstance(implementation, type):
nurbs_class = implementation
return nurbs_class.interpolate(degree, points, metric=metric, **kwargs)
@staticmethod
def to_nurbs_curve(curve, implementation = NATIVE):
nurbs_class = SvNurbsMaths.curve_classes.get(implementation)
if nurbs_class is None:
raise Exception(f"Unsupported NURBS Curve implementation: {implementation}")
else:
return nurbs_class.to_nurbs(curve, implementation)
@staticmethod
def to_nurbs_surface(surface, implementation = NATIVE):
nurbs_class = SvNurbsMaths.surface_classes.get(implementation)
if nurbs_class is None:
raise Exception(f"Unsupported NURBS Surface implementation: {implementation}")
else:
return nurbs_class.to_nurbs(surface, implementation)
def nurbs_divide(numerator, denominator):
if denominator.ndim < 2:
denominator = denominator[np.newaxis].T
good = (denominator != 0)
good_num = good.flatten()
result = np.zeros_like(numerator)
result[good_num] = numerator[good_num] / denominator[good][np.newaxis].T
return result
def nurbs_divide_flat(numerator, denominator):
good = (denominator != 0)
result = np.zeros_like(numerator)
result[good] = numerator[good] / denominator[good]
return result
def bezier_coefficient(n, k, ts):
C = binomial(n, k)
return C * ts**k * (1 - ts)**(n-k)
def elevate_bezier_degree(self_degree, control_points, delta=1):
# See "The NURBS book" (2nd edition), p.5.5, eq. 5.36
t = delta
p = self_degree
new_points = []
P = control_points
for i in range(p+t+1):
j0 = max(0, i-t)
j1 = min(p, i)
js = range(j0, j1+1)
c1 = np.array([binomial(p, j) for j in js])
c2 = np.array([binomial(t, i-j) for j in js])
ps = P[j0:j1+1, :]
numerator = (c1 * c2)[np.newaxis].T * ps
denominator = binomial(p+t, i)
#print(f"E: p {p}, i {i}, c1 {c1}, c2 {c2}, denom {denominator}, ps {ps}")
point = numerator.sum(axis=0) / denominator
new_points.append(point)
return np.array(new_points)
def reduce_bezier_degree_once(self_degree, control_points):
# See "The NURBS Book" (2nd edition), p.5.6 eq. 5.40, 5.41, 5.42
# Also, from eq. 5.43 and 5.44 there, we derive estimations of error
# bounds more precise than those which are given in eq. 5.45, 5.46
# in the same paragraph later.
p = self_degree
r = (p-1) // 2
ndim = control_points.shape[1]
alpha = [float(i) / float(p) for i in range(p)]
new_control_points = np.zeros((p, ndim))
new_control_points[0] = control_points[0]
new_control_points[p-1] = control_points[p]
if p % 2 == 0:
for i in range(1, r+1):
new_control_points[i] = (control_points[i] - alpha[i] * new_control_points[i-1]) / (1 - alpha[i])
for i in range(p-2, r, -1): # reverse order
new_control_points[i] = (control_points[i+1] - (1 - alpha[i+1])*new_control_points[i+1]) / alpha[i+1]
error = np.linalg.norm(control_points[r+1] - 0.5*(new_control_points[r] + new_control_points[r+1]))
# directly follows from eq. 5.43
error *= bezier_coefficient(p, r+1, 0.5)
else:
for i in range(1, r):
new_control_points[i] = (control_points[i] - alpha[i] * new_control_points[i-1]) / (1 - alpha[i])
for i in range(p-2, r, -1): # reverse order
new_control_points[i] = (control_points[i+1] - (1 - alpha[i+1])*new_control_points[i+1]) / alpha[i+1]
p_l = (control_points[r] - alpha[r]*new_control_points[r-1]) / (1 - alpha[r])
p_r = (control_points[r+1] - (1 - alpha[r+1])*new_control_points[r+1]) / alpha[r+1]
new_control_points[r] = 0.5 * (p_l + p_r)
error = np.linalg.norm(p_l - p_r)
# See eq. 5.44. Knowing that r == (p-1)/2 and p is odd, and
# knowing properties of binomial coefficients, we know that
# C(p,r) == C(p, r+1); from that, one can write that
# B[r,p](u) - B[r+1,p](u) = C(p,r) * u^r * (1-u)^(r+1) * (1 - 2*u) (*)
# By manually differentiating this, one can find out that it
# reaches maximums at u = (p +- sqrt(p)) / (2*p)
# (both maximums are equal due to symmetry).
max_u = (p - sqrt(p)) / (2*p)
# from (*); it's quite obvious that this is positive since max_u < 1/2
b_error = binomial(p,r) * max_u**r * (1 - max_u)**(r+1) * (1 - 2*max_u)
error *= 0.5 * (1 - alpha[r]) * b_error
return new_control_points, error
def reduce_bezier_degree(self_degree, control_points, delta=1):
max_error = 0.0
degree = self_degree
for i in range(delta):
control_points, error = reduce_bezier_degree_once(degree, control_points)
max_error = max(max_error, error)
return control_points, max_error
def from_homogenous(control_points):
if control_points.ndim == 2: # curve
weights = control_points[:,3]
weighted = control_points[:,0:3]
points = weighted / weights[np.newaxis].T
return points, weights
elif control_points.ndim == 3: # surface
weights = control_points[:,:,3]
weighted = control_points[:,:,0:3]
points = weighted / np.transpose(weights[np.newaxis], axes=(1,2,0))
return points, weights
else:
raise Exception(f"control_points have ndim={control_points.ndim}, supported are only 2 and 3")
class SvNurbsBasisFunctions(object):
def __init__(self, knotvector):
self.knotvector = np.array(knotvector)
self._cache = dict()
def function(self, i, p, reset_cache=True):
if reset_cache:
self._cache = dict()
def calc(us):
value = self._cache.get((i,p, 0))
if value is not None:
return value
u = self.knotvector
if p <= 0:
if i < 0 or i >= len(u):
value = np.zeros_like(us)
self._cache[(i,p,0)] = value
return value
else:
if i+1 >= len(u):
u_next = u[-1]
is_last = True
else:
u_next = u[i+1]
is_last = u_next >= u[-1]
if is_last:
c2 = us <= u_next
else:
c2 = us < u_next
condition = np.logical_and(u[i] <= us, c2)
value = np.where(condition, 1.0, 0.0)
self._cache[(i,p,0)] = value
return value
else:
denom1 = (u[i+p] - u[i])
denom2 = (u[i+p+1] - u[i+1])
if denom1 != 0:
n1 = self.function(i, p-1, reset_cache=False)(us)
if denom2 != 0:
n2 = self.function(i+1, p-1, reset_cache=False)(us)
if denom1 == 0 and denom2 == 0:
value = np.zeros_like(us)
self._cache[(i,p,0)] = value
return value
elif denom1 == 0 and denom2 != 0:
c2 = (u[i+p+1] - us) / denom2
value = c2 * n2
self._cache[(i,p,0)] = value
return value
elif denom1 != 0 and denom2 == 0:
c1 = (us - u[i]) / denom1
value = c1 * n1
self._cache[(i,p,0)] = value
return value
else: # denom1 != 0 and denom2 != 0
c1 = (us - u[i]) / denom1
c2 = (u[i+p+1] - us) / denom2
value = c1 * n1 + c2 * n2
self._cache[(i,p,0)] = value
return value
return calc
def derivative(self, i, p, k, reset_cache=True):
if reset_cache:
self._cache = dict()
if k == 0:
return self.function(i, p, reset_cache=False)
def calc(us):
value = self._cache.get((i, p, k))
if value is not None:
return value
n1 = self.derivative(i, p-1, k-1, reset_cache=False)(us)
n2 = self.derivative(i+1, p-1, k-1, reset_cache=False)(us)
u = self.knotvector
denom1 = u[i+p] - u[i]
denom2 = u[i+p+1] - u[i+1]
if denom1 == 0:
s1 = np.zeros_like(us)
else:
s1 = n1 / denom1
if denom2 == 0:
s2 = np.zeros_like(us)
else:
s2 = n2 / denom2
value = p*(s1 - s2)
self._cache[(i,p,k)] = value
return value
return calc
def fraction(self, i, p, weights, reset_cache=True):
if reset_cache:
self._cache = dict()
n = len(weights)
def calc(us):
numerator = self.function(i,p, reset_cache=reset_cache)(us) * weights[i]
ds = [self.function(j,p, reset_cache=False)(us) * weights[j] for j in range(n)]
denominator = sum(ds)
return nurbs_divide_flat(numerator, denominator)
return calc
def weighted_derivative(self, i, p, k, weights, reset_cache=True):
if reset_cache:
self._cache = dict()
n = len(weights)
def calc(us):
ns = self.derivative(i, p, k)(us)
numerator = ns * weights[i]
denominator = weights.sum()
return numerator / denominator
return calc
class CantInsertKnotException(Exception):
pass
class CantRemoveKnotException(Exception):
pass
class CantReduceDegreeException(Exception):
pass
Functions
def bezier_coefficient(n, k, ts)
-
Expand source code
def bezier_coefficient(n, k, ts): C = binomial(n, k) return C * ts**k * (1 - ts)**(n-k)
def elevate_bezier_degree(self_degree, control_points, delta=1)
-
Expand source code
def elevate_bezier_degree(self_degree, control_points, delta=1): # See "The NURBS book" (2nd edition), p.5.5, eq. 5.36 t = delta p = self_degree new_points = [] P = control_points for i in range(p+t+1): j0 = max(0, i-t) j1 = min(p, i) js = range(j0, j1+1) c1 = np.array([binomial(p, j) for j in js]) c2 = np.array([binomial(t, i-j) for j in js]) ps = P[j0:j1+1, :] numerator = (c1 * c2)[np.newaxis].T * ps denominator = binomial(p+t, i) #print(f"E: p {p}, i {i}, c1 {c1}, c2 {c2}, denom {denominator}, ps {ps}") point = numerator.sum(axis=0) / denominator new_points.append(point) return np.array(new_points)
def from_homogenous(control_points)
-
Expand source code
def from_homogenous(control_points): if control_points.ndim == 2: # curve weights = control_points[:,3] weighted = control_points[:,0:3] points = weighted / weights[np.newaxis].T return points, weights elif control_points.ndim == 3: # surface weights = control_points[:,:,3] weighted = control_points[:,:,0:3] points = weighted / np.transpose(weights[np.newaxis], axes=(1,2,0)) return points, weights else: raise Exception(f"control_points have ndim={control_points.ndim}, supported are only 2 and 3")
def nurbs_divide(numerator, denominator)
-
Expand source code
def nurbs_divide(numerator, denominator): if denominator.ndim < 2: denominator = denominator[np.newaxis].T good = (denominator != 0) good_num = good.flatten() result = np.zeros_like(numerator) result[good_num] = numerator[good_num] / denominator[good][np.newaxis].T return result
def nurbs_divide_flat(numerator, denominator)
-
Expand source code
def nurbs_divide_flat(numerator, denominator): good = (denominator != 0) result = np.zeros_like(numerator) result[good] = numerator[good] / denominator[good] return result
def reduce_bezier_degree(self_degree, control_points, delta=1)
-
Expand source code
def reduce_bezier_degree(self_degree, control_points, delta=1): max_error = 0.0 degree = self_degree for i in range(delta): control_points, error = reduce_bezier_degree_once(degree, control_points) max_error = max(max_error, error) return control_points, max_error
def reduce_bezier_degree_once(self_degree, control_points)
-
Expand source code
def reduce_bezier_degree_once(self_degree, control_points): # See "The NURBS Book" (2nd edition), p.5.6 eq. 5.40, 5.41, 5.42 # Also, from eq. 5.43 and 5.44 there, we derive estimations of error # bounds more precise than those which are given in eq. 5.45, 5.46 # in the same paragraph later. p = self_degree r = (p-1) // 2 ndim = control_points.shape[1] alpha = [float(i) / float(p) for i in range(p)] new_control_points = np.zeros((p, ndim)) new_control_points[0] = control_points[0] new_control_points[p-1] = control_points[p] if p % 2 == 0: for i in range(1, r+1): new_control_points[i] = (control_points[i] - alpha[i] * new_control_points[i-1]) / (1 - alpha[i]) for i in range(p-2, r, -1): # reverse order new_control_points[i] = (control_points[i+1] - (1 - alpha[i+1])*new_control_points[i+1]) / alpha[i+1] error = np.linalg.norm(control_points[r+1] - 0.5*(new_control_points[r] + new_control_points[r+1])) # directly follows from eq. 5.43 error *= bezier_coefficient(p, r+1, 0.5) else: for i in range(1, r): new_control_points[i] = (control_points[i] - alpha[i] * new_control_points[i-1]) / (1 - alpha[i]) for i in range(p-2, r, -1): # reverse order new_control_points[i] = (control_points[i+1] - (1 - alpha[i+1])*new_control_points[i+1]) / alpha[i+1] p_l = (control_points[r] - alpha[r]*new_control_points[r-1]) / (1 - alpha[r]) p_r = (control_points[r+1] - (1 - alpha[r+1])*new_control_points[r+1]) / alpha[r+1] new_control_points[r] = 0.5 * (p_l + p_r) error = np.linalg.norm(p_l - p_r) # See eq. 5.44. Knowing that r == (p-1)/2 and p is odd, and # knowing properties of binomial coefficients, we know that # C(p,r) == C(p, r+1); from that, one can write that # B[r,p](u) - B[r+1,p](u) = C(p,r) * u^r * (1-u)^(r+1) * (1 - 2*u) (*) # By manually differentiating this, one can find out that it # reaches maximums at u = (p +- sqrt(p)) / (2*p) # (both maximums are equal due to symmetry). max_u = (p - sqrt(p)) / (2*p) # from (*); it's quite obvious that this is positive since max_u < 1/2 b_error = binomial(p,r) * max_u**r * (1 - max_u)**(r+1) * (1 - 2*max_u) error *= 0.5 * (1 - alpha[r]) * b_error return new_control_points, error
Classes
class CantInsertKnotException (*args, **kwargs)
-
Common base class for all non-exit exceptions.
Expand source code
class CantInsertKnotException(Exception): pass
Ancestors
- builtins.Exception
- builtins.BaseException
class CantReduceDegreeException (*args, **kwargs)
-
Common base class for all non-exit exceptions.
Expand source code
class CantReduceDegreeException(Exception): pass
Ancestors
- builtins.Exception
- builtins.BaseException
class CantRemoveKnotException (*args, **kwargs)
-
Common base class for all non-exit exceptions.
Expand source code
class CantRemoveKnotException(Exception): pass
Ancestors
- builtins.Exception
- builtins.BaseException
class SvNurbsBasisFunctions (knotvector)
-
Expand source code
class SvNurbsBasisFunctions(object): def __init__(self, knotvector): self.knotvector = np.array(knotvector) self._cache = dict() def function(self, i, p, reset_cache=True): if reset_cache: self._cache = dict() def calc(us): value = self._cache.get((i,p, 0)) if value is not None: return value u = self.knotvector if p <= 0: if i < 0 or i >= len(u): value = np.zeros_like(us) self._cache[(i,p,0)] = value return value else: if i+1 >= len(u): u_next = u[-1] is_last = True else: u_next = u[i+1] is_last = u_next >= u[-1] if is_last: c2 = us <= u_next else: c2 = us < u_next condition = np.logical_and(u[i] <= us, c2) value = np.where(condition, 1.0, 0.0) self._cache[(i,p,0)] = value return value else: denom1 = (u[i+p] - u[i]) denom2 = (u[i+p+1] - u[i+1]) if denom1 != 0: n1 = self.function(i, p-1, reset_cache=False)(us) if denom2 != 0: n2 = self.function(i+1, p-1, reset_cache=False)(us) if denom1 == 0 and denom2 == 0: value = np.zeros_like(us) self._cache[(i,p,0)] = value return value elif denom1 == 0 and denom2 != 0: c2 = (u[i+p+1] - us) / denom2 value = c2 * n2 self._cache[(i,p,0)] = value return value elif denom1 != 0 and denom2 == 0: c1 = (us - u[i]) / denom1 value = c1 * n1 self._cache[(i,p,0)] = value return value else: # denom1 != 0 and denom2 != 0 c1 = (us - u[i]) / denom1 c2 = (u[i+p+1] - us) / denom2 value = c1 * n1 + c2 * n2 self._cache[(i,p,0)] = value return value return calc def derivative(self, i, p, k, reset_cache=True): if reset_cache: self._cache = dict() if k == 0: return self.function(i, p, reset_cache=False) def calc(us): value = self._cache.get((i, p, k)) if value is not None: return value n1 = self.derivative(i, p-1, k-1, reset_cache=False)(us) n2 = self.derivative(i+1, p-1, k-1, reset_cache=False)(us) u = self.knotvector denom1 = u[i+p] - u[i] denom2 = u[i+p+1] - u[i+1] if denom1 == 0: s1 = np.zeros_like(us) else: s1 = n1 / denom1 if denom2 == 0: s2 = np.zeros_like(us) else: s2 = n2 / denom2 value = p*(s1 - s2) self._cache[(i,p,k)] = value return value return calc def fraction(self, i, p, weights, reset_cache=True): if reset_cache: self._cache = dict() n = len(weights) def calc(us): numerator = self.function(i,p, reset_cache=reset_cache)(us) * weights[i] ds = [self.function(j,p, reset_cache=False)(us) * weights[j] for j in range(n)] denominator = sum(ds) return nurbs_divide_flat(numerator, denominator) return calc def weighted_derivative(self, i, p, k, weights, reset_cache=True): if reset_cache: self._cache = dict() n = len(weights) def calc(us): ns = self.derivative(i, p, k)(us) numerator = ns * weights[i] denominator = weights.sum() return numerator / denominator return calc
Methods
def derivative(self, i, p, k, reset_cache=True)
-
Expand source code
def derivative(self, i, p, k, reset_cache=True): if reset_cache: self._cache = dict() if k == 0: return self.function(i, p, reset_cache=False) def calc(us): value = self._cache.get((i, p, k)) if value is not None: return value n1 = self.derivative(i, p-1, k-1, reset_cache=False)(us) n2 = self.derivative(i+1, p-1, k-1, reset_cache=False)(us) u = self.knotvector denom1 = u[i+p] - u[i] denom2 = u[i+p+1] - u[i+1] if denom1 == 0: s1 = np.zeros_like(us) else: s1 = n1 / denom1 if denom2 == 0: s2 = np.zeros_like(us) else: s2 = n2 / denom2 value = p*(s1 - s2) self._cache[(i,p,k)] = value return value return calc
def fraction(self, i, p, weights, reset_cache=True)
-
Expand source code
def fraction(self, i, p, weights, reset_cache=True): if reset_cache: self._cache = dict() n = len(weights) def calc(us): numerator = self.function(i,p, reset_cache=reset_cache)(us) * weights[i] ds = [self.function(j,p, reset_cache=False)(us) * weights[j] for j in range(n)] denominator = sum(ds) return nurbs_divide_flat(numerator, denominator) return calc
def function(self, i, p, reset_cache=True)
-
Expand source code
def function(self, i, p, reset_cache=True): if reset_cache: self._cache = dict() def calc(us): value = self._cache.get((i,p, 0)) if value is not None: return value u = self.knotvector if p <= 0: if i < 0 or i >= len(u): value = np.zeros_like(us) self._cache[(i,p,0)] = value return value else: if i+1 >= len(u): u_next = u[-1] is_last = True else: u_next = u[i+1] is_last = u_next >= u[-1] if is_last: c2 = us <= u_next else: c2 = us < u_next condition = np.logical_and(u[i] <= us, c2) value = np.where(condition, 1.0, 0.0) self._cache[(i,p,0)] = value return value else: denom1 = (u[i+p] - u[i]) denom2 = (u[i+p+1] - u[i+1]) if denom1 != 0: n1 = self.function(i, p-1, reset_cache=False)(us) if denom2 != 0: n2 = self.function(i+1, p-1, reset_cache=False)(us) if denom1 == 0 and denom2 == 0: value = np.zeros_like(us) self._cache[(i,p,0)] = value return value elif denom1 == 0 and denom2 != 0: c2 = (u[i+p+1] - us) / denom2 value = c2 * n2 self._cache[(i,p,0)] = value return value elif denom1 != 0 and denom2 == 0: c1 = (us - u[i]) / denom1 value = c1 * n1 self._cache[(i,p,0)] = value return value else: # denom1 != 0 and denom2 != 0 c1 = (us - u[i]) / denom1 c2 = (u[i+p+1] - us) / denom2 value = c1 * n1 + c2 * n2 self._cache[(i,p,0)] = value return value return calc
def weighted_derivative(self, i, p, k, weights, reset_cache=True)
-
Expand source code
def weighted_derivative(self, i, p, k, weights, reset_cache=True): if reset_cache: self._cache = dict() n = len(weights) def calc(us): ns = self.derivative(i, p, k)(us) numerator = ns * weights[i] denominator = weights.sum() return numerator / denominator return calc
class SvNurbsMaths
-
This class allows modules such as curve.primitives and others to create NURBS curves or surfaces without need to import curves.nurbs or surfaces.nurbs. It is required to exclude such imports because curves.nurbs and surfaces.nurbs require curves.primitives and several other curves. and surfaces. modules.
Expand source code
class SvNurbsMaths(object): """ This class allows modules such as curve.primitives and others to create NURBS curves or surfaces without need to import curves.nurbs or surfaces.nurbs. It is required to exclude such imports because curves.nurbs and surfaces.nurbs require curves.primitives and several other curves.* and surfaces.* modules. """ NATIVE = 'NATIVE' GEOMDL = 'GEOMDL' FREECAD = 'FREECAD' # Classes by implementation curve_classes = dict() surface_classes = dict() @staticmethod def build_curve(implementation, degree, knotvector, control_points, weights=None, normalize_knots=False): kv_error = sv_knotvector.check(degree, knotvector, len(control_points)) if kv_error is not None: raise Exception(kv_error) nurbs_class = SvNurbsMaths.curve_classes.get(implementation) if nurbs_class is None and isinstance(implementation, type): nurbs_class = implementation if nurbs_class is None: raise Exception(f"Unsupported NURBS Curve implementation: {implementation}") else: return nurbs_class.build(implementation, degree, knotvector, control_points, weights, normalize_knots) @staticmethod def build_surface(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights=None, normalize_knots=False): kv_error = sv_knotvector.check(degree_u, knotvector_u, len(control_points)) if kv_error is not None: raise Exception("U direction: " + kv_error) kv_error = sv_knotvector.check(degree_v, knotvector_v, len(control_points[0])) if kv_error is not None: raise Exception("V direction: " + kv_error) nurbs_class = SvNurbsMaths.surface_classes.get(implementation) if nurbs_class is None: raise Exception(f"Unsupported NURBS Surface implementation: {implementation}") else: return nurbs_class.build(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights) @staticmethod def interpolate_curve(implementation, degree, points, metric='DISTANCE', **kwargs): nurbs_class = SvNurbsMaths.curve_classes.get(implementation) if nurbs_class is None and isinstance(implementation, type): nurbs_class = implementation return nurbs_class.interpolate(degree, points, metric=metric, **kwargs) @staticmethod def to_nurbs_curve(curve, implementation = NATIVE): nurbs_class = SvNurbsMaths.curve_classes.get(implementation) if nurbs_class is None: raise Exception(f"Unsupported NURBS Curve implementation: {implementation}") else: return nurbs_class.to_nurbs(curve, implementation) @staticmethod def to_nurbs_surface(surface, implementation = NATIVE): nurbs_class = SvNurbsMaths.surface_classes.get(implementation) if nurbs_class is None: raise Exception(f"Unsupported NURBS Surface implementation: {implementation}") else: return nurbs_class.to_nurbs(surface, implementation)
Class variables
var FREECAD
var GEOMDL
var NATIVE
var curve_classes
var surface_classes
Static methods
def build_curve(implementation, degree, knotvector, control_points, weights=None, normalize_knots=False)
-
Expand source code
@staticmethod def build_curve(implementation, degree, knotvector, control_points, weights=None, normalize_knots=False): kv_error = sv_knotvector.check(degree, knotvector, len(control_points)) if kv_error is not None: raise Exception(kv_error) nurbs_class = SvNurbsMaths.curve_classes.get(implementation) if nurbs_class is None and isinstance(implementation, type): nurbs_class = implementation if nurbs_class is None: raise Exception(f"Unsupported NURBS Curve implementation: {implementation}") else: return nurbs_class.build(implementation, degree, knotvector, control_points, weights, normalize_knots)
def build_surface(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights=None, normalize_knots=False)
-
Expand source code
@staticmethod def build_surface(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights=None, normalize_knots=False): kv_error = sv_knotvector.check(degree_u, knotvector_u, len(control_points)) if kv_error is not None: raise Exception("U direction: " + kv_error) kv_error = sv_knotvector.check(degree_v, knotvector_v, len(control_points[0])) if kv_error is not None: raise Exception("V direction: " + kv_error) nurbs_class = SvNurbsMaths.surface_classes.get(implementation) if nurbs_class is None: raise Exception(f"Unsupported NURBS Surface implementation: {implementation}") else: return nurbs_class.build(implementation, degree_u, degree_v, knotvector_u, knotvector_v, control_points, weights)
def interpolate_curve(implementation, degree, points, metric='DISTANCE', **kwargs)
-
Expand source code
@staticmethod def interpolate_curve(implementation, degree, points, metric='DISTANCE', **kwargs): nurbs_class = SvNurbsMaths.curve_classes.get(implementation) if nurbs_class is None and isinstance(implementation, type): nurbs_class = implementation return nurbs_class.interpolate(degree, points, metric=metric, **kwargs)
def to_nurbs_curve(curve, implementation='NATIVE')
-
Expand source code
@staticmethod def to_nurbs_curve(curve, implementation = NATIVE): nurbs_class = SvNurbsMaths.curve_classes.get(implementation) if nurbs_class is None: raise Exception(f"Unsupported NURBS Curve implementation: {implementation}") else: return nurbs_class.to_nurbs(curve, implementation)
def to_nurbs_surface(surface, implementation='NATIVE')
-
Expand source code
@staticmethod def to_nurbs_surface(surface, implementation = NATIVE): nurbs_class = SvNurbsMaths.surface_classes.get(implementation) if nurbs_class is None: raise Exception(f"Unsupported NURBS Surface implementation: {implementation}") else: return nurbs_class.to_nurbs(surface, implementation)