Evaluation.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 <vector>
00029 #endif
00030 
00031 #include <Mod/Mesh/App/WildMagic4/Wm4Matrix3.h>
00032 #include <Mod/Mesh/App/WildMagic4/Wm4Vector3.h>
00033 
00034 #include "Evaluation.h"
00035 #include "Iterator.h"
00036 #include "Algorithm.h"
00037 #include "Approximation.h"
00038 #include "MeshIO.h"
00039 #include "Helpers.h"
00040 #include "Grid.h"
00041 #include "TopoAlgorithm.h"
00042 #include <Base/Matrix.h>
00043 
00044 #include <Base/Sequencer.h>
00045 
00046 using namespace MeshCore;
00047 
00048 
00049 MeshOrientationVisitor::MeshOrientationVisitor() : _nonuniformOrientation(false)
00050 {
00051 }
00052 
00053 bool MeshOrientationVisitor::Visit (const MeshFacet &rclFacet, const MeshFacet &rclFrom, 
00054                                     unsigned long ulFInd, unsigned long ulLevel)
00055 {
00056     if (!rclFrom.HasSameOrientation(rclFacet)) {
00057         _nonuniformOrientation = true;
00058         return false;
00059     }
00060 
00061     return true;
00062 }
00063 
00064 bool MeshOrientationVisitor::HasNonUnifomOrientedFacets() const
00065 {
00066     return _nonuniformOrientation;
00067 }
00068 
00069 MeshOrientationCollector::MeshOrientationCollector(std::vector<unsigned long>& aulIndices, std::vector<unsigned long>& aulComplement)
00070  : _aulIndices(aulIndices), _aulComplement(aulComplement)
00071 {
00072 }
00073 
00074 bool MeshOrientationCollector::Visit (const MeshFacet &rclFacet, const MeshFacet &rclFrom, 
00075                                       unsigned long ulFInd, unsigned long ulLevel)
00076 {
00077     // different orientation of rclFacet and rclFrom
00078     if (!rclFacet.HasSameOrientation(rclFrom)) {
00079         // is not marked as false oriented
00080         if (!rclFrom.IsFlag(MeshFacet::TMP0)) {
00081             // mark this facet as false oriented
00082             rclFacet.SetFlag(MeshFacet::TMP0);
00083             _aulIndices.push_back( ulFInd );
00084         }
00085         else
00086             _aulComplement.push_back( ulFInd );
00087     }
00088     else {
00089         // same orientation but if the neighbour rclFrom is false oriented
00090         // then rclFrom is also false oriented
00091         if (rclFrom.IsFlag(MeshFacet::TMP0)) {
00092             // mark this facet as false oriented
00093             rclFacet.SetFlag(MeshFacet::TMP0);
00094             _aulIndices.push_back(ulFInd);
00095         }
00096         else
00097             _aulComplement.push_back( ulFInd );
00098     }
00099 
00100     return true;
00101 }
00102 
00103 MeshSameOrientationCollector::MeshSameOrientationCollector(std::vector<unsigned long>& aulIndices)
00104   : _aulIndices(aulIndices)
00105 {
00106 }
00107 
00108 bool MeshSameOrientationCollector::Visit (const MeshFacet &rclFacet, const MeshFacet &rclFrom, 
00109                                           unsigned long ulFInd, unsigned long ulLevel)
00110 {
00111     // different orientation of rclFacet and rclFrom
00112     if (rclFacet.HasSameOrientation(rclFrom)) {
00113         _aulIndices.push_back(ulFInd);
00114     }
00115 
00116     return true;
00117 }
00118 
00119 // ----------------------------------------------------
00120 
00121 MeshEvalOrientation::MeshEvalOrientation (const MeshKernel& rclM)
00122   : MeshEvaluation( rclM )
00123 {
00124 }
00125 
00126 MeshEvalOrientation::~MeshEvalOrientation()
00127 {
00128 }
00129 
00130 bool MeshEvalOrientation::Evaluate ()
00131 {
00132     const MeshFacetArray& rFAry = _rclMesh.GetFacets();
00133     MeshFacetArray::_TConstIterator iBeg = rFAry.begin();
00134     MeshFacetArray::_TConstIterator iEnd = rFAry.end();
00135     for (MeshFacetArray::_TConstIterator it = iBeg; it != iEnd; ++it) {
00136         for (int i = 0; i < 3; i++) {
00137             if (it->_aulNeighbours[i] != ULONG_MAX) {
00138                 const MeshFacet& rclFacet = iBeg[it->_aulNeighbours[i]];
00139                 for (int j = 0; j < 3; j++) {
00140                     if (it->_aulPoints[i] == rclFacet._aulPoints[j]) {
00141                         if ((it->_aulPoints[(i+1)%3] == rclFacet._aulPoints[(j+1)%3]) ||
00142                             (it->_aulPoints[(i+2)%3] == rclFacet._aulPoints[(j+2)%3])) {
00143                             return false; // adjacent face with wrong orientation
00144                         } 
00145                     }
00146                 }
00147             }
00148         }
00149     }
00150 
00151     return true;
00152 }
00153 
00154 unsigned long MeshEvalOrientation::HasFalsePositives(const std::vector<unsigned long>& inds) const
00155 {
00156     // All faces with wrong orientation (i.e. adjacent faces with a normal flip and their neighbours)
00157     // build a segment and are marked as TMP0. Now we check all border faces of the segments with 
00158     // their correct neighbours if there was really a normal flip. If there is no normal flip we have
00159     // a false positive.
00160     // False-positives can occur if the mesh structure has some defects which let the region-grow
00161     // algorithm fail to detect the faces with wrong orientation.
00162     const MeshFacetArray& rFAry = _rclMesh.GetFacets();
00163     MeshFacetArray::_TConstIterator iBeg = rFAry.begin();
00164     for (std::vector<unsigned long>::const_iterator it = inds.begin(); it != inds.end(); ++it) {
00165         const MeshFacet& f = iBeg[*it];
00166         for (int i = 0; i < 3; i++) {
00167             if (f._aulNeighbours[i] != ULONG_MAX) {
00168                 const MeshFacet& n = iBeg[f._aulNeighbours[i]];
00169                 if (f.IsFlag(MeshFacet::TMP0) && !n.IsFlag(MeshFacet::TMP0)) {
00170                     for (int j = 0; j < 3; j++) {
00171                         if (f.HasSameOrientation(n)) {
00172                             // adjacent face with same orientation => false positive
00173                             return f._aulNeighbours[i];
00174                         }
00175                     }
00176                 }
00177             }
00178         }
00179     }
00180 
00181     return ULONG_MAX;
00182 }
00183 
00184 std::vector<unsigned long> MeshEvalOrientation::GetIndices() const
00185 {
00186     unsigned long ulStartFacet, ulVisited;
00187 
00188     if (_rclMesh.CountFacets() == 0)
00189         return std::vector<unsigned long>();
00190 
00191     // reset VISIT flags
00192     MeshAlgorithm cAlg(_rclMesh);
00193     cAlg.ResetFacetFlag(MeshFacet::VISIT);
00194     cAlg.ResetFacetFlag(MeshFacet::TMP0);
00195 
00196     const MeshFacetArray& rFAry = _rclMesh.GetFacets();
00197     MeshFacetArray::_TConstIterator iTri = rFAry.begin();
00198     MeshFacetArray::_TConstIterator iBeg = rFAry.begin();
00199     MeshFacetArray::_TConstIterator iEnd = rFAry.end();
00200 
00201     ulVisited = 0;
00202     ulStartFacet = 0;
00203 
00204     std::vector<unsigned long> uIndices, uComplement;
00205     MeshOrientationCollector clHarmonizer(uIndices, uComplement);
00206 
00207     while (ulStartFacet !=  ULONG_MAX) {
00208         unsigned long wrongFacets = uIndices.size();
00209 
00210         uComplement.clear();
00211         uComplement.push_back( ulStartFacet );
00212         ulVisited = _rclMesh.VisitNeighbourFacets(clHarmonizer, ulStartFacet) + 1;
00213 
00214         // In the currently visited component we have found less than 40% as correct
00215         // oriented and the rest as false oriented. So, we decide that it should be the other
00216         // way round and swap the indices of this component.
00217         if (uComplement.size() < (unsigned long)(0.4f*(float)ulVisited)) {
00218             uIndices.erase(uIndices.begin()+wrongFacets, uIndices.end());
00219             uIndices.insert(uIndices.end(), uComplement.begin(), uComplement.end());
00220         }
00221 
00222         // if the mesh consists of several topologic independent components
00223         // We can search from position 'iTri' on because all elements _before_ are already visited
00224         // what we know from the previous iteration.
00225         iTri = std::find_if(iTri, iEnd, std::bind2nd(MeshIsNotFlag<MeshFacet>(), MeshFacet::VISIT));
00226 
00227         if (iTri < iEnd)
00228             ulStartFacet = iTri - iBeg;
00229         else
00230             ulStartFacet = ULONG_MAX;
00231     }
00232 
00233     // in some very rare cases where we have some strange artefacts in the mesh structure
00234     // we get false-positives. If we find some we check all 'invalid' faces again
00235     cAlg.ResetFacetFlag(MeshFacet::TMP0);
00236     cAlg.SetFacetsFlag(uIndices, MeshFacet::TMP0);
00237     ulStartFacet = HasFalsePositives(uIndices);
00238     while (ulStartFacet != ULONG_MAX) {
00239         cAlg.ResetFacetsFlag(uIndices, MeshFacet::VISIT);
00240         std::vector<unsigned long> falsePos;
00241         MeshSameOrientationCollector coll(falsePos);
00242         _rclMesh.VisitNeighbourFacets(coll, ulStartFacet);
00243 
00244         std::sort(uIndices.begin(), uIndices.end());
00245         std::sort(falsePos.begin(), falsePos.end());
00246 
00247         std::vector<unsigned long> diff;
00248         std::back_insert_iterator<std::vector<unsigned long> > biit(diff);
00249         std::set_difference(uIndices.begin(), uIndices.end(), falsePos.begin(), falsePos.end(), biit);
00250         uIndices = diff;
00251 
00252         cAlg.ResetFacetFlag(MeshFacet::TMP0);
00253         cAlg.SetFacetsFlag(uIndices, MeshFacet::TMP0);
00254         unsigned long current = ulStartFacet;
00255         ulStartFacet = HasFalsePositives(uIndices);
00256         if (current == ulStartFacet)
00257             break; // avoid an endless loop
00258     }
00259 
00260     return uIndices;
00261 }
00262 
00263 MeshFixOrientation::MeshFixOrientation (MeshKernel& rclM)
00264   : MeshValidation( rclM )
00265 {
00266 }
00267 
00268 MeshFixOrientation::~MeshFixOrientation()
00269 {
00270 }
00271 
00272 bool MeshFixOrientation::Fixup ()
00273 {
00274     MeshTopoAlgorithm(_rclMesh).HarmonizeNormals();
00275     return MeshEvalOrientation(_rclMesh).Evaluate();
00276 }
00277 
00278 // ----------------------------------------------------
00279 
00280 MeshEvalSolid::MeshEvalSolid (const MeshKernel& rclM)
00281   :MeshEvaluation( rclM )
00282 {
00283 }
00284 
00285 MeshEvalSolid::~MeshEvalSolid()
00286 {
00287 }
00288 
00289 bool MeshEvalSolid::Evaluate ()
00290 {
00291   std::vector<MeshGeomEdge> edges;
00292   _rclMesh.GetEdges( edges );
00293   for (std::vector<MeshGeomEdge>::iterator it = edges.begin(); it != edges.end(); it++)
00294   {
00295     if (it->_bBorder)
00296       return false;
00297   }
00298 
00299   return true;
00300 }
00301 
00302 // ----------------------------------------------------
00303 
00304 namespace MeshCore {
00305 
00306 struct Edge_Index
00307 {
00308     unsigned long p0, p1, f;
00309 };
00310 
00311 struct Edge_Less  : public std::binary_function<const Edge_Index&, 
00312                                                 const Edge_Index&, bool>
00313 {
00314     bool operator()(const Edge_Index& x, const Edge_Index& y) const
00315     {
00316         if (x.p0 < y.p0)
00317             return true;
00318         else if (x.p0 > y.p0)
00319             return false;
00320         else if (x.p1 < y.p1)
00321             return true;
00322         else if (x.p1 > y.p1)
00323             return false;
00324         return false;
00325     }
00326 };
00327 
00328 }
00329 
00330 bool MeshEvalTopology::Evaluate ()
00331 {
00332     // Using and sorting a vector seems to be faster and more memory-efficient
00333     // than a map.
00334     const MeshFacetArray& rclFAry = _rclMesh.GetFacets();
00335     std::vector<Edge_Index> edges;
00336     edges.reserve(3*rclFAry.size());
00337 
00338     // build up an array of edges
00339     MeshFacetArray::_TConstIterator pI;
00340     Base::SequencerLauncher seq("Checking topology...", rclFAry.size());
00341     for (pI = rclFAry.begin(); pI != rclFAry.end(); pI++) {
00342         for (int i = 0; i < 3; i++) {
00343             Edge_Index item;
00344             item.p0 = std::min<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00345             item.p1 = std::max<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00346             item.f  = pI - rclFAry.begin();
00347             edges.push_back(item);
00348         }
00349 
00350         seq.next();
00351     }
00352 
00353     // sort the edges
00354     std::sort(edges.begin(), edges.end(), Edge_Less());
00355 
00356     // search for non-manifold edges
00357     unsigned long p0 = ULONG_MAX, p1 = ULONG_MAX;
00358     nonManifoldList.clear();
00359     nonManifoldFacets.clear();
00360 
00361     int count = 0;
00362     std::vector<unsigned long> facets;
00363     std::vector<Edge_Index>::iterator pE;
00364     for (pE = edges.begin(); pE != edges.end(); pE++) {
00365         if (p0 == pE->p0 && p1 == pE->p1) {
00366             count++;
00367             facets.push_back(pE->f);
00368         }
00369         else {
00370             if (count > 2) {
00371                 // Edge that is shared by more than 2 facets
00372                 nonManifoldList.push_back(std::make_pair
00373                     <unsigned long, unsigned long>(p0, p1));
00374                 nonManifoldFacets.push_back(facets);
00375             }
00376 
00377             p0 = pE->p0;
00378             p1 = pE->p1;
00379             facets.clear();
00380             facets.push_back(pE->f);
00381             count = 1;
00382         }
00383     }
00384 
00385     return nonManifoldList.empty();
00386 }
00387 
00388 // generate indexed edge list which tangents non-manifolds
00389 void MeshEvalTopology::GetFacetManifolds (std::vector<unsigned long> &raclFacetIndList) const
00390 {
00391     raclFacetIndList.clear();
00392     const MeshFacetArray& rclFAry = _rclMesh.GetFacets();
00393     MeshFacetArray::_TConstIterator pI;
00394 
00395     for (pI = rclFAry.begin(); pI != rclFAry.end(); pI++) {
00396         for (int i = 0; i < 3; i++) {
00397             unsigned long ulPt0 = std::min<unsigned long>(pI->_aulPoints[i],  pI->_aulPoints[(i+1)%3]);
00398             unsigned long ulPt1 = std::max<unsigned long>(pI->_aulPoints[i],  pI->_aulPoints[(i+1)%3]);
00399             std::pair<unsigned long, unsigned long> edge = std::make_pair<unsigned long, unsigned long>(ulPt0, ulPt1);
00400 
00401             if (std::find(nonManifoldList.begin(), nonManifoldList.end(), edge) != nonManifoldList.end())
00402                 raclFacetIndList.push_back(pI - rclFAry.begin());
00403         }
00404     }
00405 }
00406 
00407 unsigned long MeshEvalTopology::CountManifolds() const
00408 {
00409     return nonManifoldList.size();
00410 }
00411 
00412 bool MeshFixTopology::Fixup ()
00413 {
00414     std::vector<unsigned long> indices;
00415 #if 0
00416     MeshEvalTopology eval(_rclMesh);
00417     if (!eval.Evaluate()) {
00418         eval.GetFacetManifolds(indices);
00419 
00420         // remove duplicates
00421         std::sort(indices.begin(), indices.end());
00422         indices.erase(std::unique(indices.begin(), indices.end()), indices.end());
00423 
00424         _rclMesh.DeleteFacets(indices);
00425     }
00426 #else
00427     const MeshFacetArray& rFaces = _rclMesh.GetFacets();
00428     indices.reserve(3 * nonManifoldList.size()); // allocate some memory
00429     std::list<std::vector<unsigned long> >::const_iterator it;
00430     for (it = nonManifoldList.begin(); it != nonManifoldList.end(); ++it) {
00431         std::vector<unsigned long> non_mf;
00432         non_mf.reserve(it->size());
00433         for (std::vector<unsigned long>::const_iterator jt = it->begin(); jt != it->end(); ++jt) {
00434             // fscet is only connected with one edge and there causes a non-manifold
00435             unsigned short numOpenEdges = rFaces[*jt].CountOpenEdges();
00436             if (numOpenEdges == 2)
00437                 non_mf.push_back(*jt);
00438             else if (rFaces[*jt].IsDegenerated())
00439                 non_mf.push_back(*jt);
00440         }
00441 
00442         // are we able to repair the non-manifold edge by not removing all facets?
00443         if (it->size() - non_mf.size() == 2)
00444             indices.insert(indices.end(), non_mf.begin(), non_mf.end());
00445         else
00446             indices.insert(indices.end(), it->begin(), it->end());
00447     }
00448 
00449     if (!indices.empty()) {
00450         // remove duplicates
00451         std::sort(indices.begin(), indices.end());
00452         indices.erase(std::unique(indices.begin(), indices.end()), indices.end());
00453 
00454         _rclMesh.DeleteFacets(indices);
00455         _rclMesh.RebuildNeighbours();
00456     }
00457 #endif
00458 
00459     return true;
00460 }
00461 
00462 // ---------------------------------------------------------
00463 
00464 bool MeshEvalSingleFacet::Evaluate ()
00465 {
00466   // get all non-manifolds
00467   MeshEvalTopology::Evaluate();
00468 /*
00469   // for each (multiple) single linked facet there should
00470   // exist two valid facets sharing the same edge 
00471   // so make facet 1 neighbour of facet 2 and vice versa
00472   const std::vector<MeshFacet>& rclFAry = _rclMesh.GetFacets();
00473   std::vector<MeshFacet>::const_iterator pI;
00474 
00475   std::vector<std::list<unsigned long> > aclMf = _aclManifoldList;
00476   _aclManifoldList.clear();
00477 
00478   std::map<std::pair<unsigned long, unsigned long>, std::list<unsigned long> > aclHits;
00479   std::map<std::pair<unsigned long, unsigned long>, std::list<unsigned long> >::iterator pEdge;
00480 
00481   // search for single links (a non-manifold edge and two open edges)
00482   //
00483   //
00484   // build edge <=> facet map
00485   for (pI = rclFAry.begin(); pI != rclFAry.end(); pI++)
00486   {
00487     for (int i = 0; i < 3; i++)
00488     {
00489       unsigned long ulPt0 = std::min<unsigned long>(pI->_aulPoints[i],  pI->_aulPoints[(i+1)%3]);
00490       unsigned long ulPt1 = std::max<unsigned long>(pI->_aulPoints[i],  pI->_aulPoints[(i+1)%3]);
00491       aclHits[std::pair<unsigned long, unsigned long>(ulPt0, ulPt1)].push_front(pI - rclFAry.begin());
00492     }
00493   }
00494 
00495   // now search for single links
00496   for (std::vector<std::list<unsigned long> >::const_iterator pMF = aclMf.begin(); pMF != aclMf.end(); pMF++)
00497   {
00498     std::list<unsigned long> aulManifolds;
00499     for (std::list<unsigned long>::const_iterator pF = pMF->begin(); pF != pMF->end(); ++pF)
00500     {
00501       const MeshFacet& rclF = rclFAry[*pF];
00502 
00503       unsigned long ulCtNeighbours=0;
00504       for (int i = 0; i < 3; i++)
00505       {
00506         unsigned long ulPt0 = std::min<unsigned long>(rclF._aulPoints[i],  rclF._aulPoints[(i+1)%3]);
00507         unsigned long ulPt1 = std::max<unsigned long>(rclF._aulPoints[i],  rclF._aulPoints[(i+1)%3]);
00508         std::pair<unsigned long, unsigned long> clEdge(ulPt0, ulPt1); 
00509 
00510         // number of facets sharing this edge
00511         ulCtNeighbours += aclHits[clEdge].size();
00512       }
00513 
00514       // single linked found
00515       if (ulCtNeighbours == pMF->size() + 2)
00516         aulManifolds.push_front(*pF);
00517     }
00518 
00519     if ( aulManifolds.size() > 0 )
00520       _aclManifoldList.push_back(aulManifolds);
00521   }
00522 */
00523   return (nonManifoldList.size() == 0);
00524 }
00525 
00526 bool MeshFixSingleFacet::Fixup ()
00527 {
00528   std::vector<unsigned long> aulInvalids;
00529 //  MeshFacetArray& raFacets = _rclMesh._aclFacetArray;
00530   for ( std::vector<std::list<unsigned long> >::const_iterator it=_raclManifoldList.begin();it!=_raclManifoldList.end();++it )
00531   {
00532     for ( std::list<unsigned long>::const_iterator it2 = it->begin(); it2 != it->end(); ++it2 )
00533     {
00534       aulInvalids.push_back(*it2);
00535 //      MeshFacet& rF = raFacets[*it2];
00536     }
00537   }
00538   
00539   _rclMesh.DeleteFacets(aulInvalids);
00540   return true;
00541 }
00542 
00543 // ----------------------------------------------------------------
00544 
00545 bool MeshEvalSelfIntersection::Evaluate ()
00546 {
00547     // Contains bounding boxes for every facet 
00548     std::vector<Base::BoundBox3f> boxes;
00549 
00550     // Splits the mesh using grid for speeding up the calculation
00551     MeshFacetGrid cMeshFacetGrid(_rclMesh);
00552     const MeshFacetArray& rFaces = _rclMesh.GetFacets();
00553     MeshGridIterator clGridIter(cMeshFacetGrid);
00554     unsigned long ulGridX, ulGridY, ulGridZ;
00555     cMeshFacetGrid.GetCtGrids(ulGridX, ulGridY, ulGridZ);
00556 
00557     MeshFacetIterator cMFI(_rclMesh);
00558     for (cMFI.Begin(); cMFI.More(); cMFI.Next()) {
00559         boxes.push_back((*cMFI).GetBoundBox());
00560     }
00561 
00562     // Calculates the intersections
00563     Base::SequencerLauncher seq("Checking for self-intersections...", ulGridX*ulGridY*ulGridZ);
00564     for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) {
00565         //Get the facet indices, belonging to the current grid unit
00566         std::vector<unsigned long> aulGridElements;
00567         clGridIter.GetElements(aulGridElements);
00568 
00569         seq.next();
00570         if (aulGridElements.size()==0)
00571             continue;
00572 
00573         MeshGeomFacet facet1, facet2;
00574         Base::Vector3f pt1, pt2;
00575         for (std::vector<unsigned long>::iterator it = aulGridElements.begin(); it != aulGridElements.end(); ++it) {
00576             const Base::BoundBox3f& box1 = boxes[*it];
00577             cMFI.Set(*it);
00578             facet1 = *cMFI;
00579             const MeshFacet& rface1 = rFaces[*it];
00580             for (std::vector<unsigned long>::iterator jt = it; jt != aulGridElements.end(); ++jt) {
00581                 if (jt == it) // the identical facet
00582                     continue;
00583                 // If the facets share a common vertex we do not check for self-intersections because they 
00584                 // could but usually do not intersect each other and the algorithm below would detect false-positives,
00585                 // otherwise
00586                 const MeshFacet& rface2 = rFaces[*jt];
00587                 if (rface1._aulPoints[0] == rface2._aulPoints[0] || 
00588                     rface1._aulPoints[0] == rface2._aulPoints[1] ||
00589                     rface1._aulPoints[0] == rface2._aulPoints[2])
00590                     continue; // ignore facets sharing a common vertex
00591                 if (rface1._aulPoints[1] == rface2._aulPoints[0] || 
00592                     rface1._aulPoints[1] == rface2._aulPoints[1] ||
00593                     rface1._aulPoints[1] == rface2._aulPoints[2])
00594                     continue; // ignore facets sharing a common vertex
00595                 if (rface1._aulPoints[2] == rface2._aulPoints[0] || 
00596                     rface1._aulPoints[2] == rface2._aulPoints[1] ||
00597                     rface1._aulPoints[2] == rface2._aulPoints[2])
00598                     continue; // ignore facets sharing a common vertex
00599 
00600                 const Base::BoundBox3f& box2 = boxes[*jt];
00601                 if (box1 && box2) {
00602                     cMFI.Set(*jt);
00603                     facet2 = *cMFI;
00604                     int ret = facet1.IntersectWithFacet(facet2, pt1, pt2);
00605                     if (ret == 2) {
00606                         // abort after the first detected self-intersection
00607                         return false;
00608                     }
00609                 }
00610             }
00611         }
00612     }
00613 
00614     return true;
00615 }
00616 
00617 void MeshEvalSelfIntersection::GetIntersections(const std::vector<std::pair<unsigned long, unsigned long> >& indices,
00618                                                 std::vector<std::pair<Base::Vector3f, Base::Vector3f> >& intersection) const
00619 {
00620     intersection.reserve(indices.size());
00621     MeshFacetIterator cMF1(_rclMesh);
00622     MeshFacetIterator cMF2(_rclMesh);
00623 
00624     Base::Vector3f pt1, pt2;
00625     std::vector<std::pair<unsigned long, unsigned long> >::const_iterator it;
00626     for (it = indices.begin(); it != indices.end(); ++it) {
00627         cMF1.Set(it->first);
00628         cMF2.Set(it->second);
00629 
00630         Base::BoundBox3f box1 = cMF1->GetBoundBox();
00631         Base::BoundBox3f box2 = cMF2->GetBoundBox();
00632         if (box1 && box2) {
00633             int ret = cMF1->IntersectWithFacet(*cMF2, pt1, pt2);
00634             if (ret == 2) {
00635                 intersection.push_back(std::make_pair(pt1, pt2));
00636             }
00637         }
00638     }
00639 }
00640 
00641 void MeshEvalSelfIntersection::GetIntersections(std::vector<std::pair<unsigned long, unsigned long> >& intersection) const
00642 {
00643     // Contains bounding boxes for every facet 
00644     std::vector<Base::BoundBox3f> boxes;
00645     //intersection.clear();
00646 
00647     // Splits the mesh using grid for speeding up the calculation
00648     MeshFacetGrid cMeshFacetGrid(_rclMesh);
00649     const MeshFacetArray& rFaces = _rclMesh.GetFacets();
00650     MeshGridIterator clGridIter(cMeshFacetGrid);
00651     unsigned long ulGridX, ulGridY, ulGridZ;
00652     cMeshFacetGrid.GetCtGrids(ulGridX, ulGridY, ulGridZ);
00653 
00654     MeshFacetIterator cMFI(_rclMesh);
00655     for(cMFI.Begin(); cMFI.More(); cMFI.Next()) {
00656         boxes.push_back((*cMFI).GetBoundBox());
00657     }
00658 
00659     // Calculates the intersections
00660     Base::SequencerLauncher seq("Checking for self-intersections...", ulGridX*ulGridY*ulGridZ);
00661     for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) {
00662         //Get the facet indices, belonging to the current grid unit
00663         std::vector<unsigned long> aulGridElements;
00664         clGridIter.GetElements(aulGridElements);
00665 
00666         seq.next(true);
00667         if (aulGridElements.size()==0)
00668             continue;
00669 
00670         MeshGeomFacet facet1, facet2;
00671         Base::Vector3f pt1, pt2;
00672         for (std::vector<unsigned long>::iterator it = aulGridElements.begin(); it != aulGridElements.end(); ++it) {
00673             const Base::BoundBox3f& box1 = boxes[*it];
00674             cMFI.Set(*it);
00675             facet1 = *cMFI;
00676             const MeshFacet& rface1 = rFaces[*it];
00677             for (std::vector<unsigned long>::iterator jt = it; jt != aulGridElements.end(); ++jt) {
00678                 if (jt == it) // the identical facet
00679                     continue;
00680                 // If the facets share a common vertex we do not check for self-intersections because they 
00681                 // could but usually do not intersect each other and the algorithm below would detect false-positives,
00682                 // otherwise
00683                 const MeshFacet& rface2 = rFaces[*jt];
00684                 if (rface1._aulPoints[0] == rface2._aulPoints[0] || 
00685                     rface1._aulPoints[0] == rface2._aulPoints[1] ||
00686                     rface1._aulPoints[0] == rface2._aulPoints[2])
00687                     continue; // ignore facets sharing a common vertex
00688                 if (rface1._aulPoints[1] == rface2._aulPoints[0] || 
00689                     rface1._aulPoints[1] == rface2._aulPoints[1] ||
00690                     rface1._aulPoints[1] == rface2._aulPoints[2])
00691                     continue; // ignore facets sharing a common vertex
00692                 if (rface1._aulPoints[2] == rface2._aulPoints[0] || 
00693                     rface1._aulPoints[2] == rface2._aulPoints[1] ||
00694                     rface1._aulPoints[2] == rface2._aulPoints[2])
00695                     continue; // ignore facets sharing a common vertex
00696 
00697                 const Base::BoundBox3f& box2 = boxes[*jt];
00698                 if (box1 && box2) {
00699                     cMFI.Set(*jt);
00700                     facet2 = *cMFI;
00701                     int ret = facet1.IntersectWithFacet(facet2, pt1, pt2);
00702                     if (ret == 2) {
00703                         intersection.push_back(std::make_pair
00704                             <unsigned long, unsigned long>(*it,*jt));
00705                     }
00706                 }
00707             }
00708         }
00709     }
00710 }
00711 
00712 bool MeshFixSelfIntersection::Fixup()
00713 {
00714     std::vector<unsigned long> indices;
00715     const MeshFacetArray& rFaces = _rclMesh.GetFacets();
00716     for (std::vector<std::pair<unsigned long, unsigned long> >::const_iterator
00717         it = selfIntersectons.begin(); it != selfIntersectons.end(); ++it) {
00718         unsigned short numOpenEdges1 = rFaces[it->first].CountOpenEdges();
00719         unsigned short numOpenEdges2 = rFaces[it->second].CountOpenEdges();
00720 
00721         // often we have only single or border facets that intersect other facets
00722         // in this case remove only these facets and keep the other one
00723         if (numOpenEdges1 == 0 && numOpenEdges2 > 0) {
00724             indices.push_back(it->second);
00725         }
00726         else if (numOpenEdges1 > 0 && numOpenEdges2 == 0) {
00727             indices.push_back(it->first);
00728         }
00729         else {
00730             indices.push_back(it->first);
00731             indices.push_back(it->second);
00732         }
00733     }
00734 
00735     // remove duplicates
00736     std::sort(indices.begin(), indices.end());
00737     indices.erase(std::unique(indices.begin(), indices.end()), indices.end());
00738 
00739     _rclMesh.DeleteFacets(indices);
00740 
00741     return true;
00742 }
00743 
00744 // ----------------------------------------------------------------
00745 
00746 bool MeshEvalNeighbourhood::Evaluate ()
00747 {
00748     // Note: If more than two facets are attached to the edge then we have a 
00749     // non-manifold edge here. 
00750     // This means that the neighbourhood cannot be valid, for sure. But we just
00751     // want to check whether the neighbourhood is valid for topologic correctly
00752     // edges and thus we ignore this case.
00753     // Non-manifolds are an own category of errors and are handled by the class
00754     // MeshEvalTopology.
00755     //
00756     // Using and sorting a vector seems to be faster and more memory-efficient
00757     // than a map.
00758     const MeshFacetArray& rclFAry = _rclMesh.GetFacets();
00759     std::vector<Edge_Index> edges;
00760     edges.reserve(3*rclFAry.size());
00761 
00762     // build up an array of edges
00763     MeshFacetArray::_TConstIterator pI;
00764     Base::SequencerLauncher seq("Checking indices...", rclFAry.size());
00765     for (pI = rclFAry.begin(); pI != rclFAry.end(); pI++) {
00766         for (int i = 0; i < 3; i++) {
00767             Edge_Index item;
00768             item.p0 = std::min<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00769             item.p1 = std::max<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00770             item.f  = pI - rclFAry.begin();
00771             edges.push_back(item);
00772         }
00773 
00774         seq.next();
00775     }
00776 
00777     // sort the edges
00778     std::sort(edges.begin(), edges.end(), Edge_Less());
00779 
00780     unsigned long p0 = ULONG_MAX, p1 = ULONG_MAX;
00781     unsigned long f0 = ULONG_MAX, f1 = ULONG_MAX;
00782     int count = 0;
00783     std::vector<Edge_Index>::iterator pE;
00784     for (pE = edges.begin(); pE != edges.end(); pE++) {
00785         if (p0 == pE->p0 && p1 == pE->p1) {
00786             f1 = pE->f;
00787             count++;
00788         }
00789         else {
00790             // we handle only the cases for 1 and 2, for all higher
00791             // values we have a non-manifold that is ignorned here
00792             if (count == 2) {
00793                 const MeshFacet& rFace0 = rclFAry[f0];
00794                 const MeshFacet& rFace1 = rclFAry[f1];
00795                 unsigned short side0 = rFace0.Side(p0,p1);
00796                 unsigned short side1 = rFace1.Side(p0,p1);
00797                 // Check whether rFace0 and rFace1 reference each other as
00798                 // neighbours
00799                 if (rFace0._aulNeighbours[side0]!=f1 ||
00800                     rFace1._aulNeighbours[side1]!=f0)
00801                     return false;
00802             }
00803             else if (count == 1) {
00804                 const MeshFacet& rFace = rclFAry[f0];
00805                 unsigned short side = rFace.Side(p0,p1);
00806                 // should be "open edge" but isn't marked as such
00807                 if (rFace._aulNeighbours[side] != ULONG_MAX)
00808                     return false;
00809             }
00810 
00811             p0 = pE->p0;
00812             p1 = pE->p1;
00813             f0 = pE->f;
00814             count = 1;
00815         }
00816     }
00817 
00818     return true;
00819 }
00820 
00821 std::vector<unsigned long> MeshEvalNeighbourhood::GetIndices() const
00822 {
00823     std::vector<unsigned long> inds;
00824     const MeshFacetArray& rclFAry = _rclMesh.GetFacets();
00825     std::vector<Edge_Index> edges;
00826     edges.reserve(3*rclFAry.size());
00827 
00828     // build up an array of edges
00829     MeshFacetArray::_TConstIterator pI;
00830     Base::SequencerLauncher seq("Checking indices...", rclFAry.size());
00831     for (pI = rclFAry.begin(); pI != rclFAry.end(); pI++) {
00832         for (int i = 0; i < 3; i++) {
00833             Edge_Index item;
00834             item.p0 = std::min<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00835             item.p1 = std::max<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00836             item.f  = pI - rclFAry.begin();
00837             edges.push_back(item);
00838         }
00839 
00840         seq.next();
00841     }
00842 
00843     // sort the edges
00844     std::sort(edges.begin(), edges.end(), Edge_Less());
00845 
00846     unsigned long p0 = ULONG_MAX, p1 = ULONG_MAX;
00847     unsigned long f0 = ULONG_MAX, f1 = ULONG_MAX;
00848     int count = 0;
00849     std::vector<Edge_Index>::iterator pE;
00850     for (pE = edges.begin(); pE != edges.end(); pE++) {
00851         if (p0 == pE->p0 && p1 == pE->p1) {
00852             f1 = pE->f;
00853             count++;
00854         }
00855         else {
00856             // we handle only the cases for 1 and 2, for all higher
00857             // values we have a non-manifold that is ignorned here
00858             if (count == 2) {
00859                 const MeshFacet& rFace0 = rclFAry[f0];
00860                 const MeshFacet& rFace1 = rclFAry[f1];
00861                 unsigned short side0 = rFace0.Side(p0,p1);
00862                 unsigned short side1 = rFace1.Side(p0,p1);
00863                 // Check whether rFace0 and rFace1 reference each other as
00864                 // neighbours
00865                 if (rFace0._aulNeighbours[side0]!=f1 ||
00866                     rFace1._aulNeighbours[side1]!=f0) {
00867                     inds.push_back(f0);
00868                     inds.push_back(f1);
00869                 }
00870             }
00871             else if (count == 1) {
00872                 const MeshFacet& rFace = rclFAry[f0];
00873                 unsigned short side = rFace.Side(p0,p1);
00874                 // should be "open edge" but isn't marked as such
00875                 if (rFace._aulNeighbours[side] != ULONG_MAX)
00876                     inds.push_back(f0);
00877             }
00878 
00879             p0 = pE->p0;
00880             p1 = pE->p1;
00881             f0 = pE->f;
00882             count = 1;
00883         }
00884     }
00885 
00886     // remove duplicates
00887     std::sort(inds.begin(), inds.end());
00888     inds.erase(std::unique(inds.begin(), inds.end()), inds.end());
00889 
00890     return inds;
00891 }
00892 
00893 bool MeshFixNeighbourhood::Fixup()
00894 {
00895     _rclMesh.RebuildNeighbours();
00896     return true;
00897 }
00898 
00899 void MeshKernel::RebuildNeighbours (unsigned long index)
00900 {
00901     std::vector<Edge_Index> edges;
00902     edges.reserve(3 * (this->_aclFacetArray.size() - index));
00903 
00904     // build up an array of edges
00905     MeshFacetArray::_TConstIterator pI;
00906     MeshFacetArray::_TConstIterator pB = this->_aclFacetArray.begin();
00907     for (pI = pB + index; pI != this->_aclFacetArray.end(); pI++) {
00908         for (int i = 0; i < 3; i++) {
00909             Edge_Index item;
00910             item.p0 = std::min<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00911             item.p1 = std::max<unsigned long>(pI->_aulPoints[i], pI->_aulPoints[(i+1)%3]);
00912             item.f  = pI - pB;
00913             edges.push_back(item);
00914         }
00915     }
00916 
00917     // sort the edges
00918     std::sort(edges.begin(), edges.end(), Edge_Less());
00919 
00920     unsigned long p0 = ULONG_MAX, p1 = ULONG_MAX;
00921     unsigned long f0 = ULONG_MAX, f1 = ULONG_MAX;
00922     int count = 0;
00923     std::vector<Edge_Index>::iterator pE;
00924     for (pE = edges.begin(); pE != edges.end(); pE++) {
00925         if (p0 == pE->p0 && p1 == pE->p1) {
00926             f1 = pE->f;
00927             count++;
00928         }
00929         else {
00930             // we handle only the cases for 1 and 2, for all higher
00931             // values we have a non-manifold that is ignorned here
00932             if (count == 2) {
00933                 MeshFacet& rFace0 = this->_aclFacetArray[f0];
00934                 MeshFacet& rFace1 = this->_aclFacetArray[f1];
00935                 unsigned short side0 = rFace0.Side(p0,p1);
00936                 unsigned short side1 = rFace1.Side(p0,p1);
00937                 rFace0._aulNeighbours[side0] = f1;
00938                 rFace1._aulNeighbours[side1] = f0;
00939             }
00940             else if (count == 1) {
00941                 MeshFacet& rFace = this->_aclFacetArray[f0];
00942                 unsigned short side = rFace.Side(p0,p1);
00943                 rFace._aulNeighbours[side] = ULONG_MAX;
00944             }
00945 
00946             p0 = pE->p0;
00947             p1 = pE->p1;
00948             f0 = pE->f;
00949             count = 1;
00950         }
00951     }
00952 
00953     // we handle only the cases for 1 and 2, for all higher
00954     // values we have a non-manifold that is ignorned here
00955     if (count == 2) {
00956         MeshFacet& rFace0 = this->_aclFacetArray[f0];
00957         MeshFacet& rFace1 = this->_aclFacetArray[f1];
00958         unsigned short side0 = rFace0.Side(p0,p1);
00959         unsigned short side1 = rFace1.Side(p0,p1);
00960         rFace0._aulNeighbours[side0] = f1;
00961         rFace1._aulNeighbours[side1] = f0;
00962     }
00963     else if (count == 1) {
00964         MeshFacet& rFace = this->_aclFacetArray[f0];
00965         unsigned short side = rFace.Side(p0,p1);
00966         rFace._aulNeighbours[side] = ULONG_MAX;
00967     }
00968 }
00969 
00970 void MeshKernel::RebuildNeighbours (void)
00971 {
00972     // complete rebuild
00973     RebuildNeighbours(0);
00974 }
00975 
00976 // ----------------------------------------------------------------
00977 
00978 MeshEigensystem::MeshEigensystem (const MeshKernel &rclB)
00979   : MeshEvaluation(rclB), _cU(1.0f, 0.0f, 0.0f), _cV(0.0f, 1.0f, 0.0f), _cW(0.0f, 0.0f, 1.0f)
00980 {
00981     // use the values of world coordinates as default
00982     Base::BoundBox3f box = _rclMesh.GetBoundBox();
00983     _fU = box.LengthX();
00984     _fV = box.LengthY();
00985     _fW = box.LengthZ();
00986 }
00987 
00988 Base::Matrix4D MeshEigensystem::Transform() const
00989 {
00990     // x,y,c ... vectors
00991     // R,Q   ... matrices (R is orthonormal so its transposed(=inverse) is equal to Q)
00992     //
00993     // from local (x) to world (y,c) coordinates we have the equation
00994     // y = R * x  + c
00995     //     <==> 
00996     // x = Q * y - Q * c
00997     Base::Matrix4D clTMat;
00998     // rotation part
00999     clTMat[0][0] = _cU.x; clTMat[0][1] = _cU.y; clTMat[0][2] = _cU.z; clTMat[0][3] = 0.0f;
01000     clTMat[1][0] = _cV.x; clTMat[1][1] = _cV.y; clTMat[1][2] = _cV.z; clTMat[1][3] = 0.0f;
01001     clTMat[2][0] = _cW.x; clTMat[2][1] = _cW.y; clTMat[2][2] = _cW.z; clTMat[2][3] = 0.0f;
01002     clTMat[3][0] =  0.0f; clTMat[3][1] =  0.0f; clTMat[3][2] =  0.0f; clTMat[3][3] = 1.0f;
01003 
01004     Base::Vector3f c(_cC);
01005     c = clTMat * c;
01006 
01007     // translation part
01008     clTMat[0][3] = -c.x; clTMat[1][3] = -c.y; clTMat[2][3] = -c.z;
01009 
01010     return clTMat;
01011 }
01012 
01013 bool MeshEigensystem::Evaluate()
01014 {
01015     CalculateLocalSystem();
01016 
01017     float xmin=0.0f, xmax=0.0f, ymin=0.0f, ymax=0.0f, zmin=0.0f, zmax=0.0f;
01018 
01019     Base::Vector3f clVect, clProj;
01020     float fH;
01021 
01022     const MeshPointArray& aclPoints = _rclMesh.GetPoints ();
01023     for (MeshPointArray::_TConstIterator it = aclPoints.begin(); it!=aclPoints.end(); ++it) {
01024         // u-Richtung
01025         clVect = *it - _cC;
01026         clProj.ProjToLine(clVect, _cU);
01027         clVect = clVect + clProj;
01028         fH = clVect.Length();
01029       
01030         // zeigen Vektoren in die gleiche Richtung ?
01031         if ((clVect * _cU) < 0.0f)
01032             fH = -fH;
01033 
01034         xmax = std::max<float>(xmax, fH);
01035         xmin = std::min<float>(xmin, fH);
01036 
01037         // v-Richtung
01038         clVect = *it - _cC;
01039         clProj.ProjToLine(clVect, _cV);
01040         clVect = clVect + clProj;
01041         fH = clVect.Length();
01042   
01043         // zeigen Vektoren in die gleiche Richtung ?
01044         if ((clVect * _cV) < 0.0f)
01045           fH = -fH;
01046 
01047         ymax = std::max<float>(ymax, fH);
01048         ymin = std::min<float>(ymin, fH);
01049 
01050         // w-Richtung
01051         clVect = *it - _cC;
01052         clProj.ProjToLine(clVect, _cW);
01053         clVect = clVect + clProj;
01054         fH = clVect.Length();
01055   
01056         // zeigen Vektoren in die gleiche Richtung ?
01057         if ((clVect * _cW) < 0.0f)
01058             fH = -fH;
01059 
01060         zmax = std::max<float>(zmax, fH);
01061         zmin = std::min<float>(zmin, fH);
01062     }
01063 
01064     _fU = xmax - xmin;
01065     _fV = ymax - ymin;
01066     _fW = zmax - zmin;
01067 
01068     return false; // to call Fixup() if needed
01069 }
01070 
01071 Base::Vector3f MeshEigensystem::GetBoundings() const
01072 {
01073     return Base::Vector3f ( _fU, _fV, _fW );
01074 }
01075 
01076 void MeshEigensystem::CalculateLocalSystem()
01077 {
01078     // at least one facet is needed
01079     if (_rclMesh.CountFacets() < 1)
01080         return; // cannot continue calculation
01081 
01082     const MeshPointArray& aclPoints = _rclMesh.GetPoints ();
01083     MeshPointArray::_TConstIterator it;
01084 
01085     PlaneFit planeFit;
01086     for (it = aclPoints.begin(); it!=aclPoints.end(); ++it)
01087         planeFit.AddPoint(*it);
01088 
01089     planeFit.Fit();
01090     _cC = planeFit.GetBase();
01091     _cU = planeFit.GetDirU();
01092     _cV = planeFit.GetDirV();
01093     _cW = planeFit.GetNormal();
01094 
01095     // set the sign for the vectors
01096     float fSumU, fSumV, fSumW;
01097     fSumU = fSumV = fSumW = 0.0f;
01098     for (it = aclPoints.begin(); it!=aclPoints.end(); ++it)
01099     {
01100         float fU = _cU * (*it - _cC);
01101         float fV = _cV * (*it - _cC);
01102         float fW = _cW * (*it - _cC);
01103         fSumU += (fU > 0 ? fU * fU : -fU * fU);
01104         fSumV += (fV > 0 ? fV * fV : -fV * fV);
01105         fSumW += (fW > 0 ? fW * fW : -fW * fW);
01106     }
01107 
01108     // avoid ambiguities concerning directions
01109     if (fSumU < 0.0f)
01110         _cU *= -1.0f;
01111     if (fSumV < 0.0f)
01112         _cV *= -1.0f;
01113     if (fSumW < 0.0f)
01114         _cW *= -1.0f;
01115 
01116     if ((_cU%_cV)*_cW < 0.0f)
01117         _cW = -_cW; // make a right-handed system
01118 }

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