00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00034
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
00051 rfR = Math<Real>::InvSqrt(fInvRSqr);
00052
00053
00054
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
00070
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
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
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
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);
00218 }
00219 fAMean *= fInvQuantity;
00220 fAAMean *= fInvQuantity;
00221 if (kCDir.Normalize() < Math<Real>::ZERO_TOLERANCE)
00222 {
00223 return fAAMean;
00224 }
00225
00226
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
00281
00282 template WM4_FOUNDATION_ITEM
00283 class CylinderFit3<float>;
00284
00285 template WM4_FOUNDATION_ITEM
00286 class CylinderFit3<double>;
00287
00288 }
00289