2 * OPCODE - Optimized Collision Detection
3 * http://www.codercorner.com/Opcode.htm
5 * Copyright (c) 2001-2008 Pierre Terdiman, pierre@codercorner.com
7 This software is provided 'as-is', without any express or implied warranty.
8 In no event will the authors be held liable for any damages arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it freely,
11 subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
14 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
15 3. This notice may not be removed or altered from any source distribution.
18 //! if OPC_TRITRI_EPSILON_TEST is true then we do a check (if |dv|<EPSILON then dv=0.0;) else no check is done (which is less robust, but faster)
19 #define LOCAL_EPSILON 0.000001f
30 //! Edge to edge test based on Franlin Antonio's gem: "Faster Line Segment Intersection", in Graphics Gems III, pp. 199-202
31 #define EDGE_EDGE_TEST(V0, U0, U1) \
32 Bx = U0[i0] - U1[i0]; \
33 By = U0[i1] - U1[i1]; \
34 Cx = V0[i0] - U0[i0]; \
35 Cy = V0[i1] - U0[i1]; \
38 if((f>0.0f && d>=0.0f && d<=f) || (f<0.0f && d<=0.0f && d>=f)) \
40 const float e=Ax*Cy - Ay*Cx; \
43 if(e>=0.0f && e<=f) return TRUE; \
47 if(e<=0.0f && e>=f) return TRUE; \
52 #define EDGE_AGAINST_TRI_EDGES(V0, V1, U0, U1, U2) \
54 float Bx,By,Cx,Cy,d,f; \
55 const float Ax = V1[i0] - V0[i0]; \
56 const float Ay = V1[i1] - V0[i1]; \
57 /* test edge U0,U1 against V0,V1 */ \
58 EDGE_EDGE_TEST(V0, U0, U1); \
59 /* test edge U1,U2 against V0,V1 */ \
60 EDGE_EDGE_TEST(V0, U1, U2); \
61 /* test edge U2,U1 against V0,V1 */ \
62 EDGE_EDGE_TEST(V0, U2, U0); \
66 #define POINT_IN_TRI(V0, U0, U1, U2) \
68 /* is T1 completly inside T2? */ \
69 /* check if V0 is inside tri(U0,U1,U2) */ \
70 float a = U1[i1] - U0[i1]; \
71 float b = -(U1[i0] - U0[i0]); \
72 float c = -a*U0[i0] - b*U0[i1]; \
73 float d0 = a*V0[i0] + b*V0[i1] + c; \
75 a = U2[i1] - U1[i1]; \
76 b = -(U2[i0] - U1[i0]); \
77 c = -a*U1[i0] - b*U1[i1]; \
78 const float d1 = a*V0[i0] + b*V0[i1] + c; \
80 a = U0[i1] - U2[i1]; \
81 b = -(U0[i0] - U2[i0]); \
82 c = -a*U2[i0] - b*U2[i1]; \
83 const float d2 = a*V0[i0] + b*V0[i1] + c; \
86 if(d0*d2>0.0f) return TRUE; \
91 BOOL CoplanarTriTri(const Point& n, const Point& v0, const Point& v1, const Point& v2, const Point& u0, const Point& u1, const Point& u2)
95 /* first project onto an axis-aligned plane, that maximizes the area */
96 /* of the triangles, compute indices: i0,i1. */
104 i0=1; /* A[0] is greatest */
109 i0=0; /* A[2] is greatest */
113 else /* A[0]<=A[1] */
117 i0=0; /* A[2] is greatest */
122 i0=0; /* A[1] is greatest */
127 /* test all edges of triangle 1 against the edges of triangle 2 */
128 EDGE_AGAINST_TRI_EDGES(v0, v1, u0, u1, u2);
129 EDGE_AGAINST_TRI_EDGES(v1, v2, u0, u1, u2);
130 EDGE_AGAINST_TRI_EDGES(v2, v0, u0, u1, u2);
132 /* finally, test if tri1 is totally contained in tri2 or vice versa */
133 POINT_IN_TRI(v0, u0, u1, u2);
134 POINT_IN_TRI(u0, v0, v1, v2);
140 #define NEWCOMPUTE_INTERVALS(VV0, VV1, VV2, D0, D1, D2, D0D1, D0D2, A, B, C, X0, X1) \
144 /* here we know that D0D2<=0.0 */ \
145 /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
146 A=VV2; B=(VV0 - VV2)*D2; C=(VV1 - VV2)*D2; X0=D2 - D0; X1=D2 - D1; \
150 /* here we know that d0d1<=0.0 */ \
151 A=VV1; B=(VV0 - VV1)*D1; C=(VV2 - VV1)*D1; X0=D1 - D0; X1=D1 - D2; \
153 else if(D1*D2>0.0f || D0!=0.0f) \
155 /* here we know that d0d1<=0.0 or that D0!=0.0 */ \
156 A=VV0; B=(VV1 - VV0)*D0; C=(VV2 - VV0)*D0; X0=D0 - D1; X1=D0 - D2; \
160 A=VV1; B=(VV0 - VV1)*D1; C=(VV2 - VV1)*D1; X0=D1 - D0; X1=D1 - D2; \
164 A=VV2; B=(VV0 - VV2)*D2; C=(VV1 - VV2)*D2; X0=D2 - D0; X1=D2 - D1; \
168 /* triangles are coplanar */ \
169 return CoplanarTriTri(N1, V0, V1, V2, U0, U1, U2); \
173 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
175 * Triangle/triangle intersection test routine,
176 * by Tomas Moller, 1997.
177 * See article "A Fast Triangle-Triangle Intersection Test",
178 * Journal of Graphics Tools, 2(2), 1997
180 * Updated June 1999: removed the divisions -- a little faster now!
181 * Updated October 1999: added {} to CROSS and SUB macros
183 * int NoDivTriTriIsect(float V0[3],float V1[3],float V2[3],
184 * float U0[3],float U1[3],float U2[3])
186 * \param V0 [in] triangle 0, vertex 0
187 * \param V1 [in] triangle 0, vertex 1
188 * \param V2 [in] triangle 0, vertex 2
189 * \param U0 [in] triangle 1, vertex 0
190 * \param U1 [in] triangle 1, vertex 1
191 * \param U2 [in] triangle 1, vertex 2
192 * \return true if triangles overlap
194 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
195 inline_ BOOL AABBTreeCollider::TriTriOverlap(const Point& V0, const Point& V1, const Point& V2, const Point& U0, const Point& U1, const Point& U2)
200 // Compute plane equation of triangle(V0,V1,V2)
203 const Point N1 = E1 ^ E2;
204 const float d1 =-N1 | V0;
205 // Plane equation 1: N1.X+d1=0
207 // Put U0,U1,U2 into plane equation 1 to compute signed distances to the plane
208 float du0 = (N1|U0) + d1;
209 float du1 = (N1|U1) + d1;
210 float du2 = (N1|U2) + d1;
212 // Coplanarity robustness check
213 #ifdef OPC_TRITRI_EPSILON_TEST
214 if(fabsf(du0)<LOCAL_EPSILON) du0 = 0.0f;
215 if(fabsf(du1)<LOCAL_EPSILON) du1 = 0.0f;
216 if(fabsf(du2)<LOCAL_EPSILON) du2 = 0.0f;
218 const float du0du1 = du0 * du1;
219 const float du0du2 = du0 * du2;
221 if(du0du1>0.0f && du0du2>0.0f) // same sign on all of them + not equal 0 ?
222 return FALSE; // no intersection occurs
224 // Compute plane of triangle (U0,U1,U2)
227 const Point N2 = E1 ^ E2;
228 const float d2=-N2 | U0;
229 // plane equation 2: N2.X+d2=0
231 // put V0,V1,V2 into plane equation 2
232 float dv0 = (N2|V0) + d2;
233 float dv1 = (N2|V1) + d2;
234 float dv2 = (N2|V2) + d2;
236 #ifdef OPC_TRITRI_EPSILON_TEST
237 if(fabsf(dv0)<LOCAL_EPSILON) dv0 = 0.0f;
238 if(fabsf(dv1)<LOCAL_EPSILON) dv1 = 0.0f;
239 if(fabsf(dv2)<LOCAL_EPSILON) dv2 = 0.0f;
242 const float dv0dv1 = dv0 * dv1;
243 const float dv0dv2 = dv0 * dv2;
245 if(dv0dv1>0.0f && dv0dv2>0.0f) // same sign on all of them + not equal 0 ?
246 return FALSE; // no intersection occurs
248 // Compute direction of intersection line
249 const Point D = N1^N2;
251 // Compute and index to the largest component of D
252 float max=fabsf(D[0]);
254 float bb=fabsf(D[1]);
255 float cc=fabsf(D[2]);
256 if(bb>max) max=bb,index=1;
257 if(cc>max) max=cc,index=2;
259 // This is the simplified projection onto L
260 const float vp0 = V0[index];
261 const float vp1 = V1[index];
262 const float vp2 = V2[index];
264 const float up0 = U0[index];
265 const float up1 = U1[index];
266 const float up2 = U2[index];
268 // Compute interval for triangle 1
270 NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1);
272 // Compute interval for triangle 2
274 NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1);
276 const float xx=x0*x1;
277 const float yy=y0*y1;
278 const float xxyy=xx*yy;
280 float isect1[2], isect2[2];
283 isect1[0]=tmp+b*x1*yy;
284 isect1[1]=tmp+c*x0*yy;
287 isect2[0]=tmp+e*xx*y1;
288 isect2[1]=tmp+f*xx*y0;
290 SORT(isect1[0],isect1[1]);
291 SORT(isect2[0],isect2[1]);
293 if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return FALSE;