Blender V2.61 - r43446

btVoronoiSimplexSolver.cpp

Go to the documentation of this file.
00001 
00002 /*
00003 Bullet Continuous Collision Detection and Physics Library
00004 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00005 
00006 This software is provided 'as-is', without any express or implied warranty.
00007 In no event will the authors be held liable for any damages arising from the use of this software.
00008 Permission is granted to anyone to use this software for any purpose, 
00009 including commercial applications, and to alter it and redistribute it freely, 
00010 subject to the following restrictions:
00011 
00012 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
00013 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00014 3. This notice may not be removed or altered from any source distribution.
00015     
00016     Elsevier CDROM license agreements grants nonexclusive license to use the software
00017     for any purpose, commercial or non-commercial as long as the following credit is included
00018     identifying the original source of the software:
00019 
00020     Parts of the source are "from the book Real-Time Collision Detection by
00021     Christer Ericson, published by Morgan Kaufmann Publishers,
00022     (c) 2005 Elsevier Inc."
00023         
00024 */
00025 
00026 
00027 #include "btVoronoiSimplexSolver.h"
00028 
00029 #define VERTA  0
00030 #define VERTB  1
00031 #define VERTC  2
00032 #define VERTD  3
00033 
00034 #define CATCH_DEGENERATE_TETRAHEDRON 1
00035 void    btVoronoiSimplexSolver::removeVertex(int index)
00036 {
00037     
00038     btAssert(m_numVertices>0);
00039     m_numVertices--;
00040     m_simplexVectorW[index] = m_simplexVectorW[m_numVertices];
00041     m_simplexPointsP[index] = m_simplexPointsP[m_numVertices];
00042     m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices];
00043 }
00044 
00045 void    btVoronoiSimplexSolver::reduceVertices (const btUsageBitfield& usedVerts)
00046 {
00047     if ((numVertices() >= 4) && (!usedVerts.usedVertexD))
00048         removeVertex(3);
00049 
00050     if ((numVertices() >= 3) && (!usedVerts.usedVertexC))
00051         removeVertex(2);
00052 
00053     if ((numVertices() >= 2) && (!usedVerts.usedVertexB))
00054         removeVertex(1);
00055     
00056     if ((numVertices() >= 1) && (!usedVerts.usedVertexA))
00057         removeVertex(0);
00058 
00059 }
00060 
00061 
00062 
00063 
00064 
00065 //clear the simplex, remove all the vertices
00066 void btVoronoiSimplexSolver::reset()
00067 {
00068     m_cachedValidClosest = false;
00069     m_numVertices = 0;
00070     m_needsUpdate = true;
00071     m_lastW = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT));
00072     m_cachedBC.reset();
00073 }
00074 
00075 
00076 
00077     //add a vertex
00078 void btVoronoiSimplexSolver::addVertex(const btVector3& w, const btVector3& p, const btVector3& q)
00079 {
00080     m_lastW = w;
00081     m_needsUpdate = true;
00082 
00083     m_simplexVectorW[m_numVertices] = w;
00084     m_simplexPointsP[m_numVertices] = p;
00085     m_simplexPointsQ[m_numVertices] = q;
00086 
00087     m_numVertices++;
00088 }
00089 
00090 bool    btVoronoiSimplexSolver::updateClosestVectorAndPoints()
00091 {
00092     
00093     if (m_needsUpdate)
00094     {
00095         m_cachedBC.reset();
00096 
00097         m_needsUpdate = false;
00098 
00099         switch (numVertices())
00100         {
00101         case 0:
00102                 m_cachedValidClosest = false;
00103                 break;
00104         case 1:
00105             {
00106                 m_cachedP1 = m_simplexPointsP[0];
00107                 m_cachedP2 = m_simplexPointsQ[0];
00108                 m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0]
00109                 m_cachedBC.reset();
00110                 m_cachedBC.setBarycentricCoordinates(btScalar(1.),btScalar(0.),btScalar(0.),btScalar(0.));
00111                 m_cachedValidClosest = m_cachedBC.isValid();
00112                 break;
00113             };
00114         case 2:
00115             {
00116             //closest point origin from line segment
00117                     const btVector3& from = m_simplexVectorW[0];
00118                     const btVector3& to = m_simplexVectorW[1];
00119                     btVector3 nearest;
00120 
00121                     btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.));
00122                     btVector3 diff = p - from;
00123                     btVector3 v = to - from;
00124                     btScalar t = v.dot(diff);
00125                     
00126                     if (t > 0) {
00127                         btScalar dotVV = v.dot(v);
00128                         if (t < dotVV) {
00129                             t /= dotVV;
00130                             diff -= t*v;
00131                             m_cachedBC.m_usedVertices.usedVertexA = true;
00132                             m_cachedBC.m_usedVertices.usedVertexB = true;
00133                         } else {
00134                             t = 1;
00135                             diff -= v;
00136                             //reduce to 1 point
00137                             m_cachedBC.m_usedVertices.usedVertexB = true;
00138                         }
00139                     } else
00140                     {
00141                         t = 0;
00142                         //reduce to 1 point
00143                         m_cachedBC.m_usedVertices.usedVertexA = true;
00144                     }
00145                     m_cachedBC.setBarycentricCoordinates(1-t,t);
00146                     nearest = from + t*v;
00147 
00148                     m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]);
00149                     m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]);
00150                     m_cachedV = m_cachedP1 - m_cachedP2;
00151                     
00152                     reduceVertices(m_cachedBC.m_usedVertices);
00153 
00154                     m_cachedValidClosest = m_cachedBC.isValid();
00155                     break;
00156             }
00157         case 3: 
00158             { 
00159                 //closest point origin from triangle 
00160                 btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); 
00161 
00162                 const btVector3& a = m_simplexVectorW[0]; 
00163                 const btVector3& b = m_simplexVectorW[1]; 
00164                 const btVector3& c = m_simplexVectorW[2]; 
00165 
00166                 closestPtPointTriangle(p,a,b,c,m_cachedBC); 
00167                 m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + 
00168                 m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + 
00169                 m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2]; 
00170 
00171                 m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + 
00172                 m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + 
00173                 m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2]; 
00174 
00175                 m_cachedV = m_cachedP1-m_cachedP2; 
00176 
00177                 reduceVertices (m_cachedBC.m_usedVertices); 
00178                 m_cachedValidClosest = m_cachedBC.isValid(); 
00179 
00180                 break; 
00181             }
00182         case 4:
00183             {
00184 
00185                 
00186                 btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.));
00187                 
00188                 const btVector3& a = m_simplexVectorW[0];
00189                 const btVector3& b = m_simplexVectorW[1];
00190                 const btVector3& c = m_simplexVectorW[2];
00191                 const btVector3& d = m_simplexVectorW[3];
00192 
00193                 bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC);
00194 
00195                 if (hasSeperation)
00196                 {
00197 
00198                     m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] +
00199                         m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] +
00200                         m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] +
00201                         m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3];
00202 
00203                     m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] +
00204                         m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] +
00205                         m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] +
00206                         m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3];
00207 
00208                     m_cachedV = m_cachedP1-m_cachedP2;
00209                     reduceVertices (m_cachedBC.m_usedVertices);
00210                 } else
00211                 {
00212 //                  printf("sub distance got penetration\n");
00213 
00214                     if (m_cachedBC.m_degenerate)
00215                     {
00216                         m_cachedValidClosest = false;
00217                     } else
00218                     {
00219                         m_cachedValidClosest = true;
00220                         //degenerate case == false, penetration = true + zero
00221                         m_cachedV.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
00222                     }
00223                     break;
00224                 }
00225 
00226                 m_cachedValidClosest = m_cachedBC.isValid();
00227 
00228                 //closest point origin from tetrahedron
00229                 break;
00230             }
00231         default:
00232             {
00233                 m_cachedValidClosest = false;
00234             }
00235         };
00236     }
00237 
00238     return m_cachedValidClosest;
00239 
00240 }
00241 
00242 //return/calculate the closest vertex
00243 bool btVoronoiSimplexSolver::closest(btVector3& v)
00244 {
00245     bool succes = updateClosestVectorAndPoints();
00246     v = m_cachedV;
00247     return succes;
00248 }
00249 
00250 
00251 
00252 btScalar btVoronoiSimplexSolver::maxVertex()
00253 {
00254     int i, numverts = numVertices();
00255     btScalar maxV = btScalar(0.);
00256     for (i=0;i<numverts;i++)
00257     {
00258         btScalar curLen2 = m_simplexVectorW[i].length2();
00259         if (maxV < curLen2)
00260             maxV = curLen2;
00261     }
00262     return maxV;
00263 }
00264 
00265 
00266 
00267     //return the current simplex
00268 int btVoronoiSimplexSolver::getSimplex(btVector3 *pBuf, btVector3 *qBuf, btVector3 *yBuf) const
00269 {
00270     int i;
00271     for (i=0;i<numVertices();i++)
00272     {
00273         yBuf[i] = m_simplexVectorW[i];
00274         pBuf[i] = m_simplexPointsP[i];
00275         qBuf[i] = m_simplexPointsQ[i];
00276     }
00277     return numVertices();
00278 }
00279 
00280 
00281 
00282 
00283 bool btVoronoiSimplexSolver::inSimplex(const btVector3& w)
00284 {
00285     bool found = false;
00286     int i, numverts = numVertices();
00287     //btScalar maxV = btScalar(0.);
00288     
00289     //w is in the current (reduced) simplex
00290     for (i=0;i<numverts;i++)
00291     {
00292 #ifdef BT_USE_EQUAL_VERTEX_THRESHOLD
00293         if ( m_simplexVectorW[i].distance2(w) <= m_equalVertexThreshold)
00294 #else
00295         if (m_simplexVectorW[i] == w)
00296 #endif
00297             found = true;
00298     }
00299 
00300     //check in case lastW is already removed
00301     if (w == m_lastW)
00302         return true;
00303         
00304     return found;
00305 }
00306 
00307 void btVoronoiSimplexSolver::backup_closest(btVector3& v) 
00308 {
00309     v = m_cachedV;
00310 }
00311 
00312 
00313 bool btVoronoiSimplexSolver::emptySimplex() const 
00314 {
00315     return (numVertices() == 0);
00316 
00317 }
00318 
00319 void btVoronoiSimplexSolver::compute_points(btVector3& p1, btVector3& p2) 
00320 {
00321     updateClosestVectorAndPoints();
00322     p1 = m_cachedP1;
00323     p2 = m_cachedP2;
00324 
00325 }
00326 
00327 
00328 
00329 
00330 bool    btVoronoiSimplexSolver::closestPtPointTriangle(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c,btSubSimplexClosestResult& result)
00331 {
00332     result.m_usedVertices.reset();
00333 
00334     // Check if P in vertex region outside A
00335     btVector3 ab = b - a;
00336     btVector3 ac = c - a;
00337     btVector3 ap = p - a;
00338     btScalar d1 = ab.dot(ap);
00339     btScalar d2 = ac.dot(ap);
00340     if (d1 <= btScalar(0.0) && d2 <= btScalar(0.0)) 
00341     {
00342         result.m_closestPointOnSimplex = a;
00343         result.m_usedVertices.usedVertexA = true;
00344         result.setBarycentricCoordinates(1,0,0);
00345         return true;// a; // barycentric coordinates (1,0,0)
00346     }
00347 
00348     // Check if P in vertex region outside B
00349     btVector3 bp = p - b;
00350     btScalar d3 = ab.dot(bp);
00351     btScalar d4 = ac.dot(bp);
00352     if (d3 >= btScalar(0.0) && d4 <= d3) 
00353     {
00354         result.m_closestPointOnSimplex = b;
00355         result.m_usedVertices.usedVertexB = true;
00356         result.setBarycentricCoordinates(0,1,0);
00357 
00358         return true; // b; // barycentric coordinates (0,1,0)
00359     }
00360     // Check if P in edge region of AB, if so return projection of P onto AB
00361     btScalar vc = d1*d4 - d3*d2;
00362     if (vc <= btScalar(0.0) && d1 >= btScalar(0.0) && d3 <= btScalar(0.0)) {
00363         btScalar v = d1 / (d1 - d3);
00364         result.m_closestPointOnSimplex = a + v * ab;
00365         result.m_usedVertices.usedVertexA = true;
00366         result.m_usedVertices.usedVertexB = true;
00367         result.setBarycentricCoordinates(1-v,v,0);
00368         return true;
00369         //return a + v * ab; // barycentric coordinates (1-v,v,0)
00370     }
00371 
00372     // Check if P in vertex region outside C
00373     btVector3 cp = p - c;
00374     btScalar d5 = ab.dot(cp);
00375     btScalar d6 = ac.dot(cp);
00376     if (d6 >= btScalar(0.0) && d5 <= d6) 
00377     {
00378         result.m_closestPointOnSimplex = c;
00379         result.m_usedVertices.usedVertexC = true;
00380         result.setBarycentricCoordinates(0,0,1);
00381         return true;//c; // barycentric coordinates (0,0,1)
00382     }
00383 
00384     // Check if P in edge region of AC, if so return projection of P onto AC
00385     btScalar vb = d5*d2 - d1*d6;
00386     if (vb <= btScalar(0.0) && d2 >= btScalar(0.0) && d6 <= btScalar(0.0)) {
00387         btScalar w = d2 / (d2 - d6);
00388         result.m_closestPointOnSimplex = a + w * ac;
00389         result.m_usedVertices.usedVertexA = true;
00390         result.m_usedVertices.usedVertexC = true;
00391         result.setBarycentricCoordinates(1-w,0,w);
00392         return true;
00393         //return a + w * ac; // barycentric coordinates (1-w,0,w)
00394     }
00395 
00396     // Check if P in edge region of BC, if so return projection of P onto BC
00397     btScalar va = d3*d6 - d5*d4;
00398     if (va <= btScalar(0.0) && (d4 - d3) >= btScalar(0.0) && (d5 - d6) >= btScalar(0.0)) {
00399         btScalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
00400         
00401         result.m_closestPointOnSimplex = b + w * (c - b);
00402         result.m_usedVertices.usedVertexB = true;
00403         result.m_usedVertices.usedVertexC = true;
00404         result.setBarycentricCoordinates(0,1-w,w);
00405         return true;        
00406        // return b + w * (c - b); // barycentric coordinates (0,1-w,w)
00407     }
00408 
00409     // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
00410     btScalar denom = btScalar(1.0) / (va + vb + vc);
00411     btScalar v = vb * denom;
00412     btScalar w = vc * denom;
00413     
00414     result.m_closestPointOnSimplex = a + ab * v + ac * w;
00415     result.m_usedVertices.usedVertexA = true;
00416     result.m_usedVertices.usedVertexB = true;
00417     result.m_usedVertices.usedVertexC = true;
00418     result.setBarycentricCoordinates(1-v-w,v,w);
00419     
00420     return true;
00421 //  return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w
00422 
00423 }
00424 
00425 
00426 
00427 
00428 
00430 int btVoronoiSimplexSolver::pointOutsideOfPlane(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d)
00431 {
00432     btVector3 normal = (b-a).cross(c-a);
00433 
00434     btScalar signp = (p - a).dot(normal); // [AP AB AC]
00435     btScalar signd = (d - a).dot( normal); // [AD AB AC]
00436 
00437 #ifdef CATCH_DEGENERATE_TETRAHEDRON
00438 #ifdef BT_USE_DOUBLE_PRECISION
00439 if (signd * signd < (btScalar(1e-8) * btScalar(1e-8)))
00440     {
00441         return -1;
00442     }
00443 #else
00444     if (signd * signd < (btScalar(1e-4) * btScalar(1e-4)))
00445     {
00446 //      printf("affine dependent/degenerate\n");//
00447         return -1;
00448     }
00449 #endif
00450 
00451 #endif
00452     // Points on opposite sides if expression signs are opposite
00453     return signp * signd < btScalar(0.);
00454 }
00455 
00456 
00457 bool    btVoronoiSimplexSolver::closestPtPointTetrahedron(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, btSubSimplexClosestResult& finalResult)
00458 {
00459     btSubSimplexClosestResult tempResult;
00460 
00461     // Start out assuming point inside all halfspaces, so closest to itself
00462     finalResult.m_closestPointOnSimplex = p;
00463     finalResult.m_usedVertices.reset();
00464     finalResult.m_usedVertices.usedVertexA = true;
00465     finalResult.m_usedVertices.usedVertexB = true;
00466     finalResult.m_usedVertices.usedVertexC = true;
00467     finalResult.m_usedVertices.usedVertexD = true;
00468 
00469     int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d);
00470     int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b);
00471     int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c);
00472     int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a);
00473 
00474    if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0)
00475    {
00476        finalResult.m_degenerate = true;
00477        return false;
00478    }
00479 
00480    if (!pointOutsideABC  && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC)
00481      {
00482          return false;
00483      }
00484 
00485 
00486     btScalar bestSqDist = FLT_MAX;
00487     // If point outside face abc then compute closest point on abc
00488     if (pointOutsideABC) 
00489     {
00490         closestPtPointTriangle(p, a, b, c,tempResult);
00491         btVector3 q = tempResult.m_closestPointOnSimplex;
00492         
00493         btScalar sqDist = (q - p).dot( q - p);
00494         // Update best closest point if (squared) distance is less than current best
00495         if (sqDist < bestSqDist) {
00496             bestSqDist = sqDist;
00497             finalResult.m_closestPointOnSimplex = q;
00498             //convert result bitmask!
00499             finalResult.m_usedVertices.reset();
00500             finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
00501             finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB;
00502             finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
00503             finalResult.setBarycentricCoordinates(
00504                     tempResult.m_barycentricCoords[VERTA],
00505                     tempResult.m_barycentricCoords[VERTB],
00506                     tempResult.m_barycentricCoords[VERTC],
00507                     0
00508             );
00509 
00510         }
00511     }
00512   
00513 
00514     // Repeat test for face acd
00515     if (pointOutsideACD) 
00516     {
00517         closestPtPointTriangle(p, a, c, d,tempResult);
00518         btVector3 q = tempResult.m_closestPointOnSimplex;
00519         //convert result bitmask!
00520 
00521         btScalar sqDist = (q - p).dot( q - p);
00522         if (sqDist < bestSqDist) 
00523         {
00524             bestSqDist = sqDist;
00525             finalResult.m_closestPointOnSimplex = q;
00526             finalResult.m_usedVertices.reset();
00527             finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
00528 
00529             finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB;
00530             finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC;
00531             finalResult.setBarycentricCoordinates(
00532                     tempResult.m_barycentricCoords[VERTA],
00533                     0,
00534                     tempResult.m_barycentricCoords[VERTB],
00535                     tempResult.m_barycentricCoords[VERTC]
00536             );
00537 
00538         }
00539     }
00540     // Repeat test for face adb
00541 
00542     
00543     if (pointOutsideADB)
00544     {
00545         closestPtPointTriangle(p, a, d, b,tempResult);
00546         btVector3 q = tempResult.m_closestPointOnSimplex;
00547         //convert result bitmask!
00548 
00549         btScalar sqDist = (q - p).dot( q - p);
00550         if (sqDist < bestSqDist) 
00551         {
00552             bestSqDist = sqDist;
00553             finalResult.m_closestPointOnSimplex = q;
00554             finalResult.m_usedVertices.reset();
00555             finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA;
00556             finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC;
00557             
00558             finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
00559             finalResult.setBarycentricCoordinates(
00560                     tempResult.m_barycentricCoords[VERTA],
00561                     tempResult.m_barycentricCoords[VERTC],
00562                     0,
00563                     tempResult.m_barycentricCoords[VERTB]
00564             );
00565 
00566         }
00567     }
00568     // Repeat test for face bdc
00569     
00570 
00571     if (pointOutsideBDC)
00572     {
00573         closestPtPointTriangle(p, b, d, c,tempResult);
00574         btVector3 q = tempResult.m_closestPointOnSimplex;
00575         //convert result bitmask!
00576         btScalar sqDist = (q - p).dot( q - p);
00577         if (sqDist < bestSqDist) 
00578         {
00579             bestSqDist = sqDist;
00580             finalResult.m_closestPointOnSimplex = q;
00581             finalResult.m_usedVertices.reset();
00582             //
00583             finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA;
00584             finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC;
00585             finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB;
00586 
00587             finalResult.setBarycentricCoordinates(
00588                     0,
00589                     tempResult.m_barycentricCoords[VERTA],
00590                     tempResult.m_barycentricCoords[VERTC],
00591                     tempResult.m_barycentricCoords[VERTB]
00592             );
00593 
00594         }
00595     }
00596 
00597     //help! we ended up full !
00598     
00599     if (finalResult.m_usedVertices.usedVertexA &&
00600         finalResult.m_usedVertices.usedVertexB &&
00601         finalResult.m_usedVertices.usedVertexC &&
00602         finalResult.m_usedVertices.usedVertexD) 
00603     {
00604         return true;
00605     }
00606 
00607     return true;
00608 }
00609