NurbsUtils Namespace Reference

Classes

class  array2
 

Functions

bool isKnotVectorMonotonic (const std::vector< double > &knots)
 
bool close (double a, double b, double eps)
 
int findSpan (int degree, const std::vector< double > &knots, double u)
 
double bsplineOneBasis (int i, int deg, const std::vector< double > &U, double u)
 
void bsplineBasis (int deg, int span, const std::vector< double > &knots, double u, std::vector< double > &N)
 
void bsplineDerBasis (int deg, int span, const std::vector< double > &knots, double u, int nDers, std::vector< std::vector< double >> &ders)
 
std::vector< MdoublecreateUniformKnotVector (unsigned int numberOfControlPoints, unsigned int degree, bool clampedAtStart, bool clampedAtEnd)
 Creates a uniform (clamped) knot vector. More...
 
void normalizeKnotVector (std::vector< Mdouble > &knots)
 Resets the knot vector to the interval [0, 1]. More...
 
void extendKnotVector (std::vector< Mdouble > &knots, unsigned int degree, unsigned int numStart, unsigned int numEnd, bool forceBothEndsUniform=false)
 Extends the knot vector for when control points have been added at the start or end. More...
 
Vec3D evaluate (Mdouble u, Mdouble v, std::vector< Mdouble > knotsU, std::vector< Mdouble > knotsV, std::vector< std::vector< Vec3D >> controlPoints, std::vector< std::vector< Mdouble >> weights)
 Evaluate point on a NURBS surface. More...
 

Function Documentation

◆ bsplineBasis()

void NurbsUtils::bsplineBasis ( int  deg,
int  span,
const std::vector< double > &  knots,
double  u,
std::vector< double > &  N 
)

Compute all non-zero B-spline basis functions

Parameters
[in]degDegree of the basis function.
[in]spanIndex obtained from findSpan() corresponding the u and knots.
[in]knotsKnot vector corresponding to the basis functions.
[in]uParameter to evaluate the basis functions at.
[in,out]NValues of (deg+1) non-zero basis functions.
110 {
111  N.clear();
112  N.resize(deg + 1, 0.0);
113  std::vector<double> left, right;
114  left.resize(deg + 1, 0.0);
115  right.resize(deg + 1, 0.0);
116 
117  N[0] = 1.0;
118 
119  for (int j = 1; j <= deg; j++)
120  {
121  left[j] = (u - knots[span + 1 - j]);
122  right[j] = knots[span + j] - u;
123  Mdouble saved = 0.0;
124  for (int r = 0; r < j; r++)
125  {
126  const Mdouble temp = N[r] / (right[r + 1] + left[j - r]);
127  N[r] = saved + right[r + 1] * temp;
128  saved = left[j - r] * temp;
129  }
130  N[j] = saved;
131  }
132 }
@ N
Definition: constructor.cpp:22
r
Definition: UniformPSDSelfTest.py:20
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References j, N, and UniformPSDSelfTest::r.

Referenced by NurbsSurface::evaluate(), and evaluate().

◆ bsplineDerBasis()

void NurbsUtils::bsplineDerBasis ( int  deg,
int  span,
const std::vector< double > &  knots,
double  u,
int  nDers,
std::vector< std::vector< double >> &  ders 
)

Compute all non-zero derivatives of B-spline basis functions

Parameters
[in]degDegree of the basis function.
[in]spanIndex obtained from findSpan() corresponding the u and knots.
[in]knotsKnot vector corresponding to the basis functions.
[in]uParameter to evaluate the basis functions at.
[in]nDersNumber of derivatives to compute (nDers <= deg)
[in,out]dersValues of non-zero derivatives of basis functions.
135  {
136 
137  std::vector<double> left, right;
138  left.resize(deg + 1, 0.0);
139  right.resize(deg + 1, 0.0);
140  double saved = 0.0, temp = 0.0;
141 
142  array2<double> ndu(deg + 1, deg + 1);
143  ndu(0, 0) = 1.0;
144 
145  for (int j = 1; j <= deg; j++) {
146  left[j] = u - knots[span + 1 - j];
147  right[j] = knots[span + j] - u;
148  saved = 0.0;
149 
150  for (int r = 0; r < j; r++) {
151  // Lower triangle
152  ndu(j, r) = right[r + 1] + left[j - r];
153  temp = ndu(r, j - 1) / ndu(j, r);
154  // Upper triangle
155  ndu(r, j) = saved + right[r + 1] * temp;
156  saved = left[j - r] * temp;
157  }
158 
159  ndu(j, j) = saved;
160  }
161 
162  ders.clear();
163  ders.resize(nDers + 1);
164  for (int i = 0; i < ders.size(); i++) {
165  ders[i].resize(deg + 1, 0.0);
166  }
167 
168  for (int j = 0; j <= deg; j++) {
169  ders[0][j] = ndu(j, deg);
170  }
171 
172  array2<double> a(2, deg + 1);
173 
174  for (int r = 0; r <= deg; r++) {
175  int s1 = 0;
176  int s2 = 1;
177  a(0, 0) = 1.0;
178 
179  for (int k = 1; k <= nDers; k++) {
180  double d = 0.0;
181  int rk = r - k;
182  int pk = deg - k;
183  int j1 = 0;
184  int j2 = 0;
185 
186  if (r >= k) {
187  a(s2, 0) = a(s1, 0) / ndu(pk + 1, rk);
188  d = a(s2, 0) * ndu(rk, pk);
189  }
190 
191  if (rk >= -1) {
192  j1 = 1;
193  }
194  else {
195  j1 = -rk;
196  }
197 
198  if (r - 1 <= pk) {
199  j2 = k - 1;
200  }
201  else {
202  j2 = deg - r;
203  }
204 
205  for (int j = j1; j <= j2; j++) {
206  a(s2, j) = (a(s1, j) - a(s1, j - 1)) / ndu(pk + 1, rk + j);
207  d += a(s2, j) * ndu(rk + j, pk);
208  }
209 
210  if (r <= pk) {
211  a(s2, k) = -a(s1, k - 1) / ndu(pk + 1, r);
212  d += a(s2, k) * ndu(r, pk);
213  }
214 
215 
216  ders[k][r] = d;
217 
218  int temp = s1;
219  s1 = s2;
220  s2 = temp;
221  }
222  }
223 
224  double fac = static_cast<double>(deg);
225  for (int k = 1; k <= nDers; k++) {
226  for (int j = 0; j <= deg; j++) {
227  ders[k][j] *= fac;
228  }
229  fac *= static_cast<double>(deg - k);
230  }
231 }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const Scalar * a
Definition: level2_cplx_impl.h:32
char char char int int * k
Definition: level2_impl.h:374

References a, i, j, k, and UniformPSDSelfTest::r.

Referenced by NurbsSurface::evaluateDerivatives().

◆ bsplineOneBasis()

double NurbsUtils::bsplineOneBasis ( int  i,
int  deg,
const std::vector< double > &  U,
double  u 
)

Compute a single B-spline basis function

Parameters
[in]iThe ith basis function to compute.
[in]degDegree of the basis function.
[in]UKnot vector corresponding to the basis functions.
[in]uParameter to evaluate the basis functions at.
Returns
The value of the ith basis function at u.
64 {
65  int m = static_cast<int>(U.size()) - 1;
66  // Special case
67  if ((i == 0 && close(u, U[0])) || (i == m - deg - 1 && close(u, U[m])))
68  {
69  return 1.0;
70  }
71  // Local Property
72  if (u < U[i] || u >= U[i + deg + 1])
73  {
74  return 0.0;
75  }
76  // Initialize zeroth-degree functions
77  std::vector<double> N;
78  N.resize(deg + 1);
79  for (int j = 0; j <= deg; j++)
80  {
81  N[j] = (u >= U[i + j] && u < U[i + j + 1]) ? 1.0 : 0.0;
82  }
83  // Compute triangular table
84  for (int k = 1; k <= deg; k++)
85  {
86  double saved = (close(N[0], 0.0)) ? 0.0
87  : ((u - U[i]) * N[0]) / (U[i + k] - U[i]);
88  for (int j = 0; j < deg - k + 1; j++)
89  {
90  double Uleft = U[i + j + 1];
91  double Uright = U[i + j + k + 1];
92  if (close(N[j + 1], 0.0))
93  {
94  N[j] = saved;
95  saved = 0.0;
96  }
97  else
98  {
99  double temp = N[j + 1] / (Uright - Uleft);
100  N[j] = saved + (Uright - u) * temp;
101  saved = (u - Uleft) * temp;
102  }
103  }
104  }
105  return N[0];
106 }
int * m
Definition: level2_cplx_impl.h:294
bool close(double a, double b, double eps)
Definition: NurbsUtils.cc:17
double U
Swimming speed.
Definition: two_d_variable_diff_adapt.cc:53

References close(), i, j, k, m, N, and RachelsAdvectionDiffusion::U.

◆ close()

bool NurbsUtils::close ( double  a,
double  b,
double  eps 
)
18 {
19  return (std::abs(a - b) < eps) ? true : false;
20 }
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
Scalar * b
Definition: benchVecAdd.cpp:17
double eps
Definition: crbond_bessel.cc:24

References a, abs(), b, and CRBond_Bessel::eps.

Referenced by bsplineOneBasis(), extendKnotVector(), findSpan(), and normalizeKnotVector().

◆ createUniformKnotVector()

std::vector< Mdouble > NurbsUtils::createUniformKnotVector ( unsigned int  numberOfControlPoints,
unsigned int  degree,
bool  clampedAtStart,
bool  clampedAtEnd 
)

Creates a uniform (clamped) knot vector.

Parameters
numberOfControlPointsThe number of control points the knot vector should correspond to
degreeThe degree the knot vector should correspond to
clampedAtStartWhether or not the knot vector should be clamped at the start
clampedAtEndWhether or not the knot vector should be clamped at the end
Returns
A uniform (clamped) knot vector
234 {
235  // Total number of knots
236  unsigned int numberOfKnots = numberOfControlPoints + degree + 1;
237  std::vector<Mdouble> knots;
238  knots.reserve(numberOfKnots);
239 
240  // Create uniform from 0 to 1
241  for (int i = 0; i < numberOfKnots; i++)
242  {
243  knots.push_back(i / static_cast<Mdouble>(numberOfKnots - 1));
244  }
245 
246  // When clamped at start, first degree+1 values are set to 0.
247  if (clampedAtStart)
248  {
249  for (int i = 0; i <= degree; i++)
250  {
251  knots[i] = 0.0;
252  }
253  }
254 
255  // When clamped at end, last degree+1 values are set to 1
256  if (clampedAtEnd)
257  {
258  for (int i = 0; i <= degree; i++)
259  {
260  knots[knots.size() - 1 - i] = 1.0;
261  }
262  }
263 
264  return knots;
265 }
const Mdouble degree
Definition: ExtendedMath.h:32

References constants::degree, and i.

Referenced by NurbsSurface::NurbsSurface().

◆ evaluate()

Vec3D NurbsUtils::evaluate ( Mdouble  u,
Mdouble  v,
std::vector< Mdouble knotsU,
std::vector< Mdouble knotsV,
std::vector< std::vector< Vec3D >>  controlPoints,
std::vector< std::vector< Mdouble >>  weights 
)

Evaluate point on a NURBS surface.

Parameters
uParameter to evaluate the surface at
vParameter to evaluate the surface at
knotsUKnot vector in u-direction
knotsVKnot vector in v-direction
controlPoints2D vector of control points
weights2D vector of weights
Returns
Resulting point on the surface at (u, v)
357 {
358  unsigned int degreeU = knotsU.size() - controlPoints.size() - 1;
359  unsigned int degreeV = knotsV.size() - controlPoints[0].size() - 1;
360 
361  Vec3D point = {0,0,0};
362  double temp = 0;
363 
364  // Find span and non-zero basis functions
365  int spanU = findSpan(degreeU, knotsU, u);
366  int spanV = findSpan(degreeV, knotsV, v);
367  std::vector<double> Nu, Nv;
368  bsplineBasis(degreeU, spanU, knotsU, u, Nu);
369  bsplineBasis(degreeV, spanV, knotsV, v, Nv);
370  // make linear combination
371  for (int l = 0; l <= degreeV; ++l)
372  {
373  for (int k = 0; k <= degreeU; ++k)
374  {
375  double weight = Nv[l] * Nu[k] * weights[spanU - degreeU + k][spanV - degreeV + l];
376  point += weight * controlPoints[spanU - degreeU + k][spanV - degreeV + l];
377  temp += weight;
378  }
379  }
380  point /= temp;
381  return point;
382 }
Array< int, Dynamic, 1 > v
Definition: Array_initializer_list_vector_cxx11.cpp:1
Definition: Kernel/Math/Vector.h:30
double Nu
Definition: ConstraintElementsUnitTest.cpp:40
int findSpan(int degree, const std::vector< double > &knots, double u)
Definition: NurbsUtils.cc:22
void bsplineBasis(int deg, int span, const std::vector< double > &knots, double u, std::vector< double > &N)
Definition: NurbsUtils.cc:108
list weights
Definition: calibrate.py:94

References bsplineBasis(), findSpan(), k, Constitutive_Parameters::Nu, v, and calibrate::weights.

Referenced by WearableNurbsWall::getVolumeUnderSurface(), WearableNurbsWall::getVolumeUnderSurfaceX(), main(), and NurbsSurface::set().

◆ extendKnotVector()

void NurbsUtils::extendKnotVector ( std::vector< Mdouble > &  knots,
unsigned int  degree,
unsigned int  numStart,
unsigned int  numEnd,
bool  forceBothEndsUniform = false 
)

Extends the knot vector for when control points have been added at the start or end.

Parameters
knotsThe knot vector to be extended
degreeThe nurbs degree
numStartNumber to be added at the start
numEndNumber to be added at the end
forceBothEndsUniformWhen only adding to one end, the other end can remain untouched or it can be forced to be made uniform
284 {
285  // Usually it should already be in normalized form, but just to be sure.
286  // Needed because otherwise comparing to uniform step size doesn't work.
287  normalizeKnotVector(knots);
288 
289  Mdouble uniformStepSize = 1.0 / (knots.size() - 1);
290 
291  // This only works properly when the original start and end knots are uniformly spaced.
292  // Therefore force the degree+1 number of knots at the start and end to have uniform step size
293  // and remember if they weren't already uniform, so when needed a message can be logged.
294 
295  // Since the original knot vector might change a bit, only do stuff when there are actually knots to be added.
296  if (numStart > 0 || forceBothEndsUniform)
297  {
298  // Check if first degree+1 knots are uniform.
299  // Update: also an additional number of knots added to the end should be uniform (the ones "wrapping around")
300  bool startsOfUniform = true;
301  for (int i = 0; i <= degree + numEnd; i++)
302  {
303  if (!close(knots[i], i * uniformStepSize))
304  {
305  startsOfUniform = false;
306  knots[i] = i * uniformStepSize;
307  }
308  }
309 
310  // When needed, let user know that original knot vector has been edited.
311  if (!startsOfUniform)
312  {
313  logger(INFO, "Start of knot vector (first degree+1 values) has been changed to be uniform. The shape might be slightly affected. ");
314  }
315 
316  // Insert knots at start
317  for (int i = 1; i <= numStart; i++)
318  {
319  knots.insert(knots.begin(), -i * uniformStepSize);
320  }
321  }
322 
323  // Since the original knot vector might change a bit, only do stuff when there are actually knots to be added.
324  if (numEnd > 0 || forceBothEndsUniform)
325  {
326  // Check if last degree+1 knots are uniform.
327  // Update: also an additional number of knots added to the start should be uniform (the ones "wrapping around")
328  bool endsOfUniform = true;
329  for (int i = 0; i <= degree + numStart; i++)
330  {
331  if (!close(knots[knots.size() - 1 - i], (1.0 - i * uniformStepSize)))
332  {
333  endsOfUniform = false;
334  knots[knots.size() - 1 - i] = 1.0 - i * uniformStepSize;
335  }
336  }
337 
338  // When needed, let user know that original knot vector has been edited.
339  if (!endsOfUniform)
340  {
341  logger(INFO, "End of knot vector (last degree+1 values) has been changed to be uniform. The shape might be slightly affected. ");
342  }
343 
344  // Add knots to end
345  for (int i = 1; i <= numEnd; i++)
346  {
347  knots.push_back(1.0 + i * uniformStepSize);
348  }
349  }
350 
351  // Reset to interval [0, 1]
352  normalizeKnotVector(knots);
353 }
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
#define INFO(i)
Definition: mumps_solver.h:54
void normalizeKnotVector(std::vector< Mdouble > &knots)
Resets the knot vector to the interval [0, 1].
Definition: NurbsUtils.cc:267

References close(), constants::degree, i, INFO, logger, and normalizeKnotVector().

Referenced by NurbsSurface::wrapAroundInU(), and NurbsSurface::wrapAroundInV().

◆ findSpan()

int NurbsUtils::findSpan ( int  degree,
const std::vector< double > &  knots,
double  u 
)

Find the span of the given parameter in the knot vector.

Parameters
[in]degreeDegree of the curve.
[in]knotsKnot vector of the curve.
[in]uParameter value.
Returns
Span index into the knot vector such that (span - 1) < u <= span
23 {
24  // index of last control point
25  int n = static_cast<int>(knots.size()) - degree - 2;
26 
27  // For u that is equal to last knot value
28  if (close(u, knots[n + 1]))
29  {
30  return n;
31  }
32 
33  // For values of u that lies outside the domain
34  if (u > knots[n + 1])
35  {
36  return n;
37  }
38  if (u < knots[degree])
39  {
40  return degree;
41  }
42 
43  // Binary search
44  // TODO: Replace this with std::lower_bound
45  int low = degree;
46  int high = n + 1;
47  int mid = (int) std::floor((low + high) / 2.0);
48  while (u < knots[mid] || u >= knots[mid + 1])
49  {
50  if (u < knots[mid])
51  {
52  high = mid;
53  }
54  else
55  {
56  low = mid;
57  }
58  mid = (low + high) / 2;
59  }
60  return mid;
61 }
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
return int(ret)+1
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 floor(const bfloat16 &a)
Definition: BFloat16.h:643

References close(), constants::degree, Eigen::bfloat16_impl::floor(), int(), and n.

Referenced by NurbsSurface::evaluate(), evaluate(), and NurbsSurface::evaluateDerivatives().

◆ isKnotVectorMonotonic()

bool NurbsUtils::isKnotVectorMonotonic ( const std::vector< double > &  knots)
13 {
14  return std::is_sorted(knots.begin(), knots.end());
15 }
bool is_sorted(const T &mat)
Definition: sparse_permutations.cpp:35

References is_sorted().

Referenced by NurbsSurface::set().

◆ normalizeKnotVector()

void NurbsUtils::normalizeKnotVector ( std::vector< Mdouble > &  knots)

Resets the knot vector to the interval [0, 1].

Parameters
knotsThe knot vector to be normalized
268 {
269  // Reset the interval to [0,1]
270  const Mdouble minK = knots.front();
271  const Mdouble maxK = knots.back();
272 
273  // Already in normalized form
274  if (close(minK, 0.0) && close(maxK, 1.0))
275  return;
276 
277  for (Mdouble& k : knots)
278  {
279  k = (k - minK) / (maxK - minK);
280  }
281 }

References close(), and k.

Referenced by extendKnotVector(), NurbsSurface::set(), and NurbsSurface::unclampKnots().