mPolyhedron.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "math/mPolyhedron.h"
  24. #include "platform/typetraits.h"
  25. //-----------------------------------------------------------------------------
  26. void PolyhedronVectorData::buildFromPlanes( const PlaneSetF& planes )
  27. {
  28. const U32 numSourcePlanes = planes.getNumPlanes();
  29. // Go through the planes and create edges by
  30. // intersecting the various planes.
  31. for( U32 i = 0; i < numSourcePlanes; ++ i )
  32. {
  33. const PlaneF& currentPlane = planes.getPlanes()[ i ];
  34. bool haveEdges = false;
  35. for( U32 n = 0; n < numSourcePlanes; ++ n )
  36. {
  37. if( n == i )
  38. continue;
  39. const PlaneF& intersectPlane = planes.getPlanes()[ n ];
  40. Point3F start;
  41. Point3F dir;
  42. // Intersect the two planes.
  43. if( !currentPlane.intersect( intersectPlane, start, dir ) )
  44. continue;
  45. // Absolutely make sure our direction vector is normalized.
  46. dir.normalize();
  47. // Find the two vertices on the line that are still
  48. // inside the polyhedron by clipping against the other
  49. // planes in the set.
  50. F32 minDist = TypeTraits< F32 >::MAX;
  51. F32 maxDist = TypeTraits< F32 >::MIN;
  52. Point3F v1;
  53. Point3F v2;
  54. Point3F end = start + dir;
  55. for( U32 j = 0; j < numSourcePlanes; j ++ )
  56. {
  57. // Skip if current or intersect plane.
  58. if( j == n || j == i )
  59. continue;
  60. const PlaneF& clipPlane = planes.getPlanes()[ j ];
  61. // Compute the distance at which the plane intersects
  62. // the line. Skip if parallel.
  63. F32 dist = clipPlane.intersect( start, end );
  64. if( mIsEqual( dist, PARALLEL_PLANE ) )
  65. continue;
  66. // See if the resulting vertex is even inside the planes.
  67. // Skip if not.
  68. Point3F vertex = start + dir * dist;
  69. bool isContained = true;
  70. for( U32 nplane = 0; nplane < numSourcePlanes; ++ nplane )
  71. {
  72. // Skip all planes that we used to construct this vertex.
  73. if( nplane == j || nplane == n || nplane == i )
  74. continue;
  75. if( planes.getPlanes()[ nplane ].whichSide( vertex ) == PlaneF::Back )
  76. {
  77. isContained = false;
  78. break;
  79. }
  80. }
  81. if( !isContained )
  82. continue;
  83. // Keep track of min and max distance.
  84. if( mIsEqual( dist, minDist ) || mIsEqual( dist, maxDist ) )
  85. continue;
  86. else if( dist < minDist )
  87. {
  88. if( minDist != TypeTraits< F32 >::MAX && maxDist == TypeTraits< F32 >::MIN )
  89. {
  90. maxDist = minDist;
  91. v2 = v1;
  92. }
  93. minDist = dist;
  94. v1 = vertex;
  95. }
  96. else if( dist > maxDist )
  97. {
  98. maxDist = dist;
  99. v2 = vertex;
  100. }
  101. }
  102. // Skip plane pair if there's no properly formed edge.
  103. if( minDist == TypeTraits< F32 >::MAX || maxDist == TypeTraits< F32 >::MIN || mIsEqual( minDist, maxDist ) )
  104. continue;
  105. // See if vertex 1 already exists.
  106. S32 v1index = -1;
  107. bool v1Existed = false;
  108. for( U32 nvert = 0; nvert < mPointList.size(); ++ nvert )
  109. if(mPointList[ nvert ].equal( v1, 0.001f ) )
  110. {
  111. v1index = nvert;
  112. v1Existed = true;
  113. break;
  114. }
  115. // See if vertex 2 already exists.
  116. S32 v2index = -1;
  117. bool v2Existed = false;
  118. for( U32 nvert = 0; nvert < mPointList.size(); ++ nvert )
  119. if(mPointList[ nvert ].equal( v2, 0.001f ) )
  120. {
  121. v2index = nvert;
  122. v2Existed = true;
  123. break;
  124. }
  125. // Add vertex 1, if necessary.
  126. if( !v1Existed )
  127. {
  128. v1index = mPointList.size();
  129. mPointList.push_back( v1 );
  130. }
  131. // Add vertex 2, if necessary.
  132. if( !v2Existed )
  133. {
  134. v2index = mPointList.size();
  135. mPointList.push_back( v2 );
  136. }
  137. // If both v1 and v2 already existed in the point
  138. // set, this must be an edge that we are sharing so try
  139. // to find it.
  140. const U32 thisPlaneIndex = mPlaneList.size();
  141. bool foundExistingEdge = false;
  142. if( v1Existed && v2Existed )
  143. {
  144. for( U32 nedge = 0; nedge < mEdgeList.size(); ++ nedge )
  145. {
  146. Edge& edge = mEdgeList[ nedge ];
  147. if( ( edge.vertex[ 0 ] == v1index && edge.vertex[ 1 ] == v2index ) ||
  148. ( edge.vertex[ 0 ] == v2index && edge.vertex[ 1 ] == v1index ) )
  149. {
  150. edge.face[ 1 ] = thisPlaneIndex;
  151. foundExistingEdge = true;
  152. break;
  153. }
  154. }
  155. }
  156. // Otherwise, add a new edge.
  157. if( !foundExistingEdge )
  158. {
  159. bool invert = false;
  160. // We need to make sure to maintain CW ordering on face[0],
  161. // so test to see if we need to go v1->v2 or v2->v1.
  162. Point3F normal = mCross( currentPlane, v2 - v1 );
  163. Point3F testPoint = v1 + normal;
  164. for( U32 nplane = 0; nplane < numSourcePlanes; ++ nplane )
  165. {
  166. if( nplane == i )
  167. continue;
  168. if( planes.getPlanes()[ nplane ].whichSide( testPoint ) == PlaneF::Back )
  169. {
  170. invert = true;
  171. break;
  172. }
  173. }
  174. if( !invert )
  175. {
  176. mEdgeList.push_back(
  177. Edge( thisPlaneIndex, 0, v1index, v2index )
  178. );
  179. }
  180. else
  181. {
  182. mEdgeList.push_back(
  183. Edge( thisPlaneIndex, 0, v2index, v1index )
  184. );
  185. }
  186. }
  187. // This plane has edges.
  188. haveEdges = true;
  189. }
  190. // If this plane produced edges, add it.
  191. if( haveEdges )
  192. mPlaneList.push_back( currentPlane );
  193. }
  194. }