cheshirekow  v0.1.0
triangulation.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2012 Josh Bialkowski (jbialk@mit.edu)
3  *
4  * This file is part of mpblocks.
5  *
6  * mpblocks is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * mpblocks is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with mpblocks. If not, see <http://www.gnu.org/licenses/>.
18  */
26 #ifndef MPBLOCKS_EDELSBRUNNER96_TRIANGULATION_HPP_
27 #define MPBLOCKS_EDELSBRUNNER96_TRIANGULATION_HPP_
28 
30 
31 #include <algorithm>
36 
37 namespace edelsbrunner96 {
38 
39 template <class Traits>
40 typename Traits::SimplexRef Triangulate(
41  typename Traits::Storage& storage,
42  std::initializer_list<typename Traits::PointRef> refs) {
43  typedef typename Traits::SimplexRef SimplexRef;
44  typedef typename Traits::Simplex Simplex;
45 
46  // there must be NDim + 1 points in the point set to create the initial
47  // simplices
48  assert(refs.size() == Traits::NDim + 1);
49 
50  SimplexRef simplex_refs[Traits::NDim + 1];
51  SimplexRef center_ref = storage.Promote();
52 
53  // we must construct simplices before assigning neighbors so we can
54  // point to actual addresses during neighborhood mapping
55  for (int i = 0; i < Traits::NDim + 1; i++) {
56  simplex_refs[i] = storage.Promote();
57  }
58 
59  // Note: it is now safe to grab the reference since we are not creating
60  // any new simplices and the underlying storage may not move out from under
61  // us.
62  Simplex& center_simplex = storage[center_ref];
63  std::copy(refs.begin(), refs.end(), center_simplex.V.begin());
64 
65  for (int i = 0; i < Traits::NDim + 1; i++) {
66  auto pr = storage[simplex_refs[i]].V.begin();
67  auto sr = storage[simplex_refs[i]].N.begin();
68 
69  *pr++ = storage.NullPoint();
70  *sr++ = center_ref;
71 
72  for (int j = 0; j < Traits::NDim + 1; j++) {
73  if (i == j) {
74  continue;
75  }
76  *pr++ = center_simplex.V[j];
77  *sr++ = simplex_refs[j];
78  }
79 
80  center_simplex.N[i] = simplex_refs[i];
81  }
82 
83  return center_ref;
84 }
85 
86 template <class Traits>
87 typename Traits::SimplexRef Maintain(typename Traits::Storage& storage,
88  typename Traits::PointRef point_ref,
89  typename Traits::SimplexRef return_ref,
90  std::list<Facet<Traits>>& link_facets) {
91  typedef typename Traits::SimplexRef SimplexRef;
92  typedef Facet<Traits> Facet;
93 
94  // while the link stack is not empty, flip any non-regular flippable facets
95  while (!link_facets.empty()) {
96  Facet facet = link_facets.back();
97  link_facets.pop_back();
98 
99  // if the facet no longer exists (due to some previous flip) then simply
100  // ignore it
101  if (!facet.StillExists(storage)) {
102  continue;
103  }
104 
105  // if the facet exists but it is already locally regular then we do not
106  // need to do anything
107  InducedSubcomplex<Traits> induced_subcomplex;
108  induced_subcomplex.Init(storage, facet.s);
109  if (induced_subcomplex.IsLocallyRegular(storage)) {
110  continue;
111  }
112 
113  // If it is not locally regular we must build the induced subcomplex of
114  // the facet and test if it is flippable (i.e. all reflex edges are filled
115  // by another simplex in the induced subcomplex). If it is not flippable
116  // then simply move on.
117  induced_subcomplex.Build(storage);
118  if (!induced_subcomplex.IsFlippable(storage)) {
119  continue;
120  }
121 
122  // If the facet is locally non-regular and flippable then flip it
123  induced_subcomplex.Flip(storage);
124  for (SimplexRef s_ref : induced_subcomplex.S) {
125  if (s_ref != storage.NullSimplex()) {
126  return_ref = s_ref;
127  }
128  }
129 
130  // After the flip, there can be at most one simplex which does not
131  // contain point_ref in it's vertex set. That simplex is stored in
132  // induced_subcomplex.S at the same index of as point_ref in
133  // induced_subcomplex.V.
134 
135  // Additionally, any neighbor of induced subcomplex is a neighbor of
136  // exactly one simplex inside the induced subcomplex.
137 
138  // Therefore all new simplices which contain point_ref in it's vertex
139  // set have one facet which is part of the link of the inserted point.
140  // This facet is the one across from point_ref.
141 
142  typedef std::pair<SimplexRef, SimplexRef> SimplexPair;
143  std::set<SimplexPair> facet_pairs;
144  for (int i = 0; i < Traits::NDim + 2; i++) {
145  // if i is the index of point_ref in the induced subcomplex then S[i],
146  // even if it is not null, is the one simplex which does not contain
147  // point_ref and is therefore not part of the link, except perhaps as
148  // the neighbor of a simplex which is inside the link surface.
149  if (induced_subcomplex.V[i] == point_ref) {
150  continue;
151  }
152 
153  // skip null simplices
154  SimplexRef link_simplex = induced_subcomplex.S[i];
155  if (link_simplex == storage.NullSimplex()) {
156  continue;
157  }
158 
159  // find the neighbor across from point_ref
160  SimplexRef neighbor = storage[link_simplex].NeighborAcross(point_ref);
161  // skip any link facets which are on the hull of the point set
162  if (storage[neighbor].V[0] == storage.NullPoint()) {
163  continue;
164  }
165  link_facets.emplace_back();
166  link_facets.back().Construct(storage, link_simplex, neighbor);
167  }
168  }
169 
170  return return_ref;
171 }
172 
173 
176 template <class Traits, class Container>
177 void DemoteHullSimplices(typename Traits::Storage& storage,
178  Container& visible_hull,
179  typename Traits::PointRef point_ref) {
180  typedef typename Traits::Simplex Simplex;
181  typedef typename Traits::SimplexRef SimplexRef;
182 
183  // first, demote all hull simplices by inserting point_ref into their
184  // vertex set while maintaining all neighbor relationships (i.e. resorting
185  // the V and S sets).
186  for (SimplexRef s_ref : visible_hull) {
187  /* Scope-protect s,N,V */ {
188  Simplex& s = storage[s_ref];
189  assert(s.V.end() - s.V.begin() > 1);
190 
191  SimplexRef neighbor_across = s.N[0];
192 
193  auto N = s.N.begin();
194  auto V = s.V.begin();
195 
196  // Shift all vertex and neighbor references to the left by one slot until
197  // we find the slot where the new reference belongs. Note: if all vertex
198  // references are less than the new vertex reference, then at the end
199  // of this loop V will point to s.V + NDim which is the last slot in the
200  // vertex set.
201  for (; V != s.V.end()-1 && *(V + 1) < point_ref; ++V, ++N) {
202  *V = *(V + 1);
203  *N = *(N + 1);
204  }
205 
206  *V = point_ref;
207  *N = neighbor_across;
208  s.ComputeCenter(storage);
209  }
210  }
211 }
212 
215 
222 template <class Traits, class Container>
223 std::list<std::pair<typename Traits::SimplexRef, typename Traits::SimplexRef>>
224 BuildHorizonRidge(typename Traits::Storage& storage, Container& visible_hull) {
225  typedef typename Traits::Simplex Simplex;
226  typedef typename Traits::SimplexRef SimplexRef;
227  typedef std::pair<SimplexRef, SimplexRef> Edge;
228 
229  std::list<Edge> horizon_ridge;
230  for (SimplexRef s_ref : visible_hull) {
231  Simplex& s = storage[s_ref];
232  for (int i = 0; i < Traits::NDim + 1; i++) {
233  SimplexRef neighbor_ref = s.N[i];
234  if (storage[neighbor_ref].V[0] == storage.NullPoint() &&
235  !storage[neighbor_ref].marked[simplex::VISIBLE_HULL]) {
236  horizon_ridge.emplace_back(s_ref, neighbor_ref);
237  }
238  }
239  }
240  return horizon_ridge;
241 }
242 
245 template <class Traits, class Container>
246 std::list<typename Traits::SimplexRef> FillHorizonWedges(
247  typename Traits::Storage& storage, Container& horizon_ridge,
248  typename Traits::PointRef point_ref) {
249  typedef typename Traits::Simplex Simplex;
250  typedef typename Traits::SimplexRef SimplexRef;
251  typedef typename Traits::PointRef PointRef;
252 
253  std::list<SimplexRef> horizon_wedges;
254  for (auto& pair : horizon_ridge) {
255  // Prior to demoting the first simplex in the pair, the two simplices
256  // across the horizon facet shared all but one vertex. After demoting the
257  // first simplex, they share all but two vertices.
258  SimplexRef wedge_ref = storage.Promote();
259  horizon_wedges.push_back(wedge_ref);
260  Simplex& wedge_simplex = storage[wedge_ref];
261 
262  // The wedge simplex contains those (NDim+1-2) common vertices, as well as
263  // the peak vertex, and the infinite vertex.
264  wedge_simplex.V[0] = storage.NullPoint();
265  std::set_intersection(
266  storage[pair.first].V.begin(), storage[pair.first].V.end(),
267  storage[pair.second].V.begin(), storage[pair.second].V.end(),
268  wedge_simplex.V.begin() + 1);
269  wedge_simplex.V[Traits::NDim] = point_ref;
270 
271  // If we may operate under the assumption that poin_ref, being a new point,
272  // has higher value than all vertices before it (i.e. pre-allocated block
273  // storage) then this step is unnecessary and can be optimized out.
274  // TODO (bialkowski): add scheme to optimize out this step if traits is
275  // sufficiently annotated.
276  std::sort(wedge_simplex.V.begin(), wedge_simplex.V.end());
277 
278  // We will initialize all neighbors to Null
279  for (int i = 0; i < Traits::NDim + 1; i++) {
280  wedge_simplex.N[i] = storage.NullSimplex();
281  }
282 
283  Simplex& s_a = storage[pair.first];
284  Simplex& s_b = storage[pair.second];
285  PointRef v_a[2] = {storage.NullPoint(), storage.NullPoint()};
286  PointRef v_b[2] = {storage.NullPoint(), storage.NullPoint()};
287 
288  set::SymmetricDifference(s_a.V.begin(), s_a.V.end(), s_b.V.begin(),
289  s_b.V.end(), v_a, v_b);
290  assert(v_a[0] == point_ref || v_a[1] == point_ref);
291  assert(v_b[0] == storage.NullPoint() || v_b[1] == storage.NullPoint());
292 
293  PointRef v_a_across_b = v_a[0] == point_ref ? v_a[1] : v_a[0];
294  PointRef v_b_across_a = v_b[0] == storage.NullPoint() ? v_b[1] : v_b[0];
295  assert(v_a_across_b != point_ref);
296  assert(v_a_across_b != storage.NullPoint());
297  assert(v_b_across_a != storage.NullPoint());
298  assert(s_a.NeighborAcross(v_a_across_b) == pair.second);
299  assert(s_b.NeighborAcross(v_b_across_a) == pair.first);
300 
301  // We know exactly two neighbors of the wedge simplex at this point. Also,
302  // some of the simplex's other neighbors haven't ben alloc'ed yet
303  wedge_simplex.SetNeighborAcross(point_ref, pair.second);
304  wedge_simplex.SetNeighborAcross(storage.NullPoint(), pair.first);
305  int i_first = s_a.IndexOf(v_a_across_b);
306  assert(s_a.N[i_first] == pair.second);
307  s_a.N[i_first] = wedge_ref;
308  int i_second = s_b.IndexOf(v_b_across_a);
309  assert(s_b.N[i_second] == pair.first);
310  s_b.N[i_second] = wedge_ref;
311  }
312 
313  return horizon_wedges;
314 }
315 
319 
367 template <class Traits>
368 void FindWedgeNeighbor(typename Traits::Storage& storage,
369  typename Traits::SimplexRef wedge_ref, int i) {
370  typedef typename Traits::SimplexRef SimplexRef;
371  typedef typename Traits::PointRef PointRef;
372 
373  // Copy all but the 0'th and i'th vertices
374  PointRef V_edge[Traits::NDim - 1];
375  /* scope of V */ {
376  PointRef* V = V_edge;
377  for (int j = 1; j < Traits::NDim + 1; j++) {
378  if (j == i) {
379  continue;
380  } else {
381  *V++ = storage[wedge_ref].V[j];
382  }
383  }
384  }
385 
386  SimplexRef prev_ref = wedge_ref;
387  SimplexRef next_ref = storage[wedge_ref].N[0];
388  PointRef V_diff;
389  while (next_ref != storage.NullSimplex()) {
390  // Get a list of the vertices common to both simplices
391  PointRef V_common[Traits::NDim];
392  std::set_intersection(
393  storage[prev_ref].V.begin(), storage[prev_ref].V.end(),
394  storage[next_ref].V.begin(), storage[next_ref].V.end(), V_common);
395 
396  // Find the vertex in that list which is not in the pivot edge
397  std::set_difference(V_common, V_common + Traits::NDim, V_edge,
398  V_edge + Traits::NDim - 1, &V_diff);
399 
400  // Walk across that vertex
401  prev_ref = next_ref;
402  next_ref = storage[prev_ref].NeighborAcross(V_diff);
403  }
404 
405  SimplexRef neighbor_ref = prev_ref;
406  storage[wedge_ref].N[i] = neighbor_ref;
407  storage[neighbor_ref].SetNeighborAcross(V_diff, wedge_ref);
408 }
409 
410 template <class Traits>
411 typename Traits::SimplexRef InsertOutside(
412  typename Traits::Storage& storage, typename Traits::SimplexRef simplex_ref,
413  typename Traits::PointRef point_ref) {
414  typedef typename Traits::SimplexRef SimplexRef;
415  typedef Facet<Traits> Facet;
416 
417  SimplexRef return_ref = storage.NullSimplex();
418 
419  std::list<SimplexRef> visible_hull;
420  GetVisibleHull<Traits>(storage, simplex_ref, storage[point_ref],
421  std::back_inserter(visible_hull));
422 
423  // First, mark all members of the visible hull
424  for (SimplexRef s_ref : visible_hull) {
425  assert(storage[s_ref].V[0] == storage.NullPoint());
426  storage[s_ref].marked[simplex::VISIBLE_HULL] = true;
427  return_ref = s_ref;
428  }
429 
430  // Replace infinite vertex with the newly added vertex
431  DemoteHullSimplices<Traits>(storage, visible_hull, point_ref);
432 
433  // Build the horizon ridge, which is the set of all *edges* which border
434  // the x-visible hull.
435  auto horizon_ridge = BuildHorizonRidge<Traits>(storage, visible_hull);
436 
437  // Each edge of the horizon ridge emits a new simplex to fill the wedge
438  // vacated by that facet of the demoted simplex.
439  auto horizon_wedges =
440  FillHorizonWedges<Traits>(storage, horizon_ridge, point_ref);
441 
442  // Now that the vacant wedges along the horizon ridge have been filled, we
443  // must compute the neighborhood of these new simplices. The algorithm for
444  // this is based on the horizon-ridge algorithm from Clarkson93. For each
445  // new simplex along the horizon ridge that we need to find the neighbor of,
446  // the neighbor that we need will lie across a *facet* of that simplex. That
447  // facet is composed of N vertices, one of which is the peak vertex (the
448  // newly added point). If we remove the peak vertex we are left with (N-1)
449  // vertices which we will call the "pivot edge". We will do a walk around
450  // this pivot edge until we find the neighboring simplex.
451 
452  // From our starting simplex we move to the neighbor across the infinite
453  // vertex. This neighbor shares the pivot edge, and one other vertex in
454  // common with the starting simplex. Incidentally, it is also a recently
455  // demoted simplex. We continue the walk by following that
456  // other vertex. A proof is given in the Clarkson93 paper that the walk
457  // *must* end at the desired neighbor of the starting simplex.
458  for (SimplexRef wedge_ref : horizon_wedges) {
459  // For the i'th neighbor of the wedge simplex
460  for (int i = 1; i < Traits::NDim + 1; i++) {
461  // if this neighbor is already set, then just skip it
462  if (storage[wedge_ref].N[i] != storage.NullSimplex()) {
463  continue;
464  }
465 
466  FindWedgeNeighbor<Traits>(storage, wedge_ref, i);
467  }
468  }
469 
470  /* Asci art for the link of a hull point in 2d
471  *
472  * x ______
473  * /\ /
474  * / \ /<--
475  * /____\/__
476  * A /\
477  * | / \
478  *
479  * The two facets with arrows pointing at them are the "link" of the point
480  * x (on the hull boundary). The link is composed of all facets across from
481  * the peak (inserted) vertex in all of the simplices that were demoted.
482  */
483  // stack of link facets
484  std::list<Facet> link_facets;
485 
486  // push each facet of the link onto the link stack and clear it's mark
487  for (SimplexRef s_ref : visible_hull) {
488  storage[s_ref].marked[simplex::VISIBLE_HULL] = false;
489  link_facets.emplace_back();
490  link_facets.back().Construct(storage, s_ref,
491  storage[s_ref].NeighborAcross(point_ref));
492  }
493 
494  return Maintain(storage, point_ref, return_ref, link_facets);
495 }
496 
497 template <class Traits>
498 typename Traits::SimplexRef InsertInside(
499  typename Traits::Storage& storage, typename Traits::SimplexRef simplex_ref,
500  typename Traits::PointRef point_ref) {
501  typedef typename Traits::Simplex Simplex;
502  typedef typename Traits::SimplexRef SimplexRef;
503  typedef Facet<Traits> Facet;
504 
505  SimplexRef return_ref = storage.NullSimplex();
506 
507  // The insertion operation is equivalent to a facet-less "flip" so we will
508  // reuse the code from InducedSubcomplex to handle insertions
509  InducedSubcomplex<Traits> induced_subcomplex;
510 
511  // create vertex and neighbor set with point_ref included
512  /* scope of i */ {
513  Simplex& simplex = storage[simplex_ref];
514 
515  int i = 0;
516  for (; i < Traits::NDim + 1 && simplex.V[i] < point_ref; ++i) {
517  induced_subcomplex.V[i] = simplex.V[i];
518  induced_subcomplex.S[i] = storage.NullSimplex();
519  }
520  induced_subcomplex.V[i] = point_ref;
521  induced_subcomplex.S[i] = simplex_ref;
522  ++i;
523  for (; i < Traits::NDim + 2; ++i) {
524  induced_subcomplex.V[i] = simplex.V[i - 1];
525  induced_subcomplex.S[i] = storage.NullSimplex();
526  }
527  }
528 
529  // we are abusing the data structure here, but we do not need to Init or
530  // Build because we have appropriately filled V and N above
531  induced_subcomplex.Flip(storage);
532  for (SimplexRef s_ref : induced_subcomplex.S) {
533  if (s_ref != storage.NullSimplex()) {
534  return_ref = s_ref;
535  }
536  }
537 
538  // Note: after the flip the original simplex will have been retired, so
539  // simplex_ref is no longer valid
540 
541  /* Asci art for the link of a point in 2d
542  * |
543  * ___V__
544  * /\ /|
545  * --->/ \ / |
546  * /____\/x |<-----
547  * \ /\ |
548  * --->\ / \ |
549  * \/____\|
550  * A
551  * |
552  *
553  * The six facets with arrows pointing at them are the "link" of the point
554  * x (in the center).
555  */
556  // stack of link facets
557  std::list<Facet> link_facets;
558 
559  // push each facet of the link onto the link stack
560  for (int i = 0; i < Traits::NDim + 2; i++) {
561  SimplexRef link_simplex = induced_subcomplex.S[i];
562  if (link_simplex == storage.NullSimplex()) {
563  continue;
564  }
565  SimplexRef neighbor = storage[link_simplex].NeighborAcross(point_ref);
566  // skip any link facets which are on the hull of the point set
567  if (storage[neighbor].V[0] == storage.NullPoint()) {
568  continue;
569  }
570  link_facets.emplace_back();
571  link_facets.back().Construct(storage, link_simplex, neighbor);
572  }
573 
574  return Maintain(storage, point_ref, return_ref, link_facets);
575 }
576 
578 template <class Traits>
579 void FindFillNeighbor(typename Traits::Storage& storage,
580  typename Traits::SimplexRef s_ref,
581  typename Traits::PointRef v_ref,
582  typename Traits::PointRef peak_ref) {
583  typedef typename Traits::SimplexRef SimplexRef;
584  typedef typename Traits::PointRef PointRef;
585 
586  // Copy all but the 0'th and i'th vertices
587  std::array<PointRef, Traits::NDim - 1> V_edge;
588  std::array<PointRef, 2> V_missing = {v_ref, peak_ref};
589  std::sort(V_missing.begin(), V_missing.end());
590  std::set_difference(storage[s_ref].V.begin(), storage[s_ref].V.end(),
591  V_missing.begin(), V_missing.end(), V_edge.begin());
592 
593  SimplexRef prev_ref = s_ref;
594  SimplexRef next_ref = storage[s_ref].NeighborAcross(peak_ref);
595  PointRef V_diff;
596  while (next_ref != storage.NullSimplex()) {
597  // Get a list of the vertices common to both simplices
598  std::array<PointRef, Traits::NDim> V_common;
599  std::set_intersection(storage[prev_ref].V.begin(),
600  storage[prev_ref].V.end(),
601  storage[next_ref].V.begin(),
602  storage[next_ref].V.end(), V_common.begin());
603 
604  // Find the vertex in that list which is not in the pivot edge
605  std::set_difference(V_common.begin(), V_common.end(), V_edge.begin(),
606  V_edge.end(), &V_diff);
607 
608  // Walk across that vertex
609  prev_ref = next_ref;
610  next_ref = storage[prev_ref].NeighborAcross(V_diff);
611  }
612 
613  SimplexRef neighbor_ref = prev_ref;
614  storage[s_ref].SetNeighborAcross(v_ref, neighbor_ref);
615  storage[neighbor_ref].SetNeighborAcross(V_diff, s_ref);
616 }
617 
618 template <class Traits, class Iterator>
619 typename Traits::SimplexRef InsertReplace(
620  typename Traits::Storage& storage,
621  typename Traits::PointRef point_ref,
622  Iterator S_begin, Iterator S_end) {
623  typedef typename Traits::SimplexRef SimplexRef;
624  typedef typename Traits::PointRef PointRef;
625  typedef Facet<Traits> Facet;
626 
627  SimplexRef return_ref = storage.NullSimplex();
628 
629  // first, mark all to-be-removed simplices
630  for(Iterator s_iter = S_begin; s_iter != S_end; ++s_iter) {
631  storage[*s_iter].marked[simplex::REMOVED_FOR_INSERT] = true;
632  }
633 
634  std::list<SimplexRef> new_simplices;
635  // for each simplex to be removed, find all neighbors which are not
636  // to be removed
637  for (Iterator s_iter = S_begin; s_iter != S_end; ++s_iter) {
638  SimplexRef s_ref = *s_iter;
639  for(SimplexRef neighbor_ref : storage[s_ref].N) {
640  if(storage[neighbor_ref].marked[simplex::REMOVED_FOR_INSERT]) {
641  continue;
642  }
643 
644  // find the common facet
645  std::array<PointRef, Traits::NDim + 1> V;
646  PointRef v_in_removed;
647  PointRef v_in_neighbor;
649  storage[s_ref].V.begin(), storage[s_ref].V.end(),
650  storage[neighbor_ref].V.begin(), storage[neighbor_ref].V.end(),
651  &v_in_removed, &v_in_neighbor, V.begin());
652  // add the new point
653  V.back() = point_ref;
654 
655  // create a new simplex
656  SimplexRef new_ref = storage.Promote();
657  new_simplices.push_back(new_ref);
658  std::sort(V.begin(), V.end());
659  std::copy(V.begin(), V.end(), storage[new_ref].V.begin());
660  storage[new_ref].ComputeCenter(storage);
661 
662  // reset neighbors
663  std::fill(storage[new_ref].N.begin(), storage[new_ref].N.end(),
664  storage.NullSimplex());
665 
666  // assign the one neighbor relation that we know at this point
667  storage[new_ref].SetNeighborAcross(point_ref, neighbor_ref);
668  storage[neighbor_ref].SetNeighborAcross(v_in_neighbor, new_ref);
669  }
670  }
671 
672  // Now that the vacant wedges have been filled, we must compute the
673  // neighborhood of these new simplices. The algorithm for
674  // this is based on the horizon-ridge algorithm from Clarkson93. For each
675  // new simplex that we need to find the neighbor of, the neighbor that we
676  // need will lie across a *facet* of that simplex. That
677  // facet is composed of N vertices, one of which is the peak vertex (the
678  // newly added point). If we remove the peak vertex we are left with (N-1)
679  // vertices which we will call the "pivot edge". We will do a walk around
680  // this pivot edge until we find the neighboring simplex.
681 
682  // From our starting simplex we move to the neighbor across the peak
683  // vertex. This neighbor shares the pivot edge, and one other vertex in
684  // common with the starting simplex. We continue the walk by following that
685  // other vertex. A proof is given in the Clarkson93 paper that the walk
686  // *must* end at the desired neighbor of the starting simplex.
687  for (SimplexRef wedge_ref : new_simplices) {
688  // For the i'th neighbor of the wedge simplex
689  for (PointRef v_ref : storage[wedge_ref].V) {
690  // if this neighbor is already set, then just skip it
691  if (storage[wedge_ref].NeighborAcross(v_ref) != storage.NullSimplex()) {
692  continue;
693  }
694 
695  FindFillNeighbor<Traits>(storage, wedge_ref, v_ref, point_ref);
696  }
697  }
698 
699  // Retire removed simplices
700  for (Iterator s_iter = S_begin; s_iter != S_end; ++s_iter) {
701  SimplexRef s_ref = *s_iter;
702  storage[s_ref].marked[simplex::REMOVED_FOR_INSERT] = false;
703  storage.Retire(s_ref);
704  }
705 
706  // push each non-hull facet of the link onto the link stack and clear
707  // marks
708  std::list<Facet> link_facets;
709  for (SimplexRef s_ref : new_simplices) {
710  if (storage[s_ref].V[0] != storage.NullPoint()) {
711  SimplexRef n_ref = storage[s_ref].NeighborAcross(point_ref);
712  if (storage[n_ref].V[0] != storage.NullPoint()) {
713  link_facets.emplace_back();
714  link_facets.back().Construct(storage, s_ref, n_ref);
715  }
716  }
717  }
718 
719  return_ref = new_simplices.front();
720  return Maintain(storage, point_ref, return_ref, link_facets);
721 }
722 
723 template <typename Traits>
724 typename Traits::SimplexRef FuzzyWalkInsert(
725  typename Traits::Storage& storage, const typename Traits::SimplexRef s_0,
726  const typename Traits::PointRef x_ref,
727  const typename Traits::Scalar epsilon) {
728  typedef typename Traits::SimplexRef SimplexRef;
729  std::list<SimplexRef> interference_set;
730  FuzzyWalk<Traits>(storage, s_0, storage[x_ref], epsilon,
731  std::back_inserter(interference_set));
732  return InsertReplace<Traits>(storage, x_ref, interference_set.begin(),
733  interference_set.end());
734 }
735 
736 } // namespace edelsbrunner
737 
738 #endif // EDELSBRUNNER96_TRIANGULATION_HPP_
void IntersectionAndDifference(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt1 out1, OutputIt2 out2, OutputIt3 intersect)
Collect in out1 elements from the first set not found in the second, and collect in out2 elements fro...
void FindWedgeNeighbor(typename Traits::Storage &storage, typename Traits::SimplexRef wedge_ref, int i)
Given a simplex which fills an empty wedge created by demotion of a simplex along the horizon ridge...
Traits::SimplexRef Triangulate(typename Traits::Storage &storage, std::initializer_list< typename Traits::PointRef > refs)
Initialize a triangulation with NDim+1 points and return the simplex.
Traits::SimplexRef InsertOutside(typename Traits::Storage &storage, typename Traits::SimplexRef simplex_ref, typename Traits::PointRef point_ref)
Inserts a point outside of the hull of the current point set. Note that simplex_ref must point to a h...
std::list< std::pair< typename Traits::SimplexRef, typename Traits::SimplexRef > > BuildHorizonRidge(typename Traits::Storage &storage, Container &visible_hull)
Build the horizon ridge, which is the set of all edges which border the x-visible hull...
bool IsFlippable(Storage &storage)
Return true if the facet is flippable.
void SymmetricDifference(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, OutputIt1 out1, OutputIt2 out2)
Collect in out1 elements from the first set not found in the second, and collect in out2 elements fro...
std::array< SimplexRef, 2 > s
the two simplices
Definition: facet.h:46
A facet is a (d-1)-dimensional simplex.
Definition: facet.h:42
The induced subcomplex of a facet between two simplices is the set of all simplices in the triangulat...
Traits::SimplexRef InsertReplace(typename Traits::Storage &storage, typename Traits::PointRef point_ref, Iterator S_begin, Iterator S_end)
Inserts a point into the triangulation, replacing the given simplex set which intersect the new point...
Traits::SimplexRef InsertInside(typename Traits::Storage &storage, typename Traits::SimplexRef simplex_ref, typename Traits::PointRef point_ref)
Inserts a point into a simplex, performs 1-to-n+1 flip, and performs the delaunay maintenance on the ...
void DemoteHullSimplices(typename Traits::Storage &storage, Container &visible_hull, typename Traits::PointRef point_ref)
For each infinite simplex references in hull_simplices, replace the null vertex with the vertex point...
std::list< typename Traits::SimplexRef > FillHorizonWedges(typename Traits::Storage &storage, Container &horizon_ridge, typename Traits::PointRef point_ref)
For each simplex pair (s1,s2) in , fill the empty wedge that was created when s1 was demoted to a non...
Traits::SimplexRef FuzzyWalkInsert(typename Traits::Storage &storage, const typename Traits::SimplexRef s_0, const typename Traits::PointRef x_ref, const typename Traits::Scalar epsilon)
Perform a fuzzy walk to get the set of simplices intersecting the query point, then insert the point ...
std::array< SimplexRef, Traits::NDim+2 > S
if S[i] is not null then it is the simplex in the triangulation composed of all the vertices in V exc...
simpex is a member of the visible hull
Definition: simplex.h:56
bool IsLocallyRegular(Storage &storage)
Return true if the facet is locally regular.
uint_t sort(KeyType *d_DstKey, ValueType *d_DstVal, KeyType *d_SrcKey, ValueType *d_SrcVal, uint_t arrayLength, uint_t sharedLength, Direction dir, uint_t globalThread)
kernel launcher, sorts an array of key/value pairs using the bitonic sort algorithm ...
Definition: kernels.cu.hpp:870
bool StillExists(Storage &storage)
Returns true if the two simplex references still have the same version as the time when Construct was...
Definition: facet.hpp:47
simplex has been removed during insertion of a point
Definition: simplex.h:58
Char8_t * copy(const Char8_t *s)
void Build(Storage &storage)
Fill the induced simplex by breadth-first search of the neighborhood about s[0] and s[1]...
std::array< PointRef, Traits::NDim+2 > V
the (sorted) vertices of the subcomplex
void FindFillNeighbor(typename Traits::Storage &storage, typename Traits::SimplexRef s_ref, typename Traits::PointRef v_ref, typename Traits::PointRef peak_ref)
Find the neighbor of a fill simplex that is across from v_ref.
void Init(Storage &storage, SimplexRef s0_ref, SimplexRef s1_ref)
Initialize the data structure with the two simplices and build the vertex set for the common facet...
Traits::SimplexRef Maintain(typename Traits::Storage &storage, typename Traits::PointRef point_ref, typename Traits::SimplexRef return_ref, std::list< Facet< Traits >> &link_facets)
While the link of the specified point is not locally Delaunay, continue flipping locally non-Delaunay...
void Flip(Storage &storage)
Flip the subcomplex.