Mesh.h

Go to the documentation of this file.
00001 #ifndef Mesh_HEADER
00002 #define Mesh_HEADER
00003 
00004 #include "GenericMesh.h"
00005 #include "ProtectedBall.h"
00006 #include "RefineVertex.h"
00007 #include "SimplexData.h"
00008 #include "SliverChecker.h"
00009 #include <algorithm>
00010 #include <boost/foreach.hpp>
00011 #include <boost/function_output_iterator.hpp>
00012 #include <delaunay/IncrementalDelaunay.h>
00013 #include <functional>
00014 #include <stdlib.h>
00015 #include <utilities/hash.h>
00016 #include <vector>
00017 
00018 #if 0
00019 #define dprintf(...) printf(__VA_ARGS__);
00020 #else
00021 #define dprintf(...)
00022 #endif
00023 
00027 /* signature MESH =
00028    sig
00029      type vertex
00030      type simplex
00031      type point
00032      val center : simplex -> (point * real)
00033      val split : mesh * simplex -> { v: vertex, kill: simplex list, born: simplex list }
00034      val encroached : mesh * simplex * point -> bool
00035      val notify : simplex * { kill: ball list, born: ball list, v: vertex } -> unit
00036      val getHandle : mesh -> simplex
00037    end
00038    */
00039 
00045 template <size_t ambient, size_t topo>
00046 struct Mesh : public GenericMesh<ambient> {
00047   typedef ::SimplexData<ambient, topo> SimplexData;
00048   typedef IncrementalDelaunay<ambient, topo, RefineVertex<ambient>, SimplexData> Delaunay;
00049   typedef typename Delaunay::Complex Complex;
00050   typedef typename Delaunay::Cavity Cavity;
00051   typedef typename Delaunay::Star Star;
00052   typedef typename Delaunay::Simplex Simplex;
00053   typedef typename Delaunay::Vertex Vertex;
00054   typedef typename MeshTypes<ambient>::Ball Ball;
00055   typedef typename MeshTypes<ambient>::BallSet BallSet;
00056   typedef typename MeshTypes<ambient>::GenericMesh GenericMesh;
00057   typedef Geometry::CenterRadius<ambient> CenterRadius;
00058   typedef Geometry::Point<ambient> Point;
00059   typedef Geometry::Point<topo> PPoint;
00060   typedef ::SplitData<ambient> SplitData;
00061 
00062   static const size_t ambient_dimension = ambient;
00063   static const size_t topological_dimension = topo;
00064 
00068   private:
00069   struct InitVertex {
00070     Mesh *mesh;
00071     InitVertex(Mesh *mesh): mesh(mesh) { }
00072     static bool canEnter(const Simplex&) { return true; }
00073     bool choose(const Simplex& s) {
00074       BOOST_FOREACH(Vertex *v, s) {
00075         if (topo == ambient) {
00076           v->replaceHandle(mesh->toBall(s));
00077           // the 'upper' mesh is NULL, to save a word per vertex.
00078         } else {
00079           v->addUpperMesh(mesh);
00080         }
00081       }
00082       return false;
00083     }
00084   };
00085 
00086 
00098   public:
00099   Mesh(Delaunay *del) : del_(del) {
00100     dprintf("%u-mesh %p: Projection plane %s\n", unsigned(topo), this,
00101         del_->getPlane().toString().c_str());
00102     assert(del_->isOriented());
00103     InitVertex sh(this);
00104     dfs(sh);
00105   }
00106 
00108   virtual unsigned topological() const { return topo; }
00109 
00111   const Delaunay *getDelaunay() const {
00112     return del_;
00113   }
00114 
00116   const Complex& getSimplicialComplex() const {
00117     return del_->getComplex();
00118   }
00119 
00123   Delaunay *getDelaunayDangerously() {
00124     return del_;
00125   }
00126 
00129   const Simplex& getHandle() const {
00130     return del_->getHandle();
00131   }
00132 
00135   template <class DFSData>
00136   void dfs(DFSData& data) const {
00137     del_->getComplex().dfsBySimplex(data, getHandle());
00138   }
00139 
00140 
00141   /***************************************************************************
00142    ***************************************************************************/
00143   private:
00144   template <class output_iterator>
00145   struct ConvertToBalls {
00146     static bool canEnter(const Simplex&) { return true; }
00147     bool choose(const Simplex& s) {
00148       *out_ = mesh_->toBall(s);
00149       ++out_;
00150       return false;
00151     }
00152     const Mesh *mesh_;
00153     output_iterator out_;
00154     ConvertToBalls(const Mesh *m, output_iterator o): mesh_(m), out_(o) { }
00155   };
00156 
00162   public:
00163   template <class output_iterator>
00164   output_iterator collectAllBalls(output_iterator out) const {
00165     ConvertToBalls<output_iterator> ctb(this, out);
00166     dfs(ctb);
00167     return ctb.out_;
00168   }
00169 
00170   /***************************************************************************
00171    * Convert a simplex into its protected ball.
00172    * Each simplex has a unique ball, so this is const-like.  If the ball has
00173    * not yet been created, create it here (violating constness).
00174    ***************************************************************************/
00175   Ball *toBall(const Simplex& s) const {
00176     Ball *b = getData(s).toBall();
00177     if (b == NULL) {
00178       // Create a new ball.  The ball must know the mesh as non-const,
00179       // and it calls setBall below upon creation.  Thus I violate
00180       // constness.
00181       b = makeProtectedBall(const_cast<Mesh*>(this), s);
00182     }
00183     return b;
00184   }
00185 
00187   void setBall(const Simplex& s, Ball *b) {
00188     assert(getData(s).toBall() == NULL);
00189     getDataRW(s).setBall(b);
00190   }
00191 
00192   /***************************************************************************
00193    * \name Geometric and combinatorial information about a simplex.
00194    ***************************************************************************/
00195 
00197   bool isMember(const Simplex& s) const {
00198     return del_->getComplex().isMember(s);
00199   }
00200 
00202   CenterRadius circumcenter(const Simplex& s) const {
00203     return del_->circumcenter(s);
00204   }
00205 
00207   double radiusEdge2(const Simplex& s) const {
00208     return del_->radiusEdge2(s);
00209   }
00210   double computeSigma(const Simplex& s) const {
00211     return del_->computeSigma(s);
00212   }
00213 
00218   bool encroachedBy(const Simplex& s, const Vertex *v) const {
00219     // Check if v is a vertex of s.
00220     if (s.has(v)) {
00221       dprintf("  vertex %p does not encroach %s\n", v, toBall(s)->toString().c_str());
00222       return false;
00223     }
00224 
00225     // Otherwise, precision isn't necessary here, so use the cheap computation.
00226     CenterRadius cr = circumcenter(s);
00227     bool b = v->toPoint().dist2(cr.center) < cr.radius2;
00228     dprintf("  vertex %p (%s) %s <%s,%g>  (%s)\n",
00229         v, v->toPoint().toString().c_str(),
00230         b ? "encroaches" : "does not encroach",
00231         cr.center.toString().c_str(), sqrt(cr.radius2),
00232         toBall(s)->toString().c_str());
00233     return b;
00234   }
00235 
00240   bool inSphereExact(const Simplex& s, const Vertex *v) const {
00241     assert(v->hasUpperMesh(this));
00242     if (s.has(v)) { return false; }
00243     return del_->inSphereAffine(s, v->toPoint());
00244   }
00245 
00247   bool isResolved(const Simplex& s) const {
00248     if (topological_dimension == ambient) {
00249       // obviously, since this ball is *in* the top-d mesh.
00250       return true;
00251     }
00252 
00253     // Look at each top-d simplex that we intersect.
00254     BOUNDED_FOREACH(Ball *b, getData(s).begin_uppers(), getData(s).end_uppers()) {
00255       if (b->topological() != ambient) { continue; }
00256 
00257       // Look for all the vertices.  If we find them, we're resolved by this simplex.
00258       bool hasAll = true;
00259       BOOST_FOREACH(Vertex *v, s) {
00260         if (!b->has(v)) { hasAll = false; break; }
00261       }
00262       if (hasAll) { return true; }
00263     }
00264 
00265     // if we made it here, the ball is unresolved
00266     return false;
00267   }
00268 
00269 
00271   void gatherUppers(const Simplex& s, BallSet& set) const {
00272     return getData(s).gatherUppers(set);
00273   }
00275   void gatherLowers(const Simplex& s, BallSet& set) const {
00276     return getData(s).gatherLowers(set);
00277   }
00278 
00282   bool approximatelyIntersects(const Simplex& s, const Ball *b) const {
00283     return b->approximatelyIntersects(circumcenter(s));
00284   }
00285 
00286   /***************************************************************************
00287     \name Modification routines
00288    ***************************************************************************/
00289 
00297   private:
00298   bool isDegenerate(const Simplex& s) const {
00299     if (topo == 1) {
00300       // we never split vertices, so this can't be a problem.
00301       return false;
00302     }
00303     vector<const GenericMesh*> meshes;
00304     std::copy(s[0]->begin_uppers(topo - 1), s[0]->end_uppers(topo - 1),
00305         std::back_inserter(meshes));
00306     // std::sort(meshes.begin(), meshes.end());
00307 
00308     for(size_t i = 1 ; i <= topo; ++i) {
00309       // vector<const GenericMesh*> mis;
00310       // std::copy(s[i]->begin_uppers(topo - 1), s[i]->end_uppers(topo - 1),
00311       //     std::back_inserter(mis));
00312       // std::sort(mis.begin(), mis.end());
00313 
00314       // Compute the set intersection.  Sadly, not in place, but at least we
00315       // use the swap to avoid a redundent copy.  By using the assumption that
00316       // the uppers of s[i] are sorted, we at least eliminate one copy.
00317       vector<const GenericMesh*> tmp;
00318       std::set_intersection(meshes.begin(), meshes.end(),
00319           s[i]->begin_uppers(topo - 1), s[i]->end_uppers(topo - 1),
00320           std::back_inserter(tmp));
00321       meshes.swap(tmp);
00322     }
00323 
00324     // Degeneracy only occurs if all the meshes lie on a common (topo-1)-feature.
00325     // We therefore return whether the list of such is non-empty.
00326     assert(meshes.size() == 0 || meshes.size() == 1);
00327     return !meshes.empty();
00328   }
00329 
00338   private:
00339   struct WarpClosure {
00340     Vertex *best_;
00341     double radius2_;
00342     const Point& center_;
00343     Mesh *mesh_;
00344 
00345     WarpClosure(double radius2, const Point& center, Mesh *mesh)
00346       : radius2_(radius2), center_(center), mesh_(mesh) {
00347         best_ = NULL;
00348       }
00349 
00350     bool canEnter(const Simplex& s) {
00351       // do we need this precise test?  Seems unlikely...
00352       return mesh_->getDelaunay()->inSphereAffine(s, center_);
00353     }
00354 
00355     bool choose(const Simplex& s) {
00356       BOOST_FOREACH(Vertex *v, s) {
00357         pair<Vertex*,double> p = v->findClosest(mesh_, center_, radius2_);
00358         if (p.first) {
00359           best_ = p.first;
00360           radius2_ = p.second;
00361         }
00362       }
00363       return false;
00364     }
00365   };
00366 
00368   Vertex *findWarpVertex(const Simplex& s, double k2) {
00369     WarpClosure wc(circumcenter(s).radius2 * k2, circumcenter(s).center, this);
00370     del_->getComplex().bfsBySimplex(wc, s);
00371     return wc.best_;
00372   }
00373 
00385   public:
00386   bool split(const Simplex& s, SplitData& data, Vertex *inserthint = NULL, bool force = false) {
00387     dprintf("Splitting in %u-mesh [%p] at %s\n", unsigned(topo), this, s.toString().c_str());
00388     if (inserthint) { dprintf("  Using insert-hint of %s\n", inserthint->toString().c_str()); }
00389 
00390     /* Find a vertex to warp to. */
00391     Vertex *toinsert = inserthint ? inserthint : findWarpVertex(s, data.k * data.k);
00392     bool isSteiner = toinsert == NULL;
00393 
00394     // Create the new vertex if needed.  Remember to delete it if we don't
00395     // insert it.
00396     if (isSteiner) {
00397       /*
00398        * If we're in ambient dimension 3 or higher, check if we're about to
00399        * create small slivers in higher dimension.  If so, perturb the point
00400        * until we don't.
00401        */
00402       Point newpoint = circumcenter(s).center;
00403       if (ambient >= 3 && data.sigma != 0.0) {
00404         SliverChecker<ambient> checker(getData(s).begin_uppers(),
00405             getData(s).end_uppers(), data, circumcenter(s).radius2);
00406         enum { MAX_SLIVER_ITERATIONS = 20 };
00407         unsigned ntries = 0;
00408         while(++ntries < MAX_SLIVER_ITERATIONS && checker.formsSliver(newpoint)) {
00409           /* Choose a better newpoint.  This uses the fact that projection
00410            * preserves distances. */
00411           PPoint c = del_->getPlane().project(circumcenter(s).center);
00412           c += PPoint::randPoint(data.perturbFactor);
00413           newpoint = del_->getPlane().unproject(c);
00414         }
00415         if (ntries == MAX_SLIVER_ITERATIONS) {
00416           printf("warning: can't avoid sliver after %u tries\n",
00417               MAX_SLIVER_ITERATIONS);
00418         }
00419       }
00420       toinsert = new Vertex(newpoint);
00421       toinsert->setContainingDimension(topo);
00422       if (topo < ambient) { toinsert->addUpperMesh(this); }
00423     }
00424     dprintf("  split at %s (%s) %s\n", toinsert->toString().c_str(),
00425         toinsert->toPoint().toString().c_str(),
00426         isSteiner ? "(Steiner)" : "(input)");
00427 
00428     /* Compute the cavity.  If we end up inserting, we will need the
00429      * neighbours: the union of the circumballs of cavity and neighbours covers
00430      * the star.  If we don't, the cost to have collected them is miniscule. */
00431     Cavity cavity;
00432     vector<Simplex> neighbours;
00433     del_->computeCavity(s, toinsert->toPoint(), cavity, neighbours);
00434 
00435     /* Check for encroachment.  If anything is encroached, it must be in the cavity.
00436      * TODO -- this adds a log(L/s) factor.  We should allow
00437      * single-encroachment for lower-containing-dimension vertices.
00438      */
00439     {
00440       hudson::OrderedHashSet<Ball *, hudson::HashPointer<Ball> > checked;
00441       BOOST_FOREACH(const Simplex& s, cavity) {
00442         dprintf("  checking for encroachment in %s\n", toBall(s)->toString().c_str());
00443         BOUNDED_FOREACH(Ball *b, getData(s).begin_lowers(), getData(s).end_lowers()) {
00444           if (checked.insert(b).second) { // then we've not seen it before
00445             if (b->encroachedBy(toinsert)) {
00446               data.insertEncroached(b);
00447             }
00448           }
00449         }
00450       }
00451     }
00452 
00453     // If we encroached, back out (unless forced).  The caller is responsible
00454     // for putting the current job back on the queue.
00455     if (data.encroached()) {
00456       if (force) {
00457         dprintf("  encroached; force anyway.\n");
00458       } else {
00459         dprintf("  encroached; back out and try again\n");
00460         if (isSteiner) { delete toinsert; }
00461         return false;
00462       }
00463     }
00464 
00465     dprintf("  starting ForceInsert\n");
00466 
00467     /*
00468      * Compute the star and actually insert the vertex.
00469      * In the top dimension, we have a bounding box.  In lower dimensions,
00470      * however, the star may include degenerate simplices where the point toinsert
00471      * is exactly on the boundary (because it is the result of splitting a
00472      * lower-dimensional protected ball).  We remove those from the star.
00473      */
00474     Star star;
00475     del_->computeStar(cavity, toinsert, star);
00476     if (topo != ambient && toinsert->getCD() < topo) {
00477       typename Star::iterator it = star.begin();
00478       while (it != star.end() /* recompute: we're modifying star */) {
00479         const Simplex& s = *it;
00480         if (isDegenerate(s)) {
00481           dprintf("   reject degenerate %s\n", s.toString().c_str());
00482           it = star.erase(it);
00483         } else {
00484           dprintf("   accept non-degenerate %s\n", s.toString().c_str());
00485           ++it;
00486         }
00487       }
00488     }
00489 #ifndef NDEBUG
00490     BOOST_FOREACH(const Simplex& s, star) {
00491       dprintf("   verifying %s\n", s.toString().c_str());
00492       // This may occur in d=3, and isn't a problem: we do have
00493       // slivers of 4 points "on" a plane due to numerical error.
00494       // assert(!isDegenerate(s));
00495 
00496       assert(del_->isOriented(s));
00497     }
00498 #endif
00499 
00500     dprintf("  star computed\n");
00501     del_->insertVertex(cavity, star);
00502 
00503     dprintf("  starting to reassign uppers/lowers\n");
00504 
00505     /* Link in the new star to its uppers and lowers. */
00506     BallSet lowers;
00507     BallSet uppers;
00508     typedef typename Vertex::VertexUniqueList VertexSet;
00509     typedef hudson::FastHashMap<const GenericMesh*, VertexSet, hudson::HashPointer<GenericMesh> >
00510       MeshVertexMap;
00511     MeshVertexMap upvertices;
00512     std::vector<const GenericMesh*> upmeshes;
00513 
00514     BOOST_FOREACH(const Simplex& s, cavity) {
00515       const SimplexData& sdata = getData(s);
00516       lowers.insert(sdata.begin_lowers(), sdata.end_lowers());
00517       uppers.insert(sdata.begin_uppers(), sdata.end_uppers());
00518     }
00519 
00520     BOOST_FOREACH(const Simplex& s, neighbours) {
00521       const SimplexData& sdata = getData(s);
00522       lowers.insert(sdata.begin_lowers(), sdata.end_lowers());
00523       uppers.insert(sdata.begin_uppers(), sdata.end_uppers());
00524     }
00525 
00526     // Gather the upper vertices, ordered by mesh.
00527     BOOST_FOREACH(const Ball *b, uppers) {
00528       const GenericMesh *m = b->getMesh();
00529       // find or insert the mesh into upvertices, then gather this
00530       // ball's vertices into the set.
00531       std::pair<typename MeshVertexMap::iterator, bool> p =
00532         upvertices.insert(m);
00533       if (p.second) { upmeshes.push_back(m); }
00534       VertexSet& vset = ((*p.first).second);
00535       b->gatherVertices(vset);
00536     }
00537 
00538     // Set uppers and lowers for the new star, one by one.
00539     BOOST_FOREACH(const Simplex& s, star) {
00540       BOOST_FOREACH(Ball *b, lowers) {
00541         checkAddLower(s, b);
00542       }
00543       Ball *sball = toBall(s);
00544       BOOST_FOREACH(Ball *b, uppers) {
00545         b->checkAddLower(sball);
00546       }
00547     }
00548 
00549     // Add the new vertex to each higher-dimensional mesh.
00550     BOOST_FOREACH(const GenericMesh *m, upmeshes) {
00551       const VertexSet& vset = upvertices.findOrDie(m);
00552       Vertex *closest = *std::min_element(vset.begin(), vset.end(),
00553           typename Vertex::IsCloser(toinsert));
00554       closest->addUninserted(m, toinsert);
00555     }
00556 
00557     // Reassign uninserted points in the current mesh to the new vertex.
00558     {
00559       hudson::FastHashSet<Vertex*, hudson::HashPointer<Vertex> > verts;
00560       BOOST_FOREACH(const Simplex& s, cavity) {
00561         BOOST_FOREACH(Vertex *v, s) {
00562           if (verts.insert(v).second) {
00563             v->reassignTo(this, toinsert);
00564           }
00565         }
00566       }
00567     }
00568 
00569     // Unlink the cavity.
00570     BOOST_FOREACH(const Simplex& s, cavity) {
00571       unlink(s);
00572     }
00573 
00574     // Set new handles for each vertex, if we're in top-dimension.  This may
00575     // set the handle for a vertex several times.  Doesn't cost anything.
00576     if (topo == ambient) {
00577       BOOST_FOREACH(const Simplex& s, star) {
00578         BOOST_FOREACH(Vertex *v, s) {
00579           v->replaceHandle(toBall(s));
00580         }
00581       }
00582     }
00583 
00584     // Set the return data.
00585     data.insertKill(this, cavity.begin(), cavity.end());
00586     data.insertBorn(this, star.begin(), star.end());
00587     data.setVertex(toinsert);
00588 
00589     // We inserted something, so say so.
00590     return true;
00591   }
00592 
00593   private:
00594   const Simplex& toSimplex(const Ball *b) const {
00595 #ifndef NDEBUG
00596     // This cast should never fail, so only test it at run-time in debug mode.
00597     assert(b);
00598     assert(dynamic_cast<const PBall<Mesh>*>(b));
00599 #endif
00600     return static_cast<const PBall<Mesh>*>(b)->toSimplex();
00601   }
00602 
00608   public:
00609   bool split(Vertex *v, SplitData& data) {
00610     BOOST_STATIC_ASSERT(topo == ambient);
00611     assert(v->isCrowded(this));
00612 
00613     // Collect the orbit around the vertex.
00614     vector<Simplex> orbit;
00615     Simplicial::collectStar(getSimplicialComplex(), v,
00616         toSimplex(v->getHandle()), std::back_inserter(orbit));
00617 
00618     if (v->getCD() == topo) {
00619       // this is a Steiner point; there can't be any nearby uninserted points,
00620       // or we'd have either warped to it or encroached on something.
00621       // So just find any point and insert it.  To do that, we need to find a
00622       // simplex encroached by the uninserted point.
00623       Vertex *uninserted = v->getFarVertex(this);
00624       BOOST_FOREACH(const Simplex& s, orbit) {
00625         if (getDelaunay()->inSphereAffine(s, uninserted->toPoint())) {
00626           return split(s, data, uninserted);
00627         }
00628       }
00629       // *someone* must include that vertex in its ball
00630       abort();
00631     } else {
00632       // This is an "input" point (it lies on lower-dimensional input).
00633       // Insert the farthest Voronoi node -- i.e. split the largest-radius simplex.
00634       size_t best = 0;
00635       double best_r2 = circumcenter(orbit[best]).radius2;
00636       size_t n = orbit.size();
00637       for(size_t i = 0; i < n; ++i) {
00638         double r2 = circumcenter(orbit[i]).radius2;
00639         if (r2 > best_r2) {
00640           best = i;
00641           best_r2 = r2;
00642         }
00643       }
00644       return split(orbit[best], data);
00645     }
00646   }
00647 
00648 
00649   /***************************************************************************
00650    * Check if s and b intersect; if so, link s and b.
00651    ***************************************************************************/
00652   bool checkAddLower(const Simplex& s, Ball *b) {
00653     if (approximatelyIntersects(s, b)) {
00654       dprintf("  intersection: balls %s and %s\n",
00655           toBall(s)->toString().c_str(), b->toString().c_str());
00656       getDataRW(s).blindlyAddLower(b);
00657       b->blindlyAddUpper(toBall(s));
00658       return true;
00659     }
00660     dprintf("  non-intersection: balls %s and %s\n",
00661         toBall(s)->toString().c_str(), b->toString().c_str());
00662     return false;
00663   }
00664 
00665   /***************************************************************************
00666    * Add an up pointer.  Does no checking to see whether this is appropriate.
00667    ***************************************************************************/
00668   public:
00669   void blindlyAddUpper(const Simplex& s, Ball *up) {
00670     assert(up->topological() > topo);
00671     getDataRW(s).blindlyAddUpper(up);
00672   }
00673 
00674   /***************************************************************************
00675    * Add a down pointer.  Does no checking to see whether this is appropriate.
00676    ***************************************************************************/
00677   public:
00678   void blindlyAddLower(const Simplex& s, Ball *lower) {
00679     dprintf("lower d=%u %s\nto d=%u %s\n",
00680         (unsigned)lower->topological(), lower->toString().c_str(),
00681         (unsigned)topo, s.toString().c_str());
00682     assert(lower->topological() < topo);
00683     getDataRW(s).blindlyAddLower(lower);
00684   }
00685 
00686   /***************************************************************************
00687    * Remove an up pointer.  Does no checking to see whether this is appropriate.
00688    ***************************************************************************/
00689   public:
00690   void removeUpper(const Simplex& s, Ball *up) {
00691     assert(up->topological() > topo);
00692     getDataRW(s).removeUpper(up);
00693   }
00694 
00695   /***************************************************************************
00696    * Remove a down pointer.  Does no checking to see whether this is appropriate.
00697    ***************************************************************************/
00698   public:
00699   void removeLower(const Simplex& s, Ball *lower) {
00700     assert(lower->topological() < topo);
00701     getDataRW(s).removeLower(lower);
00702   }
00703 
00704 
00705   /***************************************************************************
00706    * Remove all pointers to this simplex.
00707    ***************************************************************************/
00708   private:
00709   void unlink(const Simplex& s) {
00710     getDataRW(s).unlink();
00711   }
00712 
00713   /***************************************************************************
00714    * \name Initialization functions.
00715    *
00716    * Iterate over the entire mesh. Used in initialization.
00717    ***************************************************************************/
00718   private:
00719   struct BallNotifier {
00720     BallNotifier(Mesh *mesh, Ball *b)
00721       : mesh_(mesh), b_(b) { }
00722     Mesh *mesh_;
00723     Ball *b_;
00724     static bool canEnter(const Simplex&) { return true; }
00725     bool choose(const Simplex& s) const {
00726       mesh_->checkAddLower(s, b_);
00727       return false;
00728     }
00729   };
00730 
00731   public:
00734   void checkAddLowerToAll(Ball *b) {
00735     assert(b->topological() < topo);
00736     BallNotifier notifier(this, b);
00737     dfs(notifier);
00738   }
00739 
00740   private:
00741   const SimplexData& getData(const Simplex& s) const { return del_->getData(s); }
00742   SimplexData& getDataRW(const Simplex& s) { return del_->getDataRW(s); }
00743 
00744   Delaunay *del_;
00745 };
00746 
00747 #undef dprintf
00748 
00749 #endif

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