Geogram Version 1.9.6-rc
A programming library of geometric algorithms
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:660
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.
Definition basic.h:55
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.