1
///////////////////////////////////////////////////////////////////////////////
2
/// @file OgreOpcodeMath.cpp
3
/// @brief Triangle Intersection routines
5
/// @author The OgreOpcode Team
7
///////////////////////////////////////////////////////////////////////////////
9
/// This file is part of OgreOpcode.
11
/// A lot of the code is based on the Nebula Opcode Collision module, see docs/Nebula_license.txt
13
/// OgreOpcode is free software; you can redistribute it and/or
14
/// modify it under the terms of the GNU Lesser General Public
15
/// License as published by the Free Software Foundation; either
16
/// version 2.1 of the License, or (at your option) any later version.
18
/// OgreOpcode is distributed in the hope that it will be useful,
19
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
20
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
/// Lesser General Public License for more details.
23
/// You should have received a copy of the GNU Lesser General Public
24
/// License along with OgreOpcode; if not, write to the Free Software
25
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
///////////////////////////////////////////////////////////////////////////////
29
#include "OgreOpcodeMath.h"
36
#define SMALL_EPSILON 0.000001f
38
#define FABS(x) (fabsf(x)) /* implement as is fastest on your machine */
40
/* if USE_EPSILON_TEST is true then we do a check:
41
if |dv|<SMALL_EPSILON then dv=0.0;
42
else no check is done (which is less robust)
44
#define USE_EPSILON_TEST TRUE
48
/* sort so that a<=b */
58
/* this edge to edge test is based on Franlin Antonio's gem:
59
"Faster Line Segment Intersection", in Graphics Gems III,
61
#define EDGE_EDGE_TEST(V0,U0,U1) \
68
if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) \
73
if(e>=0 && e<=f) return true; \
77
if(e<=0 && e>=f) return true; \
81
#define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \
83
float Ax,Ay,Bx,By,Cx,Cy,e,d,f; \
86
/* test edge U0,U1 against V0,V1 */ \
87
EDGE_EDGE_TEST(V0,U0,U1); \
88
/* test edge U1,U2 against V0,V1 */ \
89
EDGE_EDGE_TEST(V0,U1,U2); \
90
/* test edge U2,U1 against V0,V1 */ \
91
EDGE_EDGE_TEST(V0,U2,U0); \
94
#define POINT_IN_TRI(V0,U0,U1,U2) \
96
float a,b,c,d0,d1,d2; \
97
/* is T1 completly inside T2? */ \
98
/* check if V0 is inside tri(U0,U1,U2) */ \
100
b=-(U1[i0]-U0[i0]); \
101
c=-a*U0[i0]-b*U0[i1]; \
102
d0=a*V0[i0]+b*V0[i1]+c; \
105
b=-(U2[i0]-U1[i0]); \
106
c=-a*U1[i0]-b*U1[i1]; \
107
d1=a*V0[i0]+b*V0[i1]+c; \
110
b=-(U0[i0]-U2[i0]); \
111
c=-a*U2[i0]-b*U2[i1]; \
112
d2=a*V0[i0]+b*V0[i1]+c; \
115
if(d0*d2>0.0) return true; \
119
static bool coplanar_tri_tri(const Vector3& N, const Vector3 tri1[3],
120
const Vector3 tri2[3])
124
/* first project onto an axis-aligned plane, that maximizes the area */
125
/* of the triangles, compute indices: i0,i1. */
133
i0=1; /* A[0] is greatest */
138
i0=0; /* A[2] is greatest */
142
else /* A[0]<=A[1] */
146
i0=0; /* A[2] is greatest */
151
i0=0; /* A[1] is greatest */
156
/* test all edges of triangle 1 against the edges of triangle 2 */
157
EDGE_AGAINST_TRI_EDGES(tri1[0],tri1[1],tri2[0],tri2[1],tri2[2]);
158
EDGE_AGAINST_TRI_EDGES(tri1[1],tri1[2],tri2[0],tri2[1],tri2[2]);
159
EDGE_AGAINST_TRI_EDGES(tri1[2],tri1[0],tri2[0],tri2[1],tri2[2]);
161
/* finally, test if tri1 is totally contained in tri2 or vice versa */
162
POINT_IN_TRI(tri1[0],tri2[0],tri2[1],tri2[2]);
163
POINT_IN_TRI(tri2[0],tri1[0],tri1[1],tri1[2]);
168
#define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \
172
/* here we know that D0D2<=0.0 */ \
173
/* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
174
A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \
178
/* here we know that d0d1<=0.0 */ \
179
A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \
181
else if(D1*D2>0.0f || D0!=0.0f) \
183
/* here we know that d0d1<=0.0 or that D0!=0.0 */ \
184
A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \
188
A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \
192
A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \
196
/* triangles are coplanar */ \
197
return coplanar_tri_tri(N1,tri1,tri2); \
202
* Tests if two triangles intersect (without divisions)
204
* @param tri1 Vertices of triangle 1
205
* @param tri2 Vertices of triangle 2
206
* @return true if the triangles intersect, otherwise false
210
bool Intersect3::triangleTriangle(const Vector3 tri1[3],
211
const Vector3 tri2[3])
216
float du0,du1,du2,dv0,dv1,dv2;
218
float isect1[2], isect2[2];
219
float du0du1,du0du2,dv0dv1,dv0dv2;
226
float xx,yy,xxyy,tmp;
228
/* compute plane equation of triangle(tri1) */
229
E1 = tri1[1] - tri1[0];
230
E2 = tri1[2] - tri1[0];
231
N1 = E1.crossProduct(E2);
232
d1=-(N1.dotProduct(tri1[0]));
233
/* plane equation 1: N1.X+d1=0 */
235
/* put tri2 into plane equation 1 to compute signed distances to the plane*/
236
du0=(N1.dotProduct(tri2[0]))+d1;
237
du1=(N1.dotProduct(tri2[1]))+d1;
238
du2=(N1.dotProduct(tri2[2]))+d1;
240
/* coplanarity robustness check */
241
#if USE_EPSILON_TEST==TRUE
242
if(FABS(du0)<SMALL_EPSILON) du0=0.0;
243
if(FABS(du1)<SMALL_EPSILON) du1=0.0;
244
if(FABS(du2)<SMALL_EPSILON) du2=0.0;
249
if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
250
return 0; /* no intersection occurs */
252
/* compute plane of triangle (tri2) */
253
E1 = tri2[1] - tri2[0];
254
E2 = tri2[2] - tri2[0];
255
N2 = E1.crossProduct(E2);
256
d2=-(N2.dotProduct(tri2[0]));
257
/* plane equation 2: N2.X+d2=0 */
259
/* put tri1 into plane equation 2 */
260
dv0=(N2.dotProduct(tri1[0]))+d2;
261
dv1=(N2.dotProduct(tri1[1]))+d2;
262
dv2=(N2.dotProduct(tri1[2]))+d2;
264
#if USE_EPSILON_TEST==TRUE
265
if(FABS(dv0)<SMALL_EPSILON) dv0=0.0;
266
if(FABS(dv1)<SMALL_EPSILON) dv1=0.0;
267
if(FABS(dv2)<SMALL_EPSILON) dv2=0.0;
273
if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
274
return 0; /* no intersection occurs */
276
/* compute direction of intersection line */
277
D = N1.crossProduct(N2);
279
/* compute and index to the largest component of D */
280
max=(float)FABS(D[0]);
282
bb=(float)FABS(D[1]);
283
cc=(float)FABS(D[2]);
284
if(bb>max) max=bb,index=1;
285
if(cc>max) max=cc,index=2;
287
/* this is the simplified projection onto L*/
296
/* compute interval for triangle 1 */
297
NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1);
299
/* compute interval for triangle 2 */
300
NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1);
307
isect1[0]=tmp+b*x1*yy;
308
isect1[1]=tmp+c*x0*yy;
311
isect2[0]=tmp+e*xx*y1;
312
isect2[1]=tmp+f*xx*y0;
314
SORT(isect1[0],isect1[1]);
315
SORT(isect2[0],isect2[1]);
317
if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return false;
321
/* sort so that a<=b */
322
#define SORT2(a,b,smallest) \
334
static inline void isect2(const Vector3 tri[3],float VV0,float VV1,float VV2,
335
float D0,float D1,float D2,float *isect0,float *isect1,Vector3 isectline[2])
337
float tmp=D0/(D0-D1);
339
*isect0=VV0+(VV1-VV0)*tmp;
340
diff = tri[1] - tri[0];
342
isectline[0] = diff + tri[0];
344
*isect1=VV0+(VV2-VV0)*tmp;
345
diff = tri[2] - tri[0];
347
isectline[1] = tri[0] + diff;
351
static inline bool compute_intervals_isectline(const Vector3 tri[3],
352
float VV0,float VV1,float VV2,float D0,float D1,float D2,
353
float D0D1,float D0D2,float *isect0,float *isect1,
354
Vector3 isectline[2])
358
/* here we know that D0D2<=0.0 */
359
/* that is D0, D1 are on the same side, D2 on the other or on the plane */
360
Vector3 newTri[3] = {tri[2], tri[0], tri[1]};
361
isect2(newTri,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectline);
365
Vector3 newTri[3] = {tri[1], tri[0], tri[2]};
366
/* here we know that d0d1<=0.0 */
367
isect2(newTri,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectline);
369
else if(D1*D2>0.0f || D0!=0.0f)
371
Vector3 newTri[3] = {tri[0], tri[1], tri[2]};
372
/* here we know that d0d1<=0.0 or that D0!=0.0 */
373
isect2(newTri,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectline);
377
Vector3 newTri[3] = {tri[1], tri[0], tri[2]};
378
isect2(newTri,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectline);
382
Vector3 newTri[3] = {tri[2], tri[0], tri[1]};
383
isect2(newTri,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectline);
387
/* triangles are coplanar */
393
#define COMPUTE_INTERVALS_ISECTLINE(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1,isectpoint0,isectpoint1) \
396
/* here we know that D0D2<=0.0 */ \
397
/* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
398
isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \
403
/* here we know that d0d1<=0.0 */ \
404
isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \
406
else if(D1*D2>0.0f || D0!=0.0f) \
408
/* here we know that d0d1<=0.0 or that D0!=0.0 */ \
409
isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,&isect0,&isect1,isectpoint0,isectpoint1); \
413
isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \
417
isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \
421
/* triangles are coplanar */ \
423
return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \
428
* Tests if two triangles intersect and compute the line of intersection
429
* (if they are not coplanar).
431
* @param tri1 Vertices of triangle 1
432
* @param tri2 Vertices of triangle 2
433
* @param[out] isectline The line segment where they intersect
434
* @param[out] coplanar Returns whether the triangles are coplanar
435
* @return true if the triangles intersect, otherwise false
439
bool Intersect3::triangleTriangle(const Vector3 tri1[3],
440
const Vector3 tri2[3],
441
Segment3& isectline, bool& coplanar)
446
float du0,du1,du2,dv0,dv1,dv2;
448
float isect1[2] = {0,0}, isect2[2] = {0,0};
449
Vector3 isectpointA[2];
450
Vector3 isectpointB[2];
451
float du0du1,du0du2,dv0dv1,dv0dv2;
456
int smallest1,smallest2;
458
/* compute plane equation of triangle(tri1) */
459
E1 = tri1[1] - tri1[0];
460
E2 = tri1[2] - tri1[0];
461
N1 = E1.crossProduct(E2);
462
d1 =-(N1.dotProduct(tri1[0]));
463
/* plane equation 1: N1.X+d1=0 */
465
/* put tri2 into plane equation 1 to compute signed distances to the plane*/
466
du0=(N1.dotProduct(tri2[0]))+d1;
467
du1=(N1.dotProduct(tri2[1]))+d1;
468
du2=(N1.dotProduct(tri2[2]))+d1;
470
/* coplanarity robustness check */
471
#if USE_EPSILON_TEST==TRUE
472
if(fabs(du0)<SMALL_EPSILON) du0=0.0;
473
if(fabs(du1)<SMALL_EPSILON) du1=0.0;
474
if(fabs(du2)<SMALL_EPSILON) du2=0.0;
479
if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
480
return 0; /* no intersection occurs */
482
/* compute plane of triangle (tri2) */
483
E1 = tri2[1] - tri2[0];
484
E2 = tri2[2] - tri2[0];
485
N2 = E1.crossProduct(E2);
486
d2=-(N2.dotProduct(tri2[0]));
487
/* plane equation 2: N2.X+d2=0 */
489
/* put tri1 into plane equation 2 */
490
dv0=(N2.dotProduct(tri1[0]))+d2;
491
dv1=(N2.dotProduct(tri1[1]))+d2;
492
dv2=(N2.dotProduct(tri1[2]))+d2;
494
#if USE_EPSILON_TEST==TRUE
495
if(fabs(dv0)<SMALL_EPSILON) dv0=0.0;
496
if(fabs(dv1)<SMALL_EPSILON) dv1=0.0;
497
if(fabs(dv2)<SMALL_EPSILON) dv2=0.0;
503
if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
504
return 0; /* no intersection occurs */
506
/* compute direction of intersection line */
507
D = N1.crossProduct(N2);
509
/* compute and index to the largest component of D */
514
if(b>max) max=b,index=1;
515
if(c>max) max=c,index=2;
517
/* this is the simplified projection onto L*/
526
/* compute interval for triangle 1 */
527
coplanar=compute_intervals_isectline(tri1,vp0,vp1,vp2,dv0,dv1,dv2,
528
dv0dv1,dv0dv2,&isect1[0],&isect1[1],isectpointA);
529
if(coplanar) return coplanar_tri_tri(N1, tri1, tri2);
532
/* compute interval for triangle 2 */
533
compute_intervals_isectline(tri2,up0,up1,up2,du0,du1,du2,
534
du0du1,du0du2,&isect2[0],&isect2[1],isectpointB);
536
SORT2(isect1[0],isect1[1],smallest1);
537
SORT2(isect2[0],isect2[1],smallest2);
539
if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
541
/* at this point, we know that the triangles intersect */
543
if(isect2[0]<isect1[0])
545
if(smallest1==0) { isectline.setStart(isectpointA[0]); }
546
else { isectline.setStart(isectpointA[1]); }
548
if(isect2[1]<isect1[1])
550
if(smallest2==0) { isectline.setEnd(isectpointB[1]); }
551
else { isectline.setEnd(isectpointB[0]); }
555
if(smallest1==0) { isectline.setEnd(isectpointA[1]); }
556
else { isectline.setEnd(isectpointA[0]); }
561
if(smallest2==0) { isectline.setStart(isectpointB[0]); }
562
else { isectline.setStart(isectpointB[1]); }
564
if(isect2[1]>isect1[1])
566
if(smallest1==0) { isectline.setEnd(isectpointA[1]); }
567
else { isectline.setEnd(isectpointA[0]); }
571
if(smallest2==0) { isectline.setEnd(isectpointB[1]); }
572
else { isectline.setEnd(isectpointB[0]); }
578
bool powerOf2(unsigned int i)
580
Ogre::String binary = decimalToBinary(i);
582
for( int index = 0; index < static_cast<int>(binary.size()); ++index )
583
if( binary[index] == '1' ) ++counter;
585
if( counter > 1 ) return false;
589
Ogre::String decimalToBinary(unsigned int i)
591
Ogre::String binary = "";
592
Ogre::String temp = "";
595
temp += (i % 2) + '0';
599
for( int counter = static_cast<int>(temp.size()); counter > 0; --counter )
600
binary += temp[counter];