00001 #ifndef PointRefiner_HEADER
00002 #define PointRefiner_HEADER
00003
00004
00005
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>
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
00037
00038
00039
00040
00041 template <unsigned ambient>
00042 struct PointRefiner : public MeshRefiner {
00043 typedef Geometry::Point<ambient> Point;
00044
00045
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
00055
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
00071
00072
00073
00074
00075
00076
00077
00078 template <class point_iterator>
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
00096
00097 virtual void refine() {
00098 doRefine();
00099 }
00100
00101
00102
00103
00104 virtual void printToNodeEle(FILE *node, FILE *ele) const {
00105 doPrint(node, ele);
00106 }
00107
00108
00109
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
00121
00122
00123
00124
00125
00126
00127
00128
00129
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
00150
00151 private:
00152 IncrementalDelaunay *del_;
00153
00154
00155
00156
00157
00158
00159
00160
00161
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_;
00184 const double k2_;
00185 const bool fastSearch_;
00186 const double userRho2_;
00187 const bool useOffcenters_;
00188 const double sigma_;
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
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
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
00228 unsigned long nlocate_;
00229 unsigned long nsupercav_;
00230 unsigned long sumsupercav_;
00231 unsigned long maxsupercav_;
00232 unsigned long nwarp_;
00233 double sumwarp_;
00234 double maxwarp_;
00235
00236
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
00284
00285
00286
00287
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
00311
00312
00313
00314
00315
00316
00317
00318 struct VertexVisitedSet;
00319 friend struct VertexVisitedSet;
00320 struct VertexVisitedSet {
00321 VertexVisitedSet(PointRefiner *pr): searchID_(++pr->searchID_) {
00322
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
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),
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)
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
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
00418
00419 void doPrint(FILE *node, FILE *ele) const {
00420
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
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
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
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
00468
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
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
00488
00489
00490 void redistributePoints(Vertex *oldv, Vertex *newv) {
00491 oldv->reassign(newv);
00492 }
00493
00494
00495
00496
00497 void initVertex(Vertex *v, const Simplex& s) {
00498 v->initHandle(s);
00499 if (v->isSteiner()) {
00500
00501
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
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527 void split(const Simplex& s, Uninserted *candidate = NULL) {
00528 dprintf("splitting %s\n", s.toString().c_str());
00529 if (!isMember(s)) {
00530
00531 dprintf(" moot\n");
00532 return;
00533 }
00534
00535
00536
00537
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
00549
00550
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
00567
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;
00575 goto makecavity;
00576 }
00577
00578 statop(nsliverretry_ += (ntries-1));
00579
00580
00581 commitStar(cavity, star, v);
00582
00583
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
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
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
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 struct SCavStruct {
00682 PointRefiner& refine_;
00683 size_t nchecked_;
00684 Point c_;
00685 double threshold2_;
00686 double searchR2_;
00687 Uninserted *best_;
00688 VertexVisitedSet visited_;
00689
00690 SCavStruct(PointRefiner& r, const CenterRadius& cr)
00691 : refine_(r), visited_(&r) {
00692 c_ = cr.center;
00693 searchR2_ = refine_.k2_ * cr.radius2;
00694 threshold2_ = refine_.fastSearch_ ? std::numeric_limits<double>::max() : (searchR2_ / 4.0);
00695 best_ = NULL;
00696 nchecked_ = 0;
00697 }
00698
00699
00700
00701
00702
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; }
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
00745
00746
00747 void commitStar(const Cavity& cavity, Star& star, Vertex *newv) {
00748 printInsert(cavity, newv);
00749
00750
00751 del_->insertVertex(cavity, star);
00752 initVertex(newv, *star.begin());
00753 nsimplices_ += (star.size() - cavity.size());
00754
00755 if (newv->isSteiner()) {
00756
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
00765 while (!crowdedSteiner_.empty()) crowdedSteiner_.pop();
00766 while (!crowdedInput_.empty()) crowdedInput_.pop();
00767 }
00768 }
00769
00770
00771
00772
00773
00774
00775
00776 if (nuninserted_ > 0) {
00777 VertexVisitedSet vset(this);
00778
00779
00780
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
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_;
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
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
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
00940 dprintf("popped crowded: %s\n", v->toString().c_str());
00941 assert(isCrowded(v));
00942 assert(v->isSteiner());
00943 statop(ops.ncrowdSteiner_++);
00944
00945
00946 Uninserted *u = v->getFarPoint();
00947
00948
00949 FindCrowdedSimplex fcs(v, u, del_);
00950 Simplex s = *del_->getComplex().findSimplex(fcs, getHandle(v));
00951
00952
00953 split(s, u);
00954 }
00955 else if (!crowdedInput_.empty()) {
00956 Vertex *v = crowdedInput_.top();
00957
00958 dprintf("popped crowded: %s\n", v->toString().c_str());
00959 assert(isCrowded(v));
00960 assert(!v->isSteiner());
00961 statop(ops.ncrowdInput_++);
00962
00963
00964 Uninserted *u = v->getFarPoint();
00965
00966
00967 FindCrowdedSimplex fcs(v, u, del_);
00968 Simplex s = *del_->getComplex().findSimplex(fcs, getHandle(v));
00969
00970
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
00989
00990
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
01004
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
01017
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
01047
01048 #undef dprintf
01049 };
01050 }
01051
01052 #endif