Geogram Version 1.10.1
A programming library of geometric algorithms
Loading...
Searching...
No Matches
predicates.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_NUMERICS_PREDICATES
41#define GEOGRAM_NUMERICS_PREDICATES
42
47
54namespace GEO {
55
62 namespace PCK {
63
67 enum SOSMode { SOS_ADDRESS, SOS_LEXICO };
68
80 void GEOGRAM_API set_SOS_mode(SOSMode m);
81
87 SOSMode GEOGRAM_API get_SOS_mode();
88
105 Sign GEOGRAM_API side1_SOS(
106 const double* p0, const double* p1,
107 const double* q0,
108 coord_index_t DIM
109 );
110
131 Sign GEOGRAM_API side2_SOS(
132 const double* p0, const double* p1, const double* p2,
133 const double* q0, const double* q1,
134 coord_index_t DIM
135 );
136
160 Sign GEOGRAM_API side3_SOS(
161 const double* p0, const double* p1,
162 const double* p2, const double* p3,
163 const double* q0, const double* q1, const double* q2,
164 coord_index_t DIM
165 );
166
194 const double* p0, const double* p1,
195 const double* p2, const double* p3,
196 double h0, double h1, double h2, double h3,
197 const double* q0, const double* q1, const double* q2,
198 bool SOS=true
199 );
200
228 Sign GEOGRAM_API side4_SOS(
229 const double* p0,
230 const double* p1, const double* p2,
231 const double* p3, const double* p4,
232 const double* q0, const double* q1,
233 const double* q2, const double* q3,
234 coord_index_t DIM
235 );
236
237
262 Sign GEOGRAM_API side4_3d(
263 const double* p0,
264 const double* p1, const double* p2,
265 const double* p3, const double* p4
266 );
267
293 Sign GEOGRAM_API side4_3d_SOS(
294 const double* p0, const double* p1,
295 const double* p2, const double* p3, const double* p4
296 );
297
314 const double* p0, const double* p1,
315 const double* p2, const double* p3,
316 const double* p4
317 );
318
319
336 const double* p0, const double* p1, const double* p2,
337 const double* p3
338 );
339
340
357 const double* p0, const double* p1, const double* p2,
358 const double* p3
359 );
360
361
386 const double* p0, const double* p1, const double* p2,
387 const double* p3,
388 double h0, double h1, double h2, double h3,
389 bool SOS=true
390 );
391
401 Sign GEOGRAM_API orient_2d(
402 const double* p0, const double* p1, const double* p2
403 );
404
405
406#ifndef GEOGRAM_PSM
417 const vec2& p0, const vec2& p1, const vec2& p2
418 ) {
419 return orient_2d(p0.data(),p1.data(),p2.data());
420 }
421#endif
422
442 const double* p0, const double* p1,
443 const double* p2, const double* p3,
444 double h0, double h1, double h2, double h3
445 );
446
447
457 Sign GEOGRAM_API orient_3d(
458 const double* p0, const double* p1,
459 const double* p2, const double* p3
460 );
461
473 Sign GEOGRAM_API orient_3d_SOS(
474 const double* p0, const double* p1,
475 const double* p2, const double* p3
476 );
477
478#ifndef GEOGRAM_PSM
489 const vec3& p0, const vec3& p1,
490 const vec3& p2, const vec3& p3
491 ) {
492 return orient_3d(p0.data(),p1.data(),p2.data(),p3.data());
493 }
494
506 inline Sign GEOGRAM_API orient_3d_SOS(
507 const vec3& p0, const vec3& p1,
508 const vec3& p2, const vec3& p3
509 ) {
510 return orient_3d_SOS(p0.data(),p1.data(),p2.data(),p3.data());
511 }
512
513#endif
514
533 const double* p0, const double* p1,
534 const double* p2, const double* p3, const double* p4,
535 double h0, double h1, double h2, double h3, double h4
536 );
537
538
559 const double* p0, const double* p1,
560 const double* p2, const double* p3, const double* p4,
561 double h0, double h1, double h2, double h3, double h4
562 );
563
564
571 Sign GEOGRAM_API det_3d(
572 const double* p0, const double* p1, const double* p2
573 );
574
575#ifndef GEOGRAM_PSM
582 inline Sign det_3d(
583 const vec3& p0, const vec3& p1, const vec3& p2
584 ) {
585 return det_3d(p0.data(), p1.data(), p2.data());
586 }
587#endif
588
595 Sign GEOGRAM_API det_4d(
596 const double* p0, const double* p1,
597 const double* p2, const double* p3
598 );
599
600#ifndef GEOGRAM_PSM
607 inline Sign det_4d(
608 const vec4& p0, const vec4& p1,
609 const vec4& p2, const vec4& p3
610 ) {
611 return det_4d(p0.data(), p1.data(), p2.data(), p3.data());
612 }
613#endif
614
623 Sign GEOGRAM_API det_compare_4d(
624 const double* p0, const double* p1,
625 const double* p2, const double* p3,
626 const double* p4
627 );
628
637 bool GEOGRAM_API aligned_3d(
638 const double* p0, const double* p1, const double* p2
639 );
640
648 Sign GEOGRAM_API dot_3d(
649 const double* p0, const double* p1, const double* p2
650 );
651
652#ifndef GEOGRAM_PSM
653
662 inline bool aligned_3d(
663 const vec3& p0, const vec3& p1, const vec3& p2
664 ) {
665 return aligned_3d(p0.data(), p1.data(), p2.data());
666 }
667
675 inline Sign dot_3d(
676 const vec3& p0, const vec3& p1, const vec3& p2
677 ) {
678 return dot_3d(p0.data(), p1.data(), p2.data());
679 }
680#endif
681
687 Sign GEOGRAM_API dot_compare_3d(
688 const double* v0, const double* v1, const double* v2
689 );
690
700 const double* p1,
701 const double* p2
702 );
703
712 bool GEOGRAM_API points_are_identical_3d(
713 const double* p1,
714 const double* p2
715 );
716
725 bool GEOGRAM_API points_are_colinear_3d(
726 const double* p1,
727 const double* p2,
728 const double* p3
729 );
730
744 const double* p0, const double* p1,
745 const double* p2, const double* p3
746 ) {
747 double a11 = p1[0] - p0[0] ;
748 double a12 = p1[1] - p0[1] ;
749 double a13 = p1[2] - p0[2] ;
750
751 double a21 = p2[0] - p0[0] ;
752 double a22 = p2[1] - p0[1] ;
753 double a23 = p2[2] - p0[2] ;
754
755 double a31 = p3[0] - p0[0] ;
756 double a32 = p3[1] - p0[1] ;
757 double a33 = p3[2] - p0[2] ;
758
759 double Delta = det3x3(
760 a11,a12,a13,
761 a21,a22,a23,
762 a31,a32,a33
763 );
764
765 return geo_sgn(Delta);
766 }
767
773 void GEOGRAM_API show_stats();
774
778 void GEOGRAM_API initialize();
779
783 void GEOGRAM_API terminate();
784 }
785}
786
787/**************************************************************************/
788
789namespace GEO {
790
791
807 template<class T, class SOS> inline Sign orient_3d_SOS_impl(
808 const T& p0, const T& p1, const T& p2, const T& p3
809 ) {
810 constexpr coord_index_t X = 0, Y = 1, Z = 2;
811 Sign s = ::GEO::PCK::orient_3d(p0, p1, p2, p3);
812 if(s != ZERO) {
813 return s;
814 }
815
816 // The perturbed determinant is as follows:
817 // | x1+eps y1+eps^2 z1+eps^4 1 |
818 // | x2+eps^8 y2+eps^16 z2+eps^32 1 |
819 // | x3+eps^64 y3+eps^128 z3+eps^256 1 |
820 // | x4+eps^512 y4+eps^1024 z4+eps^2048 1 |
821 //
822 // By developping and sorting by exponents of eps
823 // one gets the perturbations. Did it with TinyCAS:
824 // https://github.com/BrunoLevy/Experiment/blob/main/algo/tiny_cas.h
825 //
826 // | a b 1 |
827 // - The minors | c d 1 | correspond to orient_2d((a,b), (c,d), (e,f))
828 // | e f 1 |
829 //
830 // - The other terms are just difference of coordinates (orient_1d)
831
832 // Static array that encodes all the terms of the expansion.
833 static const struct SOSInfo {
834 index_t dim; // 0: constant, 1: orient_1d, 2: orient_2d
835 index_t v1, v2, v3; // local indices of the two or three vertices
836 index_t ax1, ax2; // one or two projection axes
837 Sign sign; // sign of the term
838 } sosInfo[] = {
839 {2, 1, 2, 3, Y, Z, POSITIVE}, // eps
840 {2, 1, 2, 3, X, Z, NEGATIVE}, // eps^2
841 {2, 1, 2, 3, X, Y, POSITIVE}, // eps^4
842 {2, 0, 2, 3, Y, Z, NEGATIVE}, // eps^8
843 {1, 3, 2, NO_INDEX, Z, NO_INDEX, POSITIVE}, // eps^10
844 {1, 2, 3, NO_INDEX, Y, NO_INDEX, POSITIVE}, // eps^12
845 {2, 0, 2, 3, X, Z, POSITIVE}, // eps^16
846 // z2-z3 = -term in eps^10, already seen // eps^17
847 {1, 3, 2, NO_INDEX, X, NO_INDEX, POSITIVE}, // eps^20
848 {2, 0, 2, 3, X, Y, NEGATIVE}, // eps^32
849 // y3-y2 = -term in eps^12, already seen // eps^33
850 // x2-x3 = -term in eps^20, already seen // eps^34
851 {2, 0, 1, 3, Y, Z, POSITIVE}, // eps^64
852 {1, 1, 3, NO_INDEX, Z, NO_INDEX, POSITIVE}, // eps^66
853 {1, 3, 1, NO_INDEX, Y, NO_INDEX, POSITIVE}, // eps^68
854 {1, 3, 0, NO_INDEX, Z, NO_INDEX, POSITIVE}, // eps^80
855 {0,NO_INDEX,NO_INDEX,NO_INDEX,NO_INDEX,NO_INDEX, NEGATIVE} // eps^84
856 // There are more terms (up to eps^2184) but we do not need them,
857 // since we got a (constant) non-zero coefficient for eps^84
858 };
859
860 SOS sos(p0, p1, p2, p3);
861
862 for(index_t k=0; ;++k) {
863 const SOSInfo& I = sosInfo[k];
864 switch(I.dim) {
865 case 0: {
866 return I.sign;
867 } break;
868 case 1: {
869 s = sos.orient_1d(I.v1, I.v2, I.ax1);
870 if(s != ZERO) {
871 return Sign(I.sign*s);
872 }
873 } break;
874 case 2: {
875 s = sos.orient_2d(I.v1, I.v2, I.v3, I.ax1, I.ax2);
876 if(s != ZERO) {
877 return Sign(I.sign*s);
878 }
879 } break;
880 default:
882 }
883 }
885 }
886
887 namespace Permutation {
898 template <class T> inline bool permutation_is_odd(
899 const T** orig, const T** perm, index_t n
900 ) {
901 geo_debug_assert(n <= 64);
902 Numeric::uint64 visited = 0;
903 bool odd = false;
904 for (index_t i = 0; i < n; ++i) {
905 if ((visited >> i) & 1) {
906 continue;
907 }
908 // Compute the length of the cycle starting from perm[i]
909 index_t len = 0;
910 for (index_t j = i; !((visited >> j) & 1); ) {
911 visited |= (Numeric::uint64(1) << j);
912 ++len;
913 j = index_t(std::find(orig, orig + n, perm[j]) - orig);
914 }
915 // even-length cycle contributes odd parity
916 if (len % 2 == 0) odd = !odd;
917 }
918 return odd;
919 }
920 }
921}
922
923#endif
Utilities to write geometric predicates (Predicate Construction Kit).
#define geo_assert_not_reached
Sets a non reachable point in the program.
Definition assert.h:177
#define geo_debug_assert(x)
Verifies that a condition is met.
Definition assert.h:196
T * data()
Gets modifiable vector data.
Definition vecg.h:165
Common include file, providing basic definitions. Should be included before anything else by all head...
Geometric functions in 2d and 3d.
uint64_t uint64
Definition numeric.h:148
Sign det_4d(const double *p0, const double *p1, const double *p2, const double *p3)
Computes the sign of the determinant of a 4x4 matrix formed by four 4d points.
Sign in_circle_3dlifted_SOS(const double *p0, const double *p1, const double *p2, const double *p3, double h0, double h1, double h2, double h3, bool SOS=true)
Tests whether a lifted 3d point is inside the circumscribed circle of a lifted 3d triangle.
Sign orient_3dlifted(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4, double h0, double h1, double h2, double h3, double h4)
Computes the 4d orientation test.
Sign orient_3d_SOS(const exact::vec3h &p0, const exact::vec3h &p1, const exact::vec3h &p2, const exact::vec3h &p3)
Computes the orientation predicate in 3d.
Sign dot_compare_3d(const double *v0, const double *v1, const double *v2)
Compares two dot products.
Sign side3_SOS(const double *p0, const double *p1, const double *p2, const double *p3, const double *q0, const double *q1, const double *q2, coord_index_t DIM)
Computes the side of a point (given as the intersection between a facet and two bisectors) relative t...
Sign orient_3dlifted_SOS(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4, double h0, double h1, double h2, double h3, double h4)
Computes the 4d orientation test with symbolic perturbation.
Sign side4_3d_SOS(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4)
Computes the side of a point (given as the intersection between three bisectors) relative to another ...
Sign in_circle_2d_SOS(const double *p0, const double *p1, const double *p2, const double *p3)
Tests whether a 2d point is inside the circumscribed circle of a 3d triangle.
Sign orient_2dlifted_SOS(const double *p0, const double *p1, const double *p2, const double *p3, double h0, double h1, double h2, double h3)
Computes the 3d orientation test with lifted points.
Sign orient_3d_inexact(const double *p0, const double *p1, const double *p2, const double *p3)
Computes the (approximate) orientation predicate in 3d.
Definition predicates.h:743
Sign in_circle_3d_SOS(const double *p0, const double *p1, const double *p2, const double *p3)
Tests whether a 3d point is inside the circumscribed circle of a 3d triangle.
Sign in_sphere_3d_SOS(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4)
Tests whether a 3d point is inside the circumscribed sphere of a 3d tetrahedron.
Sign side4_SOS(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4, const double *q0, const double *q1, const double *q2, const double *q3, coord_index_t DIM)
Computes the side of a point (given as the intersection between a tetrahedron and three bisectors) re...
void show_stats()
Displays some statistics about predicates, including the number of calls, the number of exact arithme...
Sign orient_2d(const vec2HE &p0, const vec2HE &p1, const vec2HE &p2)
Computes the orientation predicate in 2d.
Sign SOS(COMPARE compare, const POINT &p1, FUNC1 sos_p1, const POINT &p2, FUNC2 sos_p2, const POINT &p3, FUNC3 sos_p3, const POINT &p4, FUNC4 sos_p4)
template for writing symbolic perturbation in predicates
Definition PCK.h:172
Sign det_3d(const double *p0, const double *p1, const double *p2)
Computes the sign of the determinant of a 3x3 matrix formed by three 3d points.
Sign det_compare_4d(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4)
Computes the sign of the determinant of a 4x4 matrix formed by three 4d points and the difference of ...
Sign side4_3d(const double *p0, const double *p1, const double *p2, const double *p3, const double *p4)
Computes the side of a point (given as the intersection between three bisectors) relative to another ...
Sign dot_3d(const double *p0, const double *p1, const double *p2)
Computes the sign of the dot product between two vectors.
bool points_are_identical_3d(const double *p1, const double *p2)
Tests whether two 3d points are identical.
SOSMode
Mode for symbolic perturbations.
Definition predicates.h:67
bool points_are_colinear_3d(const double *p1, const double *p2, const double *p3)
Tests whether three 3d points are colinear.
Sign side2_SOS(const double *p0, const double *p1, const double *p2, const double *q0, const double *q1, coord_index_t DIM)
Computes the side of a point (given as the intersection between a segment and a bisector) relative to...
bool points_are_identical_2d(const double *p1, const double *p2)
Tests whether two 2d points are identical.
Sign side3_3dlifted_SOS(const double *p0, const double *p1, const double *p2, const double *p3, double h0, double h1, double h2, double h3, const double *q0, const double *q1, const double *q2, bool SOS=true)
Computes the side of a point (given as the intersection between a facet and two bisectors) relative t...
Sign side1_SOS(const double *p0, const double *p1, const double *q0, coord_index_t DIM)
Computes the side of a point (given directly) relative to a bisector.
void initialize()
Needs to be called before using any predicate.
void terminate()
Needs to be called at the end of the program.
bool aligned_3d(const vec3HE &p0, const vec3HE &p1, const vec3HE &p2)
Tests whether three 3d points are aligned.
Sign orient_3d(const vec3HE &p0, const vec3HE &p1, const vec3HE &p2, const vec3HE &p3)
Computes the orientation predicate in 3d.
SOSMode get_SOS_mode()
Gets the current mode for handling symbolic perturbations.
void set_SOS_mode(SOSMode m)
Sets the current mode for handling symbolic perturbations (SOS for Simulation Of Simplicity).
bool permutation_is_odd(const T **orig, const T **perm, index_t n)
Computes the parity of a permutation.
Definition predicates.h:898
Global Vorpaline namespace.
Definition basic.h:55
T det3x3(const T &a11, const T &a12, const T &a13, const T &a21, const T &a22, const T &a23, const T &a31, const T &a32, const T &a33)
Computes a three-by-three determinant.
Definition determinant.h:69
Sign geo_sgn(const T &x)
Gets the sign of a value.
Definition numeric.h:110
geo_index_t index_t
The type for storing and manipulating indices.
Definition numeric.h:340
Sign orient_3d_SOS_impl(const T &p0, const T &p1, const T &p2, const T &p3)
Implementation of the perturbed orient_3d predicate.
Definition predicates.h:807
Sign
Integer constants that represent the sign of a value.
Definition numeric.h:72
@ ZERO
Definition numeric.h:76
@ NEGATIVE
Definition numeric.h:74
@ POSITIVE
Definition numeric.h:78
geo_coord_index_t coord_index_t
The type for storing coordinate indices, and iterating on the coordinates of a point.
Definition numeric.h:374
Types and functions for numbers manipulation.