Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1631 lines
40 KiB

  1. //--------------------------------------------------------------------------------------------------
  2. // qhConvex.cpp
  3. //
  4. // Copyright(C) 2011 by D. Gregorius. All rights reserved.
  5. //--------------------------------------------------------------------------------------------------
  6. #include "qhConvex.h"
  7. #include <algorithm>
  8. #include <limits>
  9. #define QH_AXIS_X 0
  10. #define QH_AXIS_Y 1
  11. #define QH_AXIS_Z 2
  12. //--------------------------------------------------------------------------------------------------
  13. // Local construction utilities
  14. //--------------------------------------------------------------------------------------------------
  15. struct qhHalfSpace
  16. {
  17. qhVector3 Vertex;
  18. qhReal Area;
  19. };
  20. //--------------------------------------------------------------------------------------------------
  21. static inline qhReal qhAngle( const qhHalfSpace& H1, const qhHalfSpace& H2 )
  22. {
  23. qhReal Cos = qhDot( H1.Vertex, H2.Vertex ) / ( qhLength( H1.Vertex ) * qhLength( H2.Vertex ) );
  24. return qhArcCos( qhClamp( Cos, qhReal( -1 ), qhReal( 1 ) ) );
  25. }
  26. //--------------------------------------------------------------------------------------------------
  27. static inline qhHalfSpace qhMerge( const qhHalfSpace& H1, const qhHalfSpace& H2 )
  28. {
  29. qhHalfSpace Out;
  30. Out.Vertex = ( H1.Area * H1.Vertex + H2.Area * H2.Vertex ) / ( H1.Area + H2.Area );
  31. Out.Area = H1.Area + H2.Area;
  32. return Out;
  33. }
  34. //--------------------------------------------------------------------------------------------------
  35. static inline void qhSwap( qhIteration& Lhs, qhIteration& Rhs )
  36. {
  37. qhSwap( Lhs.Apex, Rhs.Apex );
  38. qhSwap( Lhs.Horizon, Rhs.Horizon );
  39. qhSwap( Lhs.Vertices, Rhs.Vertices );
  40. qhSwap( Lhs.Faces, Rhs.Faces );
  41. }
  42. //--------------------------------------------------------------------------------------------------
  43. static inline qhVector3 qhBuildCentroid( int VertexCount, const qhVector3* Vertices )
  44. {
  45. qhVector3 Centroid = QH_VEC3_ZERO;
  46. for ( int i = 0; i < VertexCount; ++i )
  47. {
  48. Centroid += Vertices[ i ];
  49. }
  50. QH_ASSERT( VertexCount > 3 );
  51. return Centroid / qhReal( VertexCount );
  52. }
  53. //--------------------------------------------------------------------------------------------------
  54. static void qhShiftVertices( qhArray< qhVector3 >& Vertices, int VertexCount, const qhVector3* VertexBase, const qhVector3& Translation )
  55. {
  56. Vertices.Resize( VertexCount );
  57. for ( int i = 0; i < VertexCount; ++i )
  58. {
  59. Vertices[ i ] = VertexBase[ i ] + Translation;
  60. }
  61. }
  62. //--------------------------------------------------------------------------------------------------
  63. static inline qhBounds3 qhBuildBounds( qhArray< qhVector3 >& Vertices )
  64. {
  65. qhBounds3 Bounds = QH_BOUNDS3_EMPTY;
  66. for ( int i = 0; i < Vertices.Size(); ++i )
  67. {
  68. Bounds += Vertices[ i ];
  69. }
  70. return Bounds;
  71. }
  72. //--------------------------------------------------------------------------------------------------
  73. static void qhWeldVertices( qhArray< qhVector3 >& Vertices, const qhVector3& Tolerance )
  74. {
  75. // DIRK_TODO: This is O(n^2). If this becomes a performance bottleneck
  76. // since we feed large vertex buffers we should use a grid.
  77. for ( int i = 0; i < Vertices.Size(); ++i )
  78. {
  79. for ( int k = Vertices.Size() - 1; k > i; --k )
  80. {
  81. QH_ASSERT( k > i );
  82. qhVector3 Offset = Vertices[ i ] - Vertices[ k ];
  83. if ( qhAbs( Offset.X ) < Tolerance.X && qhAbs( Offset.Y ) < Tolerance.Y && qhAbs( Offset.Z ) < Tolerance.Z )
  84. {
  85. Vertices[ k ] = Vertices.Back();
  86. Vertices.PopBack();
  87. }
  88. }
  89. }
  90. }
  91. //--------------------------------------------------------------------------------------------------
  92. static void qhFindFarthestPointsAlongCardinalAxes( int& Index1, int& Index2, qhReal Tolerance, int VertexCount, const qhVector3* VertexBase )
  93. {
  94. Index1 = Index2 = -1;
  95. qhVector3 V0 = VertexBase[ 0 ];
  96. qhVector3 Min[ 3 ] = { V0, V0, V0 };
  97. qhVector3 Max[ 3 ] = { V0, V0, V0 };
  98. int MinIndex[ 3 ] = { 0, 0, 0 };
  99. int MaxIndex[ 3 ] = { 0, 0, 0 };
  100. for ( int i = 1; i < VertexCount; ++i )
  101. {
  102. const qhVector3& V = VertexBase[ i ];
  103. // X-Axis
  104. if ( V.X < Min[ QH_AXIS_X ].X )
  105. {
  106. Min[ QH_AXIS_X ] = V;
  107. MinIndex[ QH_AXIS_X ] = i;
  108. }
  109. else if ( V.X > Max[ QH_AXIS_X ].X )
  110. {
  111. Max[ QH_AXIS_X ] = V;
  112. MaxIndex[ QH_AXIS_X ] = i;
  113. }
  114. // Y-Axis
  115. if ( V.Y < Min[ QH_AXIS_Y ].Y )
  116. {
  117. Min[ QH_AXIS_Y ] = V;
  118. MinIndex[ QH_AXIS_Y ] = i;
  119. }
  120. else if ( V.Y > Max[ QH_AXIS_Y ].Y )
  121. {
  122. Max[ QH_AXIS_Y ] = V;
  123. MaxIndex[ QH_AXIS_Y ] = i;
  124. }
  125. // Z-Axis
  126. if ( V.Z < Min[ QH_AXIS_Z ].Z )
  127. {
  128. Min[ QH_AXIS_Z ] = V;
  129. MinIndex[ QH_AXIS_Z ] = i;
  130. }
  131. else if ( V.Z > Max[ QH_AXIS_Z ].Z )
  132. {
  133. Max[ QH_AXIS_Z ] = V;
  134. MaxIndex[ QH_AXIS_Z ] = i;
  135. }
  136. }
  137. qhVector3 Distance;
  138. Distance[ QH_AXIS_X ] = Max[ QH_AXIS_X ].X - Min[ QH_AXIS_X ].X;
  139. Distance[ QH_AXIS_Y ] = Max[ QH_AXIS_Y ].Y - Min[ QH_AXIS_Y ].Y;
  140. Distance[ QH_AXIS_Z ] = Max[ QH_AXIS_Z ].Z - Min[ QH_AXIS_Z ].Z;
  141. int MaxElement = qhMaxElement( Distance );
  142. if ( Distance[ MaxElement ] > qhReal( 100 ) * Tolerance )
  143. {
  144. Index1 = MinIndex[ MaxElement ];
  145. Index2 = MaxIndex[ MaxElement ];
  146. }
  147. }
  148. //--------------------------------------------------------------------------------------------------
  149. static int qhFindFarthestPointFromLine( int Index1, int Index2, qhReal Tolerance, int VertexCount, const qhVector3* VertexBase )
  150. {
  151. const qhVector3& A = VertexBase[ Index1 ];
  152. const qhVector3& B = VertexBase[ Index2 ];
  153. qhVector3 AB = B - A;
  154. qhReal MaxDistance = qhReal( 100 ) * Tolerance;
  155. int MaxIndex = -1;
  156. for ( int i = 0; i < VertexCount; ++i )
  157. {
  158. if ( i == Index1 || i == Index2 )
  159. {
  160. continue;
  161. }
  162. const qhVector3& P = VertexBase[ i ];
  163. qhVector3 AP = P - A;
  164. qhReal s = qhDot( AP, AB ) / qhDot( AB, AB );
  165. qhVector3 Q = A + s * AB;
  166. qhReal Distance = qhDistance( P, Q );
  167. if ( Distance > MaxDistance )
  168. {
  169. MaxDistance = Distance;
  170. MaxIndex = i;
  171. }
  172. }
  173. return MaxIndex;
  174. }
  175. //--------------------------------------------------------------------------------------------------
  176. static int qhFindFarthestPointFromPlane( int Index1, int Index2, int Index3, qhReal Tolerance, int VertexCount, const qhVector3* VertexBase )
  177. {
  178. const qhVector3& A = VertexBase[ Index1 ];
  179. const qhVector3& B = VertexBase[ Index2 ];
  180. const qhVector3& C = VertexBase[ Index3 ];
  181. qhPlane Plane = qhPlane( A, B, C );
  182. Plane.Normalize();
  183. qhReal MaxDistance = qhReal( 100 ) * Tolerance;
  184. int MaxIndex = -1;
  185. for ( int i = 0; i < VertexCount; ++i )
  186. {
  187. if ( i == Index1 || i == Index2 || i == Index3 )
  188. {
  189. continue;
  190. }
  191. qhReal Distance = qhAbs( Plane.Distance( VertexBase[ i ] ) );
  192. if ( Distance > MaxDistance )
  193. {
  194. MaxDistance = Distance;
  195. MaxIndex = i;
  196. }
  197. }
  198. return MaxIndex;
  199. }
  200. //--------------------------------------------------------------------------------------------------
  201. // qhConvex
  202. //--------------------------------------------------------------------------------------------------
  203. qhConvex::qhConvex( void )
  204. : mTolerance( 0 )
  205. , mMinRadius( 0 )
  206. , mMinOutside( 0 )
  207. , mInteriorPoint( QH_VEC3_ZERO )
  208. {
  209. }
  210. //--------------------------------------------------------------------------------------------------
  211. qhConvex::~qhConvex( void )
  212. {
  213. // Destroy faces
  214. qhFace* Face = mFaceList.Begin();
  215. while ( Face != mFaceList.End() )
  216. {
  217. qhFace* Nuke = Face;
  218. Face = Face->Next;
  219. qhRemove( Nuke );
  220. DestroyFace( Nuke );
  221. }
  222. // Destroy vertices
  223. qhVertex* Vertex = mVertexList.Begin();
  224. while ( Vertex != mVertexList.End() )
  225. {
  226. qhVertex* Nuke = Vertex;
  227. Vertex = Vertex->Next;
  228. qhRemove( Nuke );
  229. DestroyVertex( Nuke );
  230. }
  231. }
  232. //--------------------------------------------------------------------------------------------------
  233. void qhConvex::Construct( int VertexCount, const qhVector3* VertexBase, qhReal RelativeWeldTolerance )
  234. {
  235. QH_ASSERT( mIterations.Size() == 0 );
  236. // Validate passed arguments
  237. if ( VertexCount < 4 || VertexBase == NULL )
  238. {
  239. return;
  240. }
  241. // Pre-process: Shift to origin and remove duplicates
  242. qhVector3 Centroid = qhBuildCentroid( VertexCount, VertexBase );
  243. qhArray< qhVector3 > Vertices;
  244. qhShiftVertices( Vertices, VertexCount, VertexBase, -Centroid );
  245. qhBounds3 Bounds = qhBuildBounds( Vertices );
  246. qhWeldVertices( Vertices, RelativeWeldTolerance * ( Bounds.Max - Bounds.Min ) );
  247. // Try to build an initial hull
  248. ComputeTolerance( Vertices );
  249. if ( !BuildInitialHull( Vertices.Size(), Vertices.Begin() ) )
  250. {
  251. return;
  252. }
  253. // Construct hull
  254. qhVertex* Vertex = NextConflictVertex();
  255. while ( Vertex != NULL )
  256. {
  257. AddVertexToHull( Vertex );
  258. Vertex = NextConflictVertex();
  259. }
  260. // Post-process: Clean and shift back to center
  261. CleanHull();
  262. // Shift hull back to original centroid
  263. ShiftHull( Centroid );
  264. }
  265. //--------------------------------------------------------------------------------------------------
  266. void qhConvex::Construct( int PlaneCount, const qhPlane* PlaneBase, qhReal RelativeWeldTolerance, const qhVector3& InternalPoint )
  267. {
  268. QH_ASSERT( mIterations.Size() == 0 );
  269. // Validate passed arguments
  270. if ( PlaneCount < 4 || PlaneBase == NULL )
  271. {
  272. return;
  273. }
  274. // Try to build dual
  275. qhArray< qhVector3 > DualVertices;
  276. DualVertices.Resize( PlaneCount );
  277. for ( int Index = 0; Index < PlaneCount; ++Index )
  278. {
  279. // Shift planes so we contain the origin
  280. qhPlane Plane = PlaneBase[ Index ];
  281. Plane.Translate( -InternalPoint );
  282. if ( Plane.Offset <= 0.0f )
  283. {
  284. return;
  285. }
  286. DualVertices[ Index ] = Plane.Normal / Plane.Offset;
  287. }
  288. qhConvex Dual;
  289. Dual.Construct( DualVertices.Size(), DualVertices.Begin(), 0.0f );
  290. if ( !Dual.IsConsistent() )
  291. {
  292. return;
  293. }
  294. // Build primal (dual of dual -> this is the convex hull defined by the planes)
  295. const qhList< qhFace >& FaceList = Dual.GetFaceList();
  296. qhArray< qhVector3 > PrimalVertices;
  297. PrimalVertices.Reserve( FaceList.Size() );
  298. for ( const qhFace* Face = FaceList.Begin(); Face != FaceList.End(); Face = Face->Next )
  299. {
  300. qhPlane Plane = Face->Plane;
  301. QH_ASSERT( Plane.Offset > 0.0f );
  302. // Shift vertices back
  303. qhVector3 Vertex = Plane.Normal / Plane.Offset + InternalPoint;
  304. PrimalVertices.PushBack( Vertex );
  305. }
  306. Construct( PrimalVertices.Size(), PrimalVertices.Begin(), RelativeWeldTolerance );
  307. }
  308. //--------------------------------------------------------------------------------------------------
  309. bool qhConvex::IsConsistent( void ) const
  310. {
  311. // Convex polyhedron invariants
  312. int V = GetVertexCount();
  313. int E = GetEdgeCount() / 2;
  314. int F = GetFaceCount();
  315. // Euler's identity
  316. if ( V - E + F != 2 )
  317. {
  318. return false;
  319. }
  320. // Edge and face invariants
  321. for ( const qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  322. {
  323. // Face invariants (Topology)
  324. if ( Face->Edge->Face != Face )
  325. {
  326. return false;
  327. }
  328. // Face invariants (Geometry)
  329. if ( Face->Plane.Distance( mInteriorPoint ) > 0 )
  330. {
  331. return false;
  332. }
  333. if ( !qhCheckConsistency( Face ) )
  334. {
  335. return false;
  336. }
  337. if ( Face->Mark != QH_MARK_VISIBLE )
  338. {
  339. return false;
  340. }
  341. const qhHalfEdge* Edge = Face->Edge;
  342. do
  343. {
  344. // Edge invariants (Topology)
  345. if ( Edge->Next->Origin != Edge->Twin->Origin )
  346. {
  347. return false;
  348. }
  349. if ( Edge->Prev->Next != Edge )
  350. {
  351. return false;
  352. }
  353. if ( Edge->Next->Prev != Edge )
  354. {
  355. return false;
  356. }
  357. if ( Edge->Twin->Twin != Edge )
  358. {
  359. return false;
  360. }
  361. if ( Edge->Face != Face )
  362. {
  363. return false;
  364. }
  365. // Edge invariants (Geometry)
  366. if ( qhDistance( Edge->Origin->Position, Edge->Twin->Origin->Position ) < qhReal( 1000 ) * QH_REAL_MIN )
  367. {
  368. return false;
  369. }
  370. Edge = Edge->Next;
  371. }
  372. while ( Edge != Face->Edge );
  373. }
  374. return true;
  375. }
  376. //--------------------------------------------------------------------------------------------------
  377. void qhConvex::Simplify( qhConvex& Convex, qhReal MaxAngle ) const
  378. {
  379. // Cluster all normals within the face tolerance
  380. typedef qhArray< const qhFace* > qhCluster;
  381. qhArray< qhCluster > Clusters;
  382. for ( const qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  383. {
  384. int BestIndex = -1;
  385. qhReal BestDot = qhCos( MaxAngle );
  386. for ( int Index = 0; Index < Clusters.Size(); ++Index )
  387. {
  388. const qhCluster& Cluster = Clusters[ Index ];
  389. QH_ASSERT( !Cluster.Empty() );
  390. qhReal Dot = qhDot( Face->Plane.Normal, Cluster[ 0 ]->Plane.Normal );
  391. if ( Dot > BestDot )
  392. {
  393. BestIndex = Index;
  394. BestDot = Dot;
  395. }
  396. }
  397. qhCluster& Cluster = BestIndex < 0 ? Clusters.Expand() : Clusters[ BestIndex ];
  398. Cluster.PushBack( Face );
  399. }
  400. // Build dual
  401. qhArray< qhVector3 > DualVertices;
  402. qhBounds3 DualBounds = QH_BOUNDS3_EMPTY;
  403. qhVector3 Centroid = GetCentroid();
  404. for ( int I = 0; I < Clusters.Size(); ++I )
  405. {
  406. const qhCluster& Cluster = Clusters[ I ];
  407. QH_ASSERT( !Cluster.Empty() );
  408. qhReal Area = 0;
  409. qhVector3 Vertex = QH_VEC3_ZERO;
  410. for ( int K = 0; K < Cluster.Size(); ++K )
  411. {
  412. const qhFace* Face = Cluster[ K ];
  413. qhPlane Plane = Face->Plane;
  414. Plane.Translate( -Centroid );
  415. QH_ASSERT( Plane.Offset > qhReal( 0 ) );
  416. Area += Face->Area;
  417. Vertex += Face->Area * ( Plane.Normal / Plane.Offset );
  418. }
  419. QH_ASSERT( Area > qhReal( 0 ) );
  420. Vertex /= Area;
  421. DualVertices.PushBack( Vertex );
  422. DualBounds += Vertex;
  423. }
  424. qhConvex Dual;
  425. Dual.Construct( DualVertices.Size(), DualVertices.Begin(), 0.0f );
  426. if ( !Dual.IsConsistent() )
  427. {
  428. return;
  429. }
  430. // Build the final hull
  431. qhArray< qhVector3 > Vertices;
  432. for ( const qhFace* Face = Dual.GetFaceList().Begin(); Face != Dual.GetFaceList().End(); Face = Face->Next )
  433. {
  434. const qhPlane& Plane = Face->Plane;
  435. QH_ASSERT( Plane.Offset > qhReal( 0 ) );
  436. qhVector3 Vertex = ( Plane.Normal / Plane.Offset ) + Centroid;
  437. Vertices.PushBack( Vertex );
  438. }
  439. Convex.Construct( Vertices.Size(), Vertices.Begin(), 0.0f );
  440. // Build half-spaces
  441. // qhVector3 Centroid = GetCentroid();
  442. //
  443. // qhArray< qhHalfSpace > HalfSpaces;
  444. // HalfSpaces.Reserve( GetFaceCount() );
  445. //
  446. // for ( const qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  447. // {
  448. // qhPlane Plane = Face->Plane;
  449. // Plane.Translate( -Centroid );
  450. // QH_ASSERT( Plane.Offset > qhReal( 0 ) );
  451. //
  452. // qhHalfSpace HalfSpace;
  453. // HalfSpace.Vertex = Plane.Normal / Plane.Offset;
  454. // HalfSpace.Area = Face->Area;
  455. //
  456. // HalfSpaces.PushBack( HalfSpace );
  457. // }
  458. //
  459. // // Merge faces within specified range
  460. // while ( true )
  461. // {
  462. // // Find global minimum
  463. // qhReal BestAngle = QH_PI;
  464. // int BestIndex1 = -1;
  465. // int BestIndex2 = -1;
  466. //
  467. // for ( int Index1 = 0; Index1 < HalfSpaces.Size(); ++Index1 )
  468. // {
  469. // const qhHalfSpace& HalfSpace1 = HalfSpaces[ Index1 ];
  470. // for ( int Index2 = Index1 + 1; Index2 < HalfSpaces.Size(); ++Index2 )
  471. // {
  472. // qhHalfSpace HalfSpace2 = HalfSpaces[ Index2 ];
  473. //
  474. // qhReal Angle = qhAngle( HalfSpace1, HalfSpace2 );
  475. // if ( Angle < BestAngle )
  476. // {
  477. // BestAngle = Angle;
  478. // BestIndex1 = Index1;
  479. // BestIndex2 = Index2;
  480. // }
  481. // }
  482. // }
  483. //
  484. // // Exit if there are no more faces to merge
  485. // if ( BestAngle > MaxAngle )
  486. // {
  487. // break;
  488. // }
  489. //
  490. // // Merge minimizing faces
  491. // const qhHalfSpace& HalfSpace1 = HalfSpaces[ BestIndex1 ];
  492. // const qhHalfSpace& HalfSpace2 = HalfSpaces[ BestIndex2 ];
  493. // qhHalfSpace HalfSpace = qhMerge( HalfSpace1, HalfSpace2 );
  494. //
  495. // // Remove merged half-spaces and add the new one. We need to remove
  496. // // the second half-space first to not invalidate the first index!
  497. // QH_ASSERT( BestIndex1 < BestIndex2 );
  498. // HalfSpaces[ BestIndex2 ] = HalfSpaces.Back();
  499. // HalfSpaces.PopBack();
  500. // HalfSpaces[ BestIndex1 ] = HalfSpaces.Back();
  501. // HalfSpaces.PopBack();
  502. //
  503. // HalfSpaces.PushBack( HalfSpace );
  504. // }
  505. //
  506. // // Build the dual
  507. // qhArray< qhVector3 > DualVertices;
  508. // DualVertices.Resize( HalfSpaces.Size() );
  509. // for ( int Index = 0; Index < HalfSpaces.Size(); ++Index )
  510. // {
  511. // DualVertices[ Index ] = HalfSpaces[ Index ].Vertex;
  512. // }
  513. //
  514. // qhConvex Dual;
  515. // Dual.Construct( DualVertices.Size(), DualVertices.Begin(), qhReal( 0 ) );
  516. // if ( !Dual.IsConsistent() )
  517. // {
  518. // return;
  519. // }
  520. //
  521. // // Build the merged hull
  522. // qhArray< qhVector3 > Vertices;
  523. // for ( const qhFace* Face = Dual.GetFaceList().Begin(); Face != Dual.GetFaceList().End(); Face = Face->Next )
  524. // {
  525. // const qhPlane& Plane = Face->Plane;
  526. // QH_ASSERT( Plane.Offset > qhReal( 0 ) );
  527. //
  528. // qhVector3 Vertex = ( Plane.Normal / Plane.Offset ) + Centroid;
  529. // Vertices.PushBack( Vertex );
  530. // }
  531. //
  532. // Convex.Construct( Vertices.Size(), Vertices.Begin(), 0.0f );
  533. }
  534. //--------------------------------------------------------------------------------------------------
  535. qhVertex* qhConvex::CreateVertex( const qhVector3& Position )
  536. {
  537. qhVertex* Vertex = (qhVertex*)qhAlloc( sizeof( qhVertex ) );
  538. new ( Vertex ) qhVertex;
  539. Vertex->Prev = NULL;
  540. Vertex->Next = NULL;
  541. Vertex->Mark = QH_MARK_CONFIRM;
  542. Vertex->Position = Position;
  543. Vertex->Edge = NULL;
  544. Vertex->ConflictFace = NULL;
  545. return Vertex;
  546. }
  547. //--------------------------------------------------------------------------------------------------
  548. void qhConvex::DestroyVertex( qhVertex* Vertex )
  549. {
  550. QH_ASSERT( !qhInList( Vertex ) );
  551. Vertex->~qhVertex();
  552. qhFree( Vertex );
  553. }
  554. //--------------------------------------------------------------------------------------------------
  555. qhFace* qhConvex::CreateFace( qhVertex* Vertex1, qhVertex* Vertex2, qhVertex* Vertex3 )
  556. {
  557. qhFace* Face = (qhFace*)qhAlloc( sizeof( qhFace ) );
  558. new ( Face ) qhFace;
  559. qhHalfEdge* Edge1 = (qhHalfEdge*)qhAlloc( sizeof( qhHalfEdge ) );
  560. qhHalfEdge* Edge2 = (qhHalfEdge*)qhAlloc( sizeof( qhHalfEdge ) );
  561. qhHalfEdge* Edge3 = (qhHalfEdge*)qhAlloc( sizeof( qhHalfEdge ) );
  562. qhPlane Plane = qhPlane( Vertex1->Position, Vertex2->Position, Vertex3->Position );
  563. qhReal Area = qhLength( Plane.Normal ) / qhReal( 2 );
  564. Plane.Normalize();
  565. // Initialize face
  566. Face->Prev = NULL;
  567. Face->Next = NULL;
  568. Face->Edge = Edge1;
  569. Face->Mark = QH_MARK_VISIBLE;
  570. Face->Area = Area;
  571. Face->Centroid = ( Vertex1->Position + Vertex2->Position + Vertex3->Position ) / qhReal( 3.0 );
  572. Face->Plane = Plane;
  573. Face->Flipped = Plane.Distance( mInteriorPoint ) > 0.0f;
  574. // Initialize edges
  575. Edge1->Prev = Edge3;
  576. Edge1->Next = Edge2;
  577. Edge1->Origin = Vertex1;
  578. Edge1->Face = Face;
  579. Edge1->Twin = NULL;
  580. Edge2->Prev = Edge1;
  581. Edge2->Next = Edge3;
  582. Edge2->Origin = Vertex2;
  583. Edge2->Face = Face;
  584. Edge2->Twin = NULL;
  585. Edge3->Prev = Edge2;
  586. Edge3->Next = Edge1;
  587. Edge3->Origin = Vertex3;
  588. Edge3->Face = Face;
  589. Edge3->Twin = NULL;
  590. return Face;
  591. }
  592. //--------------------------------------------------------------------------------------------------
  593. void qhConvex::DestroyFace( qhFace* Face )
  594. {
  595. QH_ASSERT( !qhInList( Face ) );
  596. // Edge can be null if face was merged
  597. qhHalfEdge* Edge = Face->Edge;
  598. if ( Edge != NULL )
  599. {
  600. do
  601. {
  602. qhHalfEdge* Nuke = Edge;
  603. Edge = Edge->Next;
  604. qhFree( Nuke );
  605. }
  606. while ( Edge != Face->Edge );
  607. }
  608. Face->~qhFace();
  609. qhFree( Face );
  610. }
  611. //--------------------------------------------------------------------------------------------------
  612. void qhConvex::ComputeTolerance( qhArray< qhVector3 >& Vertices )
  613. {
  614. qhBounds3 Bounds = qhBuildBounds( Vertices );
  615. qhVector3 Max = qhMax( qhAbs( Bounds.Min ), qhAbs( Bounds.Max ) );
  616. qhReal MaxSum = Max.X + Max.Y + Max.Z;
  617. qhReal MaxCoord = qhMax( Max.X, qhMax( Max.Y, Max.Z ) );
  618. qhReal MaxDistance = qhMin( QH_SQRT3 * MaxCoord, MaxSum );
  619. qhReal Tolerance = ( qhReal( 3 ) * MaxDistance * qhReal( 1.01 ) + MaxCoord ) * QH_REAL_EPSILON;
  620. mTolerance = Tolerance;
  621. mMinRadius = qhReal( 4 ) * Tolerance;
  622. mMinOutside = qhReal( 2 ) * mMinRadius;
  623. }
  624. //--------------------------------------------------------------------------------------------------
  625. bool qhConvex::BuildInitialHull( int VertexCount, const qhVector3* VertexBase )
  626. {
  627. int Index1, Index2;
  628. qhFindFarthestPointsAlongCardinalAxes( Index1, Index2, mTolerance, VertexCount, VertexBase );
  629. if ( Index1 < 0 || Index2 < 0 )
  630. {
  631. return false;
  632. }
  633. int Index3 = qhFindFarthestPointFromLine( Index1, Index2, mTolerance, VertexCount, VertexBase );
  634. if ( Index3 < 0 )
  635. {
  636. return false;
  637. }
  638. int Index4 = qhFindFarthestPointFromPlane( Index1, Index2, Index3, mTolerance, VertexCount, VertexBase );
  639. if ( Index4 < 0 )
  640. {
  641. return false;
  642. }
  643. // Compute an interior point to detect flipped faces
  644. mInteriorPoint = QH_VEC3_ZERO;
  645. mInteriorPoint += VertexBase[ Index1 ];
  646. mInteriorPoint += VertexBase[ Index2 ];
  647. mInteriorPoint += VertexBase[ Index3 ];
  648. mInteriorPoint += VertexBase[ Index4 ];
  649. mInteriorPoint /= qhReal( 4 );
  650. // Check winding order
  651. qhVector3 V1 = VertexBase[ Index1 ] - VertexBase[ Index4 ];
  652. qhVector3 V2 = VertexBase[ Index2 ] - VertexBase[ Index4 ];
  653. qhVector3 V3 = VertexBase[ Index3 ] - VertexBase[ Index4 ];
  654. if ( qhDet( V1, V2, V3 ) < qhReal( 0.0 ) )
  655. {
  656. std::swap( Index2, Index3 );
  657. }
  658. // Allocate initial vertices and save them in the vertex list
  659. qhVertex* Vertex1 = CreateVertex( VertexBase[ Index1 ] );
  660. mVertexList.PushBack( Vertex1 );
  661. qhVertex* Vertex2 = CreateVertex( VertexBase[ Index2 ] );
  662. mVertexList.PushBack( Vertex2 );
  663. qhVertex* Vertex3 = CreateVertex( VertexBase[ Index3 ] );
  664. mVertexList.PushBack( Vertex3 );
  665. qhVertex* Vertex4 = CreateVertex( VertexBase[ Index4 ] );
  666. mVertexList.PushBack( Vertex4 );
  667. // Allocate initial faces and save them in the face list
  668. qhFace* Face1 = CreateFace( Vertex1, Vertex2, Vertex3 );
  669. mFaceList.PushBack( Face1 );
  670. qhFace* Face2 = CreateFace( Vertex4, Vertex2, Vertex1 );
  671. mFaceList.PushBack( Face2 );
  672. qhFace* Face3 = CreateFace( Vertex4, Vertex3, Vertex2 );
  673. mFaceList.PushBack( Face3 );
  674. qhFace* Face4 = CreateFace( Vertex4, Vertex1, Vertex3 );
  675. mFaceList.PushBack( Face4 );
  676. // Link faces
  677. qhLinkFaces( Face1, 0, Face2, 1 );
  678. qhLinkFaces( Face1, 1, Face3, 1 );
  679. qhLinkFaces( Face1, 2, Face4, 1 );
  680. qhLinkFaces( Face2, 0, Face3, 2 );
  681. qhLinkFaces( Face3, 0, Face4, 2 );
  682. qhLinkFaces( Face4, 0, Face2, 2 );
  683. QH_ASSERT( qhCheckConsistency( Face1 ) );
  684. QH_ASSERT( qhCheckConsistency( Face2 ) );
  685. QH_ASSERT( qhCheckConsistency( Face3 ) );
  686. QH_ASSERT( qhCheckConsistency( Face4 ) );
  687. // Fill initial conflict lists
  688. for ( int i = 0; i < VertexCount; ++i )
  689. {
  690. if ( i == Index1 || i == Index2 || i == Index3 || i == Index4 )
  691. {
  692. continue;
  693. }
  694. const qhVector3& Point = VertexBase[ i ];
  695. qhReal MaxDistance = mMinOutside;
  696. qhFace* MaxFace = NULL;
  697. for ( qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  698. {
  699. qhReal Distance = Face->Plane.Distance( Point );
  700. if ( Distance > MaxDistance )
  701. {
  702. MaxDistance = Distance;
  703. MaxFace = Face;
  704. }
  705. }
  706. if ( MaxFace != NULL )
  707. {
  708. qhVertex* Vertex = CreateVertex( Point );
  709. Vertex->ConflictFace = MaxFace;
  710. MaxFace->ConflictList.PushBack( Vertex );
  711. }
  712. }
  713. return true;
  714. }
  715. //--------------------------------------------------------------------------------------------------
  716. qhVertex* qhConvex::NextConflictVertex( void )
  717. {
  718. qhVertex* MaxVertex = NULL;
  719. qhReal MaxDistance = mMinOutside;
  720. for ( qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  721. {
  722. if ( !Face->ConflictList.Empty() )
  723. {
  724. for ( qhVertex* Vertex = Face->ConflictList.Begin(); Vertex != Face->ConflictList.End(); Vertex = Vertex->Next )
  725. {
  726. QH_ASSERT( Vertex->ConflictFace == Face );
  727. qhReal Distance = Face->Plane.Distance( Vertex->Position );
  728. if ( Distance > MaxDistance )
  729. {
  730. MaxDistance = Distance;
  731. MaxVertex = Vertex;
  732. }
  733. }
  734. }
  735. }
  736. return MaxVertex;
  737. }
  738. //--------------------------------------------------------------------------------------------------
  739. void qhConvex::AddVertexToHull( qhVertex* Vertex )
  740. {
  741. // Remove vertex from conflict face
  742. qhFace* Face = Vertex->ConflictFace;
  743. Vertex->ConflictFace = NULL;
  744. Face->ConflictList.Remove( Vertex );
  745. mVertexList.PushBack( Vertex );
  746. // Find the horizon edges
  747. qhArray< qhHalfEdge* > Horizon;
  748. BuildHorizon( Horizon, Vertex, Face );
  749. QH_ASSERT( Horizon.Size() >= 3 );
  750. // Create new cone faces
  751. qhArray< qhFace* > Cone;
  752. BuildCone( Cone, Horizon, Vertex );
  753. QH_ASSERT( Cone.Size() >= 3 );
  754. #ifdef QH_DEBUG
  755. // Push iteration before merging faces
  756. AddIteration( Vertex, Horizon, mFaceList );
  757. int Iteration = mIterations.Size() - 1;
  758. #endif
  759. // Merge coplanar faces
  760. MergeFaces( Cone );
  761. // Resolve orphaned vertices
  762. ResolveVertices( Cone );
  763. // Remove hidden faces and add new ones
  764. ResolveFaces( Cone );
  765. }
  766. //--------------------------------------------------------------------------------------------------
  767. void qhConvex::AddIteration( qhVertex* Apex, const qhArray< qhHalfEdge* >& Horizon, const qhList< qhFace >& FaceList )
  768. {
  769. qhIteration& Iteration = mIterations.Expand();
  770. // Save apex
  771. Iteration.Apex = Apex->Position;
  772. // Save horizon
  773. for ( int i = 0; i < Horizon.Size(); ++i )
  774. {
  775. const qhHalfEdge* Edge = Horizon[ i ];
  776. Iteration.Horizon.PushBack( Edge->Origin->Position );
  777. }
  778. // Save current hull faces
  779. for ( const qhFace* Face = FaceList.Begin(); Face != FaceList.End(); Face = Face->Next )
  780. {
  781. int VertexCount = 0;
  782. const qhHalfEdge* Edge = Face->Edge;
  783. do
  784. {
  785. VertexCount++;
  786. Iteration.Vertices.PushBack( Edge->Origin->Position );
  787. Edge = Edge->Next;
  788. }
  789. while ( Edge != Face->Edge );
  790. Iteration.Faces.PushBack( VertexCount );
  791. }
  792. }
  793. //--------------------------------------------------------------------------------------------------
  794. void qhConvex::CleanHull( void )
  795. {
  796. // Mark all vertices on the hull as visible and set leaving edge
  797. for ( qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  798. {
  799. qhHalfEdge* Edge = Face->Edge;
  800. do
  801. {
  802. Edge->Origin->Mark = QH_MARK_VISIBLE;
  803. if ( Edge->Origin->Edge == NULL )
  804. {
  805. Edge->Origin->Edge = Edge;
  806. }
  807. Edge = Edge->Next;
  808. }
  809. while ( Edge != Face->Edge );
  810. }
  811. // Remove unconfirmed vertices
  812. qhVertex* Vertex = mVertexList.Begin();
  813. while ( Vertex != mVertexList.End() )
  814. {
  815. qhVertex* Next = Vertex->Next;
  816. if ( Vertex->Mark != QH_MARK_VISIBLE )
  817. {
  818. mVertexList.Remove( Vertex );
  819. DestroyVertex( Vertex );
  820. }
  821. Vertex = Next;
  822. }
  823. }
  824. //--------------------------------------------------------------------------------------------------
  825. void qhConvex::ShiftHull( const qhVector3& Translation )
  826. {
  827. // Transform vertices
  828. for ( qhVertex* Vertex = mVertexList.Begin(); Vertex != mVertexList.End(); Vertex = Vertex->Next )
  829. {
  830. Vertex->Position += Translation;
  831. }
  832. // Transform planes
  833. for ( qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  834. {
  835. Face->Plane.Translate( Translation );
  836. }
  837. // Shift interior point
  838. mInteriorPoint += Translation;
  839. }
  840. //--------------------------------------------------------------------------------------------------
  841. void qhConvex::BuildHorizon( qhArray< qhHalfEdge* >& Horizon, qhVertex* Apex, qhFace* Seed, qhHalfEdge* Edge1 )
  842. {
  843. // Move vertices to orphaned list
  844. Seed->Mark = QH_MARK_DELETE;
  845. qhVertex* Vertex = Seed->ConflictList.Begin();
  846. while ( Vertex != Seed->ConflictList.End() )
  847. {
  848. qhVertex* Orphan = Vertex;
  849. Vertex = Vertex->Next;
  850. Orphan->ConflictFace = NULL;
  851. Seed->ConflictList.Remove( Orphan );
  852. mOrphanedList.PushBack( Orphan );
  853. }
  854. QH_ASSERT( Seed->ConflictList.Empty() );
  855. qhHalfEdge* Edge;
  856. if ( Edge1 != NULL )
  857. {
  858. Edge = Edge1->Next;
  859. }
  860. else
  861. {
  862. Edge1 = Seed->Edge;
  863. Edge = Edge1;
  864. }
  865. do
  866. {
  867. qhHalfEdge* Twin = Edge->Twin;
  868. if ( Twin->Face->Mark == QH_MARK_VISIBLE )
  869. {
  870. if ( Twin->Face->Plane.Distance( Apex->Position ) > mMinRadius )
  871. {
  872. BuildHorizon( Horizon, Apex, Twin->Face, Twin );
  873. }
  874. else
  875. {
  876. Horizon.PushBack( Edge );
  877. }
  878. }
  879. Edge = Edge->Next;
  880. }
  881. while ( Edge != Edge1 );
  882. }
  883. //--------------------------------------------------------------------------------------------------
  884. void qhConvex::BuildCone( qhArray< qhFace* >& Cone, const qhArray< qhHalfEdge* >& Horizon, qhVertex* Apex )
  885. {
  886. // Create cone faces and link bottom edges to horizon
  887. for ( int i = 0; i < Horizon.Size(); ++i )
  888. {
  889. qhHalfEdge* Edge = Horizon[ i ];
  890. QH_ASSERT( Edge->Twin->Twin == Edge );
  891. qhFace* Face = CreateFace( Apex, Edge->Origin, Edge->Twin->Origin );
  892. Cone.PushBack( Face );
  893. // Link face to bottom edge
  894. qhLinkFace( Face, 1, Edge->Twin );
  895. }
  896. // Link new cone faces with each other
  897. qhFace* Face1 = Cone.Back();
  898. for ( int i = 0; i < Cone.Size(); ++i )
  899. {
  900. qhFace* Face2 = Cone[ i ];
  901. qhLinkFaces( Face1, 2, Face2, 0 );
  902. Face1 = Face2;
  903. }
  904. }
  905. //--------------------------------------------------------------------------------------------------
  906. void qhConvex::MergeFaces( qhArray< qhFace* >& Cone )
  907. {
  908. // Merge flipped faces
  909. for ( int i = 0; i < Cone.Size(); ++i )
  910. {
  911. qhFace* Face = Cone[ i ];
  912. if ( Face->Mark == QH_MARK_VISIBLE )
  913. {
  914. if ( Face->Flipped )
  915. {
  916. qhReal BestArea = 0;
  917. qhHalfEdge* BestEdge = NULL;
  918. qhHalfEdge* Edge = Face->Edge;
  919. do
  920. {
  921. qhHalfEdge* Twin = Edge->Twin;
  922. qhReal Area = Twin->Face->Area;
  923. if ( Area > BestArea )
  924. {
  925. BestArea = Area;
  926. BestEdge = Edge;
  927. }
  928. Edge = Edge->Next;
  929. }
  930. while ( Edge != Face->Edge );
  931. QH_ASSERT( BestEdge != NULL );
  932. ConnectFaces( BestEdge );
  933. QH_ASSERT( Face->Mark == QH_MARK_VISIBLE );
  934. QH_ASSERT( Face->Flipped );
  935. Face->Flipped = false;
  936. }
  937. }
  938. }
  939. // First merge pass
  940. for ( int i = 0; i < Cone.Size(); ++i )
  941. {
  942. qhFace* Face = Cone[ i ];
  943. if ( Face->Mark == QH_MARK_VISIBLE )
  944. {
  945. // Merge faces which are non-convex as determined by the larger face
  946. while ( FirstPass( Face ) ) {}
  947. }
  948. }
  949. // Second merge pass
  950. for ( int i = 0; i < Cone.Size(); ++i )
  951. {
  952. qhFace* Face = Cone[ i ];
  953. if ( Face->Mark == QH_MARK_CONCAVE )
  954. {
  955. Face->Mark = QH_MARK_VISIBLE;
  956. while ( SecondPass( Face ) ) {}
  957. }
  958. }
  959. }
  960. //--------------------------------------------------------------------------------------------------
  961. void qhConvex::ResolveVertices( qhArray< qhFace* >& Cone )
  962. {
  963. // Resolve orphaned vertices
  964. qhVertex* Vertex = mOrphanedList.Begin();
  965. while ( Vertex != mOrphanedList.End() )
  966. {
  967. qhVertex* Next = Vertex->Next;
  968. mOrphanedList.Remove( Vertex );
  969. qhReal MaxDistance = mMinOutside;
  970. qhFace* MaxFace = NULL;
  971. for ( int i = 0; i < Cone.Size(); ++i )
  972. {
  973. // Skip faces that got merged
  974. if ( Cone[ i ]->Mark == QH_MARK_VISIBLE )
  975. {
  976. qhReal Distance = Cone[ i ]->Plane.Distance( Vertex->Position );
  977. if ( Distance > MaxDistance )
  978. {
  979. MaxDistance = Distance;
  980. MaxFace = Cone[ i ];
  981. }
  982. }
  983. }
  984. if ( MaxFace != NULL )
  985. {
  986. QH_ASSERT( MaxFace->Mark == QH_MARK_VISIBLE );
  987. MaxFace->ConflictList.PushBack( Vertex );
  988. Vertex->ConflictFace = MaxFace;
  989. }
  990. else
  991. {
  992. // Vertex has been already removed from the orphaned list
  993. // and can be destroyed
  994. DestroyVertex( Vertex );
  995. Vertex = NULL;
  996. }
  997. Vertex = Next;
  998. }
  999. QH_ASSERT( mOrphanedList.Empty() );
  1000. }
  1001. //--------------------------------------------------------------------------------------------------
  1002. void qhConvex::ResolveFaces( qhArray< qhFace* >& Cone )
  1003. {
  1004. // Delete hidden faces
  1005. qhFace* Face = mFaceList.Begin();
  1006. while ( Face != mFaceList.End() )
  1007. {
  1008. qhFace* Nuke = Face;
  1009. Face = Face->Next;
  1010. if ( Nuke->Mark == QH_MARK_DELETE )
  1011. {
  1012. QH_ASSERT( Nuke->ConflictList.Empty() );
  1013. mFaceList.Remove( Nuke );
  1014. DestroyFace( Nuke );
  1015. }
  1016. }
  1017. // Add new faces
  1018. for ( int i = 0; i < Cone.Size(); ++i )
  1019. {
  1020. if ( Cone[ i ]->Mark == QH_MARK_DELETE )
  1021. {
  1022. DestroyFace( Cone[ i ] );
  1023. continue;
  1024. }
  1025. mFaceList.PushBack( Cone[ i ] );
  1026. }
  1027. }
  1028. //--------------------------------------------------------------------------------------------------
  1029. bool qhConvex::FirstPass( qhFace* Face )
  1030. {
  1031. bool Concave = false;
  1032. qhHalfEdge* Edge = Face->Edge;
  1033. do
  1034. {
  1035. qhHalfEdge* Twin = Edge->Twin;
  1036. if ( Face->Area > Twin->Face->Area )
  1037. {
  1038. if ( !Edge->IsConvex( mMinRadius ) )
  1039. {
  1040. // Merge
  1041. ConnectFaces( Edge );
  1042. return true;
  1043. }
  1044. else if ( !Twin->IsConvex( mMinRadius ) )
  1045. {
  1046. // Mark as concave and handle in second pass
  1047. Concave = true;
  1048. }
  1049. }
  1050. else
  1051. {
  1052. if ( !Twin->IsConvex( mMinRadius ) )
  1053. {
  1054. // Merge
  1055. ConnectFaces( Edge );
  1056. return true;
  1057. }
  1058. else if ( !Edge->IsConvex( mMinRadius ) )
  1059. {
  1060. // Mark as concave and handle in second pass
  1061. Concave = true;
  1062. }
  1063. }
  1064. Edge = Edge->Next;
  1065. }
  1066. while ( Edge != Face->Edge );
  1067. if ( Concave )
  1068. {
  1069. Face->Mark = QH_MARK_CONCAVE;
  1070. }
  1071. return false;
  1072. }
  1073. //--------------------------------------------------------------------------------------------------
  1074. bool qhConvex::SecondPass( qhFace* Face )
  1075. {
  1076. qhHalfEdge* Edge = Face->Edge;
  1077. do
  1078. {
  1079. qhHalfEdge* Twin = Edge->Twin;
  1080. if ( !Edge->IsConvex( mMinRadius ) || !Twin->IsConvex( mMinRadius ) )
  1081. {
  1082. ConnectFaces( Edge );
  1083. return true;
  1084. }
  1085. Edge = Edge->Next;
  1086. }
  1087. while ( Edge != Face->Edge );
  1088. return false;
  1089. }
  1090. //--------------------------------------------------------------------------------------------------
  1091. void qhConvex::ConnectFaces( qhHalfEdge* Edge )
  1092. {
  1093. // The absorbing face
  1094. qhFace* Face = Edge->Face;
  1095. QH_ASSERT( qhCheckConsistency( Face ) );
  1096. // Find the strip of shared edges
  1097. qhHalfEdge* Twin = Edge->Twin;
  1098. QH_ASSERT( qhCheckConsistency( Twin->Face ) );
  1099. qhHalfEdge* EdgePrev = Edge->Prev;
  1100. qhHalfEdge* EdgeNext = Edge->Next;
  1101. qhHalfEdge* TwinPrev = Twin->Prev;
  1102. qhHalfEdge* TwinNext = Twin->Next;
  1103. while ( EdgePrev->Twin->Face == Twin->Face )
  1104. {
  1105. QH_ASSERT( EdgePrev->Twin == TwinNext );
  1106. QH_ASSERT( TwinNext->Twin == EdgePrev );
  1107. EdgePrev = EdgePrev->Prev;
  1108. TwinNext = TwinNext->Next;
  1109. }
  1110. QH_ASSERT( EdgePrev->Face != TwinNext->Face );
  1111. while ( EdgeNext->Twin->Face == Twin->Face )
  1112. {
  1113. QH_ASSERT( EdgeNext->Twin == TwinPrev );
  1114. QH_ASSERT( TwinPrev->Twin == EdgeNext );
  1115. EdgeNext = EdgeNext->Next;
  1116. TwinPrev = TwinPrev->Prev;
  1117. }
  1118. QH_ASSERT( EdgeNext->Face != TwinPrev->Face );
  1119. // Make sure we don't reference a shared edge
  1120. Face->Edge = EdgePrev;
  1121. // Discard opposing face and absorb non-shared edges
  1122. qhArray< qhFace* > MergedFaces;
  1123. MergedFaces.PushBack( Twin->Face );
  1124. Twin->Face->Mark = QH_MARK_DELETE;
  1125. Twin->Face->Edge = NULL;
  1126. for ( qhHalfEdge* Absorbed = TwinNext; Absorbed != TwinPrev->Next; Absorbed = Absorbed->Next )
  1127. {
  1128. Absorbed->Face = Face;
  1129. }
  1130. // Delete shared edges (before connection)
  1131. DestroyEdges( EdgePrev->Next, EdgeNext );
  1132. DestroyEdges( TwinPrev->Next, TwinNext );
  1133. // Connect half edges (this can have side effects)
  1134. ConnectEdges( EdgePrev, TwinNext, MergedFaces );
  1135. ConnectEdges( TwinPrev, EdgeNext, MergedFaces );
  1136. // Rebuild geometry for the merges face
  1137. qhNewellPlane( Face );
  1138. QH_ASSERT( qhCheckConsistency( Face ) );
  1139. // Absorb conflict vertices
  1140. AbsorbFaces( Face, MergedFaces );
  1141. }
  1142. //--------------------------------------------------------------------------------------------------
  1143. void qhConvex::ConnectEdges( qhHalfEdge* Prev, qhHalfEdge* Next, qhArray< qhFace* >& MergedFaces )
  1144. {
  1145. QH_ASSERT( Prev != Next );
  1146. QH_ASSERT( Prev->Face == Next->Face );
  1147. // Check for redundant edges (this has side effects)
  1148. // If this condition holds true both faces are in the same
  1149. // plane since the share three vertices.
  1150. if ( Prev->Twin->Face == Next->Twin->Face )
  1151. {
  1152. // Next is redundant and will be removed.
  1153. // It should not be referenced by its associated face!
  1154. if ( Next->Face->Edge == Next )
  1155. {
  1156. Next->Face->Edge = Prev;
  1157. }
  1158. qhHalfEdge* Twin;
  1159. if ( qhVertexCount( Prev->Twin->Face ) == 3 )
  1160. {
  1161. Twin = Next->Twin->Prev->Twin;
  1162. QH_ASSERT( Twin->Face->Mark != QH_MARK_DELETE );
  1163. // If the opposing face is a triangle. We will
  1164. // get rid of it *and* its associated edges
  1165. // (Don't set OpposingFace->Edge = NULL!)
  1166. qhFace* OpposingFace = Prev->Twin->Face;
  1167. OpposingFace->Mark = QH_MARK_DELETE;
  1168. MergedFaces.PushBack( OpposingFace );
  1169. }
  1170. else
  1171. {
  1172. Twin = Next->Twin;
  1173. // Prev->Twin is redundant and will be removed.
  1174. // It should not be referenced by its associated face!
  1175. if ( Twin->Face->Edge == Prev->Twin )
  1176. {
  1177. Twin->Face->Edge = Twin;
  1178. }
  1179. Twin->Next = Prev->Twin->Next;
  1180. Twin->Next->Prev = Twin;
  1181. qhFree( Prev->Twin );
  1182. }
  1183. Prev->Next = Next->Next;
  1184. Prev->Next->Prev = Prev;
  1185. Prev->Twin = Twin;
  1186. Twin->Twin = Prev;
  1187. // Destroy redundant edge and its associated vertex
  1188. mVertexList.Remove( Next->Origin );
  1189. DestroyVertex( Next->Origin );
  1190. qhFree( Next );
  1191. // Twin->Face was modified, so recompute its plane
  1192. qhNewellPlane( Twin->Face );
  1193. QH_ASSERT( qhCheckConsistency( Twin->Face ) );
  1194. }
  1195. else
  1196. {
  1197. Prev->Next = Next;
  1198. Next->Prev = Prev;
  1199. }
  1200. }
  1201. //--------------------------------------------------------------------------------------------------
  1202. void qhConvex::DestroyEdges( qhHalfEdge* Begin, qhHalfEdge* End )
  1203. {
  1204. qhHalfEdge* Edge = Begin;
  1205. while ( Edge != End )
  1206. {
  1207. qhHalfEdge* Nuke = Edge;
  1208. Edge = Edge->Next;
  1209. // Delete vertex if there is more than one shared edge
  1210. // DIRK_TODO: Since we run over the twin edges as well this would delete the vertex twice!
  1211. // if ( Nuke != Begin )
  1212. // {
  1213. // mVertexList.Remove( Nuke->Origin );
  1214. // DestroyVertex( Nuke->Origin );
  1215. // }
  1216. qhFree( Nuke );
  1217. Nuke = NULL;
  1218. }
  1219. }
  1220. //--------------------------------------------------------------------------------------------------
  1221. void qhConvex::AbsorbFaces( qhFace* Face, qhArray< qhFace* >& MergedFaces )
  1222. {
  1223. for ( int i = 0; i < MergedFaces.Size(); ++i )
  1224. {
  1225. QH_ASSERT( MergedFaces[ i ]->Mark == QH_MARK_DELETE );
  1226. qhList< qhVertex >& ConflictList = MergedFaces[ i ]->ConflictList;
  1227. qhVertex* Vertex = ConflictList.Begin();
  1228. while ( Vertex != ConflictList.End() )
  1229. {
  1230. qhVertex* Next = Vertex->Next;
  1231. ConflictList.Remove( Vertex );
  1232. if ( Face->Plane.Distance( Vertex->Position ) > mMinOutside )
  1233. {
  1234. Face->ConflictList.PushBack( Vertex );
  1235. Vertex->ConflictFace = Face;
  1236. }
  1237. else
  1238. {
  1239. mOrphanedList.PushBack( Vertex );
  1240. }
  1241. Vertex = Next;
  1242. }
  1243. QH_ASSERT( ConflictList.Empty() );
  1244. }
  1245. }
  1246. //-------------------------------------------------------------------------------------------------
  1247. void qhConvex::GetMesh( qhMesh& Mesh ) const
  1248. {
  1249. Mesh.Vertices.Clear();
  1250. Mesh.Normals.Clear();
  1251. Mesh.Faces.Clear();
  1252. Mesh.Indices.Clear();
  1253. // Save vertices
  1254. for ( const qhVertex* Vertex = mVertexList.Begin(); Vertex != mVertexList.End(); Vertex = Vertex->Next )
  1255. {
  1256. Mesh.Vertices.PushBack( Vertex->Position );
  1257. }
  1258. // Save faces
  1259. for ( const qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  1260. {
  1261. Mesh.Normals.PushBack( Face->Plane.Normal );
  1262. int IndexStart = Mesh.Indices.Size();
  1263. const qhHalfEdge* Edge = Face->Edge;
  1264. do
  1265. {
  1266. int Index = mVertexList.IndexOf( Edge->Origin );
  1267. Mesh.Indices.PushBack( Index );
  1268. Edge = Edge->Next;
  1269. }
  1270. while ( Edge != Face->Edge );
  1271. int IndexEnd = Mesh.Indices.Size();
  1272. Mesh.Faces.PushBack( IndexEnd - IndexStart );
  1273. }
  1274. }
  1275. //-------------------------------------------------------------------------------------------------
  1276. qhMass qhConvex::ComputeMass( qhReal Density ) const
  1277. {
  1278. // M. Kallay - "Computing the Moment of Inertia of a Solid Defined by a Triangle Mesh"
  1279. qhReal Volume = qhReal( 0 );
  1280. qhVector3 Center = QH_VEC3_ZERO;
  1281. qhReal XX = qhReal( 0 ); qhReal XY = qhReal( 0 );
  1282. qhReal YY = qhReal( 0 ); qhReal XZ = qhReal( 0 );
  1283. qhReal ZZ = qhReal( 0 ); qhReal YZ = qhReal( 0 );
  1284. // Iterate over faces and triangulate in-place
  1285. for ( const qhFace* Face = mFaceList.Begin(); Face != mFaceList.End(); Face = Face->Next )
  1286. {
  1287. const qhHalfEdge* Edge1 = Face->Edge;
  1288. const qhHalfEdge* Edge2 = Edge1->Next;
  1289. const qhHalfEdge* Edge3 = Edge2->Next;
  1290. QH_ASSERT( Edge3 != Edge1 );
  1291. qhVector3 V1 = Edge1->Origin->Position;
  1292. do
  1293. {
  1294. qhVector3 V2 = Edge2->Origin->Position;
  1295. qhVector3 V3 = Edge3->Origin->Position;
  1296. // Signed volume of this tetrahedron
  1297. qhReal Det = qhDet( V1, V2, V3 );
  1298. // Contribution to mass
  1299. Volume += Det;
  1300. // Contribution to centroid
  1301. qhVector3 v4 = V1 + V2 + V3;
  1302. Center += Det * v4;
  1303. // Contribution to inertia monomials
  1304. XX += Det * ( V1.X*V1.X + V2.X*V2.X + V3.X*V3.X + v4.X*v4.X );
  1305. YY += Det * ( V1.Y*V1.Y + V2.Y*V2.Y + V3.Y*V3.Y + v4.Y*v4.Y );
  1306. ZZ += Det * ( V1.Z*V1.Z + V2.Z*V2.Z + V3.Z*V3.Z + v4.Z*v4.Z );
  1307. XY += Det * ( V1.X*V1.Y + V2.X*V2.Y + V3.X*V3.Y + v4.X*v4.Y );
  1308. XZ += Det * ( V1.X*V1.Z + V2.X*V2.Z + V3.X*V3.Z + v4.X*v4.Z );
  1309. YZ += Det * ( V1.Y*V1.Z + V2.Y*V2.Z + V3.Y*V3.Z + v4.Y*v4.Z );
  1310. Edge2 = Edge3;
  1311. Edge3 = Edge3->Next;
  1312. }
  1313. while ( Edge3 != Face->Edge );
  1314. }
  1315. QH_ASSERT( Volume > 0.0f );
  1316. // Fetch result
  1317. qhMatrix3 Inertia;
  1318. Inertia.C1.X = YY + ZZ; Inertia.C2.X = -XY; Inertia.C3.X = -XZ;
  1319. Inertia.C1.Y = -XY; Inertia.C2.Y = XX + ZZ; Inertia.C3.Y = -YZ;
  1320. Inertia.C1.Z = -XZ; Inertia.C2.Z = -YZ; Inertia.C3.Z = XX + YY;
  1321. qhMass Mass;
  1322. Mass.Weight = Density * Volume / qhReal( 6.0 );
  1323. Mass.Center = Center / ( qhReal( 4 ) * Volume );
  1324. Mass.Inertia = ( Density / qhReal( 120 ) ) * Inertia;
  1325. return Mass;
  1326. }