00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "Wm4FoundationPCH.h"
00018 #include "Wm4QuadricSurface.h"
00019
00020 namespace Wm4
00021 {
00022
00023 template <class Real>
00024 QuadricSurface<Real>::QuadricSurface ()
00025 {
00026 memset(m_afCoeff,0,10*sizeof(Real));
00027 }
00028
00029 template <class Real>
00030 QuadricSurface<Real>::QuadricSurface (const Real afCoeff[10])
00031 {
00032 for (int i = 0; i < 10; i++)
00033 {
00034 m_afCoeff[i] = afCoeff[i];
00035 }
00036
00037
00038 m_fC = m_afCoeff[0];
00039 m_kB[0] = m_afCoeff[1];
00040 m_kB[1] = m_afCoeff[2];
00041 m_kB[2] = m_afCoeff[3];
00042 m_kA[0][0] = m_afCoeff[4];
00043 m_kA[0][1] = ((Real)0.5)*m_afCoeff[5];
00044 m_kA[0][2] = ((Real)0.5)*m_afCoeff[6];
00045 m_kA[1][0] = m_kA[0][1];
00046 m_kA[1][1] = m_afCoeff[7];
00047 m_kA[1][2] = ((Real)0.5)*m_afCoeff[8];
00048 m_kA[2][0] = m_kA[0][2];
00049 m_kA[2][1] = m_kA[1][2];
00050 m_kA[2][2] = m_afCoeff[9];
00051 }
00052
00053 template <class Real>
00054 const Real* QuadricSurface<Real>::GetCoefficients () const
00055 {
00056 return m_afCoeff;
00057 }
00058
00059 template <class Real>
00060 const Matrix3<Real>& QuadricSurface<Real>::GetA () const
00061 {
00062 return m_kA;
00063 }
00064
00065 template <class Real>
00066 const Vector3<Real>& QuadricSurface<Real>::GetB () const
00067 {
00068 return m_kB;
00069 }
00070
00071 template <class Real>
00072 Real QuadricSurface<Real>::GetC () const
00073 {
00074 return m_fC;
00075 }
00076
00077 template <class Real>
00078 Real QuadricSurface<Real>::F (const Vector3<Real>& rkP) const
00079 {
00080 Real fF = rkP.Dot(m_kA*rkP + m_kB) + m_fC;
00081 return fF;
00082 }
00083
00084 template <class Real>
00085 Real QuadricSurface<Real>::FX (const Vector3<Real>& rkP) const
00086 {
00087 Real fSum = m_kA[0][0]*rkP[0] + m_kA[0][1]*rkP[1] + m_kA[0][2]*rkP[2];
00088 Real fFX = ((Real)2.0)*fSum + m_kB[0];
00089 return fFX;
00090 }
00091
00092 template <class Real>
00093 Real QuadricSurface<Real>::FY (const Vector3<Real>& rkP) const
00094 {
00095 Real fSum = m_kA[1][0]*rkP[0] + m_kA[1][1]*rkP[1] + m_kA[1][2]*rkP[2];
00096 Real fFY = ((Real)2.0)*fSum + m_kB[1];
00097 return fFY;
00098 }
00099
00100 template <class Real>
00101 Real QuadricSurface<Real>::FZ (const Vector3<Real>& rkP) const
00102 {
00103 Real fSum = m_kA[2][0]*rkP[0] + m_kA[2][1]*rkP[1] + m_kA[2][2]*rkP[2];
00104 Real fFZ = ((Real)2.0)*fSum + m_kB[2];
00105 return fFZ;
00106 }
00107
00108 template <class Real>
00109 Real QuadricSurface<Real>::FXX (const Vector3<Real>& rkP) const
00110 {
00111 Real fFXX = ((Real)2.0)*m_kA[0][0];
00112 return fFXX;
00113 }
00114
00115 template <class Real>
00116 Real QuadricSurface<Real>::FXY (const Vector3<Real>& rkP) const
00117 {
00118 Real fFXY = ((Real)2.0)*m_kA[0][1];
00119 return fFXY;
00120 }
00121
00122 template <class Real>
00123 Real QuadricSurface<Real>::FXZ (const Vector3<Real>& rkP) const
00124 {
00125 Real fFXZ = ((Real)2.0)*m_kA[0][2];
00126 return fFXZ;
00127 }
00128
00129 template <class Real>
00130 Real QuadricSurface<Real>::FYY (const Vector3<Real>& rkP) const
00131 {
00132 Real fFYY = ((Real)2.0)*m_kA[1][1];
00133 return fFYY;
00134 }
00135
00136 template <class Real>
00137 Real QuadricSurface<Real>::FYZ (const Vector3<Real>& rkP) const
00138 {
00139 Real fFYZ = ((Real)2.0)*m_kA[1][2];
00140 return fFYZ;
00141 }
00142
00143 template <class Real>
00144 Real QuadricSurface<Real>::FZZ (const Vector3<Real>& rkP) const
00145 {
00146 Real fFZZ = ((Real)2.0)*m_kA[2][2];
00147 return fFZZ;
00148 }
00149
00150 template <class Real>
00151 int QuadricSurface<Real>::GetType () const
00152 {
00153
00154
00155 RReps kReps(m_afCoeff);
00156
00157
00158 int iPositiveRoots, iNegativeRoots, iZeroRoots;
00159 GetRootSigns(kReps,iPositiveRoots,iNegativeRoots,iZeroRoots);
00160
00161
00162 int eType = QT_NONE;
00163 switch (iZeroRoots)
00164 {
00165 case 0:
00166 eType = ClassifyZeroRoots0(kReps,iPositiveRoots);
00167 break;
00168 case 1:
00169 eType = ClassifyZeroRoots1(kReps,iPositiveRoots);
00170 break;
00171 case 2:
00172 eType = ClassifyZeroRoots2(kReps,iPositiveRoots);
00173 break;
00174 case 3:
00175 eType = ClassifyZeroRoots3(kReps);
00176 break;
00177 }
00178 return eType;
00179 }
00180
00181 template <class Real>
00182 void QuadricSurface<Real>::GetRootSigns (RReps& rkReps,
00183 int& riPositiveRoots, int& riNegativeRoots, int& riZeroRoots)
00184 {
00185
00186 int iSignChangeMI, iSignChange0, iSignChangePI, iDistinctNonzeroRoots;
00187 Rational akValue[4];
00188 if (rkReps.c0 != 0)
00189 {
00190 rkReps.c3 = Rational(2,9)*rkReps.c2*rkReps.c2 -
00191 Rational(2,3)*rkReps.c1;
00192 rkReps.c4 = rkReps.c0 - Rational(1,9)*rkReps.c1*rkReps.c2;
00193
00194 if (rkReps.c3 != 0)
00195 {
00196 rkReps.c5 = -(rkReps.c1 + ((Rational(2)*rkReps.c2*rkReps.c3 +
00197 Rational(3)*rkReps.c4)*rkReps.c4)/(rkReps.c3*rkReps.c3));
00198
00199 akValue[0] = 1;
00200 akValue[1] = -rkReps.c3;
00201 akValue[2] = rkReps.c5;
00202 iSignChangeMI = 1 + GetSignChanges(3,akValue);
00203
00204 akValue[0] = -rkReps.c0;
00205 akValue[1] = rkReps.c1;
00206 akValue[2] = rkReps.c4;
00207 akValue[3] = rkReps.c5;
00208 iSignChange0 = GetSignChanges(4,akValue);
00209
00210 akValue[0] = 1;
00211 akValue[1] = rkReps.c3;
00212 akValue[2] = rkReps.c5;
00213 iSignChangePI = GetSignChanges(3,akValue);
00214 }
00215 else
00216 {
00217 akValue[0] = -rkReps.c0;
00218 akValue[1] = rkReps.c1;
00219 akValue[2] = rkReps.c4;
00220 iSignChange0 = GetSignChanges(3,akValue);
00221
00222 akValue[0] = 1;
00223 akValue[1] = rkReps.c4;
00224 iSignChangePI = GetSignChanges(2,akValue);
00225 iSignChangeMI = 1 + iSignChangePI;
00226 }
00227
00228 riPositiveRoots = iSignChange0 - iSignChangePI;
00229 assert(riPositiveRoots >= 0);
00230 riNegativeRoots = iSignChangeMI - iSignChange0;
00231 assert(riNegativeRoots >= 0);
00232 riZeroRoots = 0;
00233
00234 iDistinctNonzeroRoots = riPositiveRoots + riNegativeRoots;
00235 if (iDistinctNonzeroRoots == 2)
00236 {
00237 if (riPositiveRoots == 2)
00238 {
00239 riPositiveRoots = 3;
00240 }
00241 else if (riNegativeRoots == 2)
00242 {
00243 riNegativeRoots = 3;
00244 }
00245 else
00246 {
00247
00248
00249
00250
00251 Rational kX = Rational(1,3)*rkReps.c2;
00252 Rational kPoly = kX*(kX*(kX-rkReps.c2)+rkReps.c1)-rkReps.c0;
00253 if (kPoly > 0)
00254 {
00255 riPositiveRoots = 2;
00256 }
00257 else
00258 {
00259 riNegativeRoots = 2;
00260 }
00261 }
00262 }
00263 else if (iDistinctNonzeroRoots == 1)
00264 {
00265
00266 if (riPositiveRoots == 1)
00267 {
00268 riPositiveRoots = 3;
00269 }
00270 else
00271 {
00272 riNegativeRoots = 3;
00273 }
00274 }
00275
00276 return;
00277 }
00278
00279 if (rkReps.c1 != 0)
00280 {
00281 rkReps.c3 = Rational(1,4)*rkReps.c2*rkReps.c2 - rkReps.c1;
00282
00283 akValue[0] = -1;
00284 akValue[1] = rkReps.c3;
00285 iSignChangeMI = 1 + GetSignChanges(2,akValue);
00286
00287 akValue[0] = rkReps.c1;
00288 akValue[1] = -rkReps.c2;
00289 akValue[2] = rkReps.c3;
00290 iSignChange0 = GetSignChanges(3,akValue);
00291
00292 akValue[0] = 1;
00293 akValue[1] = rkReps.c3;
00294 iSignChangePI = GetSignChanges(2,akValue);
00295
00296 riPositiveRoots = iSignChange0 - iSignChangePI;
00297 assert( riPositiveRoots >= 0 );
00298 riNegativeRoots = iSignChangeMI - iSignChange0;
00299 assert( riNegativeRoots >= 0 );
00300 riZeroRoots = 1;
00301
00302 iDistinctNonzeroRoots = riPositiveRoots + riNegativeRoots;
00303 if (iDistinctNonzeroRoots == 1)
00304 {
00305 riPositiveRoots = 2;
00306 }
00307
00308 return;
00309 }
00310
00311 if (rkReps.c2 != 0)
00312 {
00313 riZeroRoots = 2;
00314 if (rkReps.c2 > 0)
00315 {
00316 riPositiveRoots = 1;
00317 riNegativeRoots = 0;
00318 }
00319 else
00320 {
00321 riPositiveRoots = 0;
00322 riNegativeRoots = 1;
00323 }
00324 return;
00325 }
00326
00327 riPositiveRoots = 0;
00328 riNegativeRoots = 0;
00329 riZeroRoots = 3;
00330 }
00331
00332 template <class Real>
00333 int QuadricSurface<Real>::GetSignChanges (int iQuantity,
00334 const Rational* akValue)
00335 {
00336 int iSignChanges = 0;
00337 Rational kZero(0);
00338
00339 Rational kPrev = akValue[0];
00340 for (int i = 1; i < iQuantity; i++)
00341 {
00342 Rational kNext = akValue[i];
00343 if (kNext != kZero)
00344 {
00345 if (kPrev*kNext < kZero)
00346 {
00347 iSignChanges++;
00348 }
00349
00350 kPrev = kNext;
00351 }
00352 }
00353
00354 return iSignChanges;
00355 }
00356
00357 template <class Real>
00358 int QuadricSurface<Real>::ClassifyZeroRoots0 (const RReps& rkReps,
00359 int iPositiveRoots)
00360 {
00361
00362
00363
00364
00365
00366
00367 Rational kFourDet = Rational(4)*rkReps.c0;
00368
00369 Rational kQForm = rkReps.b0*(rkReps.Sub00*rkReps.b0 -
00370 rkReps.Sub01*rkReps.b1 + rkReps.Sub02*rkReps.b2) -
00371 rkReps.b1*(rkReps.Sub01*rkReps.b0 - rkReps.Sub11*rkReps.b1 +
00372 rkReps.Sub12*rkReps.b2) + rkReps.b2*(rkReps.Sub02*rkReps.b0 -
00373 rkReps.Sub12*rkReps.b1 + rkReps.Sub22*rkReps.b2);
00374
00375 Rational kR = Rational(1,4)*kQForm/kFourDet - rkReps.c;
00376 if (kR > 0)
00377 {
00378 if (iPositiveRoots == 3)
00379 {
00380 return QT_ELLIPSOID;
00381 }
00382 else if (iPositiveRoots == 2)
00383 {
00384 return QT_HYPERBOLOID_ONE_SHEET;
00385 }
00386 else if (iPositiveRoots == 1)
00387 {
00388 return QT_HYPERBOLOID_TWO_SHEETS;
00389 }
00390 else
00391 {
00392 return QT_NONE;
00393 }
00394 }
00395 else if (kR < 0)
00396 {
00397 if (iPositiveRoots == 3)
00398 {
00399 return QT_NONE;
00400 }
00401 else if (iPositiveRoots == 2)
00402 {
00403 return QT_HYPERBOLOID_TWO_SHEETS;
00404 }
00405 else if (iPositiveRoots == 1)
00406 {
00407 return QT_HYPERBOLOID_ONE_SHEET;
00408 }
00409 else
00410 {
00411 return QT_ELLIPSOID;
00412 }
00413 }
00414
00415
00416 if (iPositiveRoots == 3 || iPositiveRoots == 0)
00417 {
00418 return QT_POINT;
00419 }
00420
00421 return QT_ELLIPTIC_CONE;
00422 }
00423
00424 template <class Real>
00425 int QuadricSurface<Real>::ClassifyZeroRoots1 (const RReps& rkReps,
00426 int iPositiveRoots)
00427 {
00428
00429
00430 QSVector kP0, kP1, kP2;
00431
00432 if (rkReps.Sub00 != 0 || rkReps.Sub01 != 0 || rkReps.Sub02 != 0)
00433 {
00434
00435 kP0 = QSVector(rkReps.Sub00,-rkReps.Sub01,rkReps.Sub02);
00436 kP1 = QSVector(rkReps.a01,rkReps.a11,rkReps.a12);
00437 kP2 = kP0.Cross(kP1);
00438 return ClassifyZeroRoots1(rkReps,iPositiveRoots,kP0,kP1,kP2);
00439 }
00440
00441 if (rkReps.Sub01 != 0 || rkReps.Sub11 != 0 || rkReps.Sub12 != 0)
00442 {
00443
00444 kP0 = QSVector(-rkReps.Sub01,rkReps.Sub11,-rkReps.Sub12);
00445 kP1 = QSVector(rkReps.a02,rkReps.a12,rkReps.a22);
00446 kP2 = kP0.Cross(kP1);
00447 return ClassifyZeroRoots1(rkReps,iPositiveRoots,kP0,kP1,kP2);
00448 }
00449
00450
00451 kP0 = QSVector(rkReps.Sub02,-rkReps.Sub12,rkReps.Sub22);
00452 kP1 = QSVector(rkReps.a00,rkReps.a01,rkReps.a02);
00453 kP2 = kP0.Cross(kP1);
00454 return ClassifyZeroRoots1(rkReps,iPositiveRoots,kP0,kP1,kP2);
00455 }
00456
00457 template <class Real>
00458 int QuadricSurface<Real>::ClassifyZeroRoots1 (const RReps& rkReps,
00459 int iPositiveRoots, const QSVector& rkP0, const QSVector& rkP1,
00460 const QSVector& rkP2)
00461 {
00462 Rational kE0 = rkP0.X()*rkReps.b0 + rkP0.Y()*rkReps.b1 +
00463 rkP0.Z()*rkReps.b2;
00464
00465 if (kE0 != 0)
00466 {
00467 if (iPositiveRoots == 1)
00468 {
00469 return QT_HYPERBOLIC_PARABOLOID;
00470 }
00471 else
00472 {
00473 return QT_ELLIPTIC_PARABOLOID;
00474 }
00475 }
00476
00477
00478 Rational kF11 = rkP1.X()*(rkReps.a00*rkP1.X() + rkReps.a01*rkP1.Y() +
00479 rkReps.a02*rkP1.Z()) + rkP1.Y()*(rkReps.a01*rkP1.X() +
00480 rkReps.a11*rkP1.Y() + rkReps.a12*rkP1.Z()) + rkP1.Z()*(
00481 rkReps.a02*rkP1.X() + rkReps.a12*rkP1.Y() + rkReps.a22*rkP1.Z());
00482
00483 Rational kF12 = rkP2.X()*(rkReps.a00*rkP1.X() + rkReps.a01*rkP1.Y() +
00484 rkReps.a02*rkP1.Z()) + rkP2.Y()*(rkReps.a01*rkP1.X() +
00485 rkReps.a11*rkP1.Y() + rkReps.a12*rkP1.Z()) + rkP2.Z()*(
00486 rkReps.a02*rkP1.X() + rkReps.a12*rkP1.Y() + rkReps.a22*rkP1.Z());
00487
00488 Rational kF22 = rkP2.X()*(rkReps.a00*rkP2.X() + rkReps.a01*rkP2.Y() +
00489 rkReps.a02*rkP2.Z()) + rkP2.Y()*(rkReps.a01*rkP2.X() +
00490 rkReps.a11*rkP2.Y() + rkReps.a12*rkP2.Z()) + rkP2.Z()*(
00491 rkReps.a02*rkP2.X() + rkReps.a12*rkP2.Y() + rkReps.a22*rkP2.Z());
00492
00493
00494 Rational kG1 = rkP1.X()*rkReps.b0 + rkP1.Y()*rkReps.b1 +
00495 rkP1.Z()*rkReps.b2;
00496 Rational kG2 = rkP2.X()*rkReps.b0 + rkP2.Y()*rkReps.b1 +
00497 rkP2.Z()*rkReps.b2;
00498
00499
00500 Rational kFourDet = Rational(4)*(kF11*kF22 - kF12*kF12);
00501 Rational kR = (kG1*(kF22*kG1-kF12*kG2)+kG2*(kF11*kG2-kF12*kG1))/kFourDet
00502 - rkReps.c;
00503
00504 if (kR > 0)
00505 {
00506 if (iPositiveRoots == 2)
00507 {
00508 return QT_ELLIPTIC_CYLINDER;
00509 }
00510 else if (iPositiveRoots == 1)
00511 {
00512 return QT_HYPERBOLIC_CYLINDER;
00513 }
00514 else
00515 {
00516 return QT_NONE;
00517 }
00518 }
00519 else if (kR < 0)
00520 {
00521 if (iPositiveRoots == 2)
00522 {
00523 return QT_NONE;
00524 }
00525 else if (iPositiveRoots == 1)
00526 {
00527 return QT_HYPERBOLIC_CYLINDER;
00528 }
00529 else
00530 {
00531 return QT_ELLIPTIC_CYLINDER;
00532 }
00533 }
00534
00535
00536 return (iPositiveRoots == 1 ? QT_TWO_PLANES : QT_LINE);
00537 }
00538
00539 template <class Real>
00540 int QuadricSurface<Real>::ClassifyZeroRoots2 (const RReps& rkReps,
00541 int iPositiveRoots)
00542 {
00543
00544
00545
00546 QSVector kP0, kP1, kP2;
00547
00548 if (rkReps.a00 != 0 || rkReps.a01 != 0 || rkReps.a02 != 0)
00549 {
00550
00551 kP2 = QSVector(rkReps.a00,rkReps.a01,rkReps.a02);
00552 }
00553 else if (rkReps.a01 != 0 || rkReps.a11 != 0 || rkReps.a12 != 0)
00554 {
00555
00556 kP2 = QSVector(rkReps.a01,rkReps.a11,rkReps.a12);
00557 }
00558 else
00559 {
00560
00561 kP2 = QSVector(rkReps.a02,rkReps.a12,rkReps.a22);
00562 }
00563
00564 if (kP2.X() != 0)
00565 {
00566 kP1.X() = kP2.Y();
00567 kP1.Y() = -kP2.X();
00568 kP1.Z() = 0;
00569 }
00570 else
00571 {
00572 kP1.X() = 0;
00573 kP1.Y() = kP2.Z();
00574 kP1.Z() = -kP2.Y();
00575 }
00576 kP0 = kP1.Cross(kP2);
00577
00578 return ClassifyZeroRoots2(rkReps,iPositiveRoots,kP0,kP1,kP2);
00579 }
00580
00581 template <class Real>
00582 int QuadricSurface<Real>::ClassifyZeroRoots2 (const RReps& rkReps,
00583 int iPositiveRoots, const QSVector& rkP0, const QSVector& rkP1,
00584 const QSVector& rkP2)
00585 {
00586 Rational kE0 = rkP0.X()*rkReps.b0 + rkP0.Y()*rkReps.b1 +
00587 rkP0.Z()*rkReps.b1;
00588
00589 if (kE0 != 0)
00590 {
00591 return QT_PARABOLIC_CYLINDER;
00592 }
00593
00594 Rational kE1 = rkP1.X()*rkReps.b0 + rkP1.Y()*rkReps.b1 +
00595 rkP1.Z()*rkReps.b1;
00596
00597 if (kE1 != 0)
00598 {
00599 return QT_PARABOLIC_CYLINDER;
00600 }
00601
00602 Rational kF2 = rkReps.c2*(rkP2.Dot(rkP2));
00603 Rational kE2 = rkP2.X()*rkReps.b0 + rkP2.Y()*rkReps.b1 +
00604 rkP2.Z()*rkReps.b1;
00605
00606 Rational kR = kE2*kE2/(Rational(4)*kF2) - rkReps.c;
00607 if (kR > 0)
00608 {
00609 if (iPositiveRoots == 1)
00610 {
00611 return QT_TWO_PLANES;
00612 }
00613 else
00614 {
00615 return QT_NONE;
00616 }
00617 }
00618 else if (kR < 0)
00619 {
00620 if (iPositiveRoots == 1)
00621 {
00622 return QT_NONE;
00623 }
00624 else
00625 {
00626 return QT_TWO_PLANES;
00627 }
00628 }
00629
00630
00631 return QT_PLANE;
00632 }
00633
00634 template <class Real>
00635 int QuadricSurface<Real>::ClassifyZeroRoots3 (const RReps& rkReps)
00636 {
00637 if (rkReps.b0 != 0 || rkReps.b1 != 0 || rkReps.b2 != 0)
00638 {
00639 return QT_PLANE;
00640 }
00641
00642 return QT_NONE;
00643 }
00644
00645
00646
00647
00648
00649 template WM4_FOUNDATION_ITEM
00650 class QuadricSurface<float>;
00651
00652 template WM4_FOUNDATION_ITEM
00653 class QuadricSurface<double>;
00654
00655 }