PointRefiner.h

Go to the documentation of this file.
00001 #ifndef PointRefiner_HEADER
00002 #define PointRefiner_HEADER
00003 
00004 /***************************************************************************
00005  * Benoit Hudson (C) 2007.
00006  ***************************************************************************/
00007 
00008 #include <geometry/Point.h>
00009 #include <delaunay/IncrementalDelaunay.h>
00010 #include <delaunay/DelaunayHelpers.h>
00011 #include <delaunay/PointVertex.h>
00012 #include <utilities/foreach.h>
00013 #include <utilities/BucketPQ.h>
00014 #include <list>
00015 #include <math.h> // sqrt
00016 #include <stack>
00017 #include <stdio.h>
00018 
00019 #include <io/PLC.h>
00020 #include <refine-common/RefineConstants.h>
00021 #include <refine-common/Refiner.h>
00022 
00023 #include "PointRefineVertex.h"
00024 
00025 #if 0
00026 #define dprintf(...) printf(__VA_ARGS__);
00027 #else
00028 #define dprintf(...)
00029 #endif
00030 
00031 #define COLLECT_STATS
00032 
00033 namespace SVR {
00034 
00035 /***************************************************************************
00036  * The refiner itself.
00037  *
00038  * Read <i>Hudson, Miller, Phillips 2006</i> to understand what is going on
00039  * here.
00040  ***************************************************************************/
00041 template <unsigned ambient>
00042 struct PointRefiner : public MeshRefiner {
00043   typedef Geometry::Point<ambient> Point;
00044 
00045   // Forward-declare so we can define IncrementalDelaunay.
00046   struct Vertex;
00047 
00048   typedef ::IncrementalDelaunay<ambient,ambient,Vertex,void, typename PointVertex<ambient>::Printer > IncrementalDelaunay;
00049   typedef typename IncrementalDelaunay::Simplex Simplex;
00050   typedef typename IncrementalDelaunay::CenterRadius CenterRadius;
00051   typedef typename IncrementalDelaunay::Cavity Cavity;
00052   typedef typename IncrementalDelaunay::Star Star;
00053 
00054   // really just a typedef, but there's a circular dependency with IncrementalDelaunay, and we
00055   // can't forward-declare typedefs.
00056   struct Vertex : public PointRefineVertex<ambient, Simplex> {
00057     public:
00058     Vertex(const Point& p) : PointRefineVertex<ambient, Simplex>(p) { }
00059     Vertex(const Point& p, size_t inputid) : PointRefineVertex<ambient, Simplex>(p, inputid) { }
00060   };
00061 
00062   typedef typename Vertex::FlagType FlagType;
00063 
00066   typedef PointRefineVertex<ambient, Simplex> Uninserted;
00067   static Vertex *promoteToVertex(Uninserted *u) { return static_cast<Vertex*>(u); }
00068 
00069   /***************************************************************************
00070    * Initialization.
00071    *
00072    * Given points and constants, create the data structures we need to support
00073    * a call to refine().
00074    *
00075    * After this call, the storage for the points in the range can be deleted:
00076    * I've made a copy.
00077    ***************************************************************************/
00078   template <class point_iterator> /* operator* must return a Point<ambient> */
00079   static PointRefiner *
00080   initialize(point_iterator begin, const point_iterator& end,
00081       RefineConstants consts) {
00082     consts.regularize(ambient, true);
00083     return new PointRefiner(begin, end, consts);
00084   }
00085 
00086   static PointRefiner *
00087   initialize(SVR_IO::PLC *plc, const RefineConstants& consts) {
00088     return initialize(
00089         plc->begin_points<ambient>(),
00090         plc->end_points<ambient>(),
00091         consts);
00092   }
00093 
00094   /***************************************************************************
00095     Refinement.
00096    ***************************************************************************/
00097   virtual void refine() {
00098     doRefine();
00099   }
00100 
00101   /***************************************************************************
00102     Printing.
00103    ***************************************************************************/
00104   virtual void printToNodeEle(FILE *node, FILE *ele) const {
00105     doPrint(node, ele);
00106   }
00107 
00108   /***************************************************************************
00109     Direct access to the underlying mesh.
00110    ***************************************************************************/
00111   IncrementalDelaunay *getDelaunay() { return del_; }
00112   static const unsigned dimension = ambient;
00113   virtual unsigned dim() const { return ambient; }
00114 
00115 
00116 
00117   /***************************************************************************
00118    ***************************************************************************
00119    ***************************************************************************
00120    * From now on, the entire implementation is private.
00121    ***************************************************************************
00122    ***************************************************************************
00123    ***************************************************************************/
00124 
00125   /***************************************************************************
00126    * \name Trace handling.
00127    *
00128    * Useful in generating pretty animations of SVR.
00129    * Off most of the time.
00130    ***************************************************************************/
00131   enum TraceItemType { QUERY, INSERT };
00132   void printItem(const Simplex& s, const Point& p, TraceItemType t) {
00133     if (!traceFile_) return;
00134     fprintf(traceFile_, "* : %c : %s", t==QUERY ? 'T' : 'F', p.toString().c_str());
00135     BOOST_FOREACH(Vertex *v, s) {
00136       fprintf(traceFile_, ": %s", v->toPoint().toString().c_str());
00137     }
00138     fprintf(traceFile_, ": %g : %s\n", sqrt(center(s).radius2), center(s).center.toString().c_str());
00139   }
00140   void printQuery(const Simplex& s, const Point& p) {
00141     printItem(s, p, QUERY);
00142   }
00143   void printInsert(const Cavity& cavity, const Vertex *v) {
00144     printItem(*cavity.begin(), v->toPoint(), INSERT);
00145   }
00146 
00147 
00148   /***************************************************************************
00149     Data members.
00150    ***************************************************************************/
00151   private:
00152   IncrementalDelaunay *del_;
00153 
00154   // Work queues, in order.  First, skinny simplices, to get
00155   // always-good-quality.  Next, crowded Voronoi cells.  Because crowded
00156   // Steiner cells are so much easier to deal with, we do those first.
00157   // After that, slivers.
00158   // The simplex queues are bucketed by size (circumradius^2), and FIFO
00159   // within a bucket.  This means we quite strongly bias towards smallest-
00160   // first, but in O(1) per operation. TODO: do the same for vertex queues.
00161   //typedef stack<Vertex*> VertexStack;
00162   typedef hudson::FrontStack<Vertex*> VertexStack;
00163   typedef hudson::BucketDoublePQ<Simplex> SimplexStack;
00164 
00165   SimplexStack skinny_;  
00166   VertexStack crowdedSteiner_; 
00167   VertexStack crowdedInput_; 
00168   SimplexStack sliver_;  
00169   SimplexStack moderateSkinny_; 
00170 
00171   std::vector<Vertex*> meshvertices_; 
00172   size_t ninputs_;               
00173   size_t nuninserted_;         
00174   size_t nsimplices_;          
00175 
00176   FlagType searchID_; 
00177 
00183   const double rho2_;     // intermediate radius/edge ratio
00184   const double k2_;       // how far to look when warping
00185   const bool fastSearch_; // if true, stop the k*r search at the first match
00186   const double userRho2_; // user-demanded radius/edge ratio
00187   const bool useOffcenters_;
00188   const double sigma_; // radius/radius ratio
00189   const double sliverGrowth_;
00190   const double perturbFactor_;
00191   static const size_t SLIVER_RETRIES = 10;
00192   const RefineConstants::NodeOrder outputNodeOrder_;
00193   FILE * const traceFile_;
00195 
00196 
00197   // stats, largely for debugging
00198 #ifndef COLLECT_STATS
00199 # define statop(op)
00200 # define statopconst(op)
00201 # define statmax(stat, val)
00202 # define statmaxforce(stat, val)
00203 #else
00204 # define statop(op) stats.op
00205 # define statopconst(op) const_cast<struct stats&>(stats).op
00206 # define statmax(stat, val) stats.stat = max(stats.stat, (val))
00207 # define statmaxconst(stat, val) const_cast<struct stats&>(stats).stat = max(stats.stat, (val))
00208   struct stats {
00209     unsigned long nrounds_;
00210     unsigned long npoints_;
00211     unsigned long ninputs_;
00212     unsigned long nretries_;
00213     unsigned long numtri_;
00214     unsigned long maxtri_;
00215     unsigned long maxcavity_;
00216     unsigned long sumcavity_;
00217 
00218     // operations
00219     struct {
00220       unsigned long nskinny_;
00221       unsigned long ncrowdSteiner_;
00222       unsigned long ncrowdInput_;
00223       unsigned long nsliver_;
00224       unsigned long nmedium_;
00225     } ops;
00226 
00227     // point location
00228     unsigned long nlocate_;
00229     unsigned long nsupercav_;
00230     unsigned long sumsupercav_;
00231     unsigned long maxsupercav_;
00232     unsigned long nwarp_;
00233     double sumwarp_; // distance
00234     double maxwarp_; // distance
00235 
00236     // intermediate element quality
00237     unsigned long nslivers_;
00238     unsigned long nsliverretry_;
00239     double maxRe_;
00240     double maxRr_;
00241 
00242     stats(const IncrementalDelaunay *del) {
00243       memset(this, 0, sizeof(*this));
00244       npoints_ = Simplicial::countVertices(del->getComplex());
00245       numtri_ = Simplicial::countSimplices(del->getComplex());
00246     }
00247 
00248     void updateTri(size_t cavitysize, size_t starsize) {
00249       npoints_++;
00250       nrounds_++;
00251       numtri_ -= cavitysize;
00252       numtri_ += starsize;
00253       maxtri_ = max(numtri_, maxtri_);
00254       maxcavity_ = (cavitysize > maxcavity_) ? cavitysize : maxcavity_;
00255       sumcavity_ += cavitysize;
00256     }
00257 
00258     void supercav(size_t scavsize, double mindist2, bool isSteiner) {
00259       nsupercav_ ++;
00260       sumsupercav_ += scavsize;
00261       maxsupercav_ = (maxsupercav_ > scavsize) ? maxsupercav_ : scavsize;
00262 
00263       if (!isSteiner) {
00264         nwarp_ ++;
00265         double mindist = sqrt(mindist2);
00266         sumwarp_ += mindist;
00267         maxwarp_ = (maxwarp_ > mindist) ? maxwarp_ : mindist;
00268       }
00269     }
00270 
00271     void print(bool ignoreSlivers) const {
00272       printf("---Stats---\n");
00273       printf("Output: %lu points, %lu simplices\n", npoints_, numtri_);
00274       printf("Max triangulation size %lu\n", maxtri_);
00275       printf("Max cavity: %lu; average %g over %lu rounds\n", maxcavity_,
00276           (double)sumcavity_ / (double)nrounds_, nrounds_);
00277       printf("Worst radius/edge: %g\n", maxRe_);
00278       if (!ignoreSlivers) {
00279         printf("%lu slivers created, %lu retries\n", nslivers_, nsliverretry_);
00280         printf("Worst sliver: %g\n", maxRr_);
00281       }
00282 
00283       /* The number of times we ducked the supercavity is the number of times we located
00284        * but didn't supercavity.
00285        *
00286        * The number of times we did any point location at all in split(.) is
00287        * the number of times we did point location when we didn't retry for slivers. */
00288       unsigned long no_supercavity = nlocate_ - nsupercav_;
00289       unsigned long no_supercavity_pct = 100 * no_supercavity / nlocate_;
00290       printf("Point location: %lu queries (%lu [%lu%%] short-cut)\n",
00291           nlocate_,
00292           no_supercavity, no_supercavity_pct);
00293 
00294       printf("Point location: visited %lu simplices (%g per slow search, max %lu)\n",
00295           sumsupercav_, (double)sumsupercav_ / (double)nsupercav_, maxsupercav_);
00296       printf("Blindly inserted input %lu times (%lu%%).\n",
00297           (ninputs_ - nwarp_), (100 * (ninputs_ - nwarp_) / ninputs_));
00298       printf("Warped %lu times (%lu%%); max warp distance ratio %g, average %g\n",
00299           nwarp_, (100 * nwarp_ / ninputs_),
00300           maxwarp_, (double)maxwarp_ / (double)nwarp_);
00301       printf("Inserted %lu Steiner points\n", (npoints_ - ninputs_));
00302       printf("Op counts: %lu skinny, %lu crowd(Steiner), %lu crowd(input), %lu sliver, %lu rho\n",
00303           ops.nskinny_, ops.ncrowdSteiner_, ops.ncrowdInput_, ops.nsliver_, ops.nmedium_);
00304       printf("-----------\n");
00305     }
00306   } stats;
00307 #endif
00308 
00309   /***************************************************************************
00310    * A mockup of an STL-like set, in order to allow easily switching
00311    * implementations.
00312    *
00313    * We use the visited flag of the Vertex class to help support the search.
00314    * The assumption is that only one search proceeds at a time.
00315    * When we run out of IDs, we iterate over all the vertices and clear their
00316    * flags.  This is exceedingly rare, and is thus stupidly cheap.
00317    ***************************************************************************/
00318   struct VertexVisitedSet;
00319   friend struct VertexVisitedSet;
00320   struct VertexVisitedSet {
00321     VertexVisitedSet(PointRefiner *pr): searchID_(++pr->searchID_) {
00322       /* If we've wrapped the id count, then clear everyone's flag. */
00323       if (searchID_ == 0) {
00324         BOOST_FOREACH(Vertex *v, pr->meshvertices_) {
00325           v->clearVisited();
00326         }
00327         searchID_ = ++pr->searchID_;
00328       }
00329     }
00330     ~VertexVisitedSet() {
00331     }
00332     struct notpair { bool second; notpair(bool b): second(b) { } };
00333     notpair insert(Vertex *v) {
00334       if (v->visitedFlag() == searchID_) { return false; }
00335       v->setVisited(searchID_);
00336       return true;
00337     }
00338     private:
00339     FlagType searchID_;
00340   };
00341 
00342 
00343   /***************************************************************************
00344    * Initialize the data structures.
00345    ***************************************************************************/
00346   template <class point_iterator>
00347   PointRefiner(const point_iterator& begin, const point_iterator& end, const RefineConstants& consts)
00348   : del_(IncrementalDelaunay::createMeshBox(begin, end, consts.rho)),
00349     rho2_(consts.rhoprime * consts.rhoprime),
00350     k2_(consts.k * consts.k),
00351     fastSearch_(true), //consts.shortcutSearch),
00352     userRho2_(consts.rho * consts.rho), useOffcenters_ (consts.useOffcenters),
00353     sigma_(consts.sigma), sliverGrowth_(consts.sliverGrowth), perturbFactor_(consts.perturbFactor),
00354     outputNodeOrder_(consts.nodeOrder),
00355     traceFile_(NULL) //consts.traceFile)
00356 #ifdef COLLECT_STATS
00357     , stats(del_)
00358 #endif
00359   {
00360     searchID_ = 0;
00361     nuninserted_ = (end-begin);
00362     dprintf("Refining on %lu points\n", (unsigned long)nuninserted_);
00363 
00364 #ifndef NDEBUG
00365     {
00366       printf("Radius/edge %g (%g intermediate)", sqrt(userRho2_), sqrt(rho2_));
00367       if (ambient == 2) {
00368         printf("; off-centers %s\n", useOffcenters_ ? "enabled" : "disabled");
00369       } else {
00370         if (sigma_ == 0.0) {
00371           printf("; slivers ignored\n");
00372         } else {
00373           printf("; sliver quality %g\n", sigma_);
00374         }
00375       }
00376     }
00377 #endif
00378 
00379     initialize(begin, end);
00380   }
00381 
00384   struct CompareVertices {
00385     bool operator()(const Vertex *a, const Vertex *b) const {
00386       return a->id() < b->id();
00387     }
00388   };
00389 
00392   void doRefine() {
00393     // This is the entire SVR algorithm, except for the details.
00394     dprintf("Running SVR\n");
00395     while(!queueEmpty()) {
00396       performQueueOperation();
00397     }
00398     statop(print(sigma_ == 0.0));
00399     assert(isClean());
00400     assert(nuninserted_ == 0);
00401 
00402     switch(outputNodeOrder_) {
00403       case RefineConstants::ID_ORDER:
00404         sort(meshvertices_.begin(), meshvertices_.end(), CompareVertices());
00405         break;
00406       case RefineConstants::INSERTION_ORDER_RENUMBER:
00407         for(size_t i = 0; i < meshvertices_.size(); ++i) {
00408           meshvertices_[i]->setID(i);
00409         }
00410         break;
00411       case RefineConstants::INSERTION_ORDER_NORENUMBER:
00412         break;
00413     }
00414   }
00415 
00416   /***************************************************************************
00417    * Print the mesh.
00418    ***************************************************************************/
00419   void doPrint(FILE *node, FILE *ele) const {
00420     /* print the .node file */
00421     fprintf(node, "%lu %u 0 0\n", (unsigned long)meshvertices_.size(), ambient);
00422     BOOST_FOREACH(Vertex *v, meshvertices_) {
00423       Delaunay::printPoint(v->id(), v->toPoint(), node);
00424     }
00425 
00426     /* print the .ele file */
00427     fprintf(ele, "%lu %u 0\n", (unsigned long)nsimplices_, ambient+1);
00428     DoPrintSimplex dps(ele);
00429     del_->getComplex().dfsBySimplex(dps, del_->getHandle());
00430   }
00431   struct DoPrintSimplex {
00432     size_t n_;
00433     FILE *out_;
00434     DoPrintSimplex(FILE *out): n_(0), out_(out) { }
00435     static bool canEnter(const Simplex&) { return true; }
00436     bool choose(const Simplex& s) {
00437       boost::array<size_t, ambient+1> arr;
00438       for (unsigned i = 0; i <= ambient; ++i) {
00439         arr[i] = s[i]->id();
00440       }
00441       Delaunay::printEle(n_++, arr, out_);
00442       return false;
00443     }
00444   };
00445 
00446   /***************************************************************************
00447    * Initialize the point-location tables and the work queues.
00448    ***************************************************************************/
00449   template <class point_iterator>
00450   void initialize(point_iterator begin, point_iterator end) {
00451     vector<Simplex> simps;
00452     Simplicial::collectSimplices(del_->getComplex(), simps);
00453     nsimplices_ = simps.size();
00454 
00455     dprintf("Starting with %u simplices\n", nsimplices_);
00456 
00457     // Find the mesh vertices, and create handles for each.
00458     VertexVisitedSet visited(this);
00459     BOOST_FOREACH(const Simplex& s, simps) {
00460       BOOST_FOREACH(Vertex *v, s) {
00461         if (!visited.insert(v).second) { continue; }
00462         initVertex(v, s);
00463       }
00464     }
00465     dprintf("Starting with %u vertices\n", (unsigned)meshvertices_.size());
00466 
00467     // Create the uninserted vertices and assign them to the mesh
00468     // Voronoi cells (i.e. the nearest mesh vertex).
00469     size_t id = 0;
00470     BOUNDED_FOREACH(const Point& p, begin, end) {
00471       Uninserted *u = new Uninserted(p, id++);
00472       Vertex *best = bestPoint<Vertex*>(meshvertices_.begin(), meshvertices_.end(), p).first;
00473       assert(best);
00474       best->assign(u);
00475     }
00476     statop(ninputs_ = id);
00477 
00478     // Queue up the work: skinny tets, crowded vertices.
00479     dprintf("Filling queues\n");
00480     addToQueues(simps.begin(), simps.end());
00481     BOOST_FOREACH(Vertex *v, meshvertices_) {
00482       addToQueues(v);
00483     }
00484   }
00485 
00486   /***************************************************************************
00487    * Maintain the points table.
00488    * Now just a call to the vertices.
00489    ***************************************************************************/
00490   void redistributePoints(Vertex *oldv, Vertex *newv) {
00491     oldv->reassign(newv);
00492   }
00493 
00494   /***************************************************************************
00495    * \name Vertex->simplex mapping.
00496    ***************************************************************************/
00497   void initVertex(Vertex *v, const Simplex& s) {
00498     v->initHandle(s);
00499     if (v->isSteiner()) {
00500       // Steiner point 0 is numbered after all the input vertices.
00501       // First, compute which Steiner point this is.  Then add ninputs_.
00502       size_t ninserted = ninputs_ - nuninserted_;
00503       size_t nsteiner = meshvertices_.size() - ninserted;
00504       size_t id = nsteiner + ninputs_;
00505       v->setID(id);
00506     }
00507     meshvertices_.push_back(v);
00508   }
00509   void setHandle(Vertex *v, const Simplex& s) {
00510     v->setHandle(s);
00511   }
00512   const Simplex& getHandle(Vertex *v) const {
00513     return v->getHandle();
00514   }
00515 
00516   /***************************************************************************
00517    * \name Splitting.
00518    *
00519    * Split a simplex.  Either use the candidate point, or try to use
00520    * the circumcenter (perhaps perturbed to avoid slivers), offcenter, or a
00521    * nearby uninserted input point.
00522    *
00523    * Warning: the candidate point, if a Steiner, is now owned by this routine.
00524    * In particular, if it causes a small sliver, I delete the candidate and
00525    * create a new one.
00526    ***************************************************************************/
00527   void split(const Simplex& s, Uninserted *candidate = NULL) {
00528     dprintf("splitting %s\n", s.toString().c_str());
00529     if (!isMember(s)) {
00530       // already removed.
00531       dprintf("  moot\n");
00532       return;
00533     }
00534 
00535     // For slivers, we want to try several times.  This requires:
00536     // (a) stopping after some number of tries.
00537     // (b) checking if new slivers are large, and thus checking our radius.
00538     const double r2_for_sliver = center(s).radius2;
00539     size_t ntries = 0;
00540 
00541     Cavity cavity;
00542     Star star;
00543     Vertex *v;
00544 
00545 makecavity:
00546 
00547     /*
00548      * Pick a vertex to insert.  This will either be the one passed in
00549      * (if we know that it's safe to insert), or one found by splitPoint(.)
00550      * Both of those give us an Uninserted point; promote it to a Vertex.
00551      */
00552     if (candidate && ntries == 0) {
00553       v = promoteToVertex(candidate);
00554     } else {
00555       dprintf("  attempt %u\n", (unsigned)ntries);
00556       v = promoteToVertex(splitPoint(s, ntries > 0));
00557     }
00558 
00559     del_->computeCavity(s, v->toPoint(), cavity);
00560     del_->computeStar(cavity, v, star);
00561     dprintf("  cavity %u, star %u, point %s\n", (unsigned)cavity.size(),
00562         (unsigned)star.size(), v->toString().c_str());
00563 
00564     ntries++;
00565 
00566     // If we care about slivers, check for new small slivers
00567     // and run that again if we found one.
00568     if (nuninserted_ == 0
00569         && v->isSteiner()
00570         && ntries < SLIVER_RETRIES
00571         && hasSmallSliver(r2_for_sliver, star)) {
00572       cavity.clear();
00573       star.clear();
00574       delete v; // v is definitely a Steiner: we just checked.
00575       goto makecavity;
00576     }
00577 
00578     statop(nsliverretry_ += (ntries-1));
00579 
00580     // Finally, commit.
00581     commitStar(cavity, star, v);
00582 
00583     // update the queues.
00584     addToQueues(star.begin(), star.end());
00585     addToQueues(v);
00586   }
00587 
00595   Uninserted * splitPoint(const Simplex& s, bool perturb) {
00596     const CenterRadius& cr = center(s);
00597     const Point& c = cr.center;
00598     double r2 = cr.radius2;
00599     dprintf("  %s, radius %g\n", c.toString().c_str(), sqrt(r2));
00600     statopconst(nlocate_++);
00601 
00602     printQuery(s, c);
00603 
00604     // Try to avoid computing the supercavity, which is very expensive.
00605     if (perturb) {
00606       Point p = c + Point::randPoint(perturbFactor_ * sqrt(r2));
00607       dprintf("  using Steiner perturbed to %s\n", p.toString().c_str());
00608       return new Uninserted(p);
00609     }
00610     if (nuninserted_ == 0) {
00611       Point offc = offcenter(s);
00612       dprintf("  no uninserted; using off-center\n");
00613       return new Uninserted(offc);
00614     }
00615 
00616     // Compute the supercavity
00617     pair<Uninserted*, double> w = findWarpPoint(s, cr);
00618     Uninserted *best = w.first;
00619 
00620     if (best) {
00621       dprintf("  warping to %s (dist %g, ratio %g)\n",
00622           best->toString().c_str(), sqrt(w.second), sqrt(w.second / r2));
00623       return best;
00624     } else {
00625       Point offc = offcenter(s);
00626       dprintf("  using off-center %s\n", offc.toString().c_str());
00627       return new Uninserted(offc);
00628     }
00629   }
00630 
00632   static double dist2(const Point& p, const Point& q) {
00633     return p.dist2(q);
00634   }
00635   template <class V>
00636   static double dist2(const Point& p, const V *v) {
00637     return v->dist2(p);
00638   }
00639   template <class V>
00640   static double dist2(const V *v, const Point& p) {
00641     return v->dist2(p);
00642   }
00643   template <class V, class U>
00644   static double dist2(const V *v, const U *u) {
00645     return u->dist2(v);
00646   }
00647 
00650   template <class iteratorV, class V>
00651   static void bestPoint(iteratorV begin, iteratorV end, const Point& c, V& best, double& mindist2) {
00652     while (begin != end) {
00653       double ambient = dist2(c, *begin);
00654       if (ambient < mindist2) {
00655         best = *begin;
00656         mindist2 = ambient;
00657       }
00658       ++begin;
00659     }
00660   }
00661   template <class V, class iteratorV>
00662   static pair<V, double> bestPoint(iteratorV begin, iteratorV end, const Point& c) {
00663     assert(begin != end);
00664     pair<V, double> p(*begin, dist2(c, *begin));
00665     ++begin;
00666     bestPoint(begin, end, c, p.first, p.second);
00667     return p;
00668   }
00669 
00670   /***************************************************************************
00671    * Search the supercavity for nearby points.  Note that any vertex whose
00672    * Voronoi cell intersects the ball has at least one circumcenter that
00673    * intersects the ball.
00674    *
00675    * We start with a search radius of k * r.
00676    * When we find a point, we shrink the radius: anything we'd see further is
00677    * no longer useful.
00678    * When we find a very close point, we cancel the search.
00679    * Of course, we only search each mesh vertex once.
00680    ***************************************************************************/
00681   struct SCavStruct {
00682     PointRefiner& refine_;
00683     size_t nchecked_;
00684     Point c_;
00685     double threshold2_; // what's good enough? (this is static; may be infinite)
00686     double searchR2_;   // how far to search? (this shrinks)
00687     Uninserted *best_;
00688     VertexVisitedSet visited_; // set of vertices we've seen
00689 
00690     SCavStruct(PointRefiner& r, const CenterRadius& cr)
00691       : refine_(r), visited_(&r) {
00692         c_ = cr.center;
00693         searchR2_ = refine_.k2_ * cr.radius2; // this is the distance to beat
00694         threshold2_ = refine_.fastSearch_ ? std::numeric_limits<double>::max() : (searchR2_ / 4.0); // good enough in kr/2
00695         best_ = NULL;
00696         nchecked_ = 0;
00697       }
00698 
00699     // We can enter if the ball of s intersects the ball defined by (c,r)
00700     // The balls intersect if |pq| < r + r'
00701     // Equivalently, check |pq|^2 < r^2 + r'^2 + 2.0 sqrt(r2r'2)
00702     // It might be worth doing a branch to avoid the sqrt, but probably not.
00703     bool canEnter(const Simplex& s) const {
00704       const CenterRadius& cr = refine_.center(s);
00705       double pq2 = c_.dist2(cr.center);
00706       double r2 = cr.radius2;
00707       double rprime2 = searchR2_;
00708       return pq2 < r2 + rprime2 + 2.0 * sqrt(r2 * rprime2);
00709     }
00710 
00711     bool choose(const Simplex& s) {
00712       nchecked_++;
00713       BOOST_FOREACH(Vertex *v, s) {
00714         if (!visited_.insert(v).second) { continue; } // already checked
00715 
00716         pair<Uninserted*, double> p;
00717         if (threshold2_ == std::numeric_limits<double>::max()) {
00718           p = v->findPoint(c_, searchR2_);
00719         } else {
00720           p = v->findClosest(c_, searchR2_);
00721         }
00722         if (p.first) {
00723           best_ = p.first;
00724           searchR2_ = p.second;
00725           if (searchR2_ < threshold2_) {
00726             return true;
00727           }
00728         }
00729       }
00730       return false;
00731     }
00732   };
00733 
00735   pair<Uninserted*, double> findWarpPoint(const Simplex& s, const CenterRadius& cr) {
00736     SCavStruct finder(*this, cr);
00737     del_->getComplex().bfsBySimplex(finder, s);
00738     statopconst(supercav(finder.nchecked_, finder.searchR2_ / cr.radius2,
00739           finder.best_ == NULL));
00740     return make_pair(finder.best_, finder.searchR2_);
00741   }
00742 
00743   /***************************************************************************
00744    * Commit the star.
00745    * Update all the necessary data structures.
00746    ***************************************************************************/
00747   void commitStar(const Cavity& cavity, Star& star, Vertex *newv) {
00748     printInsert(cavity, newv);
00749 
00750     // Update the mesh.
00751     del_->insertVertex(cavity, star);
00752     initVertex(newv, *star.begin());
00753     nsimplices_ += (star.size() - cavity.size());
00754 
00755     if (newv->isSteiner()) {
00756       // The mesh now owns this vertex, not us.
00757       del_->giveVertexOwnership(newv);
00758     } else {
00759       nuninserted_--;
00760       if (nuninserted_ == 0) {
00761 #ifndef NDEBUG
00762         printf("All input vertices in the mesh; removing slivers, improving quality.\n");
00763 #endif
00764         //crowded_.clear();
00765         while (!crowdedSteiner_.empty()) crowdedSteiner_.pop();
00766         while (!crowdedInput_.empty()) crowdedInput_.pop();
00767       }
00768     }
00769 
00770     // Redistribute the points.
00771     // Note that we need not redistribute points if
00772     // there are none to be distributed.  That keeps
00773     // some handles alive longer than necessary.
00774     // Presumably this is no big deal (presumably cheaper
00775     // than star.size() * (d+1) iterations every time).
00776     if (nuninserted_ > 0) {
00777       VertexVisitedSet vset(this);
00778       /* Ideally we'd iterate over the cavity, but we need
00779          to set new handles.  So we iterate over the star and
00780          avoid touching the new vertex. */
00781       BOOST_FOREACH(const Simplex& s, star) {
00782         BOOST_FOREACH(Vertex *oldv, s) {
00783           if (oldv == newv) { continue; }
00784           if (!vset.insert(oldv).second) { continue; }
00785           redistributePoints(oldv, newv);
00786           setHandle(oldv, s);
00787         }
00788       }
00789     }
00790 
00791     statop(updateTri(cavity.size(), star.size()));
00792   }
00793 
00794   /***************************************************************************
00795    * \name Geometric computations and predicates
00796    ***************************************************************************/
00797   const CenterRadius& center(const Simplex& s) const {
00798     return del_->circumcenter(s);
00799   }
00800   Point offcenter(const Simplex& s) const {
00801     if (useOffcenters_) {
00802       return del_->offCenter(s, userRho2_);
00803     } else {
00804       return center(s).center;
00805     }
00806   }
00807 
00808   bool inSphere(const Simplex& s, const Point& p) const {
00809     return del_->inSphereAffine(s, p);
00810   }
00811   bool inSimplex(const Simplex& s, const Point& p) const {
00812     return del_->inSimplexAffine(s, p);
00813   }
00814   bool inSphere(const Simplex& s, Vertex *v) const {
00815     return del_->inSphereAffine(s, v->toPoint());
00816   }
00817   bool inSimplex(const Simplex& s, Vertex *v) const {
00818     return del_->inSimplexAffine(s, v->toPoint());
00819   }
00820 
00821   bool isMember(const Simplex& s) const {
00822     return del_->getComplex().isMember(s);
00823   }
00824 
00825 
00826   enum Skinnyness {
00827     FAT = 0,
00828     MEDIUM,
00829     SKINNY
00830   };
00831 
00832   Skinnyness computeSkinniness(const Simplex& s) const {
00833     double re2 = del_->radiusEdge2(s);
00834     if (re2 > rho2_) {
00835       dprintf("  R/e = %g ==> skinny: %s\n", sqrt(re2), s.toString().c_str());
00836       return SKINNY;
00837     } else if (re2 > userRho2_) {
00838       dprintf("  R/e = %g ==> moderate skinny: %s\n", sqrt(re2), s.toString().c_str());
00839       return MEDIUM;
00840     } else {
00841       return FAT;
00842     }
00843   }
00844 
00845   bool isCrowded(const Vertex *v) const {
00846     if (nuninserted_ == 0) {
00847       return false;
00848     } else {
00849       return v->isCrowded();
00850     }
00851   }
00852 
00853   bool isSliver(const Simplex& s) const {
00854     if (sigma_ == 0.0) return false;
00855     if (computeSkinniness(s) != FAT) {
00856       return false;
00857     }
00858     double Rr = del_->radiusRadius(s);
00859     if (Rr > sigma_) {
00860       dprintf("  R/r = %g ==> sliver: %s\n", Rr, s.toString().c_str());
00861     }
00862     return Rr > sigma_; // TODO!!
00863   }
00864 
00866   bool hasSmallSliver(double r2, const Star& star) const {
00867     if (sigma_ == 0.0) return false;
00868     BOOST_FOREACH(const Simplex& s, star) {
00869       if (center(s).radius2 < sliverGrowth_ * r2) {
00870         if (isSliver(s)) {
00871           return true;
00872         }
00873       }
00874     }
00875     return false;
00876   }
00877 
00878   // for debugging at the end, to make sure we didn't miss something
00879   struct FindBad {
00880     const PointRefiner& refine_;
00881     FindBad( const PointRefiner& r  ): refine_(r) { }
00882     static bool canEnter(const Simplex&) { return true; }
00883     bool choose(const Simplex& s) {
00884       Skinnyness sness = refine_.computeSkinniness(s);
00885       bool sliver = refine_.isSliver(s);
00886       if (sness != FAT) {
00887         printf("skinny: %s\n", s.toString().c_str());
00888       }
00889       if (sliver) {
00890         printf("sliver: %s\n", s.toString().c_str());
00891       }
00892       bool crowd = false;
00893       BOOST_FOREACH(Vertex *v, s) {
00894         if (refine_.isCrowded(v)) {
00895           crowd = true;
00896           printf("crowded: %s\n", v->toString().c_str());
00897         }
00898       }
00899       return (sness!=FAT) || sliver || crowd;
00900     }
00901   };
00902 
00903   bool isClean() const {
00904     FindBad fb(*this);
00905     return !del_->getComplex().dfsBySimplex(fb, del_->getHandle());
00906   }
00907 
00908   /***************************************************************************
00909    * \name Queue handling
00910    ***************************************************************************/
00911   bool queueEmpty() const {
00912     return skinny_.empty()
00913       && crowdedSteiner_.empty()
00914       && crowdedInput_.empty()
00915       && sliver_.empty()
00916       && moderateSkinny_.empty();
00917   }
00918 
00919   struct FindCrowdedSimplex {
00920     Vertex *v_;
00921     Uninserted *u_;
00922     IncrementalDelaunay *del_;
00923     FindCrowdedSimplex (Vertex *v, Uninserted *u, IncrementalDelaunay *del): v_(v), u_(u), del_(del) { }
00924     bool canEnter(const Simplex& s) const { return s.has(v_); }
00925     bool choose(const Simplex& s) const { return del_->inSphereAffine(s, u_->toPoint()); }
00926   };
00927 
00928   void performQueueOperation() {
00929     if (!skinny_.empty()) {
00930       Simplex s = skinny_.top();
00931       skinny_.pop();
00932       dprintf("popped skinny: %s\n", s.toString().c_str());
00933       assert(isMember(s));
00934       statop(ops.nskinny_++);
00935       split(s);
00936     }
00937     else if (!crowdedSteiner_.empty()) {
00938       Vertex *v = crowdedSteiner_.top();
00939       // do NOT pop -- we're likely to still be crowded!
00940       dprintf("popped crowded: %s\n", v->toString().c_str());
00941       assert(isCrowded(v));
00942       assert(v->isSteiner());
00943       statop(ops.ncrowdSteiner_++);
00944 
00945       /* Pick the farthest point from v */
00946       Uninserted *u = v->getFarPoint();
00947 
00948       /* Find a simplex around v that has u in its circumball. */
00949       FindCrowdedSimplex fcs(v, u, del_);
00950       Simplex s = *del_->getComplex().findSimplex(fcs, getHandle(v));
00951 
00952       /* We know already that u is safe to insert -- else we'd have warped to u */
00953       split(s, u);
00954     }
00955     else if (!crowdedInput_.empty()) {
00956       Vertex *v = crowdedInput_.top();
00957       // do NOT pop -- we're likely to still be crowded!
00958       dprintf("popped crowded: %s\n", v->toString().c_str());
00959       assert(isCrowded(v));
00960       assert(!v->isSteiner());
00961       statop(ops.ncrowdInput_++);
00962 
00963       /* Pick the farthest point from v */
00964       Uninserted *u = v->getFarPoint();
00965 
00966       /* Find a simplex around v that has u in its circumball. */
00967       FindCrowdedSimplex fcs(v, u, del_);
00968       Simplex s = *del_->getComplex().findSimplex(fcs, getHandle(v));
00969 
00970       /* u may not be safe to insert, so find an appropriate warp point. */
00971       split(s);
00972     }
00973     else if (!sliver_.empty()) {
00974       Simplex s = sliver_.top();
00975       sliver_.pop();
00976       dprintf("popped sliver: %s\n", s.toString().c_str());
00977       assert(isMember(s));
00978       statop(ops.nsliver_++);
00979       split(s);
00980     }
00981     else if (!moderateSkinny_.empty()) {
00982       Simplex s = moderateSkinny_.top();
00983       moderateSkinny_.pop();
00984       dprintf("popped moderate skinny: %s\n", s.toString().c_str());
00985       assert(isMember(s));
00986       statop(ops.nmedium_++);
00987 
00988       /* We know there are no uninserted points left, because moderate-skinnies are
00989          processed after all crowding.  Therefore, just blindly insert the offcenter
00990          (blindly except for slivers). */
00991       assert(nuninserted_ == 0);
00992 
00993       Uninserted *offc = new Uninserted(offcenter(s));
00994       split(s, offc);
00995     }
00996     else {
00997       assert(0 && "queue is empty");
00998     }
00999   }
01000 
01001   template <class iteratorS>
01002   void addToQueues(iteratorS begin, iteratorS end) {
01003     // Clean up the queues.  This allows the complex to reap simplices,
01004     // and it allows our queues to do so also.
01005     while(!skinny_.empty() && !isMember(skinny_.top())) { skinny_.pop(); }
01006     while(!sliver_.empty() && !isMember(sliver_.top())) { sliver_.pop(); }
01007     while(!moderateSkinny_.empty() && !isMember(moderateSkinny_.top())) { moderateSkinny_.pop(); }
01008 
01009     BOUNDED_FOREACH(const Simplex& s, begin, end) {
01010       Skinnyness sness = computeSkinniness(s);
01011       if (sness == SKINNY) {
01012         dprintf("push skinny: %s\n", s.toString().c_str());
01013         skinny_.push(center(s).radius2, s);
01014         statmax(maxRe_, sqrt(del_->radiusEdge2(s)));
01015       }
01016       // else is not strictly necessary, but avoids
01017       // duplicate insertions.
01018       else if (isSliver(s)) {
01019         dprintf("push sliver: %s\n", s.toString().c_str());
01020         sliver_.push(center(s).radius2, s);
01021         statop(nslivers_++);
01022         statmax(maxRr_, del_->radiusRadius(s));
01023       }
01024       else if (sness == MEDIUM) {
01025         dprintf("push moderate skinny: %s\n", s.toString().c_str());
01026         moderateSkinny_.push(center(s).radius2, s);
01027         statmax(maxRe_, sqrt(del_->radiusEdge2(s)));
01028       }
01029       else assert(sness == FAT);
01030     }
01031   }
01032 
01033   void addToQueues(Vertex *v) {
01034     while(!crowdedSteiner_.empty() && !isCrowded(crowdedSteiner_.top())) { crowdedSteiner_.pop(); }
01035     while(!crowdedInput_.empty() && !isCrowded(crowdedInput_.top())) { crowdedInput_.pop(); }
01036     if (isCrowded(v)) {
01037       if (v->isSteiner()) {
01038         crowdedSteiner_.push(v);
01039       } else {
01040         crowdedInput_.push(v);
01041       }
01042     }
01043   }
01044 
01045   /***************************************************************************
01046    * FIN.
01047    ***************************************************************************/
01048 #undef dprintf
01049 }; // end class
01050 } // end namespace
01051 
01052 #endif

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