Wm4ApprCylinderFit3.cpp

Go to the documentation of this file.
00001 // Wild Magic Source Code
00002 // David Eberly
00003 // http://www.geometrictools.com
00004 // Copyright (c) 1998-2007
00005 //
00006 // This library is free software; you can redistribute it and/or modify it
00007 // under the terms of the GNU Lesser General Public License as published by
00008 // the Free Software Foundation; either version 2.1 of the License, or (at
00009 // your option) any later version.  The license is available for reading at
00010 // either of the locations:
00011 //     http://www.gnu.org/copyleft/lgpl.html
00012 //     http://www.geometrictools.com/License/WildMagicLicense.pdf
00013 // The license applies to versions 0 through 4 of Wild Magic.
00014 //
00015 // Version: 4.0.0 (2006/06/28)
00016 
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4ApprCylinderFit3.h"
00019 #include "Wm4ApprLineFit3.h"
00020 #include "Wm4PolynomialRoots.h"
00021 
00022 namespace Wm4
00023 {
00024 //----------------------------------------------------------------------------
00025 template <class Real>
00026 CylinderFit3<Real>::CylinderFit3 (int iQuantity, const Vector3<Real>* akPoint,
00027     Vector3<Real>& rkC, Vector3<Real>& rkU, Real& rfR, Real& rfH,
00028     bool bInputsAreInitialGuess)
00029 {
00030     Real fInvRSqr;
00031     if (!bInputsAreInitialGuess)
00032     {
00033         // Find the least-squares line that fits the data and use it as an
00034         // initial guess for the cylinder axis.
00035         Line3<Real> kLine = OrthogonalLineFit3(iQuantity,akPoint);
00036         rkC = kLine.Origin;
00037         rkU = kLine.Direction;
00038     }
00039 
00040     m_fError = Math<Real>::MAX_REAL;
00041     const int iMax = 8;
00042     int i;
00043     for (i = 0; i < iMax; i++)
00044     {
00045         m_fError = UpdateInvRSqr(iQuantity,akPoint,rkC,rkU,fInvRSqr);
00046         m_fError = UpdateDirection(iQuantity,akPoint,rkC,rkU,fInvRSqr);
00047         m_fError = UpdateCenter(iQuantity,akPoint,rkC,rkU,fInvRSqr);
00048     }
00049 
00050     // Compute the radius.
00051     rfR = Math<Real>::InvSqrt(fInvRSqr);
00052 
00053     // Project points onto fitted axis to determine extent of cylinder along
00054     // the axis.
00055     Real fTMin = rkU.Dot(akPoint[0]-rkC), fTMax = fTMin;
00056     for (i = 1; i < iQuantity; i++)
00057     {
00058         Real fT = rkU.Dot(akPoint[i]-rkC);
00059         if (fT < fTMin)
00060         {
00061             fTMin = fT;
00062         }
00063         else if (fT > fTMax)
00064         {
00065             fTMax = fT;
00066         }
00067     }
00068 
00069     // Compute the height.  Adjust the center to point that projects to
00070     // midpoint of extent.
00071     rfH = fTMax - fTMin;
00072     rkC += ((Real)0.5)*(fTMin+fTMax)*rkU;
00073 }
00074 //----------------------------------------------------------------------------
00075 template <class Real>
00076 CylinderFit3<Real>::operator Real ()
00077 {
00078     return m_fError;
00079 }
00080 //----------------------------------------------------------------------------
00081 template <class Real>
00082 Real CylinderFit3<Real>::UpdateInvRSqr (int iQuantity,
00083     const Vector3<Real>* akPoint, const Vector3<Real>& rkC,
00084     const Vector3<Real>& rkU, Real& rfInvRSqr)
00085 {
00086     Real fASum = (Real)0.0, fAASum = (Real)0.0;
00087     for (int i = 0; i < iQuantity; i++)
00088     {
00089         Vector3<Real> kDelta = akPoint[i] - rkC;
00090         Vector3<Real> kDxU = kDelta.Cross(rkU);
00091         Real fL2 = kDxU.SquaredLength();
00092         fASum += fL2;
00093         fAASum += fL2*fL2;
00094     }
00095 
00096     rfInvRSqr = fASum/fAASum;
00097     Real fMin = (Real)1.0 - rfInvRSqr*fASum/(Real)iQuantity;
00098     return fMin;
00099 }
00100 //----------------------------------------------------------------------------
00101 template <class Real>
00102 Real CylinderFit3<Real>::UpdateDirection (int iQuantity,
00103     const Vector3<Real>* akPoint, const Vector3<Real>& rkC,
00104     Vector3<Real>& rkU, Real& rfInvRSqr)
00105 {
00106     Real fInvQuantity = ((Real)1.0)/(Real)iQuantity;
00107     int i;
00108     Vector3<Real> kDelta, kDxU, kDxVDir;
00109     Real fA, fB, fC;
00110 
00111     // compute direction of steepest descent
00112     Vector3<Real> kVDir = Vector3<Real>::ZERO;
00113     Real fAMean = (Real)0.0, fAAMean = (Real)0.0;
00114     for (i = 0; i < iQuantity; i++)
00115     {
00116         kDelta = akPoint[i] - rkC;
00117         kDxU = kDelta.Cross(rkU);
00118         fA = rfInvRSqr*kDxU.SquaredLength() - (Real)1.0;
00119         fAMean += fA;
00120         fAAMean += fA*fA;
00121         kVDir.X() += fA*(rkU.X()*(kDelta.Y()*kDelta.Y() +
00122             kDelta.Z()*kDelta.Z()) - kDelta.X()*(rkU.Y()*kDelta.Y() +
00123             rkU.Z()*kDelta.Z()));
00124         kVDir.Y() += fA*(rkU.Y()*(kDelta.X()*kDelta.X() +
00125             kDelta.Z()*kDelta.Z()) - kDelta.Y()*(rkU.X()*kDelta.X() +
00126             rkU.Z()*kDelta.Z()));
00127         kVDir.Z() += fA*(rkU.Z()*(kDelta.X()*kDelta.X() + 
00128             kDelta.Y()*kDelta.Y()) - kDelta.Z()*(rkU.X()*kDelta.X() +
00129             rkU.Y()*kDelta.Y()));
00130     }
00131     fAMean *= fInvQuantity;
00132     fAAMean *= fInvQuantity;
00133     if (kVDir.Normalize() < Math<Real>::ZERO_TOLERANCE)
00134     {
00135         return fAAMean;
00136     }
00137 
00138     // compute 4th-degree polynomial for line of steepest descent
00139     Real fABMean = (Real)0.0, fACMean = (Real)0.0;
00140     Real fBBMean = (Real)0.0, fBCMean = (Real)0.0, fCCMean = (Real)0.0;
00141     for (i = 0; i < iQuantity; i++)
00142     {
00143         kDelta = akPoint[i] - rkC;
00144         kDxU = kDelta.Cross(rkU);
00145         kDxVDir = kDelta.Cross(kVDir);
00146         fA = rfInvRSqr*kDxU.SquaredLength() - (Real)1.0;
00147         fB = rfInvRSqr*(kDxU.Dot(kDxVDir));
00148         fC = rfInvRSqr*kDxVDir.SquaredLength();
00149         fABMean += fA*fB;
00150         fACMean += fA*fC;
00151         fBBMean += fB*fB;
00152         fBCMean += fB*fC;
00153         fCCMean += fC*fC;
00154     }
00155     fABMean *= fInvQuantity;
00156     fACMean *= fInvQuantity;
00157     fBBMean *= fInvQuantity;
00158     fBCMean *= fInvQuantity;
00159     fCCMean *= fInvQuantity;
00160 
00161     Polynomial1<Real> kPoly(4);
00162     kPoly[0] = fAAMean;
00163     kPoly[1] = -((Real)4.0)*fABMean;
00164     kPoly[2] = ((Real)2.0)*fACMean + ((Real)4.0)*fBBMean;
00165     kPoly[3] = -((Real)4.0)*fBCMean;
00166     kPoly[4] = fCCMean;
00167 
00168     Polynomial1<Real> kDPoly = kPoly.GetDerivative();
00169 
00170     PolynomialRoots<Real> kPR(Math<Real>::ZERO_TOLERANCE);
00171     kPR.FindA(kDPoly[0],kDPoly[1],kDPoly[2],kDPoly[3]);
00172     int iCount = kPR.GetCount();
00173     const Real* afRoot = kPR.GetRoots();
00174 
00175     Real fMin = kPoly((Real)0.0);
00176     int iMin = -1;
00177     for (i = 0; i < iCount; i++)
00178     {
00179         Real fValue = kPoly(afRoot[i]);
00180         if (fValue < fMin)
00181         {
00182             fMin = fValue;
00183             iMin = i;
00184         }
00185     }
00186 
00187     if (iMin >= 0)
00188     {
00189         rkU -= afRoot[iMin]*kVDir;
00190         Real fLength = rkU.Normalize();
00191         rfInvRSqr *= fLength*fLength;
00192     }
00193 
00194     return fMin;
00195 }
00196 //----------------------------------------------------------------------------
00197 template <class Real>
00198 Real CylinderFit3<Real>::UpdateCenter (int iQuantity,
00199     const Vector3<Real>* akPoint, Vector3<Real>& rkC,
00200     const Vector3<Real>& rkU, const Real& rfInvRSqr)
00201 {
00202     Real fInvQuantity = ((Real)1.0)/(Real)iQuantity;
00203     int i;
00204     Vector3<Real> kDelta, kDxU, kDxCDir;
00205     Real fA, fB, fC;
00206 
00207     // compute direction of steepest descent
00208     Vector3<Real> kCDir = Vector3<Real>::ZERO;
00209     Real fAMean = (Real)0.0, fAAMean = (Real)0.0;
00210     for (i = 0; i < iQuantity; i++)
00211     {
00212         kDelta = akPoint[i] - rkC;
00213         kDxU = kDelta.Cross(rkU);
00214         fA = rfInvRSqr*kDxU.SquaredLength() - (Real)1.0;
00215         fAMean += fA;
00216         fAAMean += fA*fA;
00217         kCDir += fA*(kDelta-rkU.Dot(kDelta)*rkU); // |U|=1 assumed
00218     }
00219     fAMean *= fInvQuantity;
00220     fAAMean *= fInvQuantity;
00221     if (kCDir.Normalize() < Math<Real>::ZERO_TOLERANCE)
00222     {
00223         return fAAMean;
00224     }
00225 
00226     // compute 4th-degree polynomial for line of steepest descent
00227     kDxCDir = kCDir.Cross(rkU);
00228     fC = kDxCDir.SquaredLength()*fInvQuantity*rfInvRSqr;
00229     Real fBMean = (Real)0.0,  fABMean = (Real)0.0, fBBMean = (Real)0.0;
00230     for (i = 0; i < iQuantity; i++)
00231     {
00232         kDelta = akPoint[i] - rkC;
00233         kDxU = kDelta.Cross(rkU);
00234         fA = rfInvRSqr*kDxU.SquaredLength() - (Real)1.0;
00235         fB = rfInvRSqr*(kDxU.Dot(kDxCDir));
00236         fBMean += fB;
00237         fABMean += fA*fB;
00238         fBBMean += fB*fB;
00239     }
00240     fBMean *= fInvQuantity;
00241     fABMean *= fInvQuantity;
00242     fBBMean *= fInvQuantity;
00243 
00244     Polynomial1<Real> kPoly(4);
00245     kPoly[0] = fAAMean;
00246     kPoly[1] = ((Real)4.0)*fABMean;
00247     kPoly[2] = ((Real)2.0)*fC*fAMean + ((Real)4.0)*fBBMean;
00248     kPoly[3] = ((Real)4.0)*fC*fBMean;
00249     kPoly[4] = fC*fC;
00250 
00251     Polynomial1<Real> kDPoly = kPoly.GetDerivative();
00252 
00253     PolynomialRoots<Real> kPR(Math<Real>::ZERO_TOLERANCE);
00254     kPR.FindA(kDPoly[0],kDPoly[1],kDPoly[2],kDPoly[3]);
00255     int iCount = kPR.GetCount();
00256     const Real* afRoot = kPR.GetRoots();
00257 
00258     Real fMin = kPoly((Real)0.0);
00259     int iMin = -1;
00260     for (i = 0; i < iCount; i++)
00261     {
00262         Real fValue = kPoly(afRoot[i]);
00263         if (fValue < fMin)
00264         {
00265             fMin = fValue;
00266             iMin = i;
00267         }
00268     }
00269 
00270     if (iMin >= 0)
00271     {
00272         rkC -= afRoot[iMin]*kCDir;
00273     }
00274 
00275     return fMin;
00276 }
00277 //----------------------------------------------------------------------------
00278 
00279 //----------------------------------------------------------------------------
00280 // explicit instantiation
00281 //----------------------------------------------------------------------------
00282 template WM4_FOUNDATION_ITEM
00283 class CylinderFit3<float>;
00284 
00285 template WM4_FOUNDATION_ITEM
00286 class CylinderFit3<double>;
00287 //----------------------------------------------------------------------------
00288 }
00289 

Generated on Wed Nov 23 19:01:02 2011 for FreeCAD by  doxygen 1.6.1