Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
:type v: float or [float]
:param int d: Number of derivatives to compute in each direction
:type d: [int]
:param (bool) above: Evaluation in the limit from above
:param tensor: Whether to evaluate on a tensor product grid
:type tensor: bool
:return: Derivative array *X[i,j,k]* of component *xk* evaluated at *(u[i], v[j])*
:rtype: numpy.array
"""
squeeze = all(is_singleton(t) for t in [u,v])
derivs = ensure_listlike(d, self.pardim)
if not self.rational or np.sum(derivs) < 2 or np.sum(derivs) > 3:
return super(Surface, self).derivative(u,v, d=derivs, above=above, tensor=tensor)
u = ensure_listlike(u)
v = ensure_listlike(v)
result = np.zeros((len(u), len(v), self.dimension))
# dNus = [self.bases[0].evaluate(u, d, above) for d in range(derivs[0]+1)]
# dNvs = [self.bases[1].evaluate(v, d, above) for d in range(derivs[1]+1)]
dNus = [self.bases[0].evaluate(u, d, above) for d in range(np.sum(derivs)+1)]
dNvs = [self.bases[1].evaluate(v, d, above) for d in range(np.sum(derivs)+1)]
d0ud0v = evaluate([dNus[0], dNvs[0]], self.controlpoints, tensor)
d1ud0v = evaluate([dNus[1], dNvs[0]], self.controlpoints, tensor)
d0ud1v = evaluate([dNus[0], dNvs[1]], self.controlpoints, tensor)
d1ud1v = evaluate([dNus[1], dNvs[1]], self.controlpoints, tensor)
d2ud0v = evaluate([dNus[2], dNvs[0]], self.controlpoints, tensor)
d0ud2v = evaluate([dNus[0], dNvs[2]], self.controlpoints, tensor)
W = d0ud0v[:,:,-1]
dWdu = d1ud0v[:,:,-1]
dWdv = d0ud1v[:,:,-1]
tangential derivatives at the given points.
:param u,v,...: Parametric coordinates in which to evaluate
:type u,v,...: float or [float]
:param int direction: The tangential direction
:param (bool) above: Evaluation in the limit from above
:param tensor: Whether to evaluate on a tensor product grid
:type tensor: bool
:return: Tangents
:rtype: tuple
"""
direction = kwargs.get('direction', None)
derivative = [0] * self.pardim
above = kwargs.get('above', [True] * self.pardim)
above = ensure_listlike(above, self.pardim)
tensor = kwargs.get('tensor', True)
if self.pardim == 1: # curves
direction = 0
if direction is None:
result = ()
for i in range(self.pardim):
derivative[i] = 1
# compute velocity in this direction
v = self.derivative(*params, d=derivative, above=above, tensor=tensor)
# normalize
if len(v.shape)==1:
speed = np.linalg.norm(v)
else:
def insert_knot(self, knot, direction=0):
""" Insert a new knot into the spline.
:param int direction: The direction to insert in
:param knot: The new knot(s) to insert
:type knot: float or [float]
:raises ValueError: For invalid direction
:return: self
"""
shape = self.controlpoints.shape
# for single-value input, wrap it into a list
knot = ensure_listlike(knot)
direction = check_direction(direction, self.pardim)
C = np.identity(shape[direction])
for k in knot:
C = self.bases[direction].insert_knot(k) @ C
self.controlpoints = np.tensordot(C, self.controlpoints, axes=(1, direction))
self.controlpoints = self.controlpoints.transpose(transpose_fix(self.pardim, direction))
return self
:type u,v,...: float or [float]
:param (int) d: Order of derivative to compute
:param (bool) above: Evaluation in the limit from above
:param tensor: Whether to evaluate on a tensor product grid
:type tensor: bool
:return: Derivatives
:rtype: numpy.array
"""
squeeze = all(is_singleton(p) for p in params)
params = [ensure_listlike(p) for p in params]
derivs = kwargs.get('d', [1] * self.pardim)
derivs = ensure_listlike(derivs, self.pardim)
above = kwargs.get('above', [True] * self.pardim)
above = ensure_listlike(above, self.pardim)
tensor = kwargs.get('tensor', True)
if not tensor and len({len(p) for p in params}) != 1:
raise ValueError('Parameters must have same length')
self._validate_domain(*params)
# Evaluate the derivatives of the corresponding bases at the corresponding points
# and build the result array
dNs = [b.evaluate(p, d, from_right) for b, p, d, from_right in zip(self.bases, params, derivs, above)]
result = evaluate(dNs, self.controlpoints, tensor)
# For rational curves, we need to use the quotient rule
# (n/W)' = (n' W - n W') / W^2 = n'/W - nW'/W^2
# * n'(i) = result[..., i]
surface.derivative(0.5, 0.7, d=(1,1))
:param u,v,...: Parametric coordinates in which to evaluate
:type u,v,...: float or [float]
:param (int) d: Order of derivative to compute
:param (bool) above: Evaluation in the limit from above
:param tensor: Whether to evaluate on a tensor product grid
:type tensor: bool
:return: Derivatives
:rtype: numpy.array
"""
squeeze = all(is_singleton(p) for p in params)
params = [ensure_listlike(p) for p in params]
derivs = kwargs.get('d', [1] * self.pardim)
derivs = ensure_listlike(derivs, self.pardim)
above = kwargs.get('above', [True] * self.pardim)
above = ensure_listlike(above, self.pardim)
tensor = kwargs.get('tensor', True)
if not tensor and len({len(p) for p in params}) != 1:
raise ValueError('Parameters must have same length')
self._validate_domain(*params)
# Evaluate the derivatives of the corresponding bases at the corresponding points
# and build the result array
dNs = [b.evaluate(p, d, from_right) for b, p, d, from_right in zip(self.bases, params, derivs, above)]
result = evaluate(dNs, self.controlpoints, tensor)
returned instead.
:param t: Parametric coordinates in which to evaluate
:type t: float or [float]
:param int d: Number of derivatives to compute
:param bool above: Evaluation in the limit from above
:param bool tensor: Not used in this method
:return: Derivative array
:rtype: numpy.array
"""
if not is_singleton(d):
d = d[0]
if not self.rational or d < 2 or d > 3:
return super(Curve, self).derivative(t, d=d, above=above, tensor=tensor)
t = ensure_listlike(t)
result = np.zeros((len(t), self.dimension))
d2 = np.array(self.bases[0].evaluate(t, 2, above) @ self.controlpoints)
d1 = np.array(self.bases[0].evaluate(t, 1, above) @ self.controlpoints)
d0 = np.array(self.bases[0].evaluate(t) @ self.controlpoints)
W = d0[:, -1] # W(t)
W1 = d1[:, -1] # W'(t)
W2 = d2[:, -1] # W''(t)
if d == 2:
for i in range(self.dimension):
result[:, i] = (d2[:, i] * W * W - 2 * W1 *
(d1[:, i] * W - d0[:, i] * W1) - d0[:, i] * W2 * W) / W / W / W
if d == 3:
d3 = np.array(self.bases[0].evaluate(t, 3, above) @ self.controlpoints)
W3 = d3[:,-1] # W'''(t)
W6 = W*W*W*W*W*W # W^6
def texture(self, p, ngeom, ntexture, method='full', irange=[None,None], jrange=[None,None]):
# Set the dimensions of geometry and texture map
# ngeom = np.floor(self.n / (p-1))
# ntexture = np.floor(self.n * n)
# ngeom = ngeom.astype(np.int32)
# ntexture = ntexture.astype(np.int32)
ngeom = ensure_listlike(ngeom, 3)
ntexture = ensure_listlike(ntexture, 3)
p = ensure_listlike(p, 3)
# Create the geometry
ngx, ngy, ngz = ngeom
b1 = BSplineBasis(p[0], [0]*(p[0]-1) + [i/ngx for i in range(ngx+1)] + [1]*(p[0]-1))
b2 = BSplineBasis(p[1], [0]*(p[1]-1) + [i/ngy for i in range(ngy+1)] + [1]*(p[1]-1))
b3 = BSplineBasis(p[2], [0]*(p[2]-1) + [i/ngz for i in range(ngz+1)] + [1]*(p[2]-1))
l2_fit = surface_factory.least_square_fit
vol = self.get_c0_mesh()
i = slice(irange[0], irange[1], None)
j = slice(jrange[0], jrange[1], None)
# special case number of evaluation points for full domain
if irange[1] == None: irange[1] = vol.shape[0]
""" Evaluate the object at given parametric values.
This function returns an *n1* × *n2* × ... × *dim* array, where *ni* is
the number of evaluation points in direction *i*, and *dim* is the
physical dimension of the object.
If there is only one evaluation point, a vector of length *dim* is
returned instead.
:param u,v,...: Parametric coordinates in which to evaluate
:type u,v,...: float or [float]
:return: Geometry coordinates
:rtype: numpy.array
"""
squeeze = is_singleton(params[0])
params = [ensure_listlike(p) for p in params]
self._validate_domain(*params)
# Evaluate the derivatives of the corresponding bases at the corresponding points
# and build the result array
N = self.bases[0].evaluate(params[0], sparse=True)
result = N @ self.controlpoints
# For rational objects, we divide out the weights, which are stored in the
# last coordinate
if self.rational:
for i in range(self.dimension):
result[..., i] /= result[..., -1]
result = np.delete(result, self.dimension, -1)
# Squeeze the singleton dimensions if we only have one point