00001 #ifndef Mesh_HEADER
00002 #define Mesh_HEADER
00003
00004 #include "GenericMesh.h"
00005 #include "ProtectedBall.h"
00006 #include "RefineVertex.h"
00007 #include "SimplexData.h"
00008 #include "SliverChecker.h"
00009 #include <algorithm>
00010 #include <boost/foreach.hpp>
00011 #include <boost/function_output_iterator.hpp>
00012 #include <delaunay/IncrementalDelaunay.h>
00013 #include <functional>
00014 #include <stdlib.h>
00015 #include <utilities/hash.h>
00016 #include <vector>
00017
00018 #if 0
00019 #define dprintf(...) printf(__VA_ARGS__);
00020 #else
00021 #define dprintf(...)
00022 #endif
00023
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00045 template <size_t ambient, size_t topo>
00046 struct Mesh : public GenericMesh<ambient> {
00047 typedef ::SimplexData<ambient, topo> SimplexData;
00048 typedef IncrementalDelaunay<ambient, topo, RefineVertex<ambient>, SimplexData> Delaunay;
00049 typedef typename Delaunay::Complex Complex;
00050 typedef typename Delaunay::Cavity Cavity;
00051 typedef typename Delaunay::Star Star;
00052 typedef typename Delaunay::Simplex Simplex;
00053 typedef typename Delaunay::Vertex Vertex;
00054 typedef typename MeshTypes<ambient>::Ball Ball;
00055 typedef typename MeshTypes<ambient>::BallSet BallSet;
00056 typedef typename MeshTypes<ambient>::GenericMesh GenericMesh;
00057 typedef Geometry::CenterRadius<ambient> CenterRadius;
00058 typedef Geometry::Point<ambient> Point;
00059 typedef Geometry::Point<topo> PPoint;
00060 typedef ::SplitData<ambient> SplitData;
00061
00062 static const size_t ambient_dimension = ambient;
00063 static const size_t topological_dimension = topo;
00064
00068 private:
00069 struct InitVertex {
00070 Mesh *mesh;
00071 InitVertex(Mesh *mesh): mesh(mesh) { }
00072 static bool canEnter(const Simplex&) { return true; }
00073 bool choose(const Simplex& s) {
00074 BOOST_FOREACH(Vertex *v, s) {
00075 if (topo == ambient) {
00076 v->replaceHandle(mesh->toBall(s));
00077
00078 } else {
00079 v->addUpperMesh(mesh);
00080 }
00081 }
00082 return false;
00083 }
00084 };
00085
00086
00098 public:
00099 Mesh(Delaunay *del) : del_(del) {
00100 dprintf("%u-mesh %p: Projection plane %s\n", unsigned(topo), this,
00101 del_->getPlane().toString().c_str());
00102 assert(del_->isOriented());
00103 InitVertex sh(this);
00104 dfs(sh);
00105 }
00106
00108 virtual unsigned topological() const { return topo; }
00109
00111 const Delaunay *getDelaunay() const {
00112 return del_;
00113 }
00114
00116 const Complex& getSimplicialComplex() const {
00117 return del_->getComplex();
00118 }
00119
00123 Delaunay *getDelaunayDangerously() {
00124 return del_;
00125 }
00126
00129 const Simplex& getHandle() const {
00130 return del_->getHandle();
00131 }
00132
00135 template <class DFSData>
00136 void dfs(DFSData& data) const {
00137 del_->getComplex().dfsBySimplex(data, getHandle());
00138 }
00139
00140
00141
00142
00143 private:
00144 template <class output_iterator>
00145 struct ConvertToBalls {
00146 static bool canEnter(const Simplex&) { return true; }
00147 bool choose(const Simplex& s) {
00148 *out_ = mesh_->toBall(s);
00149 ++out_;
00150 return false;
00151 }
00152 const Mesh *mesh_;
00153 output_iterator out_;
00154 ConvertToBalls(const Mesh *m, output_iterator o): mesh_(m), out_(o) { }
00155 };
00156
00162 public:
00163 template <class output_iterator>
00164 output_iterator collectAllBalls(output_iterator out) const {
00165 ConvertToBalls<output_iterator> ctb(this, out);
00166 dfs(ctb);
00167 return ctb.out_;
00168 }
00169
00170
00171
00172
00173
00174
00175 Ball *toBall(const Simplex& s) const {
00176 Ball *b = getData(s).toBall();
00177 if (b == NULL) {
00178
00179
00180
00181 b = makeProtectedBall(const_cast<Mesh*>(this), s);
00182 }
00183 return b;
00184 }
00185
00187 void setBall(const Simplex& s, Ball *b) {
00188 assert(getData(s).toBall() == NULL);
00189 getDataRW(s).setBall(b);
00190 }
00191
00192
00193
00194
00195
00197 bool isMember(const Simplex& s) const {
00198 return del_->getComplex().isMember(s);
00199 }
00200
00202 CenterRadius circumcenter(const Simplex& s) const {
00203 return del_->circumcenter(s);
00204 }
00205
00207 double radiusEdge2(const Simplex& s) const {
00208 return del_->radiusEdge2(s);
00209 }
00210 double computeSigma(const Simplex& s) const {
00211 return del_->computeSigma(s);
00212 }
00213
00218 bool encroachedBy(const Simplex& s, const Vertex *v) const {
00219
00220 if (s.has(v)) {
00221 dprintf(" vertex %p does not encroach %s\n", v, toBall(s)->toString().c_str());
00222 return false;
00223 }
00224
00225
00226 CenterRadius cr = circumcenter(s);
00227 bool b = v->toPoint().dist2(cr.center) < cr.radius2;
00228 dprintf(" vertex %p (%s) %s <%s,%g> (%s)\n",
00229 v, v->toPoint().toString().c_str(),
00230 b ? "encroaches" : "does not encroach",
00231 cr.center.toString().c_str(), sqrt(cr.radius2),
00232 toBall(s)->toString().c_str());
00233 return b;
00234 }
00235
00240 bool inSphereExact(const Simplex& s, const Vertex *v) const {
00241 assert(v->hasUpperMesh(this));
00242 if (s.has(v)) { return false; }
00243 return del_->inSphereAffine(s, v->toPoint());
00244 }
00245
00247 bool isResolved(const Simplex& s) const {
00248 if (topological_dimension == ambient) {
00249
00250 return true;
00251 }
00252
00253
00254 BOUNDED_FOREACH(Ball *b, getData(s).begin_uppers(), getData(s).end_uppers()) {
00255 if (b->topological() != ambient) { continue; }
00256
00257
00258 bool hasAll = true;
00259 BOOST_FOREACH(Vertex *v, s) {
00260 if (!b->has(v)) { hasAll = false; break; }
00261 }
00262 if (hasAll) { return true; }
00263 }
00264
00265
00266 return false;
00267 }
00268
00269
00271 void gatherUppers(const Simplex& s, BallSet& set) const {
00272 return getData(s).gatherUppers(set);
00273 }
00275 void gatherLowers(const Simplex& s, BallSet& set) const {
00276 return getData(s).gatherLowers(set);
00277 }
00278
00282 bool approximatelyIntersects(const Simplex& s, const Ball *b) const {
00283 return b->approximatelyIntersects(circumcenter(s));
00284 }
00285
00286
00287
00288
00289
00297 private:
00298 bool isDegenerate(const Simplex& s) const {
00299 if (topo == 1) {
00300
00301 return false;
00302 }
00303 vector<const GenericMesh*> meshes;
00304 std::copy(s[0]->begin_uppers(topo - 1), s[0]->end_uppers(topo - 1),
00305 std::back_inserter(meshes));
00306
00307
00308 for(size_t i = 1 ; i <= topo; ++i) {
00309
00310
00311
00312
00313
00314
00315
00316
00317 vector<const GenericMesh*> tmp;
00318 std::set_intersection(meshes.begin(), meshes.end(),
00319 s[i]->begin_uppers(topo - 1), s[i]->end_uppers(topo - 1),
00320 std::back_inserter(tmp));
00321 meshes.swap(tmp);
00322 }
00323
00324
00325
00326 assert(meshes.size() == 0 || meshes.size() == 1);
00327 return !meshes.empty();
00328 }
00329
00338 private:
00339 struct WarpClosure {
00340 Vertex *best_;
00341 double radius2_;
00342 const Point& center_;
00343 Mesh *mesh_;
00344
00345 WarpClosure(double radius2, const Point& center, Mesh *mesh)
00346 : radius2_(radius2), center_(center), mesh_(mesh) {
00347 best_ = NULL;
00348 }
00349
00350 bool canEnter(const Simplex& s) {
00351
00352 return mesh_->getDelaunay()->inSphereAffine(s, center_);
00353 }
00354
00355 bool choose(const Simplex& s) {
00356 BOOST_FOREACH(Vertex *v, s) {
00357 pair<Vertex*,double> p = v->findClosest(mesh_, center_, radius2_);
00358 if (p.first) {
00359 best_ = p.first;
00360 radius2_ = p.second;
00361 }
00362 }
00363 return false;
00364 }
00365 };
00366
00368 Vertex *findWarpVertex(const Simplex& s, double k2) {
00369 WarpClosure wc(circumcenter(s).radius2 * k2, circumcenter(s).center, this);
00370 del_->getComplex().bfsBySimplex(wc, s);
00371 return wc.best_;
00372 }
00373
00385 public:
00386 bool split(const Simplex& s, SplitData& data, Vertex *inserthint = NULL, bool force = false) {
00387 dprintf("Splitting in %u-mesh [%p] at %s\n", unsigned(topo), this, s.toString().c_str());
00388 if (inserthint) { dprintf(" Using insert-hint of %s\n", inserthint->toString().c_str()); }
00389
00390
00391 Vertex *toinsert = inserthint ? inserthint : findWarpVertex(s, data.k * data.k);
00392 bool isSteiner = toinsert == NULL;
00393
00394
00395
00396 if (isSteiner) {
00397
00398
00399
00400
00401
00402 Point newpoint = circumcenter(s).center;
00403 if (ambient >= 3 && data.sigma != 0.0) {
00404 SliverChecker<ambient> checker(getData(s).begin_uppers(),
00405 getData(s).end_uppers(), data, circumcenter(s).radius2);
00406 enum { MAX_SLIVER_ITERATIONS = 20 };
00407 unsigned ntries = 0;
00408 while(++ntries < MAX_SLIVER_ITERATIONS && checker.formsSliver(newpoint)) {
00409
00410
00411 PPoint c = del_->getPlane().project(circumcenter(s).center);
00412 c += PPoint::randPoint(data.perturbFactor);
00413 newpoint = del_->getPlane().unproject(c);
00414 }
00415 if (ntries == MAX_SLIVER_ITERATIONS) {
00416 printf("warning: can't avoid sliver after %u tries\n",
00417 MAX_SLIVER_ITERATIONS);
00418 }
00419 }
00420 toinsert = new Vertex(newpoint);
00421 toinsert->setContainingDimension(topo);
00422 if (topo < ambient) { toinsert->addUpperMesh(this); }
00423 }
00424 dprintf(" split at %s (%s) %s\n", toinsert->toString().c_str(),
00425 toinsert->toPoint().toString().c_str(),
00426 isSteiner ? "(Steiner)" : "(input)");
00427
00428
00429
00430
00431 Cavity cavity;
00432 vector<Simplex> neighbours;
00433 del_->computeCavity(s, toinsert->toPoint(), cavity, neighbours);
00434
00435
00436
00437
00438
00439 {
00440 hudson::OrderedHashSet<Ball *, hudson::HashPointer<Ball> > checked;
00441 BOOST_FOREACH(const Simplex& s, cavity) {
00442 dprintf(" checking for encroachment in %s\n", toBall(s)->toString().c_str());
00443 BOUNDED_FOREACH(Ball *b, getData(s).begin_lowers(), getData(s).end_lowers()) {
00444 if (checked.insert(b).second) {
00445 if (b->encroachedBy(toinsert)) {
00446 data.insertEncroached(b);
00447 }
00448 }
00449 }
00450 }
00451 }
00452
00453
00454
00455 if (data.encroached()) {
00456 if (force) {
00457 dprintf(" encroached; force anyway.\n");
00458 } else {
00459 dprintf(" encroached; back out and try again\n");
00460 if (isSteiner) { delete toinsert; }
00461 return false;
00462 }
00463 }
00464
00465 dprintf(" starting ForceInsert\n");
00466
00467
00468
00469
00470
00471
00472
00473
00474 Star star;
00475 del_->computeStar(cavity, toinsert, star);
00476 if (topo != ambient && toinsert->getCD() < topo) {
00477 typename Star::iterator it = star.begin();
00478 while (it != star.end() ) {
00479 const Simplex& s = *it;
00480 if (isDegenerate(s)) {
00481 dprintf(" reject degenerate %s\n", s.toString().c_str());
00482 it = star.erase(it);
00483 } else {
00484 dprintf(" accept non-degenerate %s\n", s.toString().c_str());
00485 ++it;
00486 }
00487 }
00488 }
00489 #ifndef NDEBUG
00490 BOOST_FOREACH(const Simplex& s, star) {
00491 dprintf(" verifying %s\n", s.toString().c_str());
00492
00493
00494
00495
00496 assert(del_->isOriented(s));
00497 }
00498 #endif
00499
00500 dprintf(" star computed\n");
00501 del_->insertVertex(cavity, star);
00502
00503 dprintf(" starting to reassign uppers/lowers\n");
00504
00505
00506 BallSet lowers;
00507 BallSet uppers;
00508 typedef typename Vertex::VertexUniqueList VertexSet;
00509 typedef hudson::FastHashMap<const GenericMesh*, VertexSet, hudson::HashPointer<GenericMesh> >
00510 MeshVertexMap;
00511 MeshVertexMap upvertices;
00512 std::vector<const GenericMesh*> upmeshes;
00513
00514 BOOST_FOREACH(const Simplex& s, cavity) {
00515 const SimplexData& sdata = getData(s);
00516 lowers.insert(sdata.begin_lowers(), sdata.end_lowers());
00517 uppers.insert(sdata.begin_uppers(), sdata.end_uppers());
00518 }
00519
00520 BOOST_FOREACH(const Simplex& s, neighbours) {
00521 const SimplexData& sdata = getData(s);
00522 lowers.insert(sdata.begin_lowers(), sdata.end_lowers());
00523 uppers.insert(sdata.begin_uppers(), sdata.end_uppers());
00524 }
00525
00526
00527 BOOST_FOREACH(const Ball *b, uppers) {
00528 const GenericMesh *m = b->getMesh();
00529
00530
00531 std::pair<typename MeshVertexMap::iterator, bool> p =
00532 upvertices.insert(m);
00533 if (p.second) { upmeshes.push_back(m); }
00534 VertexSet& vset = ((*p.first).second);
00535 b->gatherVertices(vset);
00536 }
00537
00538
00539 BOOST_FOREACH(const Simplex& s, star) {
00540 BOOST_FOREACH(Ball *b, lowers) {
00541 checkAddLower(s, b);
00542 }
00543 Ball *sball = toBall(s);
00544 BOOST_FOREACH(Ball *b, uppers) {
00545 b->checkAddLower(sball);
00546 }
00547 }
00548
00549
00550 BOOST_FOREACH(const GenericMesh *m, upmeshes) {
00551 const VertexSet& vset = upvertices.findOrDie(m);
00552 Vertex *closest = *std::min_element(vset.begin(), vset.end(),
00553 typename Vertex::IsCloser(toinsert));
00554 closest->addUninserted(m, toinsert);
00555 }
00556
00557
00558 {
00559 hudson::FastHashSet<Vertex*, hudson::HashPointer<Vertex> > verts;
00560 BOOST_FOREACH(const Simplex& s, cavity) {
00561 BOOST_FOREACH(Vertex *v, s) {
00562 if (verts.insert(v).second) {
00563 v->reassignTo(this, toinsert);
00564 }
00565 }
00566 }
00567 }
00568
00569
00570 BOOST_FOREACH(const Simplex& s, cavity) {
00571 unlink(s);
00572 }
00573
00574
00575
00576 if (topo == ambient) {
00577 BOOST_FOREACH(const Simplex& s, star) {
00578 BOOST_FOREACH(Vertex *v, s) {
00579 v->replaceHandle(toBall(s));
00580 }
00581 }
00582 }
00583
00584
00585 data.insertKill(this, cavity.begin(), cavity.end());
00586 data.insertBorn(this, star.begin(), star.end());
00587 data.setVertex(toinsert);
00588
00589
00590 return true;
00591 }
00592
00593 private:
00594 const Simplex& toSimplex(const Ball *b) const {
00595 #ifndef NDEBUG
00596
00597 assert(b);
00598 assert(dynamic_cast<const PBall<Mesh>*>(b));
00599 #endif
00600 return static_cast<const PBall<Mesh>*>(b)->toSimplex();
00601 }
00602
00608 public:
00609 bool split(Vertex *v, SplitData& data) {
00610 BOOST_STATIC_ASSERT(topo == ambient);
00611 assert(v->isCrowded(this));
00612
00613
00614 vector<Simplex> orbit;
00615 Simplicial::collectStar(getSimplicialComplex(), v,
00616 toSimplex(v->getHandle()), std::back_inserter(orbit));
00617
00618 if (v->getCD() == topo) {
00619
00620
00621
00622
00623 Vertex *uninserted = v->getFarVertex(this);
00624 BOOST_FOREACH(const Simplex& s, orbit) {
00625 if (getDelaunay()->inSphereAffine(s, uninserted->toPoint())) {
00626 return split(s, data, uninserted);
00627 }
00628 }
00629
00630 abort();
00631 } else {
00632
00633
00634 size_t best = 0;
00635 double best_r2 = circumcenter(orbit[best]).radius2;
00636 size_t n = orbit.size();
00637 for(size_t i = 0; i < n; ++i) {
00638 double r2 = circumcenter(orbit[i]).radius2;
00639 if (r2 > best_r2) {
00640 best = i;
00641 best_r2 = r2;
00642 }
00643 }
00644 return split(orbit[best], data);
00645 }
00646 }
00647
00648
00649
00650
00651
00652 bool checkAddLower(const Simplex& s, Ball *b) {
00653 if (approximatelyIntersects(s, b)) {
00654 dprintf(" intersection: balls %s and %s\n",
00655 toBall(s)->toString().c_str(), b->toString().c_str());
00656 getDataRW(s).blindlyAddLower(b);
00657 b->blindlyAddUpper(toBall(s));
00658 return true;
00659 }
00660 dprintf(" non-intersection: balls %s and %s\n",
00661 toBall(s)->toString().c_str(), b->toString().c_str());
00662 return false;
00663 }
00664
00665
00666
00667
00668 public:
00669 void blindlyAddUpper(const Simplex& s, Ball *up) {
00670 assert(up->topological() > topo);
00671 getDataRW(s).blindlyAddUpper(up);
00672 }
00673
00674
00675
00676
00677 public:
00678 void blindlyAddLower(const Simplex& s, Ball *lower) {
00679 dprintf("lower d=%u %s\nto d=%u %s\n",
00680 (unsigned)lower->topological(), lower->toString().c_str(),
00681 (unsigned)topo, s.toString().c_str());
00682 assert(lower->topological() < topo);
00683 getDataRW(s).blindlyAddLower(lower);
00684 }
00685
00686
00687
00688
00689 public:
00690 void removeUpper(const Simplex& s, Ball *up) {
00691 assert(up->topological() > topo);
00692 getDataRW(s).removeUpper(up);
00693 }
00694
00695
00696
00697
00698 public:
00699 void removeLower(const Simplex& s, Ball *lower) {
00700 assert(lower->topological() < topo);
00701 getDataRW(s).removeLower(lower);
00702 }
00703
00704
00705
00706
00707
00708 private:
00709 void unlink(const Simplex& s) {
00710 getDataRW(s).unlink();
00711 }
00712
00713
00714
00715
00716
00717
00718 private:
00719 struct BallNotifier {
00720 BallNotifier(Mesh *mesh, Ball *b)
00721 : mesh_(mesh), b_(b) { }
00722 Mesh *mesh_;
00723 Ball *b_;
00724 static bool canEnter(const Simplex&) { return true; }
00725 bool choose(const Simplex& s) const {
00726 mesh_->checkAddLower(s, b_);
00727 return false;
00728 }
00729 };
00730
00731 public:
00734 void checkAddLowerToAll(Ball *b) {
00735 assert(b->topological() < topo);
00736 BallNotifier notifier(this, b);
00737 dfs(notifier);
00738 }
00739
00740 private:
00741 const SimplexData& getData(const Simplex& s) const { return del_->getData(s); }
00742 SimplexData& getDataRW(const Simplex& s) { return del_->getDataRW(s); }
00743
00744 Delaunay *del_;
00745 };
00746
00747 #undef dprintf
00748
00749 #endif