1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | cfMesh: A library for mesh generation
5 \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6 \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
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
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/>.
26 \*---------------------------------------------------------------------------*/
28 #include "quadricFitting.H"
30 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 // * * * * * * * * * Private Member Functions * * * * * * * * * * * * * * * * //
37 void quadricFitting::calculateNormalVector()
39 symmTensor mat(symmTensor::zero);
41 forAll(otherPoints_, i)
43 const vector d = (otherPoints_[i] - origin_);
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 )
62 vecX_ = vecY_ = vector::zero;
63 forAll(transformedPoints_, i)
64 transformedPoints_[i] = vector::zero;
69 const plane pl(origin_, normal_);
76 const point vp = pl.nearestPoint(otherPoints_[pI]);
79 if( magSqr(vecX_) < VSMALL )
86 vecY_ = normal_ ^ vecX_;
94 "void quadricFitting::calculateCoordinateSystem()"
95 ) << "Cannot find a valid coordinate system!" << endl;
97 normal_ = vecX_ = vecY_ = vector::zero;
100 //- transform other points to this new coordinate system
101 transformedPoints_.setSize(otherPoints_.size());
103 forAll(otherPoints_, i)
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_;
114 void quadricFitting::calculateQuadricCoeffs()
116 if( mag(normal_) < VSMALL )
118 coefficients_.setSize(5);
123 simpleMatrix<scalar> mat(5, 0.0, 0.0);
124 DynList<scalar> helper;
127 forAll(transformedPoints_, i)
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();
137 for(label rowI=0;rowI<5;++rowI)
139 for(label colI=rowI;colI<5;++colI)
140 mat[rowI][colI] += helper[rowI] * helper[colI];
142 mat.source()[rowI] += helper[rowI] * p.z();
146 for(label rowI=1;rowI<5;++rowI)
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;
155 coefficients_ = mat.LUsolve();
158 void quadricFitting::calculateBestFit()
162 while( iteration++ < 10 )
164 calculateCoordinateSystem();
166 calculateQuadricCoeffs();
168 if( (mag(coefficients_[3]) > SMALL) || (mag(coefficients_[4]) > SMALL) )
170 //- correct the normal
172 Foam::sqrt(1 + sqr(coefficients_[3]) + sqr(coefficients_[4]));
174 const vector newNormal
177 coefficients_[3] * vecX_ / d -
178 coefficients_[4] * vecY_ / d
190 Info << "Other points " << otherPoints_ << endl;
191 Info << "Transformed points " << transformedPoints_ << endl;
192 Info << "normal " << normal_ << endl;
193 Info << "Coefficients " << coefficients_ << endl;
197 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
199 template<class ListType>
200 inline quadricFitting::quadricFitting
204 const ListType& otherPoints
212 transformedPoints_(),
215 otherPoints_.setSize(otherPoints.size());
216 forAll(otherPoints, i)
217 otherPoints_[i] = otherPoints[i];
219 if( magSqr(normal_) < VSMALL )
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;
236 normal_ /= mag(normal_);
242 //- Construct from point and other points
243 template<class ListType>
244 inline quadricFitting::quadricFitting
247 const ListType& otherPoints
255 transformedPoints_(),
258 otherPoints_.setSize(otherPoints.size());
259 forAll(otherPoints, i)
260 otherPoints_[i] = otherPoints[i];
262 calculateNormalVector();
267 inline quadricFitting::~quadricFitting()
271 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
273 inline const vector& quadricFitting::normal() const
278 //- Return min curvature
279 inline scalar quadricFitting::minCurvature() const
283 coefficients_[0] + coefficients_[1] -
284 sqrt(sqr(coefficients_[0] - coefficients_[1]) + sqr(coefficients_[2]))
288 //- Return max curvature
289 inline scalar quadricFitting::maxCurvature() const
293 coefficients_[0] + coefficients_[1] +
294 sqrt(sqr(coefficients_[0] - coefficients_[1]) + sqr(coefficients_[2]))
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
317 stabilise(coefficients_[0] - coefficients_[1], VSMALL)
320 return Foam::cos(theta) * vecX_ + Foam::sin(theta) * vecY_;
323 //- Return max curvature vector
324 inline vector quadricFitting::maxCurvatureVector() const
330 stabilise(coefficients_[0] - coefficients_[1], VSMALL)
333 return Foam::sin(theta) * vecX_ + Foam::cos(theta) * vecY_;
336 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
338 } // End namespace Foam
340 // ************************************************************************* //