00001 #ifndef IncrementalDelaunay_HEADER
00002 #define IncrementalDelaunay_HEADER
00003
00004
00005
00006
00007
00008 #include <boost/array.hpp>
00009 #include <geometry/BoundingBox.h>
00010 #include <geometry/Circles.h>
00011 #include <geometry/Point.h>
00012 #include <geometry/PointConvert.h>
00013 #include <geometry/ProjectionPlane.h>
00014 #include <geometry/predicates.h>
00015 #include <topology/SimplicialComplex.h>
00016 #include <topology/SimplicialHelpers.h>
00017 #include <geometry/VertexToPointIterator.h>
00018 #include "SimplexCenter.h"
00019
00021 #define DEBUG_DELAUNAY 0
00022 #if 0
00023 #define dprintf(...) printf(__VA_ARGS__);
00024 #else
00025 #define dprintf(...)
00026 #endif
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 template <unsigned ambient, unsigned topological,
00045 class Vertex_, class SimplexData = void,
00046 class VertexPrinter = typename Vertex_::Printer>
00047 class IncrementalDelaunay {
00048 public:
00049 typedef Geometry::Point<ambient> Point;
00050 typedef Geometry::Point<topological> PPoint;
00051 typedef Geometry::ProjectionPlane<ambient, topological> ProjectionPlane;
00052 typedef Geometry::BoundingBox<topological> BoundingBox;
00053 typedef Geometry::CenterRadius<ambient> CenterRadius;
00054
00055 typedef Vertex_ Vertex;
00056 private:
00057 typedef hudson::PayloadBucket<CenterRadius, SimplexData> SimplexStorage;
00058
00059 public:
00060 typedef SimplicialComplex<topological, Vertex, SimplexStorage, VertexPrinter> Complex;
00061 typedef typename Complex::Simplex Simplex;
00062 typedef typename Complex::OSimplex OSimplex;
00063 typedef typename Complex::Cavity Cavity;
00064 typedef typename Complex::Star Star;
00065
00066 private:
00067 Complex complex_;
00068 ProjectionPlane projectionPlane_;
00069 vector<Vertex*> myVertices_;
00070
00071 public:
00074 ~IncrementalDelaunay() {
00075
00076 BOOST_FOREACH(Vertex *v, myVertices_) {
00077 delete v;
00078 }
00079
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00096 public:
00100 IncrementalDelaunay(const vector<Vertex*>& verts,
00101 const vector<vector<size_t> >& indices,
00102 const ProjectionPlane& pplane)
00103 : complex_(verts, indices), projectionPlane_(pplane)
00104 {
00105 if (!isOriented(getHandle())) {
00106 complex_.flipOrientation();
00107 }
00108 assert(isOriented());
00109 }
00110
00111 public:
00112 static IncrementalDelaunay *fromSimplex(const vector<Vertex*>& verts, const ProjectionPlane& plane) {
00113 assert(verts.size() == topological + 1);
00114 vector<size_t> thesimplex;
00115 thesimplex.resize(topological + 1);
00116 for(unsigned i = 0; i < topological + 1; i++) {
00117 thesimplex[i] = i;
00118 }
00119 vector<vector<size_t> > elements;
00120 elements.push_back(thesimplex);
00121 return new IncrementalDelaunay(verts, elements, plane);
00122 }
00123
00124 static IncrementalDelaunay *fromSimplex(const vector<Vertex*>& verts) {
00125 ProjectionPlane plane (verts.begin(), verts.end(), true);
00126 return fromSimplex(verts, plane);
00127 }
00129
00130
00131
00132
00133
00134
00135
00136
00137 typedef typename hudson::Bucket<SimplexData>::reference data_ref;
00138 typedef typename hudson::Bucket<SimplexData>::const_reference data_const_ref;
00139 data_ref getDataRW(const Simplex& s) {
00140 return complex_.getDataRW(s).payload_ref();
00141 }
00142
00144 data_const_ref getData(const Simplex& s) const {
00145 return complex_.getData(s).payload_cref();
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 public:
00159 static unsigned ambientDimension() {
00160 return ambient;
00161 }
00162 static unsigned topologicalDimension() {
00163 return topological;
00164 }
00165
00166 const ProjectionPlane& getPlane() const {
00167 return projectionPlane_;
00168 }
00169
00170
00171
00172
00174 private:
00176 CenterRadius
00177 do_circumcenter(const Simplex& simplex) const {
00178 assert(isOriented(simplex));
00179 return SimplexCenter<Simplex, ambient, topological>()(simplex);
00180 }
00181
00182 public:
00189 const CenterRadius&
00190 circumcenter(const Simplex& s) const {
00191
00192 CenterRadius& cr = const_cast<Complex&>(complex_).getDataRW(s).data;
00193 if (topological != 0 && cr.radius2 == 0.0) {
00194 cr = do_circumcenter(s);
00195 }
00196 return cr;
00197 }
00198
00199
00200
00201
00202
00203 public:
00204 Point offCenter (const Simplex& s, double rho2) const {
00205
00206 if (topological != 2) {
00207 return circumcenter(s).center;
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 rho2 -= 1e-8;
00224
00225 pair<unsigned, unsigned> e = shortestEdge(s);
00226 const CenterRadius& cr = circumcenter(s);
00227 Point a = s[e.first]->toPoint();
00228 Point b = s[e.second]->toPoint();
00229 Point midpoint = (a+b) / 2.0;
00230 double elen2 = (a-b).norm2();
00231 Point centerVect = cr.center - midpoint;
00232 double norm2 = centerVect.norm2();
00233
00234 double x2 = 2.0 * elen2 * (rho2 - 0.125 + sqrt(rho2 * (rho2 - 0.25)));
00235
00236 if (norm2 < x2) {
00237 dprintf("off-center rejected: %g < %g\n", sqrt(norm2), sqrt(x2));
00238 return cr.center;
00239 } else {
00240 Point offcenter = centerVect * sqrt(x2 / norm2);
00241 dprintf("off-center accepted: %s rather than %s\n",
00242 Point(offcenter + midpoint).toString().c_str(),
00243 cr.center.toString().c_str());
00244 return offcenter + midpoint;
00245 }
00246 }
00247
00248
00249
00250
00251
00252 public:
00253 static pair<unsigned, unsigned> shortestEdge (const Simplex& s) {
00254 pair<unsigned, unsigned> best = make_pair(0,1);
00255 double bestlen2 = s[0]->toPoint().dist2(s[1]->toPoint());
00256
00257 for(unsigned i = 0; i < topological; ++i) {
00258 Point p = s[i]->toPoint();
00259 for(unsigned j = i+1; j <= topological; ++j) {
00260 Point q = s[j]->toPoint();
00261 double len2 = p.dist2(q);
00262 if (len2 < bestlen2) {
00263 bestlen2 = len2;
00264 best = make_pair(i, j);
00265 }
00266 }
00267 }
00268 return best;
00269 }
00270
00272 static double edgeLen2(const Simplex& s, const pair<unsigned, unsigned>& e) {
00273 return s[e.first]->toPoint().dist2(s[e.second]->toPoint());
00274 }
00275 static double edgeLen2(const Simplex& s) {
00276
00277 double e2 = (s[0]->toPoint() - s[1]->toPoint()).norm2();
00278 for(unsigned i = 0; i < topological; ++i) {
00279 Point p = s[i]->toPoint();
00280 for(unsigned j = i+1; j <= topological; ++j) {
00281 Point q = s[j]->toPoint();
00282 e2 = std::min(e2, (p-q).norm2());
00283 }
00284 }
00285 return e2;
00286 }
00287
00288
00289
00290
00291 public:
00292
00293 double radiusEdge2 (const Simplex& s) const {
00294 double r2 = circumcenter(s).radius2;
00295 double e2 = edgeLen2(s);
00296 assert(e2 > 0.0);
00297 return r2/e2;
00298 }
00299
00300 double volume(const Simplex& simplex) const {
00301 if (topological == ambient) {
00302 switch(ambient) {
00303 case 1: return fabs(simplex[1]->toPoint()[0] - simplex[0]->toPoint()[0]);
00304 case 2: return fabs(orient2d(simplex[0]->x(), simplex[1]->x(), simplex[2]->x())) / 2.0;
00305 case 3: return fabs(orient3d(simplex[0]->x(), simplex[1]->x(), simplex[2]->x(), simplex[3]->x())) / 6.0;
00306 default: assert(0);
00307 }
00308 } else {
00309 boost::array<PPoint, topological+1> s;
00310 projectSimplex(s, simplex);
00311 switch(topological) {
00312 case 1: return fabs(s[1][0] - s[0][0]);
00313 case 2: return fabs(orient2d(s[0].data(), s[1].data(), s[2].data())) / 2.0;
00314 case 3: return fabs(orient3d(s[0].data(), s[1].data(), s[2].data(), s[3].data())) / 6.0;
00315 default: assert(0);
00316 }
00317 }
00318 }
00319
00320
00321 double computeSigma (const Simplex& s) const {
00322 assert(ambient == 3);
00323 double V = volume(s);
00324 double e2 = edgeLen2(s);
00325 assert(e2 > 0.0);
00326 double e = sqrt(e2);
00327 double e3 = e*e*e;
00328 return V / e3;
00329 }
00330
00331
00332 double radiusRadius (const Simplex& simplex) const {
00333 double r2 = circumcenter(simplex).radius2;
00334
00335 switch(topological) {
00336 case 1:
00337 return 1.0;
00338 case 2:
00339 {
00340
00341
00342
00343
00344 double a2 = (simplex[0]->toPoint() - simplex[1]->toPoint()).norm2();
00345 double b2 = (simplex[0]->toPoint() - simplex[2]->toPoint()).norm2();
00346 double c2 = (simplex[1]->toPoint() - simplex[2]->toPoint()).norm2();
00347 double a = sqrt(a2);
00348 double b = sqrt(b2);
00349 double c = sqrt(c2);
00350
00351 double s = (a + b + c) / 2.0;
00352 double A = sqrt(s*(s-a)*(s-b)*(s-c));
00353
00354
00355 double rin = 2.0 * A / (a+b+c);
00356 return sqrt(r2) / rin;
00357 }
00358 case 3:
00359 {
00360
00361 double V6 = fabs(orient3d(simplex[0]->x(), simplex[1]->x(), simplex[2]->x(), simplex[3]->x()));
00362 double numerator = V6 / 2.0;
00363 double denominator = 0.0;
00364 OSimplex os = getComplex().orientSimplex(simplex);
00365 for (unsigned i = 0; i <= topological; ++i) {
00366 denominator += triangleArea(getComplex().getFace(i, os));
00367 }
00368 double rin = numerator / denominator;
00369 return sqrt(r2) / rin;
00370 }
00371 default:
00372 assert(0);
00373 return 0.0;
00374 }
00375 }
00376
00381 double minDihedral (const Simplex& simplex) const {
00382 assert(topological == 3);
00383 assert(ambient == 3);
00384 const Point& a = simplex[0]->toPoint();
00385 const Point& b = simplex[1]->toPoint();
00386 const Point& c = simplex[2]->toPoint();
00387 const Point& d = simplex[3]->toPoint();
00388
00389 Point ad = a - d;
00390 Point ab = a - b;
00391 Point ac = a - c;
00392 Point bd = b - d;
00393 Point bc = b - c;
00394 Point cd = c - d;
00395
00396 Point na = crossProduct(cd,bd);
00397 Point nb = crossProduct(ad,cd);
00398 Point nc = crossProduct(bd,ad);
00399 Point nd = crossProduct(ac,bc);
00400
00401 double V6 = orient3d(a.data(), b.data(), c.data(), d.data());
00402
00403 double parts[][2] = {
00404 { sqrt(ab.norm2()) , nc.dot(nd) },
00405 { sqrt(ac.norm2()) , nb.dot(nd) },
00406 { sqrt(ad.norm2()) , nb.dot(nc) },
00407 { sqrt(bc.norm2()) , na.dot(nd) },
00408 { sqrt(bd.norm2()) , na.dot(nc) },
00409 { sqrt(cd.norm2()) , na.dot(nb) }
00410 };
00411 const unsigned n = sizeof(parts)/sizeof(*parts);
00412 boost::array<double, n> theta;
00413 double worst = 1e9;
00414 for (unsigned i = 0; i < n; ++i) {
00415 if (parts[i][1] == 0) {
00416
00417 theta[i] = M_PI / 2.0;
00418 } else if (parts[i][1] < 0) {
00419
00420 theta[i] = fabs(atan(V6 * parts[i][0] / parts[i][1]));
00421 } else {
00422
00423 theta[i] = fabs(atan(V6 * parts[i][0] / parts[i][1])) + M_PI;
00424 }
00425 if (theta[i] < worst) worst = theta[i];
00426 }
00427 assert(worst > 0.0);
00428 return worst;
00429 }
00430
00434 double triangleArea (const OSimplex& simplex) const {
00435 assert(topological >= 2);
00436
00437
00438 double a = sqrt((simplex[0]->toPoint() - simplex[1]->toPoint()).norm2());
00439 double b = sqrt((simplex[0]->toPoint() - simplex[2]->toPoint()).norm2());
00440 double c = sqrt((simplex[1]->toPoint() - simplex[2]->toPoint()).norm2());
00441
00442 double s = (a + b + c) / 2.0;
00443 double A = sqrt(s*(s-a)*(s-b)*(s-c));
00444 return A;
00445 }
00446
00447
00448
00449
00450
00451 void projectSimplex(boost::array<PPoint, topological+1>& s, const Simplex& simplex) const {
00452 for(unsigned i = 0; i <= topological; i++) {
00453 s[i] = projectionPlane_.project(simplex[i]->toPoint());
00454 }
00455 }
00457
00458
00459
00460
00461
00462
00464
00465
00466
00467
00468 public:
00469 bool
00470 inSphere(const Simplex& s, const Point& p) const {
00471 assert(isOriented(s));
00472 if(ambient == topological) {
00473 BOOST_STATIC_ASSERT(topological > 1);
00474
00475 switch(ambient) {
00476 case 2:
00477
00478 return incircle(s[0]->x(), s[1]->x(), s[2]->x(), p.data()) > 0.0;
00479
00480 case 3:
00481
00482 return insphere(s[0]->x(), s[1]->x(), s[2]->x(), s[3]->x(), p.data()) < 0.0;
00483
00484 default:
00485 ;
00486
00487 }
00488 }
00489
00490
00491 CenterRadius cr = circumcenter(s);
00492 double cp2 = (cr.center - p).norm2();
00493 return cp2 < cr.radius2;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 public:
00506 bool
00507 inSphereAffine(const Simplex& simplex, const Point& p) const {
00508 if (topological == ambient || topological > 3) {
00509
00510
00511 return inSphere(simplex, p);
00512 }
00513 boost::array<PPoint, topological+1> s;
00514 projectSimplex(s, simplex);
00515 PPoint pp = projectionPlane_.project(p);
00516 BOOST_STATIC_ASSERT(topological == 2 || topological == 3);
00517 switch(topological) {
00518 case 2:
00519 return incircle(s[0].data(), s[1].data(), s[2].data(), pp.data()) > 0.0;
00520
00521 case 3:
00522 return insphere(s[0].data(), s[1].data(), s[2].data(), s[3].data(), pp.data()) < 0.0;
00523 }
00524
00525 assert(0);
00526 }
00527
00528
00529
00530
00531
00532
00533
00534 bool
00535 inSimplexAffine(const Simplex& simplex, const Point& p) const {
00536 if (ambient == topological) {
00537 return inSimplex(simplex, p);
00538 }
00539
00540 PPoint pp = projectionPlane_.project(p);
00541 boost::array<PPoint, topological+1> s;
00542 projectSimplex(s, simplex);
00543 switch(topological) {
00544 case 1:
00545
00546 return (pp[0] >= s[0][0] && pp[0] <= s[1][0])
00547 || (pp[0] >= s[1][0] && pp[0] <= s[0][0]);
00548 case 2:
00549
00550
00551 return (orient2d(s[0].data(), s[1].data(), pp.data()) >= 0.0)
00552 && (orient2d(s[1].data(), s[2].data(), pp.data()) >= 0.0)
00553 && (orient2d(s[2].data(), s[0].data(), pp.data()) >= 0.0);
00554 case 3:
00555
00556
00557 return (orient3d(s[0].data(), s[1].data(), s[2].data(), pp.data()) <= 0.0)
00558 && (orient3d(s[0].data(), s[3].data(), s[1].data(), pp.data()) <= 0.0)
00559 && (orient3d(s[0].data(), s[2].data(), s[3].data(), pp.data()) <= 0.0)
00560 && (orient3d(s[3].data(), s[2].data(), s[1].data(), pp.data()) <= 0.0);
00561 default:
00562 assert(0);
00563 return false;
00564 }
00565 }
00566
00574 private:
00575 bool
00576 inSimplex(const Simplex& s, const Point& p) const {
00577 assert(ambient == topological);
00578 switch(topological) {
00579 case 1:
00580
00581 return (p[0] >= s[0]->toPoint()[0] && p[0] <= s[1]->toPoint()[0])
00582 || (p[0] >= s[1]->toPoint()[0] && p[0] <= s[0]->toPoint()[0]);
00583 case 2:
00584
00585
00586 return (orient2d(s[0]->x(), s[1]->x(), p.data()) >= 0.0)
00587 && (orient2d(s[1]->x(), s[2]->x(), p.data()) >= 0.0)
00588 && (orient2d(s[2]->x(), s[0]->x(), p.data()) >= 0.0);
00589 case 3:
00590
00591
00592 return (orient3d(s[0]->x(), s[1]->x(), s[2]->x(), p.data()) <= 0.0)
00593 && (orient3d(s[0]->x(), s[3]->x(), s[1]->x(), p.data()) <= 0.0)
00594 && (orient3d(s[0]->x(), s[2]->x(), s[3]->x(), p.data()) <= 0.0)
00595 && (orient3d(s[3]->x(), s[2]->x(), s[1]->x(), p.data()) <= 0.0);
00596 default:
00597 assert(0);
00598 return false;
00599 }
00600 }
00601
00602
00603
00604
00605
00606
00607 private:
00608 bool
00609 isOriented_(const Simplex& simplex) const {
00610 if (topological == 1) return true;
00611 boost::array<PPoint, topological+1> s;
00612 projectSimplex(s, simplex);
00613 switch (topological) {
00614 case 1:
00615 return s[0][0] < s[1][0];
00616 case 2:
00617
00618 return orient2d(s[0].data(), s[1].data(), s[2].data()) > 0.0;
00619 case 3:
00620
00621 return orient3d(s[0].data(), s[1].data(), s[2].data(), s[3].data()) < 0.0;
00622 default:
00623 assert(0);
00624 return false;
00625 }
00626 }
00627 public:
00628 bool
00629 isOriented(const Simplex& simplex) const {
00630 bool b = isOriented_(simplex);
00631 #if DEBUG_DELAUNAY
00632 if (!b) {
00633 boost::array<PPoint, topological+1> s;
00634 projectSimplex(s, simplex);
00635 printf("Unoriented simplex: %s\n", simplex.toString().c_str());
00636 printf("Projects to: ");
00637 BOOST_FOREACH(const PPoint& p, s) {
00638 printf(" %s ", p.toString().c_str());
00639 }
00640 printf("\n");
00641 }
00642 #endif
00643 return b;
00644 }
00645
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 private:
00664 struct computeCavityStruct {
00665 const IncrementalDelaunay& del;
00666
00667 Cavity& cavity;
00668 const Point& p;
00669 computeCavityStruct(const IncrementalDelaunay& del, Cavity& cavity, const Point& p)
00670 : del(del), cavity(cavity), p(p) { }
00671 bool canEnter(const Simplex& s) const {
00672 bool b = del.inSphereAffine(s, p);
00673 dprintf("Considering %s: %s\n", s.toString().c_str(), b ? "insphere" : "out");
00674 return b;
00675 }
00676 bool choose(const Simplex& s) { cavity.add(s); return false; }
00677 };
00678
00683 struct ExtendedCavityStruct {
00684 const IncrementalDelaunay& del;
00685 Cavity& cavity;
00686 vector<Simplex>& neighbours;
00687 const Point& p;
00688 ExtendedCavityStruct(const IncrementalDelaunay& dd, Cavity& cav, vector<Simplex>& neigh, const Point& pp)
00689 : del(dd), cavity(cav), neighbours(neigh), p(pp) { }
00690 bool canEnter(const Simplex& s) {
00691 bool b = del.inSphereAffine(s, p);
00692 if (b) {
00693 cavity.add(s);
00694 } else {
00695 neighbours.push_back(s);
00696 }
00697 dprintf("Considering %s: %s\n", s.toString().c_str(), b ? "insphere" : "out");
00698 return b;
00699 }
00700 static bool choose(const Simplex&) { return false; }
00701 };
00702 public:
00703
00711 void computeCavity(const Simplex& s, const Point& p, Cavity& cavity, bool append = false) const {
00712 #ifndef NDEBUG
00713 if (!inSphereAffine(s, p)) {
00714 fprintf(stderr,
00715 "error: %s is not in the circumsphere of %s\n",
00716 p.toString().c_str(), s.toString().c_str());
00717 if (circumcenter(s).radius2 < 1e-8) {
00718 fprintf(stderr, "error: maybe there's too much refinement here?\n");
00719 }
00720 assert(inSphereAffine(s, p));
00721 }
00722 #endif
00723 if (!append) { assert(cavity.empty()); }
00724 computeCavityStruct dat(*this, cavity, p);
00725 complex_.dfsBySimplex(dat, s);
00726 }
00727
00739 void computeCavity(const Simplex& s, const Point& p, Cavity& cavity, vector<Simplex>& neighbours,
00740 bool append = false) const {
00741 assert(inSphereAffine(s, p));
00742 if (!append) {
00743 assert(cavity.empty());
00744 assert(neighbours.empty());
00745 }
00746 ExtendedCavityStruct dat(*this, cavity, neighbours, p);
00747 complex_.dfsBySimplex(dat, s);
00748 }
00749
00750
00751
00752
00753
00754
00755
00756 public:
00757 void computeStar(const Cavity& cavity, Vertex *v, Star& star) {
00758 complex_.computeStar(cavity, v, star);
00759 }
00760
00761
00762
00763
00764
00765
00766 public:
00767 void insertVertex(const Cavity& cavity, Star& star) {
00768
00769 complex_.replaceCavity(cavity, star);
00770
00771 #ifdef EXPENSIVE_ASSERTIONS
00772 assert(isOriented());
00773 assert(isDelaunay());
00774 #endif
00775 }
00776
00777
00778
00779
00780
00781
00782 public:
00783 void insertVertex(const Simplex& s, Vertex *v) {
00784 Cavity cavity;
00785 computeCavity(s, v->toPoint(), cavity);
00786 Star star;
00787 computeStar(cavity, v, star);
00788 insertVertex(cavity, star);
00789 }
00790
00791
00792
00793
00794
00795
00796 public:
00797 void expensiveInsertVertex(Vertex *v) {
00798 Simplex s = expensiveLocate(v);
00799 insertVertex(s,v);
00800 }
00801
00802
00803
00804
00805
00806
00807
00808
00810 private:
00811 struct expensiveLocateStruct {
00812 const IncrementalDelaunay& id_;
00813 const Point& p_;
00814 expensiveLocateStruct(const IncrementalDelaunay& id, const Point& p)
00815 : id_(id), p_(p) { }
00816 static bool canEnter(const Simplex&) { return true; }
00817 bool choose(const Simplex& s) {
00818 return id_.inSphereAffine(s, p_);
00819 }
00820 };
00821
00822 public:
00823 Simplex expensiveLocate(const Point& p) const {
00824 expensiveLocateStruct loc(*this, p);
00825 return * complex_.findSimplex(loc, getHandle());
00826 }
00827 Simplex expensiveLocate(const Vertex *v) const {
00828 return expensiveLocate(v->toPoint());
00829 }
00831
00832
00833
00834
00835
00837 public:
00838 const Complex& getComplex() const { return complex_; }
00839 Complex& getComplexRW() { return complex_; }
00840 const Simplex& getHandle() const { return complex_.getHandle(); }
00842
00843
00844
00845
00847 private:
00848 struct verifyOrientedStruct {
00849 const IncrementalDelaunay& id_;
00850 verifyOrientedStruct (const IncrementalDelaunay& id): id_(id) { }
00851 static bool canEnter(const Simplex&) { return true; }
00852 bool choose (const Simplex& s) {
00853 if (!id_.isOriented(s)) {
00854 dprintf("unoriented simplex: %s\n", s.toString().c_str());
00855 }
00856 return ! id_.isOriented(s);
00857 }
00858 };
00859 struct verifyDelaunayStruct {
00860 const IncrementalDelaunay& id_;
00861 verifyDelaunayStruct (const IncrementalDelaunay& id): id_(id) { }
00862 static bool canEnter(const Simplex&) { return true; }
00863 bool choose (const Simplex& s) {
00864 OSimplex oriented = id_.getComplex().orientSimplex(s);
00865 for (unsigned i = 0; i <= topological; ++i) {
00866 OSimplex neighbour = id_.getComplex().getNeighbour(topological, oriented);
00867 if (!neighbour.isInternal()) continue;
00868 Vertex *v = neighbour[topological];
00869 if (id_.inSphereAffine(s, v->toPoint())) {
00870 dprintf("non-delaunay simplex: %s vs %s\n",
00871 s.toString().c_str(), v->toString().c_str());
00872 return true;
00873 }
00874 }
00875 return false;
00876 }
00877 };
00878 public:
00879
00881 bool isOriented() const
00882 {
00883 if (topological == 1) return true;
00884
00885 verifyOrientedStruct vOS(*this);
00886 return !getComplex().dfsBySimplex(vOS, getHandle());
00887 }
00888
00890 bool isDelaunay() const
00891 {
00892 if (topological == 1) return true;
00893
00894 verifyDelaunayStruct vDS(*this);
00895 return !getComplex().dfsBySimplex(vDS, getHandle());
00896 }
00898
00899
00900
00901
00902
00903
00904
00905
00906 public:
00907 void giveVertexOwnership(Vertex *v) { myVertices_.push_back(v); }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00919 public:
00926 static IncrementalDelaunay *
00927 computeBoundingSimplex(const BoundingBox& box, const ProjectionPlane& plane, double buffer, vector<Vertex*>& corners)
00928 {
00929
00930 BoundingBox bigbox = box.scale(buffer);
00931
00932 double temp_buffer = 5.0 * ambient;
00933 double simplexsidelength = (ambient + 2) * temp_buffer * bigbox.extent;
00934
00935 PPoint origin = bigbox.mincorner - (PPoint(temp_buffer * bigbox.extent));
00936
00937 for (unsigned i = 0; i < topological; i++) {
00938 PPoint corner = origin;
00939 corner[i] += simplexsidelength;
00940 corners.push_back(new Vertex(plane.unproject(corner)));
00941 }
00942 corners.push_back(new Vertex(plane.unproject(origin)));
00943 assert(corners.size() == topological + 1);
00944
00945 return fromSimplex(corners, plane);
00946 }
00947
00948 template <class p_iterator>
00949 static IncrementalDelaunay *
00950 computeBoundingSimplex(p_iterator begin, p_iterator end, double buffer, vector<Vertex*>& corners)
00951 {
00952 ProjectionPlane plane (begin, end);
00953 BoundingBox box (begin, end, plane);
00954
00955 return computeBoundingSimplex(box, plane, buffer, corners);
00956 }
00957
00958 static vector<Vertex*>
00959 unprojectBoundingSimplex(
00960 const vector<PPoint>& points,
00961 const ProjectionPlane& plane)
00962 {
00963 vector<Vertex*> verts;
00964 BOOST_FOREACH(const PPoint& pp, points) {
00965 verts.push_back(new Vertex(plane.unproject(pp)));
00966 }
00967 return verts;
00968 }
00969
00970 static IncrementalDelaunay *makeBoundingSimplex(
00971 const ProjectionPlane& plane,
00972 const BoundingBox& box,
00973 double buffer) {
00974 vector<Vertex*> verts;
00975 IncrementalDelaunay *del = computeBoundingSimplex(box, plane, buffer, verts);
00976 del->myVertices_ = verts;
00977 return del;
00978 }
00979
00980 template <class point_iterator>
00981 static IncrementalDelaunay *makeBoundingSimplex(point_iterator begin, point_iterator end, double buffer) {
00982 ProjectionPlane plane(begin, end);
00983 BoundingBox box(begin, end, plane);
00984 return makeBoundingSimplex(plane, box, buffer);
00985 }
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995 public:
00996
00997
00998 template <class p_iterator> static IncrementalDelaunay *createOrthoBox(
00999 const p_iterator& begin,
01000 const p_iterator& end,
01001 unsigned ppd, double buffer) {
01002 assert(ppd >= 2);
01003 assert(buffer >= 0.0);
01004
01005 dprintf("Compute plane");
01006 ProjectionPlane pplane (begin, end);
01007
01008 dprintf("Compute extent");
01009 BoundingBox box = BoundingBox(begin, end, pplane);
01010 assert (box.extent > 0.0);
01011
01012 BoundingBox bigbox = box.scale(buffer);
01013 assert (bigbox.extent > 0.0);
01014 printf("Meshing domain: extent %g (buffer %g), %u points per side \n",
01015 bigbox.extent, buffer, ppd);
01016
01017
01018
01019
01020
01021
01022
01023
01024 vector<Vertex*> vcorners;
01025 IncrementalDelaunay *boundingcomplex = computeBoundingSimplex(box, pplane, buffer, vcorners);
01026
01027
01028
01029
01030
01031
01032 dprintf("Insert cube");
01033 PPoint coordinates(0.0);
01034 double surface_grid_unit = bigbox.extent / (ppd - 1.0);
01035 size_t surface_size = sizeOfSurface(ppd);
01036
01037 for (size_t i = 0; i < surface_size; i++) {
01038 PPoint surface_point = (bigbox.mincorner + (coordinates * surface_grid_unit));
01039 Vertex *surface_v = new Vertex(pplane.unproject(surface_point));
01040 dprintf("Inserting %s", surface_v->toString().c_str());
01041 if (topological != ambient) {
01042 dprintf(" (projects to %s)\n", surface_point.toString().c_str());
01043 } else { dprintf(""); }
01044
01045 boundingcomplex->giveVertexOwnership(surface_v);
01046 boundingcomplex->expensiveInsertVertex(surface_v);
01047 coordinates = incrementSurface(coordinates,ppd);
01048 }
01049 dprintf("got hypercube");
01050
01051
01052
01053
01054 boundingcomplex->removeCorners(vcorners);
01055 BOOST_FOREACH(Vertex *v, vcorners) { delete v; }
01056
01057 return boundingcomplex;
01058 }
01059
01060
01066 template <class p_iterator> static IncrementalDelaunay *createMeshBox(
01067 const p_iterator& begin,
01068 const p_iterator& end,
01069 double rho) {
01070
01071
01072 unsigned k;
01073 double D;
01074
01075
01076 const double gamma =
01077 0.5 * sqrt(topological - 1) * (1.0 + sqrt(2.0) * rho / (rho - 1.0));
01078
01079
01080
01081
01082
01083 const double epsilon = 0.5;
01084
01085 k = 1 + unsigned (ceil(2.0 * gamma + epsilon));
01086 D = gamma / (double(k) - 1.0 - 2.0 * gamma) + 1e-8;
01087
01088 return IncrementalDelaunay::createOrthoBox(
01089 begin, end, k, D);
01090 }
01091
01092
01093
01094 private:
01095 static PPoint incrementGrid(PPoint coord, unsigned ppd) {
01096 unsigned carry_bit = 0;
01097 coord[0]++;
01098 while (coord[carry_bit] >= ((double)ppd-0.5))
01099 {
01100 coord[carry_bit] = 0;
01101 carry_bit++;
01102 if (carry_bit >= topological) return PPoint(0.0);
01103 coord[carry_bit]++;
01104 }
01105 return coord;
01106 }
01107
01108
01109 private:
01110 static bool onSurface(PPoint coord, unsigned ppd) {
01111 for (unsigned j = 0; j < topological; j++) {
01112 if (coord[j] == 0) return true;
01113 if (coord[j] == ppd - 1) return true;
01114 }
01115 return false;
01116 }
01117
01118
01119 private:
01120 static PPoint incrementSurface(PPoint coord, unsigned ppd) {
01121 coord = incrementGrid(coord,ppd);
01122 while (!onSurface(coord,ppd))
01123 coord = incrementGrid(coord,ppd);
01124 return coord;
01125 }
01126
01127 private:
01128 static unsigned ipow(unsigned base, unsigned exp) {
01129 unsigned x = 1;
01130 for(unsigned i = 0; i < exp; i++) {
01131 x *= base;
01132 }
01133 return x;
01134 }
01135
01136 private:
01137 static unsigned sizeOfSurface(unsigned ppd) {
01138 return ipow(ppd, topological) - ipow(ppd-2, topological);
01139 }
01140
01141
01142
01143 private:
01144 struct CollectCorners {
01145 vector<Simplex> found_;
01146 const vector<Vertex*>& corners_;
01147 CollectCorners(const vector<Vertex*>& corners) : corners_(corners) {};
01148 static bool canEnter(const Simplex&) { return true; }
01149 bool choose(const Simplex& s) {
01150 BOOST_FOREACH(const Vertex *v, corners_) {
01151 if (s.has(v)) { found_.push_back(s); return false; }
01152 }
01153 return false;
01154 }
01155 };
01156 struct FindNotCorner {
01157 const vector<Vertex*>& corners_;
01158 FindNotCorner(const vector<Vertex*>& corners) : corners_(corners) {};
01159 static bool canEnter(const Simplex&) { return true; }
01160 bool choose(const Simplex& s) const {
01161 BOOST_FOREACH(const Vertex *v, corners_) {
01162 if (s.has(v)) { return false; }
01163 }
01164 return true;
01165 }
01166 };
01167
01168
01169 private:
01170 void removeCorners(const vector<Vertex*>& corners) {
01171 CollectCorners kf(corners);
01172 getComplex().dfsBySimplex(kf, getHandle());
01173
01174 FindNotCorner nc(corners);
01175 Simplex safeHandle = *getComplex().findSimplex(nc, getHandle());
01176
01177
01178 dprintf("found %u to kill\n", (unsigned)kf.found_.size());
01179 dprintf("new handle %s\n", safeHandle.toString().c_str());
01180 complex_.setHandle(safeHandle);
01181 BOOST_FOREACH(const Simplex& s, kf.found_) {
01182 complex_.checkedRemoveSimplex(s);
01183 }
01184 }
01185
01186
01187 public:
01188 template <class p_iterator> static IncrementalDelaunay *createSquare(
01189 const p_iterator begin, const p_iterator& end,
01190 double buffer = 1.0) {
01191 return createOrthoBox(begin, end, 2, buffer);
01192 }
01193 template <class p_iterator> static IncrementalDelaunay *create4box(
01194 const p_iterator begin, const p_iterator& end) {
01195 return createOrthoBox(begin, end, 4, 1.500001);
01196 }
01198
01199
01200
0