2 * ICE / 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.
17 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
19 * Contains a handy triangle class.
20 * \file IceTriangle.cpp
21 * \author Pierre Terdiman
22 * \date January, 17, 2000
24 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30 using namespace Opcode;
32 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34 * Contains a triangle class.
37 * \author Pierre Terdiman
41 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
43 static sdword VPlaneSideEps(const Point& v, const Plane& plane, float epsilon)
45 // Compute distance from current vertex to the plane
46 float Dist = plane.Distance(v);
48 // 1 = the vertex is on the positive side of the plane
49 // -1 = the vertex is on the negative side of the plane
50 // 0 = the vertex is on the plane (within epsilon)
51 return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0;
54 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
56 * Flips the winding order.
58 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
61 Point Tmp = mVerts[1];
62 mVerts[1] = mVerts[2];
66 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
68 * Computes the triangle area.
71 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
72 float Triangle::Area() const
74 const Point& p0 = mVerts[0];
75 const Point& p1 = mVerts[1];
76 const Point& p2 = mVerts[2];
77 return ((p0 - p1)^(p0 - p2)).Magnitude() * 0.5f;
80 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
82 * Computes the triangle perimeter.
83 * \return the perimeter
85 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
86 float Triangle::Perimeter() const
88 const Point& p0 = mVerts[0];
89 const Point& p1 = mVerts[1];
90 const Point& p2 = mVerts[2];
91 return p0.Distance(p1)
96 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
98 * Computes the triangle compacity.
99 * \return the compacity
101 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102 float Triangle::Compacity() const
104 float P = Perimeter();
105 if(P==0.0f) return 0.0f;
106 return (4.0f*PI*Area()/(P*P));
109 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
111 * Computes the triangle normal.
112 * \param normal [out] the computed normal
114 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
115 void Triangle::Normal(Point& normal) const
117 const Point& p0 = mVerts[0];
118 const Point& p1 = mVerts[1];
119 const Point& p2 = mVerts[2];
120 normal = ((p0 - p1)^(p0 - p2)).Normalize();
123 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
125 * Computes the triangle denormalized normal.
126 * \param normal [out] the computed normal
128 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
129 void Triangle::DenormalizedNormal(Point& normal) const
131 const Point& p0 = mVerts[0];
132 const Point& p1 = mVerts[1];
133 const Point& p2 = mVerts[2];
134 normal = ((p0 - p1)^(p0 - p2));
137 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
139 * Computes the triangle center.
140 * \param center [out] the computed center
142 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
143 void Triangle::Center(Point& center) const
145 const Point& p0 = mVerts[0];
146 const Point& p1 = mVerts[1];
147 const Point& p2 = mVerts[2];
148 center = (p0 + p1 + p2)*INV3;
151 PartVal Triangle::TestAgainstPlane(const Plane& plane, float epsilon) const
153 bool Pos = false, Neg = false;
155 // Loop through all vertices
156 for(udword i=0;i<3;i++)
159 sdword Side = VPlaneSideEps(mVerts[i], plane, epsilon);
161 if (Side < 0) Neg = true;
162 else if (Side > 0) Pos = true;
165 if (!Pos && !Neg) return TRI_ON_PLANE;
166 else if (Pos && Neg) return TRI_INTERSECT;
167 else if (Pos && !Neg) return TRI_PLUS_SPACE;
168 else if (!Pos && Neg) return TRI_MINUS_SPACE;
171 return TRI_FORCEDWORD;
174 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
176 * Computes the triangle moment.
177 * \param m [out] the moment
179 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
181 void Triangle::ComputeMoment(Moment& m)
183 // Compute the area of the triangle
186 // Compute the centroid
189 // Second-order components. Handle zero-area faces.
190 Point& p = mVerts[0];
191 Point& q = mVerts[1];
192 Point& r = mVerts[2];
195 // This triangle has zero area. The second order components would be eliminated with the usual formula, so, for the
196 // sake of robustness we use an alternative form. These are the centroid and second-order components of the triangle's vertices.
197 m.mCovariance.m[0][0] = (p.x*p.x + q.x*q.x + r.x*r.x);
198 m.mCovariance.m[0][1] = (p.x*p.y + q.x*q.y + r.x*r.y);
199 m.mCovariance.m[0][2] = (p.x*p.z + q.x*q.z + r.x*r.z);
200 m.mCovariance.m[1][1] = (p.y*p.y + q.y*q.y + r.y*r.y);
201 m.mCovariance.m[1][2] = (p.y*p.z + q.y*q.z + r.y*r.z);
202 m.mCovariance.m[2][2] = (p.z*p.z + q.z*q.z + r.z*r.z);
203 m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
204 m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
205 m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
209 const float OneOverTwelve = 1.0f / 12.0f;
210 m.mCovariance.m[0][0] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.x + p.x*p.x + q.x*q.x + r.x*r.x) * OneOverTwelve;
211 m.mCovariance.m[0][1] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.y + p.x*p.y + q.x*q.y + r.x*r.y) * OneOverTwelve;
212 m.mCovariance.m[1][1] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.y + p.y*p.y + q.y*q.y + r.y*r.y) * OneOverTwelve;
213 m.mCovariance.m[0][2] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.z + p.x*p.z + q.x*q.z + r.x*r.z) * OneOverTwelve;
214 m.mCovariance.m[1][2] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.z + p.y*p.z + q.y*q.z + r.y*r.z) * OneOverTwelve;
215 m.mCovariance.m[2][2] = m.mArea * (9.0f * m.mCentroid.z*m.mCentroid.z + p.z*p.z + q.z*q.z + r.z*r.z) * OneOverTwelve;
216 m.mCovariance.m[2][1] = m.mCovariance.m[1][2];
217 m.mCovariance.m[1][0] = m.mCovariance.m[0][1];
218 m.mCovariance.m[2][0] = m.mCovariance.m[0][2];
223 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
225 * Computes the triangle's smallest edge length.
226 * \return the smallest edge length
228 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
229 float Triangle::MinEdgeLength() const
231 float Min = MAX_FLOAT;
232 float Length01 = mVerts[0].Distance(mVerts[1]);
233 float Length02 = mVerts[0].Distance(mVerts[2]);
234 float Length12 = mVerts[1].Distance(mVerts[2]);
235 if(Length01 < Min) Min = Length01;
236 if(Length02 < Min) Min = Length02;
237 if(Length12 < Min) Min = Length12;
241 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
243 * Computes the triangle's largest edge length.
244 * \return the largest edge length
246 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
247 float Triangle::MaxEdgeLength() const
249 float Max = MIN_FLOAT;
250 float Length01 = mVerts[0].Distance(mVerts[1]);
251 float Length02 = mVerts[0].Distance(mVerts[2]);
252 float Length12 = mVerts[1].Distance(mVerts[2]);
253 if(Length01 > Max) Max = Length01;
254 if(Length02 > Max) Max = Length02;
255 if(Length12 > Max) Max = Length12;
259 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
261 * Computes a point on the triangle according to the stabbing information.
262 * \param u,v [in] point's barycentric coordinates
263 * \param pt [out] point on triangle
264 * \param nearvtx [out] index of nearest vertex
266 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
267 void Triangle::ComputePoint(float u, float v, Point& pt, udword* nearvtx) const
269 // Compute point coordinates
270 pt = (1.0f - u - v)*mVerts[0] + u*mVerts[1] + v*mVerts[2];
272 // Compute nearest vertex if needed
275 // Compute distance vector
276 Point d(mVerts[0].SquareDistance(pt), // Distance^2 from vertex 0 to point on the face
277 mVerts[1].SquareDistance(pt), // Distance^2 from vertex 1 to point on the face
278 mVerts[2].SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face
280 // Get smallest distance
281 *nearvtx = d.SmallestAxis();
285 void Triangle::Inflate(float fat_coeff, bool constant_border)
287 // Compute triangle center
288 Point TriangleCenter;
289 Center(TriangleCenter);
292 // Normalize => add a constant border, regardless of triangle size
293 // Don't => add more to big triangles
294 for(udword i=0;i<3;i++)
296 Point v = mVerts[i] - TriangleCenter;
298 if(constant_border) v.Normalize();
300 mVerts[i] += v * fat_coeff;