GCC Code Coverage Report


Directory: ./
File: lib/exploragram/hexdom/geometry.cpp
Date: 2026-09-07 02:28:19
Exec Total Coverage
Lines: 0 157 0.0%
Functions: 0 17 0.0%
Branches: 0 378 0.0%

Line Branch Exec Source
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 #include <exploragram/hexdom/geometry.h>
41 #include <geogram/numerics/matrix_util.h>
42 #include <geogram/basic/logger.h>
43
44 namespace {
45 using namespace GEO;
46
47 const index_t cot_edges[6][2] = {
48 { 0, 1 }, { 0, 2 }, { 0, 3 }, { 1, 2 }, { 2, 3 }, { 3, 1 }
49 } ;
50
51 }
52
53 namespace GEO {
54
55 CoTan3D::CoTan3D(vec3 P[4], double* anisotropy_as_xx_yy_zz_xy_yz_xz ) {
56 tetvol = (1. / 6.) * dot(P[3] - P[0], cross(P[1] - P[0], P[2] - P[0]));
57 Matrix<6, double> M;
58 M.load_zero();
59 double isotrope_objective[6] = { 1, 1, 1, 0, 0, 0 };
60 double *RHS = anisotropy_as_xx_yy_zz_xy_yz_xz;
61 if (RHS == nullptr)
62 RHS = isotrope_objective;
63 FOR(e, 6){
64 vec3 geom = P[cot_edges[e][1]] - P[cot_edges[e][0]];
65 M(0, e) = geom.x*geom.x;
66 M(1, e) = geom.y*geom.y;
67 M(2, e) = geom.z*geom.z;
68 M(3, e) = 2. * geom.x*geom.y;
69 M(4, e) = 2. * geom.y*geom.z;
70 M(5, e) = 2. * geom.z*geom.x;
71 }
72 Matrix<6, double> inv;
73 bool invertible = M.compute_inverse(inv);
74 if (!invertible) GEO::Logger::out("HexDom") << "Solve did not work" << std::endl;
75 mult(inv, RHS, w);
76 }
77
78
79 index_t CoTan3D::org(index_t e) { return cot_edges[e][0]; }
80 index_t CoTan3D::dest(index_t e) { return cot_edges[e][1]; }
81 double CoTan3D::coeff(index_t e) { return w[e]; }
82
83 void CoTan3D::check_for_grad(vec3 P[4], vec3 grad){
84 double v[4];
85 FOR(i, 4) v[i] = dot(grad, P[i]);
86 double sum = 0;
87 FOR(e, 6) sum += (v[dest(e)] - v[org(e)])*(v[dest(e)] - v[org(e)])* coeff(e);
88 std::cerr << "NRJ = " << grad.length2()
89 << "\t\twith cot = " << sum
90 << "\t\tratio = " << grad.length2() / sum
91 << std::endl;
92 }
93
94 /*******************************************************************************/
95
96 TrglGradient::TrglGradient(const vec3& p0, const vec3& p1, const vec3& p2) {
97 initialize(p0, p1, p2);
98 }
99
100 TrglGradient::TrglGradient() {
101 }
102
103 void TrglGradient::initialize(const vec3& p0, const vec3& p1, const vec3& p2) {
104
105 // Computing TX[] and TY[],
106 // i.e. the coefficients such that:
107 // | df/dX = TX[0].f(v0) + TX[1].f(v1) + TX[2].f(v2)
108 // | df/dY = TY[0].f(v0) + TY[1].f(v1) + TY[2].f(v2)
109 //
110 // (in other words, these coefficient give the gradient of a property
111 // interpolated in the triangle T = (a0, a1, a2).
112
113 // The equations of the coefficients can be simplified,
114 // the general equations are given as code in comments
115 // marked by the tag [simplified]
116
117 vertex_[0] = p0;
118 vertex_[1] = p1;
119 vertex_[2] = p2;
120
121 // Step1: find an orthonormal basis (X, Y) for the triangle.
122 //----------------------------------------------------------
123
124 vec3 origin;
125 vec3 X;
126 vec3 Y;
127 vec3 Z;
128
129 basis(origin, X, Y, Z); // Rem: origin = v0.
130
131 // Step2: compute the coordinates of the three vertices of the
132 // triangle in this basis.
133 //------------------------------------------------------------
134
135 // [simplified] double x0 = 0.0 ;
136 // [simplified] double y0 = 0.0 ;
137 vec3 V1 = p1 - p0;
138 double x1 = sqrt(dot(V1, V1));
139
140 // [simplified] double y1 = 0.0 ;
141 vec3 V2 = p2 - p0;
142 double x2 = dot(V2, X);
143 double y2 = dot(V2, Y);
144
145
146 // Step3: compute the six coefficients TXi and TYi allowing to
147 // compute the two components of the gradient of a function in
148 // the basis (I,X,Y).
149 //------------------------------------------------------------
150
151 // [simplified]
152 // double d = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) ;
153
154 double d = x1 * y2;
155
156 if (fabs(d) < 1e-10) {
157 Logger::warn("TrglGrad")
158 << "Attempted gradient computation on a flat triangle"
159 << std::endl;
160 d = 1.0;
161 is_flat_ = true;
162 } else {
163 is_flat_ = false;
164 }
165
166 // [simplified] TX_[0] = (y1 - y2) / d ;
167 // [simplified] TX_[1] = (y2 - y0) / d ;
168 // [simplified] TX_[2] = (y0 - y1) / d ;
169
170 double xx1 = (x1 == 0.0) ? 1.0 : x1;
171
172 TX_[0] = -1.0 / xx1;
173 TX_[1] = 1.0 / xx1;
174 TX_[2] = 0.0;
175
176 // [simplified] TY_[0] = (x2 - x1) / d ;
177 // [simplified] TY_[1] = (x0 - x2) / d ;
178 // [simplified] TY_[2] = (x1 - x0) / d ;
179
180 double yy2 = (y2 == 0.0) ? 1.0 : y2;
181
182 TY_[0] = x2 / d - 1.0 / yy2;
183 TY_[1] = -x2 / d;
184 TY_[2] = 1.0 / yy2;
185 }
186
187 void TrglGradient::basis(vec3& origin, vec3& X, vec3& Y, vec3& Z) const {
188 const vec3& p0 = vertex_[0];
189 const vec3& p1 = vertex_[1];
190 const vec3& p2 = vertex_[2];
191
192 X = normalize(p1 - p0);
193 Z = normalize(cross(X, p2 - p0));
194 Y = cross(Z, X);
195 origin = p0;
196 }
197
198 vec3 TrglGradient::gradient_3d(double value0, double value1, double value2) const {
199 double x = TX_[0] * value0 + TX_[1] * value1; // Note: TX_[2] = 0
200 double y = TY_[0] * value0 + TY_[1] * value1 + TY_[2] * value2;
201 vec3 O;
202 vec3 X, Y, Z;
203 basis(O, X, Y, Z);
204 return x*X + y*Y;
205 }
206
207 /**********************************************************************************/
208
209 // _____ _____ ____ _____ _ _ _
210 // | __ \ / ____| /\ |___ \| __ \ | | | | | |
211 // | |__) | | / \ __) | | | | ______ ______ _ __ ___ | |_ ___ ___ _ __ | |_ ___ _ __ ___ __| |
212 // | ___/| | / /\ \ |__ <| | | | |______|______| | '_ \ / _ \| __| / __/ _ \ '_ \| __/ _ \ '__/ _ \/ _` |
213 // | | | |____ / ____ \ ___) | |__| | | | | | (_) | |_ | (_| __/ | | | || __/ | | __/ (_| |
214 // |_| \_____/_/ \_\ |____/|_____/ |_| |_|\___/ \__| \___\___|_| |_|\__\___|_| \___|\__,_|
215 //
216 //
217
218 void UncenteredPCA3D::begin_points(){
219 nb_points_ = 0;
220 sum_weights_ = M_[0] = M_[1] = M_[2] = M_[3] = M_[4] = M_[5] = 0;
221 }
222
223 void UncenteredPCA3D::point(const vec3& p, double weight){
224 M_[0] += weight * p.x*p.x;
225 M_[1] += weight * p.x*p.y; M_[2] += weight * p.y*p.y;
226 M_[3] += weight * p.x*p.z; M_[4] += weight * p.y*p.z; M_[5] += weight * p.z*p.z;
227 nb_points_++;
228 sum_weights_ += weight;
229 }
230
231 void UncenteredPCA3D::end_points(){
232 for (int i = 0; i < 6; i++) M_[i] = M_[i] / sum_weights_;
233 if (M_[0] <= 0) M_[0] = 1.e-30;
234 if (M_[2] <= 0) M_[2] = 1.e-30;
235 if (M_[5] <= 0) M_[5] = 1.e-30;
236 double eigen_vectors[9];
237 // TODO: remove this dependance
238 GEO::MatrixUtil::semi_definite_symmetric_eigen(M_, 3, eigen_vectors, eigen_value);
239
240 for (int i = 0; i < 3; i++) axis[i] = normalize(vec3(eigen_vectors[3 * i + 0], eigen_vectors[3 * i + 1], eigen_vectors[3 * i + 2]));
241 }
242
243
244 /**********************************************************************************/
245 /* Triangle-Triangle and Triangle-Box intersection routines by Tomas Moller, 1997 */
246 /**********************************************************************************/
247
248 // [Bruno] Modernized it a bit and replaced some macros with templates.
249
250 template <class T> inline T FABS(T x) {
251 return T(::fabs(double(x)));
252 }
253
254 /* if USE_EPSILON_TEST is true then we do a check:
255 * if |dv|<EPSILON then dv=0.0;
256 * else no check is done (which is less robust)
257 */
258 #define USE_EPSILON_TEST
259
260 const double EPSILON = 0.000001;
261
262 template <class T> inline void CROSS(T dest[3], const T v1[3], const T v2[3]) {
263 dest[0] = v1[1] * v2[2] - v1[2] * v2[1];
264 dest[1] = v1[2] * v2[0] - v1[0] * v2[2];
265 dest[2] = v1[0] * v2[1] - v1[1] * v2[0];
266 }
267
268 template <class T> inline T DOT(T v1[3], T v2[3]) {
269 return (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]);
270 }
271
272 template <class T> inline void SUB(T dest[3], const T v1[3], const T v2[3]) {
273 dest[0] = v1[0] - v2[0];
274 dest[1] = v1[1] - v2[1];
275 dest[2] = v1[2] - v2[2];
276 }
277
278 /* sort so that a<=b */
279 template <class T> inline void SORT(T& a, T& b) {
280 if(a>b) {
281 std::swap(a,b);
282 }
283 }
284
285 /* this edge to edge test is based on Franlin Antonio's gem:
286 * "Faster Line Segment Intersection", in Graphics Gems III,
287 * pp. 199-202
288 */
289 #define EDGE_EDGE_TEST(V0,U0,U1) \
290 Bx = U0[i0] - U1[i0]; \
291 By = U0[i1] - U1[i1]; \
292 Cx = V0[i0] - U0[i0]; \
293 Cy = V0[i1] - U0[i1]; \
294 f = Ay*Bx - Ax*By; \
295 d = By*Cx - Bx*Cy; \
296 if ((f>0 && d >= 0 && d <= f) || (f<0 && d <= 0 && d >= f)) \
297 { \
298 e = Ax*Cy - Ay*Cx; \
299 if (f>0) \
300 { \
301 if (e >= 0 && e <= f) return 1; \
302 } \
303 else \
304 { \
305 if (e <= 0 && e >= f) return 1; \
306 } \
307 }
308
309 #define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \
310 { \
311 double Ax, Ay, Bx, By, Cx, Cy, e, d, f; \
312 Ax = V1[i0] - V0[i0]; \
313 Ay = V1[i1] - V0[i1]; \
314 /* test edge U0,U1 against V0,V1 */ \
315 EDGE_EDGE_TEST(V0, U0, U1); \
316 /* test edge U1,U2 against V0,V1 */ \
317 EDGE_EDGE_TEST(V0, U1, U2); \
318 /* test edge U2,U1 against V0,V1 */ \
319 EDGE_EDGE_TEST(V0, U2, U0); \
320 }
321
322 #define POINT_IN_TRI(V0,U0,U1,U2) \
323 { \
324 double a, b, c, d0, d1, d2; \
325 /* is T1 completly inside T2? */ \
326 /* check if V0 is inside tri(U0,U1,U2) */ \
327 a = U1[i1] - U0[i1]; \
328 b = -(U1[i0] - U0[i0]); \
329 c = -a*U0[i0] - b*U0[i1]; \
330 d0 = a*V0[i0] + b*V0[i1] + c; \
331 \
332 a = U2[i1] - U1[i1]; \
333 b = -(U2[i0] - U1[i0]); \
334 c = -a*U1[i0] - b*U1[i1]; \
335 d1 = a*V0[i0] + b*V0[i1] + c; \
336 \
337 a = U0[i1] - U2[i1]; \
338 b = -(U0[i0] - U2[i0]); \
339 c = -a*U2[i0] - b*U2[i1]; \
340 d2 = a*V0[i0] + b*V0[i1] + c; \
341 if (d0*d1>0.0) \
342 { \
343 if (d0*d2>0.0) return 1; \
344 } \
345 }
346
347 static int coplanar_tri_tri(
348 double N[3], double V0[3], double V1[3], double V2[3],
349 double U0[3], double U1[3], double U2[3]
350 ) {
351 double A[3];
352 short i0, i1;
353 /* first project onto an axis-aligned plane, that maximizes the area */
354 /* of the triangles, compute indices: i0,i1. */
355 A[0] = FABS(N[0]);
356 A[1] = FABS(N[1]);
357 A[2] = FABS(N[2]);
358 if (A[0]>A[1])
359 {
360 if (A[0]>A[2])
361 {
362 i0 = 1; /* A[0] is greatest */
363 i1 = 2;
364 }
365 else
366 {
367 i0 = 0; /* A[2] is greatest */
368 i1 = 1;
369 }
370 }
371 else /* A[0]<=A[1] */
372 {
373 if (A[2]>A[1])
374 {
375 i0 = 0; /* A[2] is greatest */
376 i1 = 1;
377 }
378 else
379 {
380 i0 = 0; /* A[1] is greatest */
381 i1 = 2;
382 }
383 }
384
385 /* test all edges of triangle 1 against the edges of triangle 2 */
386 EDGE_AGAINST_TRI_EDGES(V0, V1, U0, U1, U2);
387 EDGE_AGAINST_TRI_EDGES(V1, V2, U0, U1, U2);
388 EDGE_AGAINST_TRI_EDGES(V2, V0, U0, U1, U2);
389
390 /* finally, test if tri1 is totally contained in tri2 or vice versa */
391 POINT_IN_TRI(V0, U0, U1, U2);
392 POINT_IN_TRI(U0, V0, V1, V2);
393
394 return 0;
395 }
396
397
398
399 #define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \
400 { \
401 if (D0D1>0.0) \
402 { \
403 /* here we know that D0D2<=0.0 */ \
404 /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
405 A = VV2; B = (VV0 - VV2)*D2; C = (VV1 - VV2)*D2; X0 = D2 - D0; X1 = D2 - D1; \
406 } \
407 else if (D0D2>0.0) \
408 { \
409 /* here we know that d0d1<=0.0 */ \
410 A = VV1; B = (VV0 - VV1)*D1; C = (VV2 - VV1)*D1; X0 = D1 - D0; X1 = D1 - D2; \
411 } \
412 else if (D1*D2>0.0 || D0 != 0.0) \
413 { \
414 /* here we know that d0d1<=0.0 or that D0!=0.0 */ \
415 A = VV0; B = (VV1 - VV0)*D0; C = (VV2 - VV0)*D0; X0 = D0 - D1; X1 = D0 - D2; \
416 } \
417 else if (D1 != 0.0) \
418 { \
419 A = VV1; B = (VV0 - VV1)*D1; C = (VV2 - VV1)*D1; X0 = D1 - D0; X1 = D1 - D2; \
420 } \
421 else if (D2 != 0.0) \
422 { \
423 A = VV2; B = (VV0 - VV2)*D2; C = (VV1 - VV2)*D2; X0 = D2 - D0; X1 = D2 - D1; \
424 } \
425 else \
426 { \
427 /* triangles are coplanar */ \
428 return coplanar_tri_tri(N1, V0, V1, V2, U0, U1, U2); \
429 } \
430 }
431
432 int NoDivTriTriIsect(
433 double V0[3], double V1[3], double V2[3],
434 double U0[3], double U1[3], double U2[3]
435 ) {
436 double E1[3], E2[3];
437 double N1[3], N2[3], d1, d2;
438 double du0, du1, du2, dv0, dv1, dv2;
439 double D[3];
440 double isect1[2], isect2[2];
441 double du0du1, du0du2, dv0dv1, dv0dv2;
442 short index;
443 double vp0, vp1, vp2;
444 double up0, up1, up2;
445 double bb, cc, max;
446
447 /* compute plane equation of triangle(V0,V1,V2) */
448 SUB(E1, V1, V0);
449 SUB(E2, V2, V0);
450 CROSS(N1, E1, E2);
451 d1 = -DOT(N1, V0);
452 /* plane equation 1: N1.X+d1=0 */
453
454 /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
455 du0 = DOT(N1, U0) + d1;
456 du1 = DOT(N1, U1) + d1;
457 du2 = DOT(N1, U2) + d1;
458
459 /* coplanarity robustness check */
460 #ifdef USE_EPSILON_TEST
461 if (FABS(du0)<EPSILON) du0 = 0.0;
462 if (FABS(du1)<EPSILON) du1 = 0.0;
463 if (FABS(du2)<EPSILON) du2 = 0.0;
464 #endif
465 du0du1 = du0*du1;
466 du0du2 = du0*du2;
467
468 if (du0du1>0.0 && du0du2>0.0) /* same sign on all of them + not equal 0 ? */
469 return 0; /* no intersection occurs */
470
471 /* compute plane of triangle (U0,U1,U2) */
472 SUB(E1, U1, U0);
473 SUB(E2, U2, U0);
474 CROSS(N2, E1, E2);
475 d2 = -DOT(N2, U0);
476 /* plane equation 2: N2.X+d2=0 */
477
478 /* put V0,V1,V2 into plane equation 2 */
479 dv0 = DOT(N2, V0) + d2;
480 dv1 = DOT(N2, V1) + d2;
481 dv2 = DOT(N2, V2) + d2;
482
483 #ifdef USE_EPSILON_TEST
484 if (FABS(dv0)<EPSILON) dv0 = 0.0;
485 if (FABS(dv1)<EPSILON) dv1 = 0.0;
486 if (FABS(dv2)<EPSILON) dv2 = 0.0;
487 #endif
488
489 dv0dv1 = dv0*dv1;
490 dv0dv2 = dv0*dv2;
491
492 if (dv0dv1>0.0 && dv0dv2>0.0) /* same sign on all of them + not equal 0 ? */
493 return 0; /* no intersection occurs */
494
495 /* compute direction of intersection line */
496 CROSS(D, N1, N2);
497
498 /* compute and index to the largest component of D */
499 max = (double)FABS(D[0]);
500 index = 0;
501 bb = (double)FABS(D[1]);
502 cc = (double)FABS(D[2]);
503 if (bb>max) {max = bb; index = 1;}
504 if (cc>max) {max = cc; index = 2;}
505
506 /* this is the simplified projection onto L*/
507 vp0 = V0[index];
508 vp1 = V1[index];
509 vp2 = V2[index];
510
511 up0 = U0[index];
512 up1 = U1[index];
513 up2 = U2[index];
514
515 /* compute interval for triangle 1 */
516 double a, b, c, x0, x1;
517 NEWCOMPUTE_INTERVALS(vp0, vp1, vp2, dv0, dv1, dv2, dv0dv1, dv0dv2, a, b, c, x0, x1);
518
519 /* compute interval for triangle 2 */
520 double d, e, f, y0, y1;
521 NEWCOMPUTE_INTERVALS(up0, up1, up2, du0, du1, du2, du0du1, du0du2, d, e, f, y0, y1);
522
523 double xx, yy, xxyy, tmp;
524 xx = x0*x1;
525 yy = y0*y1;
526 xxyy = xx*yy;
527
528 tmp = a*xxyy;
529 isect1[0] = tmp + b*x1*yy;
530 isect1[1] = tmp + c*x0*yy;
531
532 tmp = d*xxyy;
533 isect2[0] = tmp + e*xx*y1;
534 isect2[1] = tmp + f*xx*y0;
535
536 SORT(isect1[0], isect1[1]);
537 SORT(isect2[0], isect2[1]);
538
539 if (isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
540 return 1;
541 }
542
543 /*******************************************************************************/
544
545 #define X 0
546 #define Y 1
547 #define Z 2
548
549 template <class T> inline void FINDMINMAX(T x0, T x1, T x2, T& min, T& max) {
550 min = max = x0;
551 if(x1<min) min=x1;
552 if(x1>max) max=x1;
553 if(x2<min) min=x2;
554 if(x2>max) max=x2;
555 }
556
557 static int planeBoxOverlap(float normal[3], float d, float maxbox[3]) {
558 int q;
559 float vmin[3], vmax[3];
560 for (q = X; q <= Z; q++)
561 {
562 if (normal[q]>0.0f)
563 {
564 vmin[q] = -maxbox[q];
565 vmax[q] = maxbox[q];
566 }
567 else
568 {
569 vmin[q] = maxbox[q];
570 vmax[q] = -maxbox[q];
571 }
572 }
573 if (DOT(normal, vmin) + d>0.0f) return 0;
574 if (DOT(normal, vmax) + d >= 0.0f) return 1;
575
576 return 0;
577 }
578
579 /*======================== X-tests ========================*/
580 #define AXISTEST_X01(a, b, fa, fb) \
581 p0 = a*v0[Y] - b*v0[Z]; \
582 p2 = a*v2[Y] - b*v2[Z]; \
583 if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
584 rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
585 if(min>rad || max<-rad) return 0;
586
587 #define AXISTEST_X2(a, b, fa, fb) \
588 p0 = a*v0[Y] - b*v0[Z]; \
589 p1 = a*v1[Y] - b*v1[Z]; \
590 if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
591 rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
592 if(min>rad || max<-rad) return 0;
593
594 /*======================== Y-tests ========================*/
595 #define AXISTEST_Y02(a, b, fa, fb) \
596 p0 = -a*v0[X] + b*v0[Z]; \
597 p2 = -a*v2[X] + b*v2[Z]; \
598 if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
599 rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
600 if(min>rad || max<-rad) return 0;
601
602 #define AXISTEST_Y1(a, b, fa, fb) \
603 p0 = -a*v0[X] + b*v0[Z]; \
604 p1 = -a*v1[X] + b*v1[Z]; \
605 if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
606 rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
607 if(min>rad || max<-rad) return 0;
608
609 /*======================== Z-tests ========================*/
610
611 #define AXISTEST_Z12(a, b, fa, fb) \
612 p1 = a*v1[X] - b*v1[Y]; \
613 p2 = a*v2[X] - b*v2[Y]; \
614 if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
615 rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
616 if(min>rad || max<-rad) return 0;
617
618 #define AXISTEST_Z0(a, b, fa, fb) \
619 p0 = a*v0[X] - b*v0[Y]; \
620 p1 = a*v1[X] - b*v1[Y]; \
621 if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
622 rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
623 if(min>rad || max<-rad) return 0;
624
625
626 int triBoxOverlap(
627 float boxcenter[3], float boxhalfsize[3], float triverts[3][3]
628 ) {
629
630 /* use separating axis theorem to test overlap between triangle and box */
631 /* need to test for overlap in these directions: */
632 /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
633 /* we do not even need to test these) */
634 /* 2) normal of the triangle */
635 /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
636 /* this gives 3x3=9 more tests */
637 float v0[3], v1[3], v2[3];
638 float min, max, d, p0, p1, p2, rad, fex, fey, fez;
639 float normal[3], e0[3], e1[3], e2[3];
640
641 /* This is the fastest branch on Sun */
642 /* move everything so that the boxcenter is in (0,0,0) */
643 SUB(v0, triverts[0], boxcenter);
644 SUB(v1, triverts[1], boxcenter);
645 SUB(v2, triverts[2], boxcenter);
646
647 /* compute triangle edges */
648 SUB(e0, v1, v0); /* tri edge 0 */
649 SUB(e1, v2, v1); /* tri edge 1 */
650 SUB(e2, v0, v2); /* tri edge 2 */
651
652 /* Bullet 3: */
653 /* test the 9 tests first (this was faster) */
654 fex = FABS(e0[X]);
655 fey = FABS(e0[Y]);
656 fez = FABS(e0[Z]);
657 AXISTEST_X01(e0[Z], e0[Y], fez, fey);
658 AXISTEST_Y02(e0[Z], e0[X], fez, fex);
659 AXISTEST_Z12(e0[Y], e0[X], fey, fex);
660
661 fex = FABS(e1[X]);
662 fey = FABS(e1[Y]);
663 fez = FABS(e1[Z]);
664 AXISTEST_X01(e1[Z], e1[Y], fez, fey);
665 AXISTEST_Y02(e1[Z], e1[X], fez, fex);
666 AXISTEST_Z0(e1[Y], e1[X], fey, fex);
667
668 fex = FABS(e2[X]);
669 fey = FABS(e2[Y]);
670 fez = FABS(e2[Z]);
671 AXISTEST_X2(e2[Z], e2[Y], fez, fey);
672 AXISTEST_Y1(e2[Z], e2[X], fez, fex);
673 AXISTEST_Z12(e2[Y], e2[X], fey, fex);
674
675 /* Bullet 1: */
676 /* first test overlap in the {x,y,z}-directions */
677 /* find min, max of the triangle each direction, and test for overlap in */
678 /* that direction -- this is equivalent to testing a minimal AABB around */
679 /* the triangle against the AABB */
680
681 /* test in X-direction */
682 FINDMINMAX(v0[X], v1[X], v2[X], min, max);
683 if (min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0;
684
685 /* test in Y-direction */
686 FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max);
687 if (min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0;
688
689 /* test in Z-direction */
690 FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max);
691 if (min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0;
692
693 /* Bullet 2: */
694 /* test if the box intersects the plane of the triangle */
695 /* compute plane equation of triangle: normal*x+d=0 */
696 CROSS(normal, e0, e1);
697 d = -DOT(normal, v0); /* plane eq: normal.x+d=0 */
698 if (!planeBoxOverlap(normal, d, boxhalfsize)) return 0;
699
700 return 1; /* box and triangle overlaps */
701 }
702
703 /*******************************************************************************/
704
705
706 }
707