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 // ************************************************************************* //
Foam::NURBSbasis::basisDerivativeU
scalar basisDerivativeU(const label iCP, const label degree, const scalar u) const
Basis derivative w.r.t u.
Definition: NURBSbasis.C:190
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::NURBSbasis::basisValue
scalar basisValue(const label iCP, const label degree, const scalar u) const
Basis value.
Definition: NURBSbasis.C:140
Foam::NURBSbasis
NURBSbasis function. Used to construct NURBS curves, surfaces and volumes.
Definition: NURBSbasis.H:55
Foam::NURBSbasis::insertKnot
label insertKnot(const scalar uBar)
Definition: NURBSbasis.C:298
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::dictionary::get
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:107
Foam::NURBSbasis::basisDerivativeUU
scalar basisDerivativeUU(const label iCP, const label degree, const scalar u) const
Basis second derivative w.r.t u.
Definition: NURBSbasis.C:231
Foam::Field< scalar >
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
NURBSbasis.H
DebugInfo
#define DebugInfo
Report an information message using Foam::Info.
Definition: messageStream.H:382
Foam::List< scalar >
Foam::NURBSbasis::NURBSbasis
NURBSbasis(const label nCPs, const label degree, const scalarField &knots)
Construct from number of control points, knot vector and basis order.
Definition: NURBSbasis.C:84
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::NURBSbasis::checkRange
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:273