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-------------------------------------------------------------------------------
12License
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
34namespace Foam
35{
36
37// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38
40
41// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42
43void 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
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{
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// ************************************************************************* //
NURBSbasis function. Used to construct NURBS curves, surfaces and volumes.
Definition: NURBSbasis.H:56
scalar basisDerivativeUU(const label iCP, const label degree, const scalar u) const
Basis second derivative w.r.t u.
Definition: NURBSbasis.C:231
scalar basisDerivativeU(const label iCP, const label degree, const scalar u) const
Basis derivative w.r.t u.
Definition: NURBSbasis.C:190
const label & degree() const
Definition: NURBSbasisI.H:40
scalar basisValue(const label iCP, const label degree, const scalar u) const
Basis value.
Definition: NURBSbasis.C:140
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
label insertKnot(const scalar uBar)
Definition: NURBSbasis.C:298
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
#define DebugInfo
Report an information message using Foam::Info.
Namespace for OpenFOAM.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
dictionary dict