00001 // GMTL is (C) Copyright 2001-2010 by Allen Bierbaum 00002 // Distributed under the GNU Lesser General Public License 2.1 with an 00003 // addendum covering inlined code. (See accompanying files LICENSE and 00004 // LICENSE.addendum or http://www.gnu.org/copyleft/lesser.txt) 00005 00006 #ifndef _GMTL_TRI_H_ 00007 #define _GMTL_TRI_H_ 00008 00009 #include <gmtl/Point.h> 00010 #include <gmtl/Vec.h> 00011 #include <gmtl/VecOps.h> 00012 00013 namespace gmtl 00014 { 00022 template< class DATA_TYPE > 00023 class Tri 00024 { 00025 public: 00029 Tri() {} 00030 00041 Tri( const Point<DATA_TYPE, 3>& p1, const Point<DATA_TYPE, 3>& p2, 00042 const Point<DATA_TYPE, 3>& p3) 00043 { 00044 mVerts[0] = p1; 00045 mVerts[1] = p2; 00046 mVerts[2] = p3; 00047 } 00048 00054 Tri( const Tri<DATA_TYPE>& tri ) 00055 { 00056 mVerts[0] = tri[0]; 00057 mVerts[1] = tri[1]; 00058 mVerts[2] = tri[2]; 00059 } 00060 00070 Point<DATA_TYPE, 3>& operator[]( const unsigned idx ) 00071 { 00072 gmtlASSERT( idx <= 2 ); 00073 return mVerts[idx]; 00074 } 00075 const Point<DATA_TYPE, 3>& operator[]( const unsigned idx ) const 00076 { 00077 gmtlASSERT( idx <= 2 ); 00078 return mVerts[idx]; 00079 } 00081 00092 Vec<DATA_TYPE, 3> edge( int idx ) const 00093 { 00094 gmtlASSERT( (0 <= idx) && (idx <= 2) ); 00095 int idx2 = ( idx == 2 ) ? 0 : idx + 1; 00096 return (mVerts[idx2] - mVerts[idx]); 00097 } 00098 00106 Vec<DATA_TYPE, 3> edge( int idx, int idy ) const 00107 { 00108 gmtlASSERT( (0 <= idx) && (idx <= 2) ); 00109 gmtlASSERT( (0 <= idy) && (idy <= 2) ); 00110 return (mVerts[idy] - mVerts[idx]); 00111 } 00112 00113 00114 00125 void set( const Point<DATA_TYPE, 3>& p1, const Point<DATA_TYPE, 3>& p2, 00126 const Point<DATA_TYPE, 3>& p3 ) 00127 { 00128 mVerts[0] = p1; 00129 mVerts[1] = p2; 00130 mVerts[2] = p3; 00131 } 00132 00133 public: 00137 Point<DATA_TYPE, 3> mVerts[3]; 00138 }; 00139 00140 // convenience typedefs 00141 typedef Tri<float> Trif; 00142 typedef Tri<double> Trid; 00143 typedef Tri<int> Trii; 00144 } 00145 00146 /* 00147 // Finds the point on the seg nearest to pt. 00148 // on the perimeter of the triangle. 00149 // Returns the nearest point in nearPt 00150 inline 00151 void sgTri::findNearestEdgePt(const sgVec3& pt, sgVec3& nearPt) const 00152 { 00153 // find all the closest pts on the segs that make the tri 00154 // return the closest one 00155 00156 sgSeg seg1; seg1.makePts(_v1, _v2); 00157 sgSeg seg2; seg2.makePts(_v2, _v3); 00158 sgSeg seg3; seg3.makePts(_v3, _v1); 00159 00160 sgVec3 pt1; seg1.findNearestPt(pt, pt1); 00161 sgVec3 pt2; seg2.findNearestPt(pt, pt2); 00162 sgVec3 pt3; seg3.findNearestPt(pt, pt3); 00163 00164 float dist1 = SG_SQUARE(pt1[0]-pt[0]) + SG_SQUARE(pt1[1]-pt[1]) + SG_SQUARE(pt1[2]-pt[2]); 00165 float dist2 = SG_SQUARE(pt2[0]-pt[0]) + SG_SQUARE(pt2[1]-pt[1]) + SG_SQUARE(pt2[2]-pt[2]); 00166 float dist3 = SG_SQUARE(pt3[0]-pt[0]) + SG_SQUARE(pt3[1]-pt[1]) + SG_SQUARE(pt3[2]-pt[2]); 00167 00168 if((dist1 < dist2) && (dist1 < dist3)) // dist1 is min 00169 nearPt = pt1; 00170 else if(dist2 < dist3) // dist2 is min 00171 nearPt = pt2; 00172 else 00173 nearPt = pt3; // dist3 is min 00174 } 00175 00176 00177 00178 // Returns wether the pt is in the triangle 00179 inline 00180 int sgTri::ptIn(const sgVec3& pt) const 00181 { 00182 // Graphic Gems I: Page 392 00183 int i0, i1, i2; // Axis indices 00184 float u0, u1, u2, v0, v1, v2, alpha, beta; 00185 i0 = 0; 00186 00187 sgVec3 triNormal = (_v2-_v1).cross((_v3-_v1)); 00188 //sgPlane triPlane; 00189 //triPlane.makePts(_v1, _v2, _v3); 00190 00191 // Find max index 00192 // NOTE: note the fabs. I added because of bug in GG code with negative normals 00193 for(int index=0;index<3;index++) 00194 if (fabs(triNormal.vec[index]) > fabs(triNormal.vec[i0])) 00195 i0 = index; 00196 00197 if(i0 == 0) 00198 { i1 = 1; i2 = 2; } 00199 else if (i0 == 1) 00200 { i1 = 2; i2 = 0; } 00201 else 00202 { i1 =0; i2 = 1; } 00203 00204 u0 = pt[i1] - _v1[i1]; 00205 v0 = pt[i2] - _v1[i2]; 00206 u1 = _v2[i1] - _v1[i1]; 00207 u2 = _v3[i1] - _v1[i1]; 00208 v1 = _v2[i2] - _v1[i2]; 00209 v2 = _v3[i2] - _v1[i2]; 00210 if(u1 == 0) 00211 { 00212 beta = (u0/u2); 00213 if((beta >= 0) && (beta<= 1)) 00214 alpha = (v0 - (beta*v2))/v1; 00215 } 00216 else 00217 { 00218 beta = ((v0*u1) - (u0*v1))/((v2*u1) - (u2*v1)); 00219 if((beta >= 0) && (beta<= 1)) 00220 alpha = (u0 - (beta*u2))/u1; 00221 } 00222 00223 return ((alpha >= 0) && (beta >= 0) && ((alpha+beta) <= 1)); 00224 } 00225 00226 00227 00228 // Finds the point on the seg nearest to pt. 00229 // Returns the nearest point in nearPt 00230 void sgTri::findNearestPt(const sgVec3& pt, sgVec3& nearPt) const 00231 { 00232 // find nearest pt on plaane. 00233 // if it is in the tri, return it. 00234 // Otherwise return the pt closest on the edge of the tri 00235 00236 sgPlane triPlane; 00237 triPlane.makePts(_v1, _v2, _v3); 00238 triPlane.findNearestPt(pt, nearPt); 00239 00240 if(!ptIn(nearPt)) 00241 findNearestEdgePt(pt, nearPt); 00242 } 00243 */ 00244 00245 #endif 00246