Forward compatibility: flex
[foam-extend-3.2.git] / src / mesh / cfMesh / utilities / helperClasses / geometry / quadricFitting / quadricFittingI.H
blob58d0d8d724799388d7f67f2d0df7ef1931adba52
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | cfMesh: A library for mesh generation
4    \\    /   O peration     |
5     \\  /    A nd           | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6      \\/     M anipulation  | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
8 License
9     This file is part of cfMesh.
11     cfMesh is free software; you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation; either version 3 of the License, or (at your
14     option) any later version.
16     cfMesh is distributed in the hope that it will be useful, but WITHOUT
17     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19     for more details.
21     You should have received a copy of the GNU General Public License
22     along with cfMesh.  If not, see <http://www.gnu.org/licenses/>.
24 Description
26 \*---------------------------------------------------------------------------*/
28 #include "quadricFitting.H"
30 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32 namespace Foam
35 // * * * * * * * * * Private Member Functions * * * * * * * * * * * * * * * * //
37 void quadricFitting::calculateNormalVector()
39     symmTensor mat(symmTensor::zero);
41     forAll(otherPoints_, i)
42     {
43         const vector d = (otherPoints_[i] - origin_);
45         mat += symm(d * d);
46     }
48     mat /= otherPoints_.size();
50     //- find the eigenvalues of the tensor
51     const vector ev = eigenValues(mat);
53     //- estimate the normal as the eigenvector associated
54     //- to the smallest eigenvalue
55     normal_ = eigenVector(mat, ev[0]);
58 void quadricFitting::calculateCoordinateSystem()
60     if( mag(normal_) < VSMALL )
61     {
62         vecX_ = vecY_ = vector::zero;
63         forAll(transformedPoints_, i)
64             transformedPoints_[i] = vector::zero;
66         return;
67     }
69     const plane pl(origin_, normal_);
71     bool valid(false);
73     label pI(0);
74     while( !valid )
75     {
76         const point vp = pl.nearestPoint(otherPoints_[pI]);
77         vecX_ = vp - origin_;
79         if( magSqr(vecX_) < VSMALL )
80         {
81             ++pI;
82             continue;
83         }
85         vecX_ /= mag(vecX_);
86         vecY_ = normal_ ^ vecX_;
87         valid = true;
88     }
90     if( !valid )
91     {
92         FatalErrorIn
93         (
94             "void quadricFitting::calculateCoordinateSystem()"
95         ) << "Cannot find a valid coordinate system!" << endl;
97         normal_ = vecX_ = vecY_ = vector::zero;
98     }
100     //- transform other points to this new coordinate system
101     transformedPoints_.setSize(otherPoints_.size());
103     forAll(otherPoints_, i)
104     {
105         const vector delta = (otherPoints_[i] - origin_);
106         point& p = transformedPoints_[i];
108         p.x() = delta & vecX_;
109         p.y() = delta & vecY_;
110         p.z() = delta & normal_;
111     }
114 void quadricFitting::calculateQuadricCoeffs()
116     if( mag(normal_) < VSMALL )
117     {
118         coefficients_.setSize(5);
119         coefficients_ = 0.0;
120         return;
121     }
123     simpleMatrix<scalar> mat(5, 0.0, 0.0);
124     DynList<scalar> helper;
125     helper.setSize(5);
127     forAll(transformedPoints_, i)
128     {
129         const point& p = transformedPoints_[i];
131         helper[0] = sqr(p.x());
132         helper[1] = sqr(p.y());
133         helper[2] = p.x() * p.y();
134         helper[3] = p.x();
135         helper[4] = p.y();
137         for(label rowI=0;rowI<5;++rowI)
138         {
139             for(label colI=rowI;colI<5;++colI)
140                 mat[rowI][colI] += helper[rowI] * helper[colI];
142             mat.source()[rowI] += helper[rowI] * p.z();
143         }
144     }
146     for(label rowI=1;rowI<5;++rowI)
147     {
148         for(label colI=0;colI<rowI;++colI)
149             mat[rowI][colI] = mat[colI][rowI];
151         if( mag(mat[rowI][rowI]) < SMALL )
152             mat[rowI][rowI] = SMALL;
153     }
155     coefficients_ = mat.LUsolve();
158 void quadricFitting::calculateBestFit()
160     label iteration(0);
162     while( iteration++ < 10 )
163     {
164         calculateCoordinateSystem();
166         calculateQuadricCoeffs();
168         if( (mag(coefficients_[3]) > SMALL) || (mag(coefficients_[4]) > SMALL) )
169         {
170             //- correct the normal
171             const scalar d =
172                 Foam::sqrt(1 + sqr(coefficients_[3]) + sqr(coefficients_[4]));
174             const vector newNormal
175             (
176                 normal_ / d -
177                 coefficients_[3] * vecX_ / d -
178                 coefficients_[4] * vecY_ / d
179             );
181             normal_ = newNormal;
182         }
183         else
184         {
185             break;
186         }
187     }
189     # ifdef DEBUGQuadric
190     Info << "Other points " << otherPoints_ << endl;
191     Info << "Transformed points " << transformedPoints_ << endl;
192     Info << "normal " << normal_ << endl;
193     Info << "Coefficients " << coefficients_ << endl;
194     # endif
197 // * * * * * * * * * * * * * * * *  Constructors * * * * * * * * * * * * * * //
199 template<class ListType>
200 inline quadricFitting::quadricFitting
202     const point& origin,
203     const vector normal,
204     const ListType& otherPoints
207     origin_(origin),
208     normal_(normal),
209     vecX_(vector::zero),
210     vecY_(vector::zero),
211     otherPoints_(),
212     transformedPoints_(),
213     coefficients_()
215     otherPoints_.setSize(otherPoints.size());
216     forAll(otherPoints, i)
217         otherPoints_[i] = otherPoints[i];
219     if( magSqr(normal_) < VSMALL )
220     {
221         FatalErrorIn
222         (
223             "template<class ListType>\n"
224             "inline quadricFitting::quadricFitting"
225             "(const point& origin, const vector normal,"
226             " const ListType& otherPoints)"
227         ) << "Cannot construct the quadric surface for point "
228             << origin_ << " because the normal does not exist!"
229             << "\nThis indicates that the input"
230             << " surface mesh is of poor quality" << exit(FatalError);
232         normal_ = vector::zero;
233     }
234     else
235     {
236         normal_ /= mag(normal_);
237     }
239     calculateBestFit();
242 //- Construct from point and other points
243 template<class ListType>
244 inline quadricFitting::quadricFitting
246     const point& origin,
247     const ListType& otherPoints
250     origin_(origin),
251     normal_(),
252     vecX_(),
253     vecY_(),
254     otherPoints_(),
255     transformedPoints_(),
256     coefficients_()
258     otherPoints_.setSize(otherPoints.size());
259     forAll(otherPoints, i)
260         otherPoints_[i] = otherPoints[i];
262     calculateNormalVector();
264     calculateBestFit();
267 inline quadricFitting::~quadricFitting()
271 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
273 inline const vector& quadricFitting::normal() const
275     return normal_;
278 //- Return min curvature
279 inline scalar quadricFitting::minCurvature() const
281     return
282     (
283         coefficients_[0] + coefficients_[1] -
284         sqrt(sqr(coefficients_[0] - coefficients_[1]) + sqr(coefficients_[2]))
285     );
288 //- Return max curvature
289 inline scalar quadricFitting::maxCurvature() const
291     return
292     (
293         coefficients_[0] + coefficients_[1] +
294         sqrt(sqr(coefficients_[0] - coefficients_[1]) + sqr(coefficients_[2]))
295     );
298 //- Return mean curvature
299 inline scalar quadricFitting::meanCurvature() const
301     return 0.5 * (minCurvature() + maxCurvature());
304 //- Return Gaussian curvature
305 inline scalar quadricFitting::gaussianCurvature() const
307     return minCurvature() * maxCurvature();
310 //- Return min curvature vector
311 inline vector quadricFitting::minCurvatureVector() const
313     const scalar theta =
314     0.5 * Foam::atan
315     (
316         coefficients_[2] /
317         stabilise(coefficients_[0] - coefficients_[1], VSMALL)
318     );
320     return Foam::cos(theta) * vecX_ + Foam::sin(theta) * vecY_;
323 //- Return max curvature vector
324 inline vector quadricFitting::maxCurvatureVector() const
326     const scalar theta =
327         0.5 * Foam::atan
328         (
329             coefficients_[2] /
330             stabilise(coefficients_[0] - coefficients_[1], VSMALL)
331         );
333     return Foam::sin(theta) * vecX_ + Foam::cos(theta) * vecY_;
336 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
338 } // End namespace Foam
340 // ************************************************************************* //