MeshCleaner.h

Go to the documentation of this file.
00001 #ifndef Cleaner_HEADER
00002 #define Cleaner_HEADER
00003 
00004 #ifdef HAVE_CONFIG_H
00005 # include <config.h>
00006 #endif
00007 
00008 #include "Mesh.h"
00009 #include <utilities/hash.h>
00010 #include <vector>
00011 
00012 #if 0
00013 #define dprintf(...) printf(__VA_ARGS__);
00014 #else
00015 #define dprintf(...)
00016 #endif
00017 
00024 template <unsigned ambient, unsigned topological>
00025 class MeshCleaner {
00026   BOOST_STATIC_ASSERT(ambient >= topological);
00027   BOOST_STATIC_ASSERT(topological >= 2);
00028 
00029   typedef typename Mesh<ambient, topological>::Delaunay Delaunay;
00030   typedef typename Delaunay::Simplex Simplex;
00031   typedef typename Delaunay::Vertex Vertex;
00032   typedef typename Delaunay::Complex Complex;
00033   typedef typename Complex::OSimplex OSimplex;
00034   typedef ::GenericMesh<ambient> GenericMesh;
00035 
00038   struct FindCorners {
00039     hudson::FastHashSet<Vertex*, hudson::HashPointer<Vertex>, false > corners_;
00040     std::vector<Simplex> corner_seeds_;
00041     template <class v_iterator>
00042     FindCorners(v_iterator begin, v_iterator end) {
00043       corners_.insert(begin, end);
00044     }
00045     static bool canEnter(const Simplex&) { return true; }
00046     bool choose(const Simplex& s) {
00047       BOOST_FOREACH(Vertex *v, s) {
00048         if (corners_.has(v)) {
00049           corner_seeds_.push_back(s);
00050           break;
00051         }
00052       }
00053       return false;
00054     }
00055   };
00056 
00057 
00059   typedef hudson::OrderedHashSet<Simplex, hudson::hash_by_call<Simplex> >
00060     SimplexSet;
00061 
00063   struct FindAllDead {
00064     const SimplexSet& live;
00065     SimplexSet& dead;
00066     FindAllDead(const SimplexSet& live, SimplexSet& dead) : live(live), dead(dead) { }
00067     static bool canEnter(const Simplex&) { return true; }
00068     bool choose(const Simplex& s) {
00069       if (!live.has(s)) {
00070         dead.insert(s);
00071       }
00072       return false;
00073     }
00074   };
00075 
00076   public:
00084   static void traverseComponent(Delaunay *del, const Simplex& seed,
00085       SimplexSet& component,
00086       hudson::SmallList<Simplex>& next_seeds)
00087   {
00088     const Complex& c = del->getComplex();
00089     hudson::FrontStack<Simplex> fringe;
00090     // std::stack<Simplex> fringe; // inexplicably, this fails.
00091     fringe.push(seed);
00092     dprintf("traversing component from seed %s\n", seed.toString().c_str());
00093 
00094     // Run DFS: find all the cells connected to the corners and mark them.
00095     while (!fringe.empty()) {
00096       Simplex s = fringe.top();
00097       fringe.pop();
00098 
00099       if (component.has(s)) { continue; /* already been here */ }
00100       component.insert(s);
00101       dprintf("  reachable: %s\n", s.toString().c_str());
00102 
00103       // collect neighbours
00104       OSimplex os = c.orientSimplex(s);
00105       for (size_t faceID = 0; faceID <= topological; ++faceID) {
00106         // Jump into the neighbour..
00107         OSimplex neigh = c.getNeighbour(faceID, os);
00108 
00109         // If there is no neighbour, stop here.
00110         if (!neigh.isInternal()) {
00111           continue;
00112         }
00113 
00114         // Compute the face.
00115         OSimplex fi = c.getFace(faceID, os);
00116 
00117         // Enter through this face unless all vertices share a
00118         // common (d-1)-mesh.  TODO: this was copied from
00119         // Mesh::isDegenerate; should be factored out.
00120 
00121         // Compute the intersection of the set of (d-1) meshes on which the
00122         // vertices of this face lie.
00123         std::vector<const GenericMesh*> meshes;
00124         std::copy(fi[0]->begin_uppers(topological-1), fi[0]->end_uppers(topological-1),
00125             std::back_inserter(meshes));
00126 
00127         for(size_t i = 1 ; i <= topological - 1; ++i) {
00128           // This uses the assumption that the meshes are stored in sorted order.
00129           std::vector<const GenericMesh*> tmp;
00130           std::set_intersection(meshes.begin(), meshes.end(),
00131               fi[i]->begin_uppers(topological - 1), fi[i]->end_uppers(topological - 1),
00132               std::back_inserter(tmp));
00133           meshes.swap(tmp);
00134         }
00135 
00136         // Either all vertices share one common d-1 face, or none.  Not two!
00137         assert(meshes.size() == 0 || meshes.size() == 1);
00138 
00139         if (meshes.empty()) {
00140           // If they share no common face, then we can continue on through.
00141           fringe.push(neigh);
00142         } else {
00143           // This is a boundary, stop here and mark it as a seed.
00144           next_seeds.push_front(neigh);
00145         }
00146       }
00147     }
00148   }
00149 
00162   template <class v_iterator>
00163   static bool clean(Delaunay *del, v_iterator begin_corners, v_iterator end_corners,
00164       hudson::SmallList<Simplex> *optional_output = 0) {
00165     const Complex& c = del->getComplex();
00166 
00167     dprintf("Performing cleanup on a %u-mesh\n", topological);
00168 
00169     // Search for the corners; seed the DFS there (this takes its own DFS).
00170     FindCorners fc(begin_corners, end_corners);
00171     c.dfsBySimplex(fc, c.getHandle());
00172 
00173     dprintf("Computing exterior simplices\n");
00174     SimplexSet exterior;
00175     hudson::SmallList<Simplex> interior_seeds;
00176     BOOST_FOREACH(const Simplex& seed, fc.corner_seeds_) {
00177       traverseComponent(del, seed, exterior, interior_seeds);
00178     }
00179 
00180     dprintf("Computing interior simplices\n");
00181     SimplexSet interior;
00182     hudson::SmallList<Simplex> ignored_seeds;
00183     BOOST_FOREACH(const Simplex& seed, interior_seeds) {
00184       if (exterior.has(seed)) { continue; } // handle walking through a hole
00185       traverseComponent(del, seed, interior, ignored_seeds);
00186     }
00187 
00188     if (interior.empty()) {
00189       // Not watertight -- we killed all the simplices.  Leave the mesh untouched
00190       // and return false.
00191       dprintf("Non-watertight!\n");
00192       return false;
00193     }
00194 
00195     // Compute the set of dead simplices.
00196     FindAllDead fd(interior, exterior);
00197     c.dfsBySimplex(fd, c.getHandle());
00198 
00199     // Get a writeable handle to the complex and slough off the necrosis.
00200     Complex& c_writable = del->getComplexRW();
00201     assert(!exterior.has(interior.front()));
00202     c_writable.setHandle(interior.front());
00203     BOOST_FOREACH(const Simplex& toslough, exterior) {
00204       c_writable.checkedRemoveSimplex(toslough);
00205     }
00206 
00207     if (optional_output) {
00208       BOOST_FOREACH(const Simplex& s, interior) {
00209         optional_output->push_front(s);
00210       }
00211     }
00212 
00213     // Who owns the vertices?  This seems to imply a memory leak...
00214     return true;
00215   }
00216 };
00217 
00218 #undef dprintf
00219 
00220 #endif

Generated on Thu Mar 27 19:04:12 2008 by  doxygen 1.4.6