TopoAlgorithm.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2005 Imetric 3D GmbH                                    *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 # include <algorithm>
00028 # include <utility>
00029 # include <queue>
00030 #endif
00031 
00032 #include <Mod/Mesh/App/WildMagic4/Wm4MeshCurvature.h>
00033 #include <Mod/Mesh/App/WildMagic4/Wm4Vector3.h>
00034 
00035 #include "TopoAlgorithm.h"
00036 #include "Iterator.h"
00037 #include "MeshKernel.h"
00038 #include "Algorithm.h"
00039 #include "Evaluation.h"
00040 #include "Triangulation.h"
00041 #include <Base/Console.h>
00042 
00043 using namespace MeshCore;
00044 
00045 MeshTopoAlgorithm::MeshTopoAlgorithm (MeshKernel &rclM)
00046 : _rclMesh(rclM), _needsCleanup(false), _cache(0)
00047 {
00048 }
00049 
00050 MeshTopoAlgorithm::~MeshTopoAlgorithm (void)
00051 {
00052   if ( _needsCleanup )
00053     Cleanup();
00054   EndCache();
00055 }
00056 
00057 bool MeshTopoAlgorithm::InsertVertex(unsigned long ulFacetPos, const Base::Vector3f&  rclPoint)
00058 {
00059   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00060   MeshFacet  clNewFacet1, clNewFacet2;
00061 
00062   // insert new point
00063   unsigned long ulPtCnt = _rclMesh._aclPointArray.size();
00064   unsigned long ulPtInd = this->GetOrAddIndex(rclPoint);
00065   unsigned long ulSize  = _rclMesh._aclFacetArray.size();
00066 
00067   if ( ulPtInd < ulPtCnt )
00068     return false; // the given point is already part of the mesh => creating new facets would be an illegal operation
00069 
00070   // adjust the facets
00071   //
00072   // first new facet
00073   clNewFacet1._aulPoints[0] = rclF._aulPoints[1];
00074   clNewFacet1._aulPoints[1] = rclF._aulPoints[2];
00075   clNewFacet1._aulPoints[2] = ulPtInd;
00076   clNewFacet1._aulNeighbours[0] = rclF._aulNeighbours[1];
00077   clNewFacet1._aulNeighbours[1] = ulSize+1;
00078   clNewFacet1._aulNeighbours[2] = ulFacetPos;
00079   // second new facet
00080   clNewFacet2._aulPoints[0] = rclF._aulPoints[2];
00081   clNewFacet2._aulPoints[1] = rclF._aulPoints[0];
00082   clNewFacet2._aulPoints[2] = ulPtInd;
00083   clNewFacet2._aulNeighbours[0] = rclF._aulNeighbours[2];
00084   clNewFacet2._aulNeighbours[1] = ulFacetPos;
00085   clNewFacet2._aulNeighbours[2] = ulSize;
00086   // adjust the neighbour facet
00087   if (rclF._aulNeighbours[1] != ULONG_MAX)
00088     _rclMesh._aclFacetArray[rclF._aulNeighbours[1]].ReplaceNeighbour(ulFacetPos, ulSize);
00089   if (rclF._aulNeighbours[2] != ULONG_MAX)
00090     _rclMesh._aclFacetArray[rclF._aulNeighbours[2]].ReplaceNeighbour(ulFacetPos, ulSize+1);
00091   // original facet
00092   rclF._aulPoints[2] = ulPtInd;
00093   rclF._aulNeighbours[1] = ulSize;
00094   rclF._aulNeighbours[2] = ulSize+1;
00095 
00096   // insert new facets
00097   _rclMesh._aclFacetArray.push_back(clNewFacet1);
00098   _rclMesh._aclFacetArray.push_back(clNewFacet2);
00099 
00100   return true;
00101 }
00102 
00103 bool MeshTopoAlgorithm::SnapVertex(unsigned long ulFacetPos, const Base::Vector3f& rP)
00104 {
00105   MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
00106   if (!rFace.HasOpenEdge())
00107     return false;
00108   Base::Vector3f cNo1 = _rclMesh.GetNormal(rFace);
00109   for (short i=0; i<3; i++)
00110   {
00111     if (rFace._aulNeighbours[i]==ULONG_MAX)
00112     {
00113       const Base::Vector3f& rPt1 = _rclMesh._aclPointArray[rFace._aulPoints[i]];
00114       const Base::Vector3f& rPt2 = _rclMesh._aclPointArray[rFace._aulPoints[(i+1)%3]];
00115       Base::Vector3f cNo2 = (rPt2 - rPt1) % cNo1;
00116       Base::Vector3f cNo3 = (rP - rPt1) % (rPt2 - rPt1);
00117       float fD2 = Base::DistanceP2(rPt1, rPt2);
00118       float fTV = (rP-rPt1) * (rPt2-rPt1);
00119 
00120       // Point is on the edge
00121       if ( cNo3.Length() < FLOAT_EPS )
00122       {
00123         unsigned long uCt = _rclMesh.CountFacets();
00124         SplitOpenEdge(ulFacetPos, i, rP);
00125         return uCt < _rclMesh.CountFacets();
00126       }
00127       else if ( (rP - rPt1)*cNo2 > 0.0f && fD2 >= fTV && fTV >= 0.0f )
00128       {
00129         MeshFacet cTria;
00130         cTria._aulPoints[0] = this->GetOrAddIndex(rP);
00131         cTria._aulPoints[1] = rFace._aulPoints[(i+1)%3];
00132         cTria._aulPoints[2] = rFace._aulPoints[i];
00133         cTria._aulNeighbours[1] = ulFacetPos;
00134         rFace._aulNeighbours[i] = _rclMesh.CountFacets();
00135         _rclMesh._aclFacetArray.push_back(cTria);
00136         return true;
00137       }
00138     }
00139   }
00140 
00141   return false;
00142 }
00143 
00144 void MeshTopoAlgorithm::OptimizeTopology(float fMaxAngle)
00145 {
00146   // For each internal edge get the adjacent facets. When doing an edge swap we must update
00147   // this structure.
00148   std::map<std::pair<unsigned long, unsigned long>, std::vector<unsigned long> > aEdge2Face;
00149   for (MeshFacetArray::_TIterator pI = _rclMesh._aclFacetArray.begin(); pI != _rclMesh._aclFacetArray.end(); pI++)
00150   {
00151     for (int i = 0; i < 3; i++)
00152     {
00153       // ignore open edges
00154       if ( pI->_aulNeighbours[i] != ULONG_MAX ) {
00155         unsigned long ulPt0 = std::min<unsigned long>(pI->_aulPoints[i],  pI->_aulPoints[(i+1)%3]);
00156         unsigned long ulPt1 = std::max<unsigned long>(pI->_aulPoints[i],  pI->_aulPoints[(i+1)%3]);
00157         aEdge2Face[std::pair<unsigned long, unsigned long>(ulPt0, ulPt1)].push_back(pI - _rclMesh._aclFacetArray.begin());
00158       }
00159     }
00160   }
00161 
00162   // fill up this list with all internal edges and perform swap edges until this list is empty
00163   std::list<std::pair<unsigned long, unsigned long> > aEdgeList;
00164   std::map<std::pair<unsigned long, unsigned long>, std::vector<unsigned long> >::iterator pE;
00165   for (pE = aEdge2Face.begin(); pE != aEdge2Face.end(); ++pE) {
00166     if (pE->second.size() == 2) // make sure that we really have an internal edge
00167       aEdgeList.push_back(pE->first);
00168   }
00169 
00170   // to be sure to avoid an endless loop
00171   unsigned long uMaxIter = 5 * aEdge2Face.size();
00172 
00173   // Perform a swap edge where needed
00174   while ( !aEdgeList.empty() && uMaxIter > 0 ) {
00175     // get the first edge and remove it from the list
00176     std::pair<unsigned long, unsigned long> aEdge = aEdgeList.front();
00177     aEdgeList.pop_front();
00178     uMaxIter--;
00179 
00180     // get the adjacent facets to this edge
00181     pE = aEdge2Face.find( aEdge );
00182 
00183     // this edge has been removed some iterations before
00184     if ( pE == aEdge2Face.end() )
00185       continue;
00186 
00187     // Is swap edge allowed and sensible?
00188     if ( !ShouldSwapEdge(pE->second[0], pE->second[1], fMaxAngle) )
00189       continue;
00190 
00191     // ok, here we should perform a swap edge to minimize the maximum angle
00192     if ( /*fMax12 > fMax34*/true ) {
00193       // swap the edge
00194       SwapEdge(pE->second[0], pE->second[1]);
00195       
00196       MeshFacet& rF1 = _rclMesh._aclFacetArray[pE->second[0]];
00197       MeshFacet& rF2 = _rclMesh._aclFacetArray[pE->second[1]];
00198       unsigned short side1 = rF1.Side(aEdge.first, aEdge.second);
00199       unsigned short side2 = rF2.Side(aEdge.first, aEdge.second);
00200 
00201       // adjust the edge list
00202       for ( int i=0; i<3; i++ ) {
00203         std::map<std::pair<unsigned long, unsigned long>, std::vector<unsigned long> >::iterator it;
00204         // first facet
00205         unsigned long ulPt0 = std::min<unsigned long>(rF1._aulPoints[i],  rF1._aulPoints[(i+1)%3]);
00206         unsigned long ulPt1 = std::max<unsigned long>(rF1._aulPoints[i],  rF1._aulPoints[(i+1)%3]);
00207         it = aEdge2Face.find( std::make_pair(ulPt0, ulPt1) );
00208         if ( it != aEdge2Face.end() ) {
00209           if ( it->second[0] == pE->second[1] )
00210             it->second[0] = pE->second[0];
00211           else if ( it->second[1] == pE->second[1] )
00212             it->second[1] = pE->second[0];
00213           aEdgeList.push_back( it->first );
00214         }
00215 
00216         // second facet
00217         ulPt0 = std::min<unsigned long>(rF2._aulPoints[i],  rF2._aulPoints[(i+1)%3]);
00218         ulPt1 = std::max<unsigned long>(rF2._aulPoints[i],  rF2._aulPoints[(i+1)%3]);
00219         it = aEdge2Face.find( std::make_pair(ulPt0, ulPt1) );
00220         if ( it != aEdge2Face.end() ) {
00221           if ( it->second[0] == pE->second[0] )
00222             it->second[0] = pE->second[1];
00223           else if ( it->second[1] == pE->second[0] )
00224             it->second[1] = pE->second[1];
00225           aEdgeList.push_back( it->first );
00226         }
00227       }
00228 
00229       // Now we must remove the edge and replace it through the new edge
00230       unsigned long ulPt0 = std::min<unsigned long>(rF1._aulPoints[(side1+1)%3], rF2._aulPoints[(side2+1)%3]);
00231       unsigned long ulPt1 = std::max<unsigned long>(rF1._aulPoints[(side1+1)%3], rF2._aulPoints[(side2+1)%3]);
00232       std::pair<unsigned long, unsigned long> aNewEdge = std::make_pair(ulPt0, ulPt1);
00233       aEdge2Face[aNewEdge] = pE->second;
00234       aEdge2Face.erase(pE);
00235     }
00236   }
00237 }
00238 
00239 // Cosine of the maximum angle in triangle (v1,v2,v3)
00240 static float cos_maxangle(const Base::Vector3f &v1,
00241                           const Base::Vector3f &v2,
00242                           const Base::Vector3f &v3)
00243 {
00244     float a = Base::Distance(v2,v3);
00245     float b = Base::Distance(v3,v1);
00246     float c = Base::Distance(v1,v2);
00247     float A = a * (b*b + c*c - a*a);
00248     float B = b * (c*c + a*a - b*b);
00249     float C = c * (a*a + b*b - c*c);
00250     return 0.5f * std::min<float>(std::min<float>(A,B),C) / (a*b*c); // min cosine == max angle
00251 }
00252 
00253 static float swap_benefit(const Base::Vector3f &v1, const Base::Vector3f &v2,
00254                           const Base::Vector3f &v3, const Base::Vector3f &v4)
00255 {
00256     Base::Vector3f n124 = (v4 - v2) % (v1 - v2);
00257     Base::Vector3f n234 = (v3 - v2) % (v4 - v2);
00258     if ((n124 * n234) <= 0.0f)
00259         return 0.0f; // avoid normal flip
00260 
00261     return std::max<float>(-cos_maxangle(v1,v2,v3), -cos_maxangle(v1,v3,v4)) -
00262            std::max<float>(-cos_maxangle(v1,v2,v4), -cos_maxangle(v2,v3,v4));
00263 }
00264 
00265 float MeshTopoAlgorithm::SwapEdgeBenefit(unsigned long f, int e) const
00266 {
00267     const MeshFacetArray& faces = _rclMesh.GetFacets();
00268     const MeshPointArray& vertices = _rclMesh.GetPoints();
00269 
00270     unsigned long n = faces[f]._aulNeighbours[e];
00271     if (n == ULONG_MAX)
00272         return 0.0f; // border edge
00273 
00274     unsigned long v1 = faces[f]._aulPoints[e];
00275     unsigned long v2 = faces[f]._aulPoints[(e+1)%3];
00276     unsigned long v3 = faces[f]._aulPoints[(e+2)%3];
00277     unsigned short s = faces[n].Side(faces[f]);
00278     if (s == USHRT_MAX) {
00279         std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: error in neighbourhood "
00280                   << "of faces " << f << " and " << n << std::endl;
00281         return 0.0f; // topological error
00282     }
00283     unsigned long v4 = faces[n]._aulPoints[(s+2)%3];
00284     if (v3 == v4) {
00285         std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: duplicate faces "
00286                   << f << " and " << n << std::endl;
00287         return 0.0f; // duplicate faces
00288     }
00289     return swap_benefit(vertices[v2], vertices[v3],
00290                         vertices[v1], vertices[v4]);
00291 }
00292 
00293 typedef std::pair<unsigned long,int> FaceEdge; // (face, edge) pair
00294 typedef std::pair<float, FaceEdge> FaceEdgePriority;
00295 
00296 void MeshTopoAlgorithm::OptimizeTopology()
00297 {
00298     // Find all edges that can be swapped and insert them into a
00299     // priority queue
00300     const MeshFacetArray& faces = _rclMesh.GetFacets();
00301     unsigned long nf = _rclMesh.CountFacets();
00302     std::priority_queue<FaceEdgePriority> todo;
00303     for (unsigned long i = 0; i < nf; i++) {
00304         for (int j = 0; j < 3; j++) {
00305             float b = SwapEdgeBenefit(i, j);
00306             if (b > 0.0f)
00307                 todo.push(std::make_pair(b, std::make_pair(i, j)));
00308         }
00309     }
00310 
00311     // Edges are sorted in decreasing order with respect to their benefit
00312     while (!todo.empty()) {
00313         unsigned long f = todo.top().second.first;
00314         int e = todo.top().second.second;
00315         todo.pop();
00316         // Check again if the swap should still be done
00317         if (SwapEdgeBenefit(f, e) <= 0.0f)
00318             continue;
00319         // OK, swap the edge
00320         unsigned long f2 = faces[f]._aulNeighbours[e];
00321         SwapEdge(f, f2);
00322         // Insert new edges into queue, if necessary
00323         for (int j = 0; j < 3; j++) {
00324             float b = SwapEdgeBenefit(f, j);
00325             if (b > 0.0f)
00326                 todo.push(std::make_pair(b, std::make_pair(f, j)));
00327         }
00328         for (int j = 0; j < 3; j++) {
00329             float b = SwapEdgeBenefit(f2, j);
00330             if (b > 0.0f)
00331                 todo.push(std::make_pair(b, std::make_pair(f2, j)));
00332         }
00333     }
00334 }
00335 
00336 void MeshTopoAlgorithm::DelaunayFlip(float fMaxAngle)
00337 {
00338     // For each internal edge get the adjacent facets.
00339     std::set<std::pair<unsigned long, unsigned long> > aEdge2Face;
00340     unsigned long index = 0;
00341     for (MeshFacetArray::_TIterator pI = _rclMesh._aclFacetArray.begin(); pI != _rclMesh._aclFacetArray.end(); pI++, index++) {
00342         for (int i = 0; i < 3; i++) {
00343             // ignore open edges
00344             if (pI->_aulNeighbours[i] != ULONG_MAX) {
00345                 unsigned long ulFt0 = std::min<unsigned long>(index, pI->_aulNeighbours[i]);
00346                 unsigned long ulFt1 = std::max<unsigned long>(index, pI->_aulNeighbours[i]);
00347                 aEdge2Face.insert(std::pair<unsigned long, unsigned long>(ulFt0, ulFt1));
00348             }
00349         }
00350     }
00351 
00352     Base::Vector3f center;
00353     while (!aEdge2Face.empty()) {
00354         std::set<std::pair<unsigned long, unsigned long> >::iterator it = aEdge2Face.begin();
00355         std::pair<unsigned long, unsigned long> edge = *it;
00356         aEdge2Face.erase(it);
00357         if (ShouldSwapEdge(edge.first, edge.second, fMaxAngle)) {
00358             float radius = _rclMesh.GetFacet(edge.first).CenterOfCircumCircle(center);
00359             radius *= radius;
00360             const MeshFacet& face_1 = _rclMesh._aclFacetArray[edge.first];
00361             const MeshFacet& face_2 = _rclMesh._aclFacetArray[edge.second];
00362             unsigned short side = face_2.Side(edge.first);
00363             Base::Vector3f vertex = _rclMesh.GetPoint(face_2._aulPoints[(side+1)%3]);
00364             if (Base::DistanceP2(center, vertex) < radius) {
00365                 SwapEdge(edge.first, edge.second);
00366                 for (int i=0; i<3; i++) {
00367                     if (face_1._aulNeighbours[i] != ULONG_MAX && face_1._aulNeighbours[i] != edge.second) {
00368                         unsigned long ulFt0 = std::min<unsigned long>(edge.first, face_1._aulNeighbours[i]);
00369                         unsigned long ulFt1 = std::max<unsigned long>(edge.first, face_1._aulNeighbours[i]);
00370                         aEdge2Face.insert(std::pair<unsigned long, unsigned long>(ulFt0, ulFt1));
00371                     }
00372                     if (face_2._aulNeighbours[i] != ULONG_MAX && face_2._aulNeighbours[i] != edge.first) {
00373                         unsigned long ulFt0 = std::min<unsigned long>(edge.second, face_2._aulNeighbours[i]);
00374                         unsigned long ulFt1 = std::max<unsigned long>(edge.second, face_2._aulNeighbours[i]);
00375                         aEdge2Face.insert(std::pair<unsigned long, unsigned long>(ulFt0, ulFt1));
00376                     }
00377                 }
00378             }
00379         }
00380     }
00381 }
00382 
00383 int MeshTopoAlgorithm::DelaunayFlip()
00384 {
00385     int cnt_swap=0;
00386     _rclMesh._aclFacetArray.ResetFlag(MeshFacet::TMP0);
00387     unsigned long cnt_facets = _rclMesh._aclFacetArray.size();
00388     for (unsigned long i=0;i<cnt_facets;i++) {
00389         const MeshFacet& f_face = _rclMesh._aclFacetArray[i];
00390         if (f_face.IsFlag(MeshFacet::TMP0))
00391             continue;
00392         for (int j=0;j<3;j++) {
00393             unsigned long n = f_face._aulNeighbours[j];
00394             if (n != ULONG_MAX) {
00395                 const MeshFacet& n_face = _rclMesh._aclFacetArray[n];
00396                 if (n_face.IsFlag(MeshFacet::TMP0))
00397                     continue;
00398                 unsigned short k = n_face.Side(f_face);
00399                 MeshGeomFacet f1 = _rclMesh.GetFacet(f_face);
00400                 MeshGeomFacet f2 = _rclMesh.GetFacet(n_face);
00401                 Base::Vector3f c1, c2, p1, p2;
00402                 p1 = f1._aclPoints[(j+2)%3];
00403                 p2 = f2._aclPoints[(k+2)%3];
00404                 float r1 = f1.CenterOfCircumCircle(c1);
00405                 r1 = r1*r1;
00406                 float r2 = f2.CenterOfCircumCircle(c2);
00407                 r2 = r2*r2;
00408                 float d1 = Base::DistanceP2(c1, p2);
00409                 float d2 = Base::DistanceP2(c2, p1);
00410                 if (d1 < r1 || d2 < r2) {
00411                     SwapEdge(i, n);
00412                     cnt_swap++;
00413                     f_face.SetFlag(MeshFacet::TMP0);
00414                     n_face.SetFlag(MeshFacet::TMP0);
00415                 }
00416             }
00417         }
00418     }
00419 
00420     return cnt_swap;
00421 }
00422 
00423 void MeshTopoAlgorithm::AdjustEdgesToCurvatureDirection()
00424 {
00425   std::vector< Wm4::Vector3<float> > aPnts;
00426   MeshPointIterator cPIt( _rclMesh );
00427   aPnts.reserve(_rclMesh.CountPoints());
00428   for ( cPIt.Init(); cPIt.More(); cPIt.Next() )
00429     aPnts.push_back( Wm4::Vector3<float>( cPIt->x, cPIt->y, cPIt->z ) );
00430 
00431   // get all point connections
00432   std::vector<int> aIdx;
00433   const MeshFacetArray& raFts = _rclMesh.GetFacets();
00434   aIdx.reserve( 3*raFts.size() );
00435 
00436   // Build map of edges to the referencing facets
00437   unsigned long k = 0;
00438   std::map<std::pair<unsigned long, unsigned long>, std::list<unsigned long> > aclEdgeMap;
00439   for ( std::vector<MeshFacet>::const_iterator jt = raFts.begin(); jt != raFts.end(); ++jt, k++ )
00440   {
00441     for (int i=0; i<3; i++)
00442     {
00443       unsigned long ulT0 = jt->_aulPoints[i];
00444       unsigned long ulT1 = jt->_aulPoints[(i+1)%3];
00445       unsigned long ulP0 = std::min<unsigned long>(ulT0, ulT1);
00446       unsigned long ulP1 = std::max<unsigned long>(ulT0, ulT1);
00447       aclEdgeMap[std::make_pair<unsigned long, unsigned long>(ulP0, ulP1)].push_front(k);
00448       aIdx.push_back( (int)jt->_aulPoints[i] );
00449     }
00450   }
00451 
00452   // compute vertex based curvatures
00453   Wm4::MeshCurvature<float> meshCurv(_rclMesh.CountPoints(), &(aPnts[0]), _rclMesh.CountFacets(), &(aIdx[0]));
00454 
00455   // get curvature information now
00456   const Wm4::Vector3<float>* aMaxCurvDir = meshCurv.GetMaxDirections();
00457   const Wm4::Vector3<float>* aMinCurvDir = meshCurv.GetMinDirections();
00458   const float* aMaxCurv = meshCurv.GetMaxCurvatures();
00459   const float* aMinCurv = meshCurv.GetMinCurvatures();
00460 
00461   raFts.ResetFlag(MeshFacet::VISIT);
00462   const MeshPointArray& raPts = _rclMesh.GetPoints();
00463   for ( std::map<std::pair<unsigned long, unsigned long>, std::list<unsigned long> >::iterator kt = aclEdgeMap.begin(); kt != aclEdgeMap.end(); ++kt )
00464   {
00465     if ( kt->second.size() == 2 ) {
00466       unsigned long uPt1 = kt->first.first;
00467       unsigned long uPt2 = kt->first.second;
00468       unsigned long uFt1 = kt->second.front();
00469       unsigned long uFt2 = kt->second.back();
00470 
00471       const MeshFacet& rFace1 = raFts[uFt1];
00472       const MeshFacet& rFace2 = raFts[uFt2];
00473       if ( rFace1.IsFlag(MeshFacet::VISIT) || rFace2.IsFlag(MeshFacet::VISIT) )
00474         continue;
00475 
00476       unsigned long uPt3, uPt4;
00477       unsigned short side = rFace1.Side(uPt1, uPt2);
00478       uPt3 = rFace1._aulPoints[(side+2)%3];
00479       side = rFace2.Side(uPt1, uPt2);
00480       uPt4 = rFace2._aulPoints[(side+2)%3];
00481       
00482       Wm4::Vector3<float> dir;
00483       float fActCurvature;
00484       if ( fabs(aMinCurv[uPt1]) > fabs(aMaxCurv[uPt1]) ) {
00485         fActCurvature = aMinCurv[uPt1];
00486         dir = aMaxCurvDir[uPt1];
00487       } else {
00488         fActCurvature = aMaxCurv[uPt1];
00489         dir = aMinCurvDir[uPt1];
00490       }
00491 
00492       Base::Vector3f cMinDir(dir.X(), dir.Y(), dir.Z());
00493       Base::Vector3f cEdgeDir1 = raPts[uPt1] - raPts[uPt2];
00494       Base::Vector3f cEdgeDir2 = raPts[uPt3] - raPts[uPt4];
00495       cMinDir.Normalize(); cEdgeDir1.Normalize(); cEdgeDir2.Normalize();
00496     
00497       // get the plane and calculate the distance to the fourth point
00498       MeshGeomFacet cPlane(raPts[uPt1], raPts[uPt2], raPts[uPt3]);
00499       // positive or negative distance
00500       float fDist = raPts[uPt4].DistanceToPlane(cPlane._aclPoints[0], cPlane.GetNormal());
00501 
00502       float fLength12 = Base::Distance(raPts[uPt1], raPts[uPt2]);
00503       float fLength34 = Base::Distance(raPts[uPt3], raPts[uPt4]);
00504       if ( fabs(cEdgeDir1*cMinDir) < fabs(cEdgeDir2*cMinDir) )
00505       {
00506         if ( IsSwapEdgeLegal(uFt1, uFt2) && fLength34 < 1.05f*fLength12 && fActCurvature*fDist > 0.0f) {
00507           SwapEdge(uFt1, uFt2);
00508           rFace1.SetFlag(MeshFacet::VISIT);
00509           rFace2.SetFlag(MeshFacet::VISIT);
00510         }
00511       }
00512     }
00513   }
00514 }
00515 
00516 bool MeshTopoAlgorithm::InsertVertexAndSwapEdge(unsigned long ulFacetPos, const Base::Vector3f&  rclPoint, float fMaxAngle)
00517 {
00518   if ( !InsertVertex(ulFacetPos, rclPoint) )
00519     return false;
00520 
00521   // get the created elements
00522   unsigned long ulF1Ind = _rclMesh._aclFacetArray.size()-2;
00523   unsigned long ulF2Ind = _rclMesh._aclFacetArray.size()-1;
00524   MeshFacet& rclF1 = _rclMesh._aclFacetArray[ulFacetPos];
00525   MeshFacet& rclF2 = _rclMesh._aclFacetArray[ulF1Ind];
00526   MeshFacet& rclF3 = _rclMesh._aclFacetArray[ulF2Ind];
00527 
00528   // first facet
00529   int i;
00530   for ( i=0; i<3; i++ )
00531   {
00532     unsigned long uNeighbour = rclF1._aulNeighbours[i];
00533     if ( uNeighbour!=ULONG_MAX && uNeighbour!=ulF1Ind && uNeighbour!=ulF2Ind )
00534     {
00535       if ( ShouldSwapEdge(ulFacetPos, uNeighbour, fMaxAngle) ) {
00536         SwapEdge(ulFacetPos, uNeighbour);
00537         break;
00538       }
00539     }
00540   }
00541   for ( i=0; i<3; i++ )
00542   {
00543     // second facet
00544     unsigned long uNeighbour = rclF2._aulNeighbours[i];
00545     if ( uNeighbour!=ULONG_MAX && uNeighbour!=ulFacetPos && uNeighbour!=ulF2Ind )
00546     {
00547       if ( ShouldSwapEdge(ulF1Ind, uNeighbour, fMaxAngle) ) {
00548         SwapEdge(ulF1Ind, uNeighbour);
00549         break;
00550       }
00551     }
00552   }
00553 
00554   // third facet
00555   for ( i=0; i<3; i++ )
00556   {
00557     unsigned long uNeighbour = rclF3._aulNeighbours[i];
00558     if ( uNeighbour!=ULONG_MAX && uNeighbour!=ulFacetPos && uNeighbour!=ulF1Ind )
00559     {
00560       if ( ShouldSwapEdge(ulF2Ind, uNeighbour, fMaxAngle) ) {
00561         SwapEdge(ulF2Ind, uNeighbour);
00562         break;
00563       }
00564     }
00565   }
00566 
00567   return true;
00568 }
00569 
00570 bool MeshTopoAlgorithm::IsSwapEdgeLegal(unsigned long ulFacetPos, unsigned long ulNeighbour) const
00571 {
00572   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00573   MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
00574 
00575   unsigned short uFSide = rclF.Side(rclN);
00576   unsigned short uNSide = rclN.Side(rclF);
00577 
00578   if (uFSide == USHRT_MAX || uNSide == USHRT_MAX) 
00579     return false; // not neighbours
00580 
00581   Base::Vector3f cP1 = _rclMesh._aclPointArray[rclF._aulPoints[uFSide]];
00582   Base::Vector3f cP2 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide+1)%3]];
00583   Base::Vector3f cP3 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide+2)%3]];
00584   Base::Vector3f cP4 = _rclMesh._aclPointArray[rclN._aulPoints[(uNSide+2)%3]];
00585 
00586   // do not allow to create degenerated triangles
00587   MeshGeomFacet cT3(cP4, cP3, cP1);
00588   if ( cT3.IsDegenerated() )
00589     return false;
00590   MeshGeomFacet cT4(cP3, cP4, cP2);
00591   if ( cT4.IsDegenerated() )
00592     return false;
00593 
00594   // We must make sure that the two adjacent triangles builds a convex polygon, otherwise 
00595   // the swap edge operation is illegal
00596   Base::Vector3f cU = cP2-cP1;
00597   Base::Vector3f cV = cP4-cP3;
00598   // build a helper plane through cP1 that must separate cP3 and cP4
00599   Base::Vector3f cN1 = (cU % cV) % cU;
00600   if ( ((cP3-cP1)*cN1)*((cP4-cP1)*cN1) >= 0.0f )
00601     return false; // not convex
00602   // build a helper plane through cP3 that must separate cP1 and cP2
00603   Base::Vector3f cN2 = (cU % cV) % cV;
00604   if ( ((cP1-cP3)*cN2)*((cP2-cP3)*cN2) >= 0.0f )
00605     return false; // not convex
00606 
00607   return true;
00608 }
00609 
00610 bool MeshTopoAlgorithm::ShouldSwapEdge(unsigned long ulFacetPos, unsigned long ulNeighbour, float fMaxAngle) const
00611 {
00612   if ( !IsSwapEdgeLegal(ulFacetPos, ulNeighbour) )
00613     return false;
00614 
00615   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00616   MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
00617 
00618   unsigned short uFSide = rclF.Side(rclN);
00619   unsigned short uNSide = rclN.Side(rclF);
00620 
00621   Base::Vector3f cP1 = _rclMesh._aclPointArray[rclF._aulPoints[uFSide]];
00622   Base::Vector3f cP2 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide+1)%3]];
00623   Base::Vector3f cP3 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide+2)%3]];
00624   Base::Vector3f cP4 = _rclMesh._aclPointArray[rclN._aulPoints[(uNSide+2)%3]];
00625 
00626   MeshGeomFacet cT1(cP1, cP2, cP3); float fMax1 = cT1.MaximumAngle();
00627   MeshGeomFacet cT2(cP2, cP1, cP4); float fMax2 = cT2.MaximumAngle();
00628   MeshGeomFacet cT3(cP4, cP3, cP1); float fMax3 = cT3.MaximumAngle();
00629   MeshGeomFacet cT4(cP3, cP4, cP2); float fMax4 = cT4.MaximumAngle();
00630 
00631   // get the angle between the triangles
00632   Base::Vector3f cN1 = cT1.GetNormal();
00633   Base::Vector3f cN2 = cT2.GetNormal();
00634   if ( cN1.GetAngle(cN2) > fMaxAngle )
00635     return false;
00636 
00637   float fMax12 = std::max<float>(fMax1, fMax2);
00638   float fMax34 = std::max<float>(fMax3, fMax4);
00639 
00640   return  fMax12 > fMax34;
00641 }
00642 
00643 void MeshTopoAlgorithm::SwapEdge(unsigned long ulFacetPos, unsigned long ulNeighbour)
00644 {
00645   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00646   MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
00647 
00648   unsigned short uFSide = rclF.Side(rclN);
00649   unsigned short uNSide = rclN.Side(rclF);
00650 
00651   if (uFSide == USHRT_MAX || uNSide == USHRT_MAX) 
00652     return; // not neighbours
00653 
00654   // adjust the neighbourhood
00655   if (rclF._aulNeighbours[(uFSide+1)%3] != ULONG_MAX)
00656     _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide+1)%3]].ReplaceNeighbour(ulFacetPos, ulNeighbour);
00657   if (rclN._aulNeighbours[(uNSide+1)%3] != ULONG_MAX)
00658     _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+1)%3]].ReplaceNeighbour(ulNeighbour, ulFacetPos);
00659 
00660   // swap the point and neighbour indices
00661   rclF._aulPoints[(uFSide+1)%3] = rclN._aulPoints[(uNSide+2)%3];
00662   rclN._aulPoints[(uNSide+1)%3] = rclF._aulPoints[(uFSide+2)%3];
00663   rclF._aulNeighbours[uFSide] = rclN._aulNeighbours[(uNSide+1)%3];
00664   rclN._aulNeighbours[uNSide] = rclF._aulNeighbours[(uFSide+1)%3];
00665   rclF._aulNeighbours[(uFSide+1)%3] = ulNeighbour;
00666   rclN._aulNeighbours[(uNSide+1)%3] = ulFacetPos;
00667 }
00668 
00669 bool MeshTopoAlgorithm::SplitEdge(unsigned long ulFacetPos, unsigned long ulNeighbour, const Base::Vector3f& rP)
00670 {
00671   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00672   MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
00673 
00674   unsigned short uFSide = rclF.Side(rclN);
00675   unsigned short uNSide = rclN.Side(rclF);
00676 
00677   if (uFSide == USHRT_MAX || uNSide == USHRT_MAX) 
00678     return false; // not neighbours
00679 
00680   unsigned long uPtCnt = _rclMesh._aclPointArray.size();
00681   unsigned long uPtInd = this->GetOrAddIndex(rP);
00682   unsigned long ulSize = _rclMesh._aclFacetArray.size();
00683 
00684   // the given point is already part of the mesh => creating new facets would
00685   // be an illegal operation
00686   if (uPtInd < uPtCnt)
00687     return false;
00688 
00689   // adjust the neighbourhood
00690   if (rclF._aulNeighbours[(uFSide+1)%3] != ULONG_MAX)
00691     _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide+1)%3]].ReplaceNeighbour(ulFacetPos, ulSize);
00692   if (rclN._aulNeighbours[(uNSide+2)%3] != ULONG_MAX)
00693     _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+2)%3]].ReplaceNeighbour(ulNeighbour, ulSize+1);
00694 
00695   MeshFacet cNew1, cNew2;
00696   cNew1._aulPoints[0] = uPtInd;
00697   cNew1._aulPoints[1] = rclF._aulPoints[(uFSide+1)%3];
00698   cNew1._aulPoints[2] = rclF._aulPoints[(uFSide+2)%3];
00699   cNew1._aulNeighbours[0] = ulSize+1;
00700   cNew1._aulNeighbours[1] = rclF._aulNeighbours[(uFSide+1)%3];
00701   cNew1._aulNeighbours[2] = ulFacetPos;
00702 
00703   cNew2._aulPoints[0] = rclN._aulPoints[uNSide];
00704   cNew2._aulPoints[1] = uPtInd;
00705   cNew2._aulPoints[2] = rclN._aulPoints[(uNSide+2)%3];
00706   cNew2._aulNeighbours[0] = ulSize;
00707   cNew2._aulNeighbours[1] = ulNeighbour;
00708   cNew2._aulNeighbours[2] = rclN._aulNeighbours[(uNSide+2)%3];
00709 
00710   // adjust the facets
00711   rclF._aulPoints[(uFSide+1)%3] = uPtInd;
00712   rclF._aulNeighbours[(uFSide+1)%3] = ulSize;
00713   rclN._aulPoints[uNSide] = uPtInd;
00714   rclN._aulNeighbours[(uNSide+2)%3] = ulSize+1;
00715 
00716   // insert new facets
00717   _rclMesh._aclFacetArray.push_back(cNew1);
00718   _rclMesh._aclFacetArray.push_back(cNew2);
00719 
00720   return true;
00721 }
00722 
00723 void MeshTopoAlgorithm::SplitOpenEdge(unsigned long ulFacetPos, unsigned short uSide, const Base::Vector3f& rP)
00724 {
00725   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00726   if (rclF._aulNeighbours[uSide] != ULONG_MAX) 
00727     return; // not open
00728 
00729   unsigned long uPtCnt = _rclMesh._aclPointArray.size();
00730   unsigned long uPtInd = this->GetOrAddIndex(rP);
00731   unsigned long ulSize = _rclMesh._aclFacetArray.size();
00732 
00733   if ( uPtInd < uPtCnt )
00734     return; // the given point is already part of the mesh => creating new facets would be an illegal operation
00735 
00736   // adjust the neighbourhood
00737   if (rclF._aulNeighbours[(uSide+1)%3] != ULONG_MAX)
00738     _rclMesh._aclFacetArray[rclF._aulNeighbours[(uSide+1)%3]].ReplaceNeighbour(ulFacetPos, ulSize);
00739 
00740   MeshFacet cNew;
00741   cNew._aulPoints[0] = uPtInd;
00742   cNew._aulPoints[1] = rclF._aulPoints[(uSide+1)%3];
00743   cNew._aulPoints[2] = rclF._aulPoints[(uSide+2)%3];
00744   cNew._aulNeighbours[0] = ULONG_MAX;
00745   cNew._aulNeighbours[1] = rclF._aulNeighbours[(uSide+1)%3];
00746   cNew._aulNeighbours[2] = ulFacetPos;
00747 
00748   // adjust the facets
00749   rclF._aulPoints[(uSide+1)%3] = uPtInd;
00750   rclF._aulNeighbours[(uSide+1)%3] = ulSize;
00751 
00752   // insert new facets
00753   _rclMesh._aclFacetArray.push_back(cNew);
00754 }
00755 
00756 bool MeshTopoAlgorithm::Vertex_Less::operator ()(const Base::Vector3f& u,
00757                                                  const Base::Vector3f& v) const
00758 {
00759     if (fabs (u.x - v.x) > FLOAT_EPS)
00760         return u.x < v.x;
00761     if (fabs (u.y - v.y) > FLOAT_EPS)
00762         return u.y < v.y;
00763     if (fabs (u.z - v.z) > FLOAT_EPS)
00764         return u.z < v.z;
00765     return false;
00766 }
00767 
00768 void MeshTopoAlgorithm::BeginCache()
00769 {
00770     if (_cache) {
00771         delete _cache;
00772     }
00773     _cache = new tCache();
00774     unsigned long nbPoints = _rclMesh._aclPointArray.size();
00775     for (unsigned int pntCpt = 0 ; pntCpt < nbPoints ; ++pntCpt) {
00776         _cache->insert(std::make_pair(_rclMesh._aclPointArray[pntCpt],pntCpt));
00777     }
00778 }
00779 
00780 void MeshTopoAlgorithm::EndCache()
00781 {
00782     if (_cache) {
00783         _cache->clear();
00784         delete _cache;
00785         _cache = 0;
00786     }
00787 }
00788 
00789 unsigned long MeshTopoAlgorithm::GetOrAddIndex (const MeshPoint &rclPoint)
00790 {
00791     if (!_cache)
00792         return _rclMesh._aclPointArray.GetOrAddIndex(rclPoint);
00793 
00794     unsigned long sz = _rclMesh._aclPointArray.size();
00795     std::pair<tCache::iterator,bool> retval = _cache->insert(std::make_pair(rclPoint,sz));
00796     if (retval.second)
00797         _rclMesh._aclPointArray.push_back(rclPoint);
00798     return retval.first->second;
00799 }
00800 
00801 std::vector<unsigned long> MeshTopoAlgorithm::GetFacetsToPoint(unsigned long uFacetPos, unsigned long uPointPos) const
00802 {
00803   // get all facets this point is referenced by
00804   std::list<unsigned long> aReference;
00805   aReference.push_back(uFacetPos);
00806   std::set<unsigned long> aRefFacet;
00807   while ( !aReference.empty() )
00808   {
00809     unsigned long uIndex = aReference.front();
00810     aReference.pop_front();
00811     aRefFacet.insert(uIndex);
00812     MeshFacet& rFace = _rclMesh._aclFacetArray[uIndex];
00813     for ( int i=0; i<3; i++ ) {
00814       if ( rFace._aulPoints[i] == uPointPos ) {
00815         if ( rFace._aulNeighbours[i] != ULONG_MAX )
00816         {
00817           if ( aRefFacet.find(rFace._aulNeighbours[i]) == aRefFacet.end() )
00818             aReference.push_back( rFace._aulNeighbours[i] );
00819         }
00820         if ( rFace._aulNeighbours[(i+2)%3] != ULONG_MAX )
00821         {
00822           if ( aRefFacet.find(rFace._aulNeighbours[(i+2)%3]) == aRefFacet.end() )
00823             aReference.push_back( rFace._aulNeighbours[(i+2)%3] );
00824         }
00825         break;
00826       }
00827     }
00828   }
00829 
00830   //copy the items
00831   std::vector<unsigned long> aRefs;
00832   aRefs.insert(aRefs.end(), aRefFacet.begin(), aRefFacet.end());
00833   return aRefs;
00834 }
00835 
00836 void MeshTopoAlgorithm::Cleanup()
00837 {
00838   _rclMesh.RemoveInvalids();
00839   _needsCleanup = false;
00840 }
00841 
00842 bool MeshTopoAlgorithm::CollapseEdge(unsigned long ulFacetPos, unsigned long ulNeighbour)
00843 {
00844   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00845   MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
00846 
00847   unsigned short uFSide = rclF.Side(rclN);
00848   unsigned short uNSide = rclN.Side(rclF);
00849 
00850   if (uFSide == USHRT_MAX || uNSide == USHRT_MAX) 
00851     return false; // not neighbours
00852 
00853   if (!rclF.IsValid() || !rclN.IsValid())
00854     return false; // the facets are marked invalid from a previous run
00855 
00856   // get the point index we want to remove
00857   unsigned long ulPointPos = rclF._aulPoints[uFSide];
00858   unsigned long ulPointNew = rclN._aulPoints[uNSide];
00859 
00860   // get all facets this point is referenced by
00861   std::vector<unsigned long> aRefs = GetFacetsToPoint(ulFacetPos, ulPointPos);
00862   for ( std::vector<unsigned long>::iterator it = aRefs.begin(); it != aRefs.end(); ++it )
00863   {
00864     MeshFacet& rFace = _rclMesh._aclFacetArray[*it];
00865     rFace.Transpose( ulPointPos, ulPointNew );
00866   }
00867 
00868   // set the new neighbourhood
00869   if (rclF._aulNeighbours[(uFSide+1)%3] != ULONG_MAX)
00870     _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide+1)%3]].ReplaceNeighbour(ulFacetPos, rclF._aulNeighbours[(uFSide+2)%3]);
00871   if (rclF._aulNeighbours[(uFSide+2)%3] != ULONG_MAX)
00872     _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide+2)%3]].ReplaceNeighbour(ulFacetPos, rclF._aulNeighbours[(uFSide+1)%3]);
00873   if (rclN._aulNeighbours[(uNSide+1)%3] != ULONG_MAX)
00874     _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+1)%3]].ReplaceNeighbour(ulNeighbour, rclN._aulNeighbours[(uNSide+2)%3]);
00875   if (rclN._aulNeighbours[(uNSide+2)%3] != ULONG_MAX)
00876     _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+2)%3]].ReplaceNeighbour(ulNeighbour, rclN._aulNeighbours[(uNSide+1)%3]);
00877 
00878   // isolate the both facets and the point
00879   rclF._aulNeighbours[0] = ULONG_MAX;
00880   rclF._aulNeighbours[1] = ULONG_MAX;
00881   rclF._aulNeighbours[2] = ULONG_MAX;
00882   rclF.SetInvalid();
00883   rclN._aulNeighbours[0] = ULONG_MAX;
00884   rclN._aulNeighbours[1] = ULONG_MAX;
00885   rclN._aulNeighbours[2] = ULONG_MAX;
00886   rclN.SetInvalid();
00887   _rclMesh._aclPointArray[ulPointPos].SetInvalid();
00888 
00889   _needsCleanup = true;
00890 
00891   return true;
00892 }
00893 
00894 bool MeshTopoAlgorithm::CollapseFacet(unsigned long ulFacetPos)
00895 {
00896     MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
00897     if (!rclF.IsValid())
00898         return false; // the facet is marked invalid from a previous run
00899 
00900     // get the point index we want to remove
00901     unsigned long ulPointInd0 = rclF._aulPoints[0];
00902     unsigned long ulPointInd1 = rclF._aulPoints[1];
00903     unsigned long ulPointInd2 = rclF._aulPoints[2];
00904 
00905     // move the vertex to the gravity center
00906     Base::Vector3f cCenter = _rclMesh.GetGravityPoint(rclF);
00907     _rclMesh._aclPointArray[ulPointInd0] = cCenter;
00908 
00909     // set the new point indices for all facets that share one of the points to be deleted
00910     std::vector<unsigned long> aRefs = GetFacetsToPoint(ulFacetPos, ulPointInd1);
00911     for (std::vector<unsigned long>::iterator it = aRefs.begin(); it != aRefs.end(); ++it) {
00912         MeshFacet& rFace = _rclMesh._aclFacetArray[*it];
00913         rFace.Transpose(ulPointInd1, ulPointInd0);
00914     }
00915     
00916     aRefs = GetFacetsToPoint(ulFacetPos, ulPointInd2);
00917     for (std::vector<unsigned long>::iterator it = aRefs.begin(); it != aRefs.end(); ++it) {
00918         MeshFacet& rFace = _rclMesh._aclFacetArray[*it];
00919         rFace.Transpose(ulPointInd2, ulPointInd0);
00920     }
00921 
00922     // set the neighbourhood of the circumjacent facets
00923     for (int i=0; i<3; i++) {
00924         if (rclF._aulNeighbours[i] == ULONG_MAX)
00925             continue;
00926         MeshFacet& rclN = _rclMesh._aclFacetArray[rclF._aulNeighbours[i]];
00927         unsigned short uNSide = rclN.Side(rclF);
00928 
00929         if (rclN._aulNeighbours[(uNSide+1)%3] != ULONG_MAX) {
00930             _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+1)%3]]
00931                     .ReplaceNeighbour(rclF._aulNeighbours[i],rclN._aulNeighbours[(uNSide+2)%3]);
00932         }
00933         if (rclN._aulNeighbours[(uNSide+2)%3] != ULONG_MAX) {
00934             _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+2)%3]]
00935                     .ReplaceNeighbour(rclF._aulNeighbours[i],rclN._aulNeighbours[(uNSide+1)%3]);
00936         }
00937 
00938         // Isolate the neighbours from the topology
00939         rclN._aulNeighbours[0] = ULONG_MAX;
00940         rclN._aulNeighbours[1] = ULONG_MAX;
00941         rclN._aulNeighbours[2] = ULONG_MAX;
00942         rclN.SetInvalid();
00943     }
00944 
00945     // Isolate this facet and make two of its points invalid
00946     rclF._aulNeighbours[0] = ULONG_MAX;
00947     rclF._aulNeighbours[1] = ULONG_MAX;
00948     rclF._aulNeighbours[2] = ULONG_MAX;
00949     rclF.SetInvalid();
00950     _rclMesh._aclPointArray[ulPointInd1].SetInvalid();
00951     _rclMesh._aclPointArray[ulPointInd2].SetInvalid();
00952 
00953     _needsCleanup = true;
00954 
00955     return true;
00956 }
00957 
00959 void MeshTopoAlgorithm::SplitFacet(unsigned long ulFacetPos, const Base::Vector3f& rP1, const Base::Vector3f& rP2)
00960 {
00961   float fEps = MESH_MIN_EDGE_LEN;
00962   MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
00963   MeshPoint& rVertex0 = _rclMesh._aclPointArray[rFace._aulPoints[0]];
00964   MeshPoint& rVertex1 = _rclMesh._aclPointArray[rFace._aulPoints[1]];
00965   MeshPoint& rVertex2 = _rclMesh._aclPointArray[rFace._aulPoints[2]];
00966 
00967   unsigned short equalP1=USHRT_MAX, equalP2=USHRT_MAX;
00968   if ( Base::Distance(rVertex0, rP1) < fEps )
00969     equalP1=0;
00970   else if ( Base::Distance(rVertex1, rP1) < fEps )
00971     equalP1=1;
00972   else if ( Base::Distance(rVertex2, rP1) < fEps )
00973     equalP1=2;
00974   if ( Base::Distance(rVertex0, rP2) < fEps )
00975     equalP2=0;
00976   else if ( Base::Distance(rVertex1, rP2) < fEps )
00977     equalP2=1;
00978   else if ( Base::Distance(rVertex2, rP2) < fEps )
00979     equalP2=2;
00980 
00981   // both points are coincident with the corner points
00982   if ( equalP1 != USHRT_MAX && equalP2 != USHRT_MAX )
00983     return; // must not split the facet
00984 
00985   if ( equalP1 != USHRT_MAX )
00986   {
00987     // get the edge to the second given point and perform a split edge operation
00988     float fMinDist = FLOAT_MAX;
00989     unsigned short iEdgeNo=USHRT_MAX;
00990     for ( unsigned short i=0; i<3; i++ )
00991     {
00992       Base::Vector3f cBase(_rclMesh._aclPointArray[rFace._aulPoints[i]]);
00993       Base::Vector3f cEnd (_rclMesh._aclPointArray[rFace._aulPoints[(i+1)%3]]);
00994       Base::Vector3f cDir = cEnd - cBase;
00995 
00996       float fDist = rP2.DistanceToLine(cBase, cDir);
00997       if ( fMinDist < fDist )
00998       {
00999         fMinDist = fDist;
01000         iEdgeNo = i;
01001       }
01002     }
01003     if ( fMinDist < 0.05f )
01004     {
01005       if ( rFace._aulNeighbours[iEdgeNo] != ULONG_MAX )
01006         SplitEdge(ulFacetPos, rFace._aulNeighbours[iEdgeNo], rP2);
01007       else
01008         SplitOpenEdge(ulFacetPos, iEdgeNo, rP2);
01009     }
01010   }
01011   else if ( equalP2 != USHRT_MAX )
01012   {
01013     // get the edge to the first given point and perform a split edge operation
01014     float fMinDist = FLOAT_MAX;
01015     unsigned short iEdgeNo=USHRT_MAX;
01016     for ( unsigned short i=0; i<3; i++ )
01017     {
01018       Base::Vector3f cBase(_rclMesh._aclPointArray[rFace._aulPoints[i]]);
01019       Base::Vector3f cEnd (_rclMesh._aclPointArray[rFace._aulPoints[(i+1)%3]]);
01020       Base::Vector3f cDir = cEnd - cBase;
01021 
01022       float fDist = rP1.DistanceToLine(cBase, cDir);
01023       if ( fMinDist < fDist )
01024       {
01025         fMinDist = fDist;
01026         iEdgeNo = i;
01027       }
01028     }
01029     if ( fMinDist < 0.05f )
01030     {
01031       if ( rFace._aulNeighbours[iEdgeNo] != ULONG_MAX )
01032         SplitEdge(ulFacetPos, rFace._aulNeighbours[iEdgeNo], rP1);
01033       else
01034         SplitOpenEdge(ulFacetPos, iEdgeNo, rP1);
01035     }
01036   }
01037   else
01038   {
01039     // search for the matching edges
01040     unsigned short iEdgeNo1=USHRT_MAX, iEdgeNo2=USHRT_MAX;
01041     float fMinDist1 = FLOAT_MAX, fMinDist2 = FLOAT_MAX;
01042     const MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
01043     for ( unsigned short i=0; i<3; i++ )
01044     {
01045       Base::Vector3f cBase(_rclMesh._aclPointArray[rFace._aulPoints[i]]);
01046       Base::Vector3f cEnd (_rclMesh._aclPointArray[rFace._aulPoints[(i+1)%3]]);
01047       Base::Vector3f cDir = cEnd - cBase;
01048 
01049       float fDist = rP1.DistanceToLine(cBase, cDir);
01050       if ( fMinDist1 < fDist )
01051       {
01052         fMinDist1 = fDist;
01053         iEdgeNo1 = i;
01054       }
01055       fDist = rP2.DistanceToLine(cBase, cDir);
01056       if ( fMinDist2 < fDist )
01057       {
01058         fMinDist2 = fDist;
01059         iEdgeNo2 = i;
01060       }
01061     }
01062 
01063     if ( iEdgeNo1 == iEdgeNo2 || fMinDist1 >= 0.05f || fMinDist2 >= 0.05f ) 
01064       return; // no valid configuration
01065 
01066     // make first point lying on the previous edge
01067     Base::Vector3f cP1 = rP1;
01068     Base::Vector3f cP2 = rP2;
01069     if ( (iEdgeNo2+1)%3 == iEdgeNo1 )
01070     {
01071       unsigned short tmp = iEdgeNo1;
01072       iEdgeNo1 = iEdgeNo2;
01073       iEdgeNo2 = tmp;
01074       cP1 = rP2;
01075       cP2 = rP1;
01076     }
01077 
01078     // split up the facet now
01079     if ( rFace._aulNeighbours[iEdgeNo1] != ULONG_MAX )
01080       SplitNeighbourFacet(ulFacetPos, iEdgeNo1, cP1);
01081     if ( rFace._aulNeighbours[iEdgeNo2] != ULONG_MAX )
01082       SplitNeighbourFacet(ulFacetPos, iEdgeNo2, cP1);
01083   }
01084 }
01085 
01086 void MeshTopoAlgorithm::SplitNeighbourFacet(unsigned long ulFacetPos, unsigned short uFSide, const Base::Vector3f rPoint)
01087 {
01088   MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
01089 
01090   unsigned long ulNeighbour = rclF._aulNeighbours[uFSide];
01091   MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
01092 
01093   unsigned short uNSide = rclN.Side(rclF);
01094 
01095   //unsigned long uPtCnt = _rclMesh._aclPointArray.size();
01096   unsigned long uPtInd = this->GetOrAddIndex(rPoint);
01097   unsigned long ulSize = _rclMesh._aclFacetArray.size();
01098 
01099   // adjust the neighbourhood
01100   if (rclN._aulNeighbours[(uNSide+1)%3] != ULONG_MAX)
01101     _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide+1)%3]].ReplaceNeighbour(ulNeighbour, ulSize);
01102 
01103   MeshFacet cNew;
01104   cNew._aulPoints[0] = uPtInd;
01105   cNew._aulPoints[1] = rclN._aulPoints[(uNSide+1)%3];
01106   cNew._aulPoints[2] = rclN._aulPoints[(uNSide+2)%3];
01107   cNew._aulNeighbours[0] = ulFacetPos;
01108   cNew._aulNeighbours[1] = rclN._aulNeighbours[(uNSide+1)%3];
01109   cNew._aulNeighbours[2] = ulNeighbour;
01110 
01111   // adjust the facet
01112   rclN._aulPoints[(uNSide+1)%3] = uPtInd;
01113   rclN._aulNeighbours[(uNSide+1)%3] = ulSize;
01114 
01115   // insert new facet
01116   _rclMesh._aclFacetArray.push_back(cNew);
01117 }
01118 
01119 #if 0
01120   // create 3 new facets
01121   MeshGeomFacet clFacet;
01122 
01123   // facet [P1, Ei+1, P2]
01124   clFacet._aclPoints[0] = cP1;
01125   clFacet._aclPoints[1] = _rclMesh._aclPointArray[rFace._aulPoints[(iEdgeNo1+1)%3]];
01126   clFacet._aclPoints[2] = cP2;
01127   clFacet.CalcNormal();
01128   _aclNewFacets.push_back(clFacet);
01129   // facet [P2, Ei+2, Ei]
01130   clFacet._aclPoints[0] = cP2;
01131   clFacet._aclPoints[1] = _rclMesh._aclPointArray[rFace._aulPoints[(iEdgeNo1+2)%3]];
01132   clFacet._aclPoints[2] = _rclMesh._aclPointArray[rFace._aulPoints[iEdgeNo1]];
01133   clFacet.CalcNormal();
01134   _aclNewFacets.push_back(clFacet);
01135   // facet [P2, Ei, P1]
01136   clFacet._aclPoints[0] = cP2;
01137   clFacet._aclPoints[1] = _rclMesh._aclPointArray[rFace._aulPoints[iEdgeNo1]];
01138   clFacet._aclPoints[2] = cP1;
01139   clFacet.CalcNormal();
01140   _aclNewFacets.push_back(clFacet);
01141 #endif
01142 
01143 void MeshTopoAlgorithm::RemoveDegeneratedFacet(unsigned long index)
01144 {
01145   if (index >= _rclMesh._aclFacetArray.size()) return;
01146   MeshFacet& rFace = _rclMesh._aclFacetArray[index];
01147 
01148   // coincident corners (either topological or geometrical)
01149   for (int i=0; i<3; i++) {
01150     const MeshPoint& rE0 = _rclMesh._aclPointArray[rFace._aulPoints[i]];
01151     const MeshPoint& rE1 = _rclMesh._aclPointArray[rFace._aulPoints[(i+1)%3]];
01152     if (rE0 == rE1) {
01153       unsigned long uN1 = rFace._aulNeighbours[(i+1)%3];
01154       unsigned long uN2 = rFace._aulNeighbours[(i+2)%3];
01155       if (uN2 != ULONG_MAX)
01156         _rclMesh._aclFacetArray[uN2].ReplaceNeighbour(index, uN1);
01157       if (uN1 != ULONG_MAX)
01158         _rclMesh._aclFacetArray[uN1].ReplaceNeighbour(index, uN2);
01159 
01160       // isolate the face and remove it
01161       rFace._aulNeighbours[0] = ULONG_MAX;
01162       rFace._aulNeighbours[1] = ULONG_MAX;
01163       rFace._aulNeighbours[2] = ULONG_MAX;
01164       _rclMesh.DeleteFacet(index);
01165       return;
01166     }
01167   }
01168 
01169   // We have a facet of the form
01170   // P0 +----+------+P2
01171   //         P1
01172   for (int j=0; j<3; j++) {
01173     Base::Vector3f cVec1 = _rclMesh._aclPointArray[rFace._aulPoints[(j+1)%3]] - _rclMesh._aclPointArray[rFace._aulPoints[j]];
01174     Base::Vector3f cVec2 = _rclMesh._aclPointArray[rFace._aulPoints[(j+2)%3]] - _rclMesh._aclPointArray[rFace._aulPoints[j]];
01175 
01176     // adjust the neighbourhoods and point indices
01177     if (cVec1 * cVec2 < 0.0f) {
01178       unsigned long uN1 = rFace._aulNeighbours[(j+1)%3];
01179       if (uN1 != ULONG_MAX) {
01180         // get the neighbour and common edge side
01181         MeshFacet& rNb = _rclMesh._aclFacetArray[uN1];
01182         unsigned short side = rNb.Side(index);
01183 
01184         // bend the point indices
01185         rFace._aulPoints[(j+2)%3] = rNb._aulPoints[(side+2)%3];
01186         rNb._aulPoints[(side+1)%3] = rFace._aulPoints[j];
01187 
01188         // set correct neighbourhood
01189         unsigned long uN2 = rFace._aulNeighbours[(j+2)%3];
01190         rNb._aulNeighbours[side] = uN2;
01191         if (uN2 != ULONG_MAX) {
01192           _rclMesh._aclFacetArray[uN2].ReplaceNeighbour(index, uN1);
01193         }
01194         unsigned long uN3 = rNb._aulNeighbours[(side+1)%3];
01195         rFace._aulNeighbours[(j+1)%3] = uN3;
01196         if (uN3 != ULONG_MAX) {
01197           _rclMesh._aclFacetArray[uN3].ReplaceNeighbour(uN1, index);
01198         }
01199         rNb._aulNeighbours[(side+1)%3] = index;
01200         rFace._aulNeighbours[(j+2)%3] = uN1;
01201       }
01202       else
01203         _rclMesh.DeleteFacet(index);
01204 
01205       return;
01206     }
01207   }
01208 }
01209 
01210 void MeshTopoAlgorithm::RemoveCorruptedFacet(unsigned long index)
01211 {
01212   if (index >= _rclMesh._aclFacetArray.size()) return;
01213   MeshFacet& rFace = _rclMesh._aclFacetArray[index];
01214 
01215   // coincident corners (topological)
01216   for (int i=0; i<3; i++) {
01217     if (rFace._aulPoints[i] == rFace._aulPoints[(i+1)%3]) {
01218       unsigned long uN1 = rFace._aulNeighbours[(i+1)%3];
01219       unsigned long uN2 = rFace._aulNeighbours[(i+2)%3];
01220       if (uN2 != ULONG_MAX)
01221         _rclMesh._aclFacetArray[uN2].ReplaceNeighbour(index, uN1);
01222       if (uN1 != ULONG_MAX)
01223         _rclMesh._aclFacetArray[uN1].ReplaceNeighbour(index, uN2);
01224 
01225       // isolate the face and remove it
01226       rFace._aulNeighbours[0] = ULONG_MAX;
01227       rFace._aulNeighbours[1] = ULONG_MAX;
01228       rFace._aulNeighbours[2] = ULONG_MAX;
01229       _rclMesh.DeleteFacet(index);
01230       return;
01231     }
01232   }
01233 }
01234 
01235 void MeshTopoAlgorithm::FillupHoles(unsigned long length, int level,
01236                                     AbstractPolygonTriangulator& cTria,
01237                                     std::list<std::vector<unsigned long> >& aFailed)
01238 {
01239     // get the mesh boundaries as an array of point indices
01240     std::list<std::vector<unsigned long> > aBorders;
01241     MeshAlgorithm cAlgo(_rclMesh);
01242     cAlgo.GetMeshBorders(aBorders);
01243 
01244     // split boundary loops if needed
01245     cAlgo.SplitBoundaryLoops(aBorders);
01246 
01247     // get the facets to a point
01248     MeshRefPointToFacets cPt2Fac(_rclMesh);
01249 
01250     MeshFacetArray newFacets;
01251     MeshPointArray newPoints;
01252     unsigned long numberOfOldPoints = _rclMesh._aclPointArray.size();
01253     for ( std::list<std::vector<unsigned long> >::iterator it = aBorders.begin(); it != aBorders.end(); ++it ) {
01254         if ( it->size()-1 > length )
01255             continue; // boundary with too many edges
01256         MeshFacetArray cFacets;
01257         MeshPointArray cPoints;
01258         if (cAlgo.FillupHole(*it, cTria, cFacets, cPoints, level, &cPt2Fac)) {
01259             if (it->front() == it->back())
01260                 it->pop_back();
01261             // the triangulation may produce additional points which we must take into account when appending to the mesh
01262             unsigned long countBoundaryPoints = it->size();
01263             unsigned long countDifference = cPoints.size() - countBoundaryPoints;
01264             if (countDifference > 0) {
01265                 MeshPointArray::_TIterator pt = cPoints.begin() + countBoundaryPoints;
01266                 for (unsigned long i=0; i<countDifference; i++, pt++) {
01267                     it->push_back(numberOfOldPoints++);
01268                     newPoints.push_back(*pt);
01269                 }
01270             }
01271             for (MeshFacetArray::_TIterator kt = cFacets.begin(); kt != cFacets.end(); ++kt ) {
01272                 kt->_aulPoints[0] = (*it)[kt->_aulPoints[0]];
01273                 kt->_aulPoints[1] = (*it)[kt->_aulPoints[1]];
01274                 kt->_aulPoints[2] = (*it)[kt->_aulPoints[2]];
01275                 newFacets.push_back(*kt);
01276             }
01277         }
01278         else {
01279             aFailed.push_back(*it);
01280         }
01281     }
01282 
01283     // insert new points and faces into the mesh structure
01284     _rclMesh._aclPointArray.insert(_rclMesh._aclPointArray.end(), newPoints.begin(), newPoints.end());
01285     for (MeshPointArray::_TIterator it = newPoints.begin(); it != newPoints.end(); ++it)
01286         _rclMesh._clBoundBox &= *it;
01287     if (!newFacets.empty())
01288         _rclMesh.AddFacets(newFacets);
01289 }
01290 
01291 void MeshTopoAlgorithm::FillupHoles(int level, AbstractPolygonTriangulator& cTria,
01292                                     const std::list<std::vector<unsigned long> >& aBorders,
01293                                     std::list<std::vector<unsigned long> >& aFailed)
01294 {
01295     // get the facets to a point
01296     MeshRefPointToFacets cPt2Fac(_rclMesh);
01297     MeshAlgorithm cAlgo(_rclMesh);
01298 
01299     MeshFacetArray newFacets;
01300     MeshPointArray newPoints;
01301     unsigned long numberOfOldPoints = _rclMesh._aclPointArray.size();
01302     for (std::list<std::vector<unsigned long> >::const_iterator it = aBorders.begin(); it != aBorders.end(); ++it) {
01303         MeshFacetArray cFacets;
01304         MeshPointArray cPoints;
01305         std::vector<unsigned long> bound = *it;
01306         if (cAlgo.FillupHole(bound, cTria, cFacets, cPoints, level, &cPt2Fac)) {
01307             if (bound.front() == bound.back())
01308                 bound.pop_back();
01309             // the triangulation may produce additional points which we must take into account when appending to the mesh
01310             unsigned long countBoundaryPoints = bound.size();
01311             unsigned long countDifference = cPoints.size() - countBoundaryPoints;
01312             if (countDifference > 0) {
01313                 MeshPointArray::_TIterator pt = cPoints.begin() + countBoundaryPoints;
01314                 for (unsigned long i=0; i<countDifference; i++, pt++) {
01315                     bound.push_back(numberOfOldPoints++);
01316                     newPoints.push_back(*pt);
01317                 }
01318             }
01319             for (MeshFacetArray::_TIterator kt = cFacets.begin(); kt != cFacets.end(); ++kt ) {
01320                 kt->_aulPoints[0] = bound[kt->_aulPoints[0]];
01321                 kt->_aulPoints[1] = bound[kt->_aulPoints[1]];
01322                 kt->_aulPoints[2] = bound[kt->_aulPoints[2]];
01323                 newFacets.push_back(*kt);
01324             }
01325         }
01326         else {
01327             aFailed.push_back(*it);
01328         }
01329     }
01330 
01331     // insert new points and faces into the mesh structure
01332     _rclMesh._aclPointArray.insert(_rclMesh._aclPointArray.end(), newPoints.begin(), newPoints.end());
01333     for (MeshPointArray::_TIterator it = newPoints.begin(); it != newPoints.end(); ++it)
01334         _rclMesh._clBoundBox &= *it;
01335     if (!newFacets.empty())
01336         _rclMesh.AddFacets(newFacets);
01337 }
01338 
01339 void MeshTopoAlgorithm::FindHoles(unsigned long length,
01340                                   std::list<std::vector<unsigned long> >& aBorders) const
01341 {
01342     std::list<std::vector<unsigned long> > border;
01343     MeshAlgorithm cAlgo(_rclMesh);
01344     cAlgo.GetMeshBorders(border);
01345     for (std::list<std::vector<unsigned long> >::iterator it = border.begin();
01346         it != border.end(); ++it) {
01347         if (it->size() <= length) aBorders.push_back(*it);
01348     }
01349 }
01350 
01351 void MeshTopoAlgorithm::FindComponents(unsigned long count, std::vector<unsigned long>& findIndices)
01352 {
01353   std::vector<std::vector<unsigned long> > segments;
01354   MeshComponents comp(_rclMesh);
01355   comp.SearchForComponents(MeshComponents::OverEdge,segments);
01356 
01357   for (std::vector<std::vector<unsigned long> >::iterator it = segments.begin(); it != segments.end(); ++it) {
01358     if (it->size() <= (unsigned long)count)
01359       findIndices.insert(findIndices.end(), it->begin(), it->end());
01360   }
01361 }
01362 
01363 void MeshTopoAlgorithm::RemoveComponents(unsigned long count)
01364 {
01365   std::vector<unsigned long> removeFacets;
01366   FindComponents(count, removeFacets);
01367   if (!removeFacets.empty())
01368     _rclMesh.DeleteFacets(removeFacets);
01369 }
01370 
01371 void MeshTopoAlgorithm::HarmonizeNormals (void)
01372 {
01373   std::vector<unsigned long> uIndices = MeshEvalOrientation(_rclMesh).GetIndices();
01374   for ( std::vector<unsigned long>::iterator it = uIndices.begin(); it != uIndices.end(); ++it )
01375     _rclMesh._aclFacetArray[*it].FlipNormal();
01376 }
01377 
01378 void MeshTopoAlgorithm::FlipNormals (void)
01379 {
01380   for (MeshFacetArray::_TIterator i = _rclMesh._aclFacetArray.begin(); i < _rclMesh._aclFacetArray.end(); i++)
01381     i->FlipNormal();
01382 }
01383 
01384 // ---------------------------------------------------------------------------
01385 
01407 MeshComponents::MeshComponents( const MeshKernel& rclMesh )
01408 : _rclMesh(rclMesh)
01409 {
01410 }
01411 
01412 MeshComponents::~MeshComponents()
01413 {
01414 }
01415 
01416 void MeshComponents::SearchForComponents(TMode tMode, std::vector<std::vector<unsigned long> >& aclT) const
01417 {
01418   // all facets
01419   std::vector<unsigned long> aulAllFacets(_rclMesh.CountFacets());
01420   unsigned long k = 0;
01421   for (std::vector<unsigned long>::iterator pI = aulAllFacets.begin(); pI != aulAllFacets.end(); pI++)
01422     *pI = k++;
01423 
01424   SearchForComponents( tMode, aulAllFacets, aclT );
01425 }
01426 
01427 void MeshComponents::SearchForComponents(TMode tMode, const std::vector<unsigned long>& aSegment, std::vector<std::vector<unsigned long> >& aclT) const
01428 {
01429   unsigned long ulStartFacet, ulVisited;
01430 
01431   if (_rclMesh.CountFacets() == 0)
01432     return;
01433 
01434   // reset VISIT flags
01435   MeshAlgorithm cAlgo(_rclMesh);
01436   cAlgo.SetFacetFlag(MeshFacet::VISIT);
01437   cAlgo.ResetFacetsFlag(aSegment, MeshFacet::VISIT);
01438   
01439   const MeshFacetArray& rFAry = _rclMesh.GetFacets();
01440   MeshFacetArray::_TConstIterator iTri = rFAry.begin();
01441   MeshFacetArray::_TConstIterator iBeg = rFAry.begin();
01442   MeshFacetArray::_TConstIterator iEnd = rFAry.end();
01443 
01444   // start from the first not visited facet
01445   ulVisited = cAlgo.CountFacetFlag(MeshFacet::VISIT);
01446   iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshIsNotFlag<MeshFacet>(), MeshFacet::VISIT));
01447   ulStartFacet = iTri - iBeg;
01448 
01449   // visitor
01450   std::vector<unsigned long> aclComponent;
01451   std::vector<std::vector<unsigned long> > aclConnectComp;
01452   MeshTopFacetVisitor clFVisitor( aclComponent );
01453 
01454   while ( ulStartFacet !=  ULONG_MAX )
01455   {
01456     // collect all facets of a component
01457     aclComponent.clear();
01458     if (tMode == OverEdge)
01459       ulVisited += _rclMesh.VisitNeighbourFacets(clFVisitor, ulStartFacet);
01460     else if (tMode == OverPoint)
01461       ulVisited += _rclMesh.VisitNeighbourFacetsOverCorners(clFVisitor, ulStartFacet);
01462 
01463     // get also start facet
01464     aclComponent.push_back(ulStartFacet);
01465     aclConnectComp.push_back(aclComponent);
01466 
01467     // if the mesh consists of several topologic independent components
01468     // We can search from position 'iTri' on because all elements _before_ are already visited
01469     // what we know from the previous iteration.
01470     iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshIsNotFlag<MeshFacet>(), MeshFacet::VISIT));
01471 
01472     if (iTri < iEnd)
01473       ulStartFacet = iTri - iBeg;
01474     else
01475       ulStartFacet = ULONG_MAX;
01476   }
01477 
01478   // sort components by size (descending order)
01479   std::sort(aclConnectComp.begin(), aclConnectComp.end(), CNofFacetsCompare());  
01480   aclT = aclConnectComp;
01481 }

Generated on Wed Nov 23 19:00:46 2011 for FreeCAD by  doxygen 1.6.1