Files
Extern/fist/Include/numerics.h
T
SaraP 05ca0d3376 Extern :
- aggiunto FIST 6.8 ( già modificato per integrazione nelle nostre librerie).
2025-03-04 16:37:58 +01:00

491 lines
20 KiB
C

/*****************************************************************************/
/* */
/* F I S T : Fast, Industrial-Strength Triangulation */
/* */
/*****************************************************************************/
/* */
/* (C) Martin Held */
/* (C) Universitaet Salzburg, Salzburg, Austria */
/* */
/* This code is not in the public domain. All rights reserved! Please make */
/* sure to read the full copyright statement contained in api_functions.cpp. */
/* */
/*****************************************************************************/
#define BaseLength(u, v, base, delta) { \
(base).x = (v).x - (u).x; \
(base).y = (v).y - (u).y; \
delta = Abs(TO_MDOUBLE((base).x)) + Abs(TO_MDOUBLE((base).y)); }
#define SideLength(u, v, base, delta) { \
(base).x = (v).x - (u).x; \
(base).y = (v).y - (u).y; \
delta = (base).x * (base).x + (base).y * (base).y; }
#define PntPntDist(u, v, base, delta) { \
(base).x = (v).x - (u).x; \
(base).y = (v).y - (u).y; \
delta = sqrt((base).x * (base).x + (base).y * (base).y); }
#define PntPntDistSqd(u, v, base, delta) { \
(base).x = TO_MDOUBLE((v).x) - TO_MDOUBLE((u).x); \
(base).y = TO_MDOUBLE((v).y) - TO_MDOUBLE((u).y); \
delta = (base).x * (base).x + (base).y * (base).y; }
/* */
/* this macro checks whether i3, which is collinear with i1, i2, is */
/* between i1, i2. note that we rely on the lexicographic sorting of the */
/* points! */
/* */
#define InBetween(i1, i2, i3) \
((i1 <= i3) && (i3 <= i2))
#define StrictlyInBetween(i1, i2, i3) \
((i1 < i3) && (i3 < i2))
/* */
/* this macro checks whether i3, which is collinear with i1, i2, is */
/* between i1, i2. note that we do _not_ rely on the lexicographic sorting */
/* of the points! */
/* */
#define InBetweenEps(data, i1, i2, i3) \
(((Min(data->points[i1].x, data->points[i2].x) - EPS) <= data->points[i3].x) && \
((Min(data->points[i1].y, data->points[i2].y) - EPS) <= data->points[i3].y) && \
((Max(data->points[i1].x, data->points[i2].x) + EPS) >= data->points[i3].x) && \
((Max(data->points[i1].y, data->points[i2].y) + EPS) >= data->points[i3].y))
/* */
/* this macro computes the determinant det(points[i],points[j],points[k]) */
/* in a consistent way. */
/* */
#ifdef JRC_PREDICATE
double orient2dfast(point pa, point pb, point pc);
double orient2d(point pa, point pb, point pc);
#define StableDet2D(i, j, k, det) \
{ assert(InPointsList(i)); \
assert(InPointsList(j)); \
assert(InPointsList(k)); \
\
if ((i == j) || (i == k) || (j == k)) { \
det = C_0_0; \
} \
else { \
det = orient2d(points[i], points[j], points[k]); \
} \
}
#else
#define StableDet2D(data, tmp, i, j, k, det) \
{ assert(InPointsList(data,i)); \
assert(InPointsList(data,j)); \
assert(InPointsList(data,k)); \
\
if ((i == j) || (i == k) || (j == k)) { \
det = C_0_0; \
} \
else { \
tmp.numerics_h_p = data->points[i]; \
tmp.numerics_h_q = data->points[j]; \
tmp.numerics_h_r = data->points[k]; \
\
if (i < j) { \
if (j < k) /* i < j < k */ \
det = Det2D(tmp.numerics_h_p, tmp.numerics_h_q, tmp.numerics_h_r); \
else if (i < k) /* i < k < j */ \
det = -Det2D(tmp.numerics_h_p, tmp.numerics_h_r, tmp.numerics_h_q); \
else /* k < i < j */ \
det = Det2D(tmp.numerics_h_r, tmp.numerics_h_p, tmp.numerics_h_q); \
} \
else { \
if (i < k) /* j < i < k */ \
det = -Det2D(tmp.numerics_h_q, tmp.numerics_h_p, tmp.numerics_h_r); \
else if (j < k) /* j < k < i */ \
det = Det2D(tmp.numerics_h_q, tmp.numerics_h_r, tmp.numerics_h_p); \
else /* k < j < i */ \
det = -Det2D(tmp.numerics_h_r, tmp.numerics_h_q, tmp.numerics_h_p); \
} \
} \
}
#endif
/* */
/* this macro sets ori to +1 if the points i, j, k are given in CCW order, */
/* -1 if the points i, j, k are given in CW order, */
/* 0 if the points i, j, k are collinear. */
/* */
#define Orientation(data, tmp, i, j, k, ori) \
{ StableDet2D(data, tmp, i, j, k, tmp.numerics_h_det); \
\
if (lt(tmp.numerics_h_det, EPS)) ori = -1; \
else if (gt(tmp.numerics_h_det, EPS)) ori = 1; \
else ori = 0; \
}
/* */
/* this macro sets ori to +1 if the points i, j, k are given in CCW order, */
/* -1 if the points i, j, k are given in CW order, */
/* 0 if the points i, j, k are collinear. */
/* */
#define OrientationThres(data, tmp, i, j, k, ori, thres) \
{ StableDet2D(data, tmp, i, j, k, tmp.numerics_h_det); \
\
if (lt(tmp.numerics_h_det, thres)) ori = -1; \
else if (gt(tmp.numerics_h_det, thres)) ori = 1; \
else ori = 0; \
}
/* */
/* this macro checks whether l is in the cone defined by i, j and j, k */
/* */
#define IsInConeStrict(data, tmp, i, j, k, l, convex, flag, thres) \
{ assert(InPointsList(data, i)); \
assert(InPointsList(data, j)); \
assert(InPointsList(data, k)); \
assert(InPointsList(data, l)); \
\
flag = true; \
if (convex) { \
if ((l != i) && (i != j)) { \
OrientationThres(data, tmp, i, j, l, tmp.numerics_h_ori1, thres); \
if (tmp.numerics_h_ori1 <= 0) flag = false; \
} \
if ((l != k) && (j != k) && (flag == true)) { \
OrientationThres(data, tmp, j, k, l, tmp.numerics_h_ori2, thres); \
if (tmp.numerics_h_ori2 <= 0) flag = false; \
} \
} \
else { \
OrientationThres(data, tmp, i, j, l, tmp.numerics_h_ori1, thres); \
if (tmp.numerics_h_ori1 <= 0) { \
OrientationThres(data, tmp, j, k, l, tmp.numerics_h_ori2, thres); \
if (tmp.numerics_h_ori2 <= 0) flag = false; \
} \
} \
}
/* */
/* this macro checks whether l is in the cone defined by i, j and j, k */
/* */
#define IsInCone(data, tmp, i, j, k, l, convex, flag) \
{ assert(InPointsList(data, i)); \
assert(InPointsList(data, j)); \
assert(InPointsList(data, k)); \
assert(InPointsList(data, l)); \
\
flag = true; \
if (convex) { \
if ((l != i) && (i != j)) { \
Orientation(data, tmp, i, j, l, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 < 0) flag = false; \
else if (tmp.numerics_h_ori1 == 0) { \
if (i < j) { \
if (!InBetween(i, j, l)) flag = false; \
} \
else { \
if (!InBetween(j, i, l)) flag = false; \
} \
} \
} \
if ((l != k) && (j != k) && (flag == true)) { \
Orientation(data, tmp, j, k, l, tmp.numerics_h_ori2); \
if (tmp.numerics_h_ori2 < 0) flag = false; \
else if (tmp.numerics_h_ori2 == 0) { \
if (j < k) { \
if (!InBetween(j, k, l)) flag = false; \
} \
else { \
if (!InBetween(k, j, l)) flag = false; \
} \
} \
} \
} \
else { \
Orientation(data, tmp, i, j, l, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 <= 0) { \
Orientation(data, tmp, j, k, l, tmp.numerics_h_ori2); \
if (tmp.numerics_h_ori2 <= 0) { \
if (tmp.numerics_h_ori1 == 0) { \
if (!InBetween(i, j, l)) flag = false; \
} \
else if (tmp.numerics_h_ori2 == 0) { \
if (!InBetween(j, k, l)) flag = false; \
} \
else flag = false; \
} \
} \
} \
}
/* */
/* this macro checks whether l is in the cone defined by i, j and j, k */
/* */
#define IsInConeEps(data, tmp, i, j, k, l, convex, flag) \
{ assert(InPointsList(data, i)); \
assert(InPointsList(data, j)); \
assert(InPointsList(data, k)); \
assert(InPointsList(data, l)); \
\
flag = true; \
if (convex) { \
if ((l != i) && (i != j)) { \
Orientation(data, tmp, i, j, l, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 < 0) flag = false; \
else if (tmp.numerics_h_ori1 == 0) { \
if (!InBetweenEps(data, i, j, l)) flag = false; \
} \
} \
if ((l != k) && (j != k) && (flag == true)) { \
Orientation(data, tmp, j, k, l, tmp.numerics_h_ori2); \
if (tmp.numerics_h_ori2 < 0) flag = false; \
else if (tmp.numerics_h_ori2 == 0) { \
if (!InBetweenEps(data, j, k, l)) flag = false; \
} \
} \
} \
else { \
Orientation(data, tmp, i, j, l, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 <= 0) { \
Orientation(data, tmp, j, k, l, tmp.numerics_h_ori2); \
if (tmp.numerics_h_ori2 <= 0) { \
if (tmp.numerics_h_ori1 == 0) { \
if (!InBetweenEps(data, i, j, l)) flag = false; \
} \
else if (tmp.numerics_h_ori2 == 0) { \
if (!InBetweenEps(data, j, k, l)) flag = false; \
} \
else flag = false; \
} \
} \
} \
}
/* */
/* this macro checks whether the diagonal j, l is in the cone defined by */
/* i, j and j, k. if left then j, k, l forms the ear to be tested. */
/* otherwise, i, j, k forms the ear to be tested. */
/* */
#define DiagIsInConeEps(data, tmp, i, j, k, l, convex, left, flag) \
{ assert(InPointsList(data, i)); \
assert(InPointsList(data, j)); \
assert(InPointsList(data, k)); \
assert(InPointsList(data, l)); \
\
flag = true; \
if (convex) { \
if (left) { \
if ((l != i) && (i != j)) { \
Orientation(data, tmp, i, j, l, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 < 0) flag = false; \
else if (tmp.numerics_h_ori1 == 0) { \
if (InBetweenEps(data, j, l, i)) flag = false; \
} \
} \
} \
else { \
if ((l != k) && (j != k)) { \
Orientation(data, tmp, j, k, l, tmp.numerics_h_ori2); \
if (tmp.numerics_h_ori2 < 0) flag = false; \
else if (tmp.numerics_h_ori2 == 0) { \
if (InBetweenEps(data, j, l, k)) flag = false; \
} \
} \
} \
} \
}
#define DiagIsInCone(data, tmp, i, j, k, l, convex, left, flag) \
{ assert(InPointsList(data, i)); \
assert(InPointsList(data, j)); \
assert(InPointsList(data, k)); \
assert(InPointsList(data, l)); \
\
flag = true; \
if (convex) { \
if (left) { \
if ((l != i) && (i != j)) { \
Orientation(data, tmp, i, j, l, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 < 0) flag = false; \
else if (tmp.numerics_h_ori1 == 0) { \
if (InBetween(j, l, i)) flag = false; \
} \
} \
} \
else { \
if ((l != k) && (j != k)) { \
Orientation(data, tmp, j, k, l, tmp.numerics_h_ori2); \
if (tmp.numerics_h_ori2 < 0) flag = false; \
else if (tmp.numerics_h_ori2 == 0) { \
if (InBetween(j, l, k)) flag = false; \
} \
} \
} \
} \
}
/* */
/* returns */
/* -2 ... if angle is 360 degrees */
/* -1 ... if angle between 180 and 360 degrees */
/* 0 ... if angle is 180 degrees */
/* 1 ... if angle between 0 and 180 degrees */
/* 2 ... if angle is 0 degrees */
/* 3 ... if angle is about 180 degrees and triangle is very small */
/* */
inline int IsConvexAngle(listdef *list, datadef *data, int i, int j, int k,
list_ind ind) {
assert(InPointsList(data, i));
assert(InPointsList(data, j));
assert(InPointsList(data, k));
tmp_data_def tmp;
if (i == j) {
if (j == k) {
/* */
/* all three vertices are identical. we set the angle to -2. */
/* using -2 means to err on the safe side, as all the */
/* incarnations of this vertex will be clipped right at the */
/* start of the ear-clipping algorithm. thus, eventually there */
/* will be no other duplicates at this vertex position, and the */
/* regular classification of angles will yield the correct */
/* answer for j. */
/* */
return -2;
}
else {
/* */
/* two of the three vertices are identical; we set the angle to */
/* to 2 order to enable clipping of j. */
/* */
return 2;
}
}
else if (j == k) {
/* */
/* two vertices are identical. we could either determine the angle */
/* by means of yet another lengthy analysis, or simply set the */
/* angle to -1. using -1 means to err on the safe side, as all the */
/* incarnations of this vertex will be clipped right at the start */
/* of the ear-clipping algorithm. thus, eventually there will be no */
/* other duplicates at this vertex position, and the regular */
/* classification of angles will yield the correct answer for j. */
/* */
return -1;
} else {
StableDet2D(data, tmp, i, j, k, tmp.numerics_h_det);
if (gt(tmp.numerics_h_det, EPS)) {
return 1;
}
else if (lt(tmp.numerics_h_det, EPS)) {
return -1;
}
else {
/* */
/* 0, 180, or 360 degrees. */
/* */
VectorSub2D(data->points[i], data->points[j], tmp.numerics_h_p);
VectorSub2D(data->points[k], data->points[j], tmp.numerics_h_q);
tmp.numerics_h_dot = DotProduct2D(tmp.numerics_h_p, tmp.numerics_h_q);
if (tmp.numerics_h_dot < C_0_0) {
/* */
/* 180 degrees. */
/* */
/*data->numerics_h_dot = sqrt(Length2D(data->numerics_h_p)); */
/*data->numerics_h_dot += sqrt(Length2D(data->numerics_h_q)); */
if (tmp.numerics_h_det > C_0_0) return 1;
else return 0;
}
else {
/* */
/* 0 or 360 degrees? this cannot be judged locally, and more */
/* work is needed. */
/* */
return SpikeAngle(list, data, i, j, k, ind);
}
}
}
}
/* */
/* this macro checks whether point i4 is inside of or on the boundary */
/* of the triangle i1, i2, i3 */
/* */
#define PntInTriangle(data, tmp, i1, i2, i3, i4, inside) \
{ \
inside = false; \
Orientation(data, tmp, i2, i3, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 >= 0) { \
Orientation(data, tmp, i1, i2, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 >= 0) { \
Orientation(data, tmp, i3, i1, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 >= 0) inside = true; \
} \
} \
}
/* */
/* this macro checks whether point i4 is inside of or on the boundary */
/* of the triangle i1, i2, i3. it also returns a classification if i4 is */
/* on the boundary of the triangle (except for the edge i2, i3). */
/* */
#define VtxInTriangle(data, tmp, i1, i2, i3, i4, inside, classifier) \
{ \
inside = false; \
Orientation(data, tmp, i2, i3, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 >= 0) { \
Orientation(data, tmp, i1, i2, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 > 0) { \
Orientation(data, tmp, i3, i1, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 > 0) { \
inside = true; \
classifier = 0; \
} \
else if (tmp.numerics_h_ori1 == 0) { \
inside = true; \
classifier = 1; \
} \
} \
else if (tmp.numerics_h_ori1 == 0) { \
Orientation(data, tmp, i3, i1, i4, tmp.numerics_h_ori1); \
if (tmp.numerics_h_ori1 > 0) { \
inside = true; \
classifier = 2; \
} \
else if (tmp.numerics_h_ori1 == 0) { \
inside = true; \
classifier = 3; \
} \
} \
} \
}
#define ComputeRatio(A, B, C, RATIO) \
{ \
if (Min(B, C) <= ZERO) { \
RATIO = Min(B, C); \
} \
else { \
RATIO = CD_1_0 + (A - B - C) / (CD_2_0 * sqrt(B * C)); \
} \
}