NURBSbasis.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2007-2019 PCOpt/NTUA
9  Copyright (C) 2013-2019 FOSS GP
10  Copyright (C) 2019 OpenCFD Ltd.
11 -------------------------------------------------------------------------------
12 License
13  This file is part of OpenFOAM.
14 
15  OpenFOAM is free software: you can redistribute it and/or modify it
16  under the terms of the GNU General Public License as published by
17  the Free Software Foundation, either version 3 of the License, or
18  (at your option) any later version.
19 
20  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
21  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  for more details.
24 
25  You should have received a copy of the GNU General Public License
26  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "NURBSbasis.H"
31 
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 
39 defineTypeNameAndDebug(NURBSbasis, 1);
40 
41 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 
43 void NURBSbasis::computeKnots()
44 {
45  // Sanity check
46  if (basisDegree_ >(nCPs_ - 1))
47  {
49  << "B - splines basis degree can be at most equal to the "
50  << "number of control points minus 1"
51  << exit(FatalError);
52  }
53 
54  // First zero knots
55  for (label ik = 0; ik < basisDegree_ + 1; ik++)
56  {
57  knots_ = scalar(0);
58  }
59 
60  // Intermediate knots
61  label firstCPIndex(basisDegree_ + 1);
62  label lastCPIndex(knots_.size() - basisDegree_ - 1);
63  label size(knots_.size() - 2*basisDegree_ - 2);
64 
65  for (label ik = 0; ik < size; ik++)
66  {
67  knots_[ik + firstCPIndex] = scalar(ik + 1)/scalar(size + 1);
68  }
69 
70  // Last unity knots
71  for (label ik = 0; ik < basisDegree_ + 1; ik++)
72  {
73  knots_[ik + lastCPIndex] = scalar(1);
74  }
75 
76  DebugInfo
77  << "Using knots " << knots_ << endl;
78 }
79 
80 
81 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
82 
84 (
85  const label nCPs,
86  const label degree,
87  const scalarField& knots
88 )
89 :
90  nCPs_(nCPs),
91  basisDegree_(degree),
92  knots_(knots)
93 {}
94 
95 
97 (
98  const label nCPs,
99  const label degree
100 )
101 :
102  nCPs_(nCPs),
103  basisDegree_(degree),
104  knots_((nCPs_ + basisDegree_ + 1), Zero)
105 {
106  computeKnots();
107 }
108 
109 
111 (
112  const dictionary& dict
113 )
114 :
115  nCPs_(dict.get<label>("nCPs")),
116  basisDegree_(dict.get<label>("basisDegree")),
117  knots_((nCPs_ + basisDegree_ + 1), Zero)
118 {
119  computeKnots();
120 }
121 
122 
124 (
125  const NURBSbasis& basis
126 )
127 :
128  nCPs_(basis.nCPs_),
129  basisDegree_(basis.basisDegree_),
130  knots_(basis.knots_)
131 {
132  DebugInfo
133  << "Copied basis function" << endl;
134 }
135 
136 
137 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
138 
140 (
141  const label iCP,
142  const label degree,
143  const scalar u
144 ) const
145 {
146  scalar value(0);
147 
148  if (checkRange(u, iCP, degree))
149  {
150  // If the degree reached zero, return step function
151  if (degree == 0)
152  {
153  if ((u >= knots_[iCP]) && (u < knots_[iCP + 1]))
154  {
155  value = scalar(1);
156  }
157  else if ((u == 1) && (knots_[iCP + 1] == 1))
158  {
159  value = scalar(1);
160  }
161  }
162  // Else, call recursively until reaching zero degree
163  else
164  {
165  const scalar denom1(knots_[iCP + degree] - knots_[iCP]);
166  const scalar denom2(knots_[iCP + degree + 1] - knots_[iCP + 1]);
167 
168  if (denom1 != 0)
169  {
170  value +=
171  (u - knots_[iCP])
172  * basisValue(iCP, degree - 1, u)
173  / denom1;
174  }
175  if (denom2 != 0)
176  {
177  value +=
178  (knots_[iCP + degree + 1] - u)
179  * basisValue(iCP + 1, degree - 1, u)
180  / denom2;
181  }
182  }
183  }
184 
185  return value;
186 }
187 
188 
190 (
191  const label iCP,
192  const label degree,
193  const scalar u
194 ) const
195 {
196  // Zero basis function has a zero derivative,
197  // irrespective of the knot span: ignore that case
198  // - else, call recursively until reaching zero degree
199  scalar derivative(0);
200 
201  if ((degree != 0) && checkRange(u, iCP, degree))
202  {
203  const scalar denom1(knots_[iCP + degree] - knots_[iCP]);
204  const scalar denom2(knots_[iCP + degree + 1] - knots_[iCP + 1]);
205 
206  if (denom1 != 0)
207  {
208  derivative +=
209  (
210  (u - knots_[iCP])
211  * basisDerivativeU(iCP, degree - 1, u)
212  + basisValue(iCP, degree - 1, u)
213  ) / denom1;
214  }
215  if (denom2 != 0)
216  {
217  derivative +=
218  (
219  (knots_[iCP + degree + 1] - u)
220  * basisDerivativeU(iCP + 1, degree - 1, u)
221  - basisValue(iCP + 1, degree - 1, u)
222  ) / denom2;
223  }
224  }
225 
226  return derivative;
227 }
228 
229 
231 (
232  const label iCP,
233  const label degree,
234  const scalar u
235 ) const
236 {
237  // Zero basis function has a zero derivative,
238  // irrespective of the knot span: ignore that case
239  // - else, call recursively until reaching zero degree
240  scalar derivative(0);
241 
242  if ((degree != 0) && checkRange(u, iCP, degree))
243  {
244  scalar denom1 = (knots_[iCP + degree] - knots_[iCP]);
245  scalar denom2 = (knots_[iCP + degree + 1] - knots_[iCP + 1]);
246 
247  if (denom1 != 0)
248  {
249  derivative +=
250  (
251  (u - knots_[iCP])
252  * basisDerivativeUU(iCP, degree - 1, u)
253  + 2*basisDerivativeU(iCP, degree - 1, u)
254  ) / denom1;
255  }
256 
257  if (denom2 != 0)
258  {
259  derivative +=
260  (
261  (knots_[iCP + degree + 1] - u)
262  * basisDerivativeUU(iCP + 1, degree - 1, u)
263  - 2*basisDerivativeU(iCP + 1, degree - 1, u)
264  ) / denom2;
265  }
266  }
267 
268  return derivative;
269 }
270 
271 
273 (
274  const scalar u,
275  const label CPI,
276  const label degree
277 ) const
278 {
279  // Find what section of the curve given u is in.
280  const scalar lowerBound(knots_[CPI]);
281  const scalar upperBound(knots_[CPI + degree + 1]);
282 
283  // Check in-range requirements.
284  if
285  (
286  ((u == scalar(1)) && (lowerBound <= u) && (u <= upperBound))
287  || ((u != scalar(1)) && (lowerBound <= u) && (u < upperBound))
288  )
289  {
290  return true;
291  }
292 
293  return false;
294 }
295 
296 
298 (
299  const scalar uBar
300 )
301 {
302  // Find the index of insertion, accounting for uBar=1.
303  scalarList newKnots((knots_.size()+1), Zero);
304  label kInsert(-1);
305 
306  for (label kI = 0; kI < (knots_.size()-1); kI++)
307  {
308  if (knots_[kI + 1] > uBar)
309  {
310  kInsert = kI;
311  break;
312  }
313  }
314 
315  if (kInsert == -1)
316  {
317  kInsert = knots_.size()-1;
318  }
319 
320  // Update data.
321  for (label kI = 0; kI<(kInsert + 1); kI++)
322  {
323  newKnots[kI] = knots_[kI];
324  }
325 
326  newKnots[kInsert + 1] = uBar;
327 
328  for (label kI= (kInsert + 2); kI < newKnots.size(); kI++)
329  {
330  newKnots[kI] = knots_[kI - 1];
331  }
332 
333  // Add the new CP info and return the insertion point.
334  knots_ = newKnots;
335  nCPs_++;
336 
337  return kInsert;
338 }
339 
340 
341 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
342 
343 } // End namespace Foam
344 
345 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
NURBSbasis(const label nCPs, const label degree, const scalarField &knots)
Construct from number of control points, knot vector and basis order.
Definition: NURBSbasis.C:77
NURBSbasis function. Used to construct NURBS curves, surfaces and volumes.
Definition: NURBSbasis.H:51
label insertKnot(const scalar uBar)
Adds the new knot&#39;s u value, increments the nCPs and returns &#39;k&#39;, the index of the newly inserted uVa...
Definition: NURBSbasis.C:291
const label & degree() const
Definition: NURBSbasisI.H:33
#define DebugInfo
Report an information message using Foam::Info.
scalar basisDerivativeUU(const label iCP, const label degree, const scalar u) const
Basis second derivative w.r.t u.
Definition: NURBSbasis.C:224
scalar basisValue(const label iCP, const label degree, const scalar u) const
Basis value.
Definition: NURBSbasis.C:133
scalar basisDerivativeU(const label iCP, const label degree, const scalar u) const
Basis derivative w.r.t u.
Definition: NURBSbasis.C:183
defineTypeNameAndDebug(combustionModel, 0)
bool checkRange(const scalar u, const label CPI, const label degree) const
Checks to see if given u is affected by given CP.
Definition: NURBSbasis.C:266
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127