Graphite Version 3
An experimental 3D geometry processing program
Loading...
Searching...
No Matches
delaunay_2d.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2000-2022 Inria
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the ALICE Project-Team nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Contact: Bruno Levy
30 *
31 * https://www.inria.fr/fr/bruno-levy
32 *
33 * Inria,
34 * Domaine de Voluceau,
35 * 78150 Le Chesnay - Rocquencourt
36 * FRANCE
37 *
38 */
39
40#ifndef GEOGRAM_DELAUNAY_DELAUNAY_2D
41#define GEOGRAM_DELAUNAY_DELAUNAY_2D
42
47
48#include <stack>
49
55namespace GEO {
56
106 class GEOGRAM_API Delaunay2d : public Delaunay {
107 public:
121 Delaunay2d(coord_index_t dimension = 2);
122
126 void set_vertices(index_t nb_vertices, const double* vertices) override;
127
131 index_t nearest_vertex(const double* p) const override;
132
142 bool has_empty_cells() const {
143 return has_empty_cells_;
144 }
145
152 void abort_if_empty_cell(bool x) {
153 abort_if_empty_cell_ = x;
154 }
155
156 protected:
157
164 static constexpr index_t NO_TRIANGLE = NO_INDEX;
165
178
199 const double* p, index_t hint = NO_TRIANGLE,
200 bool thread_safe = false,
201 Sign* orient = nullptr
202 ) const;
203
222 const double* p, index_t hint, index_t max_iter
223 ) const;
224
233 index_t insert(index_t v, index_t hint = NO_TRIANGLE);
234
259 index_t v,
260 index_t t, const Sign* orient,
261 index_t& t_bndry, index_t& e_bndry,
262 index_t& first, index_t& last
263 );
264
281 const double* p, index_t t,
282 index_t& t_bndry, index_t& e_bndry,
283 index_t& first, index_t& last
284 );
285
301 index_t v,
302 index_t t_bndry, index_t e_bndry
303 );
304
305 /*** Combinatorics - new and delete ******************************/
306
314 index_t max_t() const {
315 return cell_to_v_store_.size() / 3;
316 }
317
318
334 static constexpr index_t NOT_IN_LIST = ~index_t(0);
335
351 static constexpr index_t NOT_IN_LIST_BIT =
352 index_t(1) << (sizeof(index_t)*8-1) ;
353
359 static constexpr index_t END_OF_LIST = ~NOT_IN_LIST_BIT;
360
379 geo_debug_assert(t < max_t());
380 return (cell_next_[t] & NOT_IN_LIST_BIT) == 0;
381 }
382
394 geo_debug_assert(t < max_t());
395 geo_debug_assert(triangle_is_in_list(t));
396 return cell_next_[t];
397 }
398
410 geo_debug_assert(t < max_t());
411 geo_debug_assert(!triangle_is_in_list(t));
412 if(last == END_OF_LIST) {
413 geo_debug_assert(first == END_OF_LIST);
414 first = last = t;
415 cell_next_[t] = END_OF_LIST;
416 } else {
417 cell_next_[t] = first;
418 first = t;
419 }
420 }
421
432 geo_debug_assert(t < max_t());
433 geo_debug_assert(triangle_is_in_list(t));
434 cell_next_[t] = NOT_IN_LIST;
435 }
436
443 static constexpr index_t VERTEX_AT_INFINITY = NO_INDEX;
444
456 return
457 (cell_to_v_store_[3 * t] != NO_INDEX) &&
458 (cell_to_v_store_[3 * t + 1] != NO_INDEX) &&
459 (cell_to_v_store_[3 * t + 2] != NO_INDEX) ;
460 }
461
473 bool triangle_is_real(index_t t) const {
474 return !triangle_is_free(t) && triangle_is_finite(t);
475 }
476
487 return
488 !triangle_is_free(t) && (
489 cell_to_v_store_[3 * t] == VERTEX_AT_INFINITY ||
490 cell_to_v_store_[3 * t + 1] == VERTEX_AT_INFINITY ||
491 cell_to_v_store_[3 * t + 2] == VERTEX_AT_INFINITY
492 );
493 }
494
505 bool triangle_is_free(index_t t) const {
506 return triangle_is_in_list(t);
507 }
508
517 index_t result;
518 if(first_free_ == END_OF_LIST) {
519 cell_to_v_store_.resize(
520 cell_to_v_store_.size() + 3, NO_INDEX
521 );
522 cell_to_cell_store_.resize(
523 cell_to_cell_store_.size() + 3, NO_INDEX
524 );
525 // index_t(NOT_IN_LIST) is necessary, else with
526 // NOT_IN_LIST alone the compiler tries to generate a
527 // reference to NOT_IN_LIST resulting in a link error.
528 cell_next_.push_back(index_t(NOT_IN_LIST));
529 result = max_t() - 1;
530 } else {
531 result = first_free_;
532 first_free_ = triangle_next(first_free_);
533 remove_triangle_from_list(result);
534 }
535
536 cell_to_cell_store_[3 * result] = NO_INDEX;
537 cell_to_cell_store_[3 * result + 1] = NO_INDEX;
538 cell_to_cell_store_[3 * result + 2] = NO_INDEX;
539
540 return result;
541 }
542
555 index_t result = new_triangle();
556 cell_to_v_store_[3 * result] = v1;
557 cell_to_v_store_[3 * result + 1] = v2;
558 cell_to_v_store_[3 * result + 2] = v3;
559 return result;
560 }
561
570 cur_stamp_ = (stamp | NOT_IN_LIST_BIT);
571 }
572
589 return cell_next_[t] == cur_stamp_;
590 }
591
606 cell_next_[t] = cur_stamp_;
607 }
608
609 /**** Combinatorics ****************************************/
610
628 geo_debug_assert(e < 3);
629 geo_debug_assert(v < 2);
630 return index_t(triangle_edge_vertex_[e][v]);
631 }
632
641 geo_debug_assert(t < max_t());
642 geo_debug_assert(lv < 3);
643 return cell_to_v_store_[3 * t + lv];
644 }
645
654 geo_debug_assert(t < max_t());
655 // Find local index of v in triangle t vertices.
656 const index_t* T = &(cell_to_v_store_[3 * t]);
657 return find_3(T,v);
658 }
659
660
669 geo_debug_assert(t < max_t());
670 geo_debug_assert(lv < 3);
671 geo_debug_assert(cell_to_v_store_[3 * t + lv] != NO_INDEX);
672 return cell_to_v_store_[3 * t + lv];
673 }
674
682 geo_debug_assert(t < max_t());
683 geo_debug_assert(lv < 3);
684 cell_to_v_store_[3 * t + lv] = v;
685 }
686
694 geo_debug_assert(t < max_t());
695 geo_debug_assert(le < 3);
696 index_t result = cell_to_cell_store_[3 * t + le];
697 return result;
698 }
699
708 geo_debug_assert(t1 < max_t());
709 geo_debug_assert(t2 < max_t());
710 geo_debug_assert(le1 < 3);
711 geo_debug_assert(t1 != t2);
712 cell_to_cell_store_[3 * t1 + le1] = t2;
713 }
714
724 geo_debug_assert(t1 < max_t());
725 geo_debug_assert(t2 < max_t());
726 geo_debug_assert(t1 != t2);
727
728 // Find local index of t2 in triangle t1 adajcent tets.
729 const index_t* T = &(cell_to_cell_store_[3 * t1]);
730 index_t result = find_3(T,t2);
731
732 // Sanity check: make sure that t1 is adjacent to t2
733 // only once!
734 geo_debug_assert(triangle_adjacent(t1,(result+1)%3) != t2);
735 geo_debug_assert(triangle_adjacent(t1,(result+2)%3) != t2);
736 return result;
737 }
738
751 index_t t,
752 index_t v0, index_t v1, index_t v2,
753 index_t a0, index_t a1, index_t a2
754 ) {
755 geo_debug_assert(t < max_t());
756 cell_to_v_store_[3 * t] = v0;
757 cell_to_v_store_[3 * t + 1] = v1;
758 cell_to_v_store_[3 * t + 2] = v2;
759 cell_to_cell_store_[3 * t] = a0;
760 cell_to_cell_store_[3 * t + 1] = a1;
761 cell_to_cell_store_[3 * t + 2] = a2;
762 }
763
764 /******* Predicates ******************************************/
765
779 bool triangle_is_conflict(index_t t, const double* p) const {
780
781 // Lookup triangle vertices
782 const double* pv[3];
783 for(index_t i=0; i<3; ++i) {
784 index_t v = triangle_vertex(t,i);
785 pv[i] = (v == NO_INDEX) ? nullptr : vertex_ptr(v);
786 }
787
788 // Check for virtual triangles (then in_circle()
789 // is replaced with orient2d())
790 for(index_t le = 0; le < 3; ++le) {
791
792 if(pv[le] == nullptr) {
793
794 // Facet of a virtual triangle opposite to
795 // infinite vertex corresponds to
796 // the triangle on the convex hull of the points.
797 // Orientation is obtained by replacing vertex lf
798 // with p.
799 pv[le] = p;
800 Sign sign = PCK::orient_2d(pv[0],pv[1],pv[2]);
801
802 if(sign > 0) {
803 return true;
804 }
805
806 if(sign < 0) {
807 return false;
808 }
809
810 // If sign is zero, we check the real triangle
811 // adjacent to the facet on the convex hull.
812 geo_debug_assert(triangle_adjacent(t, le) != NO_INDEX);
813 index_t t2 = triangle_adjacent(t, le);
814 geo_debug_assert(!triangle_is_virtual(t2));
815
816 // If t2 is already chained in the conflict list,
817 // then it is conflict
818 if(triangle_is_in_list(t2)) {
819 return true;
820 }
821
822 // If t2 is marked, then it is not in conflict.
823 if(triangle_is_marked(t2)) {
824 return false;
825 }
826
827 return triangle_is_conflict(t2, p);
828 }
829 }
830
831 // If the triangle is a finite one, it is in conflict
832 // if its circumscribed sphere contains the point (this is
833 // the standard case).
834
835 if(weighted_) {
836 double h0 = heights_[finite_triangle_vertex(t, 0)];
837 double h1 = heights_[finite_triangle_vertex(t, 1)];
838 double h2 = heights_[finite_triangle_vertex(t, 2)];
839 index_t pindex = index_t(
840 (p - vertex_ptr(0)) / int(vertex_stride_)
841 );
842 double h = heights_[pindex];
843 return (PCK::orient_2dlifted_SOS(
844 pv[0],pv[1],pv[2],p,h0,h1,h2,h
845 ) > 0) ;
846 }
847
848 return (PCK::in_circle_2d_SOS(pv[0], pv[1], pv[2], p) > 0);
849 }
850
851 protected:
852
861 static inline index_t find_3(const index_t* T, index_t v) {
862 // The following expression is 10% faster than using
863 // if() statements. This uses the C++ norm, that
864 // ensures that the 'true' boolean value converted to
865 // an int is always 1. With most compilers, this avoids
866 // generating branching instructions.
867 // Thank to Laurent Alonso for this idea.
868 index_t result = index_t( (T[1] == v) | ((T[2] == v) * 2) );
869 // Sanity check, important if it was T[0], not explicitly
870 // tested (detects input that does not meet the precondition).
871 geo_debug_assert(T[result] == v);
872 return result;
873 }
874
878 ~Delaunay2d() override;
879
884 void show_triangle(index_t t) const;
885
893
899 void show_list(index_t first, const std::string& list_name) const;
900
904 void check_combinatorics(bool verbose = false) const;
905
909 void check_geometry(bool verbose = false) const;
910
911 private:
912 vector<index_t> cell_to_v_store_;
913 vector<index_t> cell_to_cell_store_;
914 vector<index_t> cell_next_;
915 vector<index_t> reorder_;
916 index_t cur_stamp_; // used for marking
917 index_t first_free_;
918 bool weighted_;
919 vector<double> heights_; // only used in weighted mode
920
924 bool debug_mode_;
925
929 bool verbose_debug_mode_;
930
934 bool benchmark_mode_;
935
944 static char triangle_edge_vertex_[3][2];
945
949 std::stack<index_t> S_;
950
954 bool has_empty_cells_;
955
960 bool abort_if_empty_cell_;
961 };
962
963 /************************************************************************/
964
976 class GEOGRAM_API RegularWeightedDelaunay2d : public Delaunay2d {
977 public:
988
989 protected:
994 };
995}
996
997#endif
#define geo_debug_assert(x)
Verifies that a condition is met.
Definition assert.h:196
Implementation of Delaunay in 2d.
void find_conflict_zone_iterative(const double *p, index_t t, index_t &t_bndry, index_t &e_bndry, index_t &first, index_t &last)
This function is used to implement find_conflict_zone.
void set_triangle(index_t t, index_t v0, index_t v1, index_t v2, index_t a0, index_t a1, index_t a2)
Sets the vertices and adjacent triangles of a triangle.
bool triangle_is_finite(index_t t) const
Tests whether a given triangle is a finite one.
static index_t triangle_edge_vertex(index_t e, index_t v)
Returns the local index of a vertex by edge and by local vertex index in the edge.
bool triangle_is_real(index_t t) const
Tests whether a triangle is a real one.
static index_t find_3(const index_t *T, index_t v)
Finds the index of an integer in an array of three integers.
void set_vertices(index_t nb_vertices, const double *vertices) override
Sets the vertices of this Delaunay, and recomputes the cells.
bool triangle_is_in_list(index_t t) const
Tests whether a triangle belongs to a linked list.
index_t triangle_next(index_t t) const
Gets the index of a successor of a triangle.
void set_triangle_mark_stamp(index_t stamp)
Generates a unique stamp for marking tets.
index_t triangle_vertex(index_t t, index_t lv) const
Gets the index of a vertex of a triangle.
void show_list(index_t first, const std::string &list_name) const
For debugging purposes, displays a triangle.
index_t locate_inexact(const double *p, index_t hint, index_t max_iter) const
Finds the triangle that (approximately) contains a point using inexact predicates.
index_t max_t() const
Maximum valid index for a triangle.
Delaunay2d(coord_index_t dimension=2)
Constructs a new Delaunay2d.
~Delaunay2d() override
Delaunay2d destructor.
void show_triangle(index_t t) const
For debugging purposes, displays a triangle.
void set_triangle_adjacent(index_t t1, index_t le1, index_t t2)
Sets a triangle-to-triangle adjacency.
void check_geometry(bool verbose=false) const
For debugging purposes, test some geometrical properties.
bool triangle_is_virtual(index_t t) const
Tests whether a triangle is a virtual one.
void abort_if_empty_cell(bool x)
Specifies behavior if an empty cell is detected.
index_t stellate_conflict_zone(index_t v, index_t t_bndry, index_t e_bndry)
Creates a star of triangles filling the conflict zone.
bool create_first_triangle(index_t &iv0, index_t &iv1, index_t &iv2)
Finds in the pointset a set of three non-colinear points.
index_t find_triangle_adjacent(index_t t1, index_t t2) const
Finds the index of the edge accros which t1 is adjacent to t2_in.
index_t insert(index_t v, index_t hint=NO_TRIANGLE)
Inserts a point in the triangulation.
void set_triangle_vertex(index_t t, index_t lv, index_t v)
Sets a triangle-to-vertex adjacency.
void find_conflict_zone(index_t v, index_t t, const Sign *orient, index_t &t_bndry, index_t &e_bndry, index_t &first, index_t &last)
Determines the list of triangles in conflict with a given point.
index_t finite_triangle_vertex(index_t t, index_t lv) const
Gets the index of a vertex of a triangle.
index_t triangle_adjacent(index_t t, index_t le) const
Gets the index of a triangle adjacent to another one.
void remove_triangle_from_list(index_t t)
Removes a triangle from the linked list it belongs to.
void mark_triangle(index_t t)
Marks a triangle.
index_t find_triangle_vertex(index_t t, index_t v) const
Finds the index of the vertex in a triangle.
index_t locate(const double *p, index_t hint=NO_TRIANGLE, bool thread_safe=false, Sign *orient=nullptr) const
Finds the triangle that contains a point.
bool has_empty_cells() const
Tests whether the Laguerre diagram has empty cells.
bool triangle_is_marked(index_t t) const
Tests whether a triangle is marked.
index_t new_triangle(index_t v1, index_t v2, index_t v3)
Creates a new triangle.
void add_triangle_to_list(index_t t, index_t &first, index_t &last)
Adds a triangle to a linked list.
bool triangle_is_free(index_t t) const
Tests whether a triangle is in the free list.
index_t nearest_vertex(const double *p) const override
Computes the nearest vertex from a query point.
void check_combinatorics(bool verbose=false) const
For debugging purposes, tests some combinatorial properties.
index_t new_triangle()
Creates a new triangle.
void show_triangle_adjacent(index_t t, index_t le) const
For debugging purposes, displays a triangle adjacency.
bool triangle_is_conflict(index_t t, const double *p) const
Tests whether a given triangle is in conflict with a given 3d point.
Abstract interface for Delaunay triangulation in Nd.
Definition delaunay.h:71
Regular Delaunay triangulation of weighted points.
~RegularWeightedDelaunay2d() override
RegularWeightedDelaunay2d destructor.
RegularWeightedDelaunay2d(coord_index_t dimension=3)
Constructs a new Regular Delaunay2d triangulation.
Vector with aligned memory allocation.
Definition memory.h:710
Abstract interface for Delaunay.
Common include file, providing basic definitions. Should be included before anything else by all head...
Geometric functions in 2d and 3d.
Global Vorpaline namespace.
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:329
Sign
Integer constants that represent the sign of a value.
Definition numeric.h:68
geo_coord_index_t coord_index_t
The type for storing coordinate indices, and iterating on the coordinates of a point.
Definition numeric.h:363
Filtered exact predicates for restricted Voronoi diagrams.