ConvexHullBuilder.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <Jolt/Jolt.h>
  4. #include <Jolt/Geometry/ConvexHullBuilder.h>
  5. #include <Jolt/Geometry/ConvexHullBuilder2D.h>
  6. #include <Jolt/Geometry/ClosestPoint.h>
  7. #include <Jolt/Core/StringTools.h>
  8. JPH_SUPPRESS_WARNINGS_STD_BEGIN
  9. #include <unordered_set>
  10. #include <fstream>
  11. JPH_SUPPRESS_WARNINGS_STD_END
  12. #ifdef JPH_CONVEX_BUILDER_DEBUG
  13. #include <Jolt/Renderer/DebugRenderer.h>
  14. #endif
  15. JPH_NAMESPACE_BEGIN
  16. ConvexHullBuilder::Face::~Face()
  17. {
  18. // Free all edges
  19. Edge *e = mFirstEdge;
  20. if (e != nullptr)
  21. {
  22. do
  23. {
  24. Edge *next = e->mNextEdge;
  25. delete e;
  26. e = next;
  27. } while (e != mFirstEdge);
  28. }
  29. }
  30. void ConvexHullBuilder::Face::CalculateNormalAndCentroid(const Vec3 *inPositions)
  31. {
  32. // Get point that we use to construct a triangle fan
  33. Edge *e = mFirstEdge;
  34. Vec3 y0 = inPositions[e->mStartIdx];
  35. // Get the 2nd point
  36. e = e->mNextEdge;
  37. Vec3 y1 = inPositions[e->mStartIdx];
  38. // Start accumulating the centroid
  39. mCentroid = y0 + y1;
  40. int n = 2;
  41. // Start accumulating the normal
  42. mNormal = Vec3::sZero();
  43. // Loop over remaining edges accumulating normals in a triangle fan fashion
  44. for (e = e->mNextEdge; e != mFirstEdge; e = e->mNextEdge)
  45. {
  46. // Get the 3rd point
  47. Vec3 y2 = inPositions[e->mStartIdx];
  48. // Calculate edges (counter clockwise)
  49. Vec3 e0 = y1 - y0;
  50. Vec3 e1 = y2 - y1;
  51. Vec3 e2 = y0 - y2;
  52. // The best normal is calculated by using the two shortest edges
  53. // See: https://box2d.org/posts/2014/01/troublesome-triangle/
  54. // The difference in normals is most pronounced when one edge is much smaller than the others (in which case the others must have roughly the same length).
  55. // Therefore we can suffice by just picking the shortest from 2 edges and use that with the 3rd edge to calculate the normal.
  56. // We first check which of the edges is shorter: e1 or e2
  57. UVec4 e1_shorter_than_e2 = Vec4::sLess(e1.DotV4(e1), e2.DotV4(e2));
  58. // We calculate both normals and then select the one that had the shortest edge for our normal (this avoids branching)
  59. Vec3 normal_e01 = e0.Cross(e1);
  60. Vec3 normal_e02 = e2.Cross(e0);
  61. mNormal += Vec3::sSelect(normal_e02, normal_e01, e1_shorter_than_e2);
  62. // Accumulate centroid
  63. mCentroid += y2;
  64. n++;
  65. // Update y1 for next triangle
  66. y1 = y2;
  67. }
  68. // Finalize centroid
  69. mCentroid /= float(n);
  70. }
  71. void ConvexHullBuilder::Face::Initialize(int inIdx0, int inIdx1, int inIdx2, const Vec3 *inPositions)
  72. {
  73. JPH_ASSERT(mFirstEdge == nullptr);
  74. JPH_ASSERT(inIdx0 != inIdx1 && inIdx0 != inIdx2 && inIdx1 != inIdx2);
  75. // Create 3 edges
  76. Edge *e0 = new Edge(this, inIdx0);
  77. Edge *e1 = new Edge(this, inIdx1);
  78. Edge *e2 = new Edge(this, inIdx2);
  79. // Link edges
  80. e0->mNextEdge = e1;
  81. e1->mNextEdge = e2;
  82. e2->mNextEdge = e0;
  83. mFirstEdge = e0;
  84. CalculateNormalAndCentroid(inPositions);
  85. }
  86. ConvexHullBuilder::ConvexHullBuilder(const Positions &inPositions) :
  87. mPositions(inPositions)
  88. {
  89. #ifdef JPH_CONVEX_BUILDER_DEBUG
  90. mIteration = 0;
  91. // Center the drawing of the first hull around the origin and calculate the delta offset between states
  92. mOffset = Vec3::sZero();
  93. if (mPositions.empty())
  94. {
  95. // No hull will be generated
  96. mDelta = Vec3::sZero();
  97. }
  98. else
  99. {
  100. Vec3 maxv = Vec3::sReplicate(-FLT_MAX), minv = Vec3::sReplicate(FLT_MAX);
  101. for (Vec3 v : mPositions)
  102. {
  103. minv = Vec3::sMin(minv, v);
  104. maxv = Vec3::sMax(maxv, v);
  105. mOffset -= v;
  106. }
  107. mOffset /= float(mPositions.size());
  108. mDelta = Vec3((maxv - minv).GetX() + 0.5f, 0, 0);
  109. mOffset += mDelta; // Don't start at origin, we're already drawing the final hull there
  110. }
  111. #endif
  112. }
  113. void ConvexHullBuilder::FreeFaces()
  114. {
  115. for (Face *f : mFaces)
  116. delete f;
  117. mFaces.clear();
  118. }
  119. void ConvexHullBuilder::AssignPointToFace(int inPositionIdx, const Faces &inFaces) const
  120. {
  121. Vec3 point = mPositions[inPositionIdx];
  122. Face *best_face = nullptr;
  123. float best_dist_sq = 0.0f;
  124. // Test against all faces
  125. for (Face *f : inFaces)
  126. if (!f->mRemoved)
  127. {
  128. // Determine distance to face
  129. float dot = f->mNormal.Dot(point - f->mCentroid);
  130. if (dot > 0.0f)
  131. {
  132. float dist_sq = dot * dot / f->mNormal.LengthSq();
  133. if (dist_sq > best_dist_sq)
  134. {
  135. best_face = f;
  136. best_dist_sq = dist_sq;
  137. }
  138. }
  139. }
  140. // If this point is in front of the face, add it to the conflict list
  141. if (best_face != nullptr)
  142. {
  143. if (best_dist_sq > best_face->mFurthestPointDistanceSq)
  144. {
  145. // This point is futher away than any others, update the distance and add point as last point
  146. best_face->mFurthestPointDistanceSq = best_dist_sq;
  147. best_face->mConflictList.push_back(inPositionIdx);
  148. }
  149. else
  150. {
  151. // Not the furthest point, add it as the before last point
  152. best_face->mConflictList.push_back(best_face->mConflictList.back());
  153. best_face->mConflictList[best_face->mConflictList.size() - 2] = inPositionIdx;
  154. }
  155. }
  156. }
  157. float ConvexHullBuilder::DetermineCoplanarDistance() const
  158. {
  159. // Formula as per: Implementing Quickhull - Dirk Gregorius.
  160. Vec3 vmax = Vec3::sZero();
  161. for (Vec3 v : mPositions)
  162. vmax = Vec3::sMax(vmax, v.Abs());
  163. return 3.0f * FLT_EPSILON * (vmax.GetX() + vmax.GetY() + vmax.GetZ());
  164. }
  165. int ConvexHullBuilder::GetNumVerticesUsed() const
  166. {
  167. unordered_set<int> used_verts;
  168. for (Face *f : mFaces)
  169. {
  170. Edge *e = f->mFirstEdge;
  171. do
  172. {
  173. used_verts.insert(e->mStartIdx);
  174. e = e->mNextEdge;
  175. } while (e != f->mFirstEdge);
  176. }
  177. return (int)used_verts.size();
  178. }
  179. bool ConvexHullBuilder::ContainsFace(const vector<int> &inIndices) const
  180. {
  181. for (Face *f : mFaces)
  182. {
  183. Edge *e = f->mFirstEdge;
  184. vector<int>::const_iterator index = find(inIndices.begin(), inIndices.end(), e->mStartIdx);
  185. if (index != inIndices.end())
  186. {
  187. size_t matches = 0;
  188. do
  189. {
  190. // Check if index matches
  191. if (*index != e->mStartIdx)
  192. break;
  193. // Increment number of matches
  194. matches++;
  195. // Next index in list of inIndices
  196. index++;
  197. if (index == inIndices.end())
  198. index = inIndices.begin();
  199. // Next edge
  200. e = e->mNextEdge;
  201. } while (e != f->mFirstEdge);
  202. if (matches == inIndices.size())
  203. return true;
  204. }
  205. }
  206. return false;
  207. }
  208. ConvexHullBuilder::EResult ConvexHullBuilder::Initialize(int inMaxVertices, float inTolerance, const char *&outError)
  209. {
  210. // Free the faces possibly left over from an earlier hull
  211. FreeFaces();
  212. // Test that we have at least 3 points
  213. if (mPositions.size() < 3)
  214. {
  215. outError = "Need at least 3 points to make a hull";
  216. return EResult::TooFewPoints;
  217. }
  218. // Determine a suitable tolerance for detecting that points are coplanar
  219. float coplanar_tolerance_sq = Square(DetermineCoplanarDistance());
  220. // Increase desired tolerance if accuracy doesn't allow it
  221. float tolerance_sq = max(coplanar_tolerance_sq, Square(inTolerance));
  222. // Find point furthest from the origin
  223. int idx1 = -1;
  224. float max_dist_sq = -1.0f;
  225. for (int i = 0; i < (int)mPositions.size(); ++i)
  226. {
  227. float dist_sq = mPositions[i].LengthSq();
  228. if (dist_sq > max_dist_sq)
  229. {
  230. max_dist_sq = dist_sq;
  231. idx1 = i;
  232. }
  233. }
  234. JPH_ASSERT(idx1 >= 0);
  235. // Find point that is furthest away from this point
  236. int idx2 = -1;
  237. max_dist_sq = -1.0f;
  238. for (int i = 0; i < (int)mPositions.size(); ++i)
  239. if (i != idx1)
  240. {
  241. float dist_sq = (mPositions[i] - mPositions[idx1]).LengthSq();
  242. if (dist_sq > max_dist_sq)
  243. {
  244. max_dist_sq = dist_sq;
  245. idx2 = i;
  246. }
  247. }
  248. JPH_ASSERT(idx2 >= 0);
  249. // Find point that forms the biggest triangle
  250. int idx3 = -1;
  251. float best_triangle_area_sq = -1.0f;
  252. for (int i = 0; i < (int)mPositions.size(); ++i)
  253. if (i != idx1 && i != idx2)
  254. {
  255. float triangle_area_sq = (mPositions[idx1] - mPositions[i]).Cross(mPositions[idx2] - mPositions[i]).LengthSq();
  256. if (triangle_area_sq > best_triangle_area_sq)
  257. {
  258. best_triangle_area_sq = triangle_area_sq;
  259. idx3 = i;
  260. }
  261. }
  262. JPH_ASSERT(idx3 >= 0);
  263. if (best_triangle_area_sq < cMinTriangleAreaSq)
  264. {
  265. outError = "Could not find a suitable initial triangle because its area was too small";
  266. return EResult::Degenerate;
  267. }
  268. // Check if we have only 3 vertices
  269. if (mPositions.size() == 3)
  270. {
  271. // Create two triangles (back to back)
  272. Face *t1 = CreateTriangle(idx1, idx2, idx3);
  273. Face *t2 = CreateTriangle(idx1, idx3, idx2);
  274. // Link faces edges
  275. sLinkFace(t1->mFirstEdge, t2->mFirstEdge->mNextEdge->mNextEdge);
  276. sLinkFace(t1->mFirstEdge->mNextEdge, t2->mFirstEdge->mNextEdge);
  277. sLinkFace(t1->mFirstEdge->mNextEdge->mNextEdge, t2->mFirstEdge);
  278. #ifdef JPH_CONVEX_BUILDER_DEBUG
  279. // Draw current state
  280. DrawState();
  281. #endif
  282. return EResult::Success;
  283. }
  284. // Find point that forms the biggest tetrahedron
  285. Vec3 initial_plane_normal = (mPositions[idx2] - mPositions[idx1]).Cross(mPositions[idx3] - mPositions[idx1]).Normalized();
  286. Vec3 initial_plane_centroid = (mPositions[idx1] + mPositions[idx2] + mPositions[idx3]) / 3.0f;
  287. int idx4 = -1;
  288. float max_dist = 0.0f;
  289. for (int i = 0; i < (int)mPositions.size(); ++i)
  290. if (i != idx1 && i != idx2 && i != idx3)
  291. {
  292. float dist = (mPositions[i] - initial_plane_centroid).Dot(initial_plane_normal);
  293. if (abs(dist) > abs(max_dist))
  294. {
  295. max_dist = dist;
  296. idx4 = i;
  297. }
  298. }
  299. // Check if the hull is coplanar
  300. if (Square(max_dist) <= 25.0f * coplanar_tolerance_sq)
  301. {
  302. // First project all points in 2D space
  303. Vec3 base1 = initial_plane_normal.GetNormalizedPerpendicular();
  304. Vec3 base2 = initial_plane_normal.Cross(base1);
  305. vector<Vec3> positions_2d;
  306. positions_2d.reserve(mPositions.size());
  307. for (Vec3 v : mPositions)
  308. positions_2d.push_back(Vec3(base1.Dot(v), base2.Dot(v), 0));
  309. // Build hull
  310. vector<int> edges_2d;
  311. ConvexHullBuilder2D builder_2d(positions_2d);
  312. ConvexHullBuilder2D::EResult result = builder_2d.Initialize(idx1, idx2, idx3, inMaxVertices, inTolerance, edges_2d);
  313. // Create faces (back to back)
  314. Face *f1 = CreateFace();
  315. Face *f2 = CreateFace();
  316. // Create edges for face 1
  317. vector<Edge *> edges_f1;
  318. edges_f1.reserve(edges_2d.size());
  319. for (int start_idx : edges_2d)
  320. {
  321. Edge *edge = new Edge(f1, start_idx);
  322. if (edges_f1.empty())
  323. f1->mFirstEdge = edge;
  324. else
  325. edges_f1.back()->mNextEdge = edge;
  326. edges_f1.push_back(edge);
  327. }
  328. edges_f1.back()->mNextEdge = f1->mFirstEdge;
  329. // Create edges for face 2
  330. vector<Edge *> edges_f2;
  331. edges_f2.reserve(edges_2d.size());
  332. for (int i = (int)edges_2d.size() - 1; i >= 0; --i)
  333. {
  334. Edge *edge = new Edge(f2, edges_2d[i]);
  335. if (edges_f2.empty())
  336. f2->mFirstEdge = edge;
  337. else
  338. edges_f2.back()->mNextEdge = edge;
  339. edges_f2.push_back(edge);
  340. }
  341. edges_f2.back()->mNextEdge = f2->mFirstEdge;
  342. // Link edges
  343. for (size_t i = 0; i < edges_2d.size(); ++i)
  344. sLinkFace(edges_f1[i], edges_f2[(2 * edges_2d.size() - 2 - i) % edges_2d.size()]);
  345. // Calculate the plane for both faces
  346. f1->CalculateNormalAndCentroid(mPositions.data());
  347. f2->mNormal = -f1->mNormal;
  348. f2->mCentroid = f1->mCentroid;
  349. #ifdef JPH_CONVEX_BUILDER_DEBUG
  350. // Draw current state
  351. DrawState();
  352. #endif
  353. return result == ConvexHullBuilder2D::EResult::MaxVerticesReached? EResult::MaxVerticesReached : EResult::Success;
  354. }
  355. // Ensure the planes are facing outwards
  356. if (max_dist < 0.0f)
  357. swap(idx2, idx3);
  358. // Create tetrahedron
  359. Face *t1 = CreateTriangle(idx1, idx2, idx4);
  360. Face *t2 = CreateTriangle(idx2, idx3, idx4);
  361. Face *t3 = CreateTriangle(idx3, idx1, idx4);
  362. Face *t4 = CreateTriangle(idx1, idx3, idx2);
  363. // Link face edges
  364. sLinkFace(t1->mFirstEdge, t4->mFirstEdge->mNextEdge->mNextEdge);
  365. sLinkFace(t1->mFirstEdge->mNextEdge, t2->mFirstEdge->mNextEdge->mNextEdge);
  366. sLinkFace(t1->mFirstEdge->mNextEdge->mNextEdge, t3->mFirstEdge->mNextEdge);
  367. sLinkFace(t2->mFirstEdge, t4->mFirstEdge->mNextEdge);
  368. sLinkFace(t2->mFirstEdge->mNextEdge, t3->mFirstEdge->mNextEdge->mNextEdge);
  369. sLinkFace(t3->mFirstEdge, t4->mFirstEdge);
  370. // Build the initial conflict lists
  371. Faces faces { t1, t2, t3, t4 };
  372. for (int idx = 0; idx < (int)mPositions.size(); ++idx)
  373. if (idx != idx1 && idx != idx2 && idx != idx3 && idx != idx4)
  374. AssignPointToFace(idx, faces);
  375. #ifdef JPH_CONVEX_BUILDER_DEBUG
  376. // Draw current state including conflict list
  377. DrawState(true);
  378. // Increment iteration counter
  379. ++mIteration;
  380. #endif
  381. // Overestimate of the actual amount of vertices we use, for limiting the amount of vertices in the hull
  382. int num_vertices_used = 4;
  383. // Loop through the remainder of the points and add them
  384. for (;;)
  385. {
  386. // Find the face with the furthest point on it
  387. Face *face_with_furthest_point = nullptr;
  388. float furthest_dist_sq = 0.0f;
  389. for (Face *f : mFaces)
  390. if (f->mFurthestPointDistanceSq > furthest_dist_sq)
  391. {
  392. furthest_dist_sq = f->mFurthestPointDistanceSq;
  393. face_with_furthest_point = f;
  394. }
  395. // If there is none closer than our tolerance value, we're done
  396. if (face_with_furthest_point == nullptr || furthest_dist_sq < tolerance_sq)
  397. break;
  398. // Check if we have a limit on the max vertices that we should produce
  399. if (num_vertices_used >= inMaxVertices)
  400. {
  401. // Count the actual amount of used vertices (we did not take the removal of any vertices into account)
  402. num_vertices_used = GetNumVerticesUsed();
  403. // Check if there are too many
  404. if (num_vertices_used >= inMaxVertices)
  405. return EResult::MaxVerticesReached;
  406. }
  407. // We're about to add another vertex
  408. ++num_vertices_used;
  409. // Take the furthest point
  410. int furthest_point_idx = face_with_furthest_point->mConflictList.back();
  411. face_with_furthest_point->mConflictList.pop_back();
  412. // Add the point to the hull
  413. Faces new_faces;
  414. AddPoint(face_with_furthest_point, furthest_point_idx, coplanar_tolerance_sq, new_faces);
  415. // Redistribute points on conflict lists belonging to removed faces
  416. for (const Face *face : mFaces)
  417. if (face->mRemoved)
  418. for (int idx : face->mConflictList)
  419. AssignPointToFace(idx, new_faces);
  420. // Permanently delete faces that we removed in AddPoint()
  421. GarbageCollectFaces();
  422. #ifdef JPH_CONVEX_BUILDER_DEBUG
  423. // Draw state at the end of this step including conflict list
  424. DrawState(true);
  425. // Increment iteration counter
  426. ++mIteration;
  427. #endif
  428. }
  429. return EResult::Success;
  430. }
  431. void ConvexHullBuilder::AddPoint(Face *inFacingFace, int inIdx, float inCoplanarToleranceSq, Faces &outNewFaces)
  432. {
  433. // Get position
  434. Vec3 pos = mPositions[inIdx];
  435. #ifdef JPH_CONVEX_BUILDER_DEBUG
  436. // Draw point to be added
  437. DebugRenderer::sInstance->DrawMarker(cDrawScale * (mOffset + pos), Color::sYellow, 0.1f);
  438. DebugRenderer::sInstance->DrawText3D(cDrawScale * (mOffset + pos), ConvertToString(inIdx), Color::sWhite);
  439. #endif
  440. #ifdef JPH_ENABLE_ASSERTS
  441. // Check if structure is intact
  442. ValidateFaces();
  443. #endif
  444. // Find edge of convex hull of faces that are not facing the new vertex
  445. FullEdges edges;
  446. FindEdge(inFacingFace, pos, edges);
  447. JPH_ASSERT(edges.size() >= 3);
  448. // Create new faces
  449. outNewFaces.reserve(edges.size());
  450. for (const FullEdge &e : edges)
  451. {
  452. JPH_ASSERT(e.mStartIdx != e.mEndIdx);
  453. Face *f = CreateTriangle(e.mStartIdx, e.mEndIdx, inIdx);
  454. outNewFaces.push_back(f);
  455. }
  456. // Link edges
  457. for (Faces::size_type i = 0; i < outNewFaces.size(); ++i)
  458. {
  459. sLinkFace(outNewFaces[i]->mFirstEdge, edges[i].mNeighbourEdge);
  460. sLinkFace(outNewFaces[i]->mFirstEdge->mNextEdge, outNewFaces[(i + 1) % outNewFaces.size()]->mFirstEdge->mNextEdge->mNextEdge);
  461. }
  462. // Loop on faces that were modified until nothing needs to be checked anymore
  463. Faces affected_faces = outNewFaces;
  464. while (!affected_faces.empty())
  465. {
  466. // Take the next face
  467. Face *face = affected_faces.back();
  468. affected_faces.pop_back();
  469. if (!face->mRemoved)
  470. {
  471. // Merge with neighbour if this is a degenerate face
  472. MergeDegenerateFace(face, affected_faces);
  473. // Merge with coplanar neighbours (or when the neighbour forms a concave edge)
  474. if (!face->mRemoved)
  475. MergeCoplanarOrConcaveFaces(face, inCoplanarToleranceSq, affected_faces);
  476. }
  477. }
  478. #ifdef JPH_ENABLE_ASSERTS
  479. // Check if structure is intact
  480. ValidateFaces();
  481. #endif
  482. }
  483. void ConvexHullBuilder::GarbageCollectFaces()
  484. {
  485. for (int i = (int)mFaces.size() - 1; i >= 0; --i)
  486. {
  487. Face *f = mFaces[i];
  488. if (f->mRemoved)
  489. {
  490. FreeFace(f);
  491. mFaces.erase(mFaces.begin() + i);
  492. }
  493. }
  494. }
  495. ConvexHullBuilder::Face *ConvexHullBuilder::CreateFace()
  496. {
  497. // Call provider to create face
  498. Face *f = new Face();
  499. #ifdef JPH_CONVEX_BUILDER_DEBUG
  500. // Remember iteration counter
  501. f->mIteration = mIteration;
  502. #endif
  503. // Add to list
  504. mFaces.push_back(f);
  505. return f;
  506. }
  507. ConvexHullBuilder::Face *ConvexHullBuilder::CreateTriangle(int inIdx1, int inIdx2, int inIdx3)
  508. {
  509. Face *f = CreateFace();
  510. f->Initialize(inIdx1, inIdx2, inIdx3, mPositions.data());
  511. return f;
  512. }
  513. void ConvexHullBuilder::FreeFace(Face *inFace)
  514. {
  515. JPH_ASSERT(inFace->mRemoved);
  516. #ifdef JPH_ENABLE_ASSERTS
  517. // Make sure that this face is not connected
  518. Edge *e = inFace->mFirstEdge;
  519. if (e != nullptr)
  520. do
  521. {
  522. JPH_ASSERT(e->mNeighbourEdge == nullptr);
  523. e = e->mNextEdge;
  524. } while (e != inFace->mFirstEdge);
  525. #endif
  526. // Free the face
  527. delete inFace;
  528. }
  529. void ConvexHullBuilder::sLinkFace(Edge *inEdge1, Edge *inEdge2)
  530. {
  531. // Check not connected yet
  532. JPH_ASSERT(inEdge1->mNeighbourEdge == nullptr);
  533. JPH_ASSERT(inEdge2->mNeighbourEdge == nullptr);
  534. JPH_ASSERT(inEdge1->mFace != inEdge2->mFace);
  535. // Check vertices match
  536. JPH_ASSERT(inEdge1->mStartIdx == inEdge2->mNextEdge->mStartIdx);
  537. JPH_ASSERT(inEdge2->mStartIdx == inEdge1->mNextEdge->mStartIdx);
  538. // Link up
  539. inEdge1->mNeighbourEdge = inEdge2;
  540. inEdge2->mNeighbourEdge = inEdge1;
  541. }
  542. void ConvexHullBuilder::sUnlinkFace(Face *inFace)
  543. {
  544. // Unlink from neighbours
  545. Edge *e = inFace->mFirstEdge;
  546. do
  547. {
  548. if (e->mNeighbourEdge != nullptr)
  549. {
  550. // Validate that neighbour points to us
  551. JPH_ASSERT(e->mNeighbourEdge->mNeighbourEdge == e);
  552. // Unlink
  553. e->mNeighbourEdge->mNeighbourEdge = nullptr;
  554. e->mNeighbourEdge = nullptr;
  555. }
  556. e = e->mNextEdge;
  557. } while (e != inFace->mFirstEdge);
  558. }
  559. void ConvexHullBuilder::FindEdge(Face *inFacingFace, Vec3Arg inVertex, FullEdges &outEdges) const
  560. {
  561. // Assert that we were given an empty array
  562. JPH_ASSERT(outEdges.empty());
  563. // Should start with a facing face
  564. JPH_ASSERT(inFacingFace->IsFacing(inVertex));
  565. // Flag as removed
  566. inFacingFace->mRemoved = true;
  567. // Instead of recursing, we build our own stack with the information we need
  568. struct StackEntry
  569. {
  570. Edge * mFirstEdge;
  571. Edge * mCurrentEdge;
  572. };
  573. constexpr int cMaxEdgeLength = 128;
  574. StackEntry stack[cMaxEdgeLength];
  575. int cur_stack_pos = 0;
  576. static_assert(alignof(Edge) >= 2, "Need lowest bit to indicate to tell if we completed the loop");
  577. // Start with the face / edge provided
  578. stack[0].mFirstEdge = inFacingFace->mFirstEdge;
  579. stack[0].mCurrentEdge = reinterpret_cast<Edge *>(reinterpret_cast<uintptr_t>(inFacingFace->mFirstEdge) | 1); // Set lowest bit of pointer to make it different from the first edge
  580. for (;;)
  581. {
  582. StackEntry &cur_entry = stack[cur_stack_pos];
  583. // Next edge
  584. Edge *raw_e = cur_entry.mCurrentEdge;
  585. Edge *e = reinterpret_cast<Edge *>(reinterpret_cast<uintptr_t>(raw_e) & ~uintptr_t(1)); // Remove the lowest bit which was used to indicate that this is the first edge we're testing
  586. cur_entry.mCurrentEdge = e->mNextEdge;
  587. // If we're back at the first edge we've completed the face and we're done
  588. if (raw_e == cur_entry.mFirstEdge)
  589. {
  590. // This face needs to be removed, unlink it now, caller will free
  591. sUnlinkFace(e->mFace);
  592. // Pop from stack
  593. if (--cur_stack_pos < 0)
  594. break;
  595. }
  596. else
  597. {
  598. // Visit neighbour face
  599. Edge *ne = e->mNeighbourEdge;
  600. if (ne != nullptr)
  601. {
  602. Face *n = ne->mFace;
  603. if (!n->mRemoved)
  604. {
  605. // Check if vertex is on the front side of this face
  606. if (n->IsFacing(inVertex))
  607. {
  608. // Vertex on front, this face needs to be removed
  609. n->mRemoved = true;
  610. // Add element to the stack of elements to visit
  611. cur_stack_pos++;
  612. JPH_ASSERT(cur_stack_pos < cMaxEdgeLength);
  613. StackEntry &new_entry = stack[cur_stack_pos];
  614. new_entry.mFirstEdge = ne;
  615. new_entry.mCurrentEdge = ne->mNextEdge; // We don't need to test this edge again since we came from it
  616. }
  617. else
  618. {
  619. // Vertex behind, keep edge
  620. FullEdge full;
  621. full.mNeighbourEdge = ne;
  622. full.mStartIdx = e->mStartIdx;
  623. full.mEndIdx = ne->mStartIdx;
  624. outEdges.push_back(full);
  625. }
  626. }
  627. }
  628. }
  629. }
  630. // Assert that we have a fully connected loop
  631. #ifdef JPH_ENABLE_ASSERTS
  632. for (int i = 0; i < (int)outEdges.size(); ++i)
  633. JPH_ASSERT(outEdges[i].mEndIdx == outEdges[(i + 1) % outEdges.size()].mStartIdx);
  634. #endif
  635. #ifdef JPH_CONVEX_BUILDER_DEBUG
  636. // Draw edge of facing faces
  637. for (int i = 0; i < (int)outEdges.size(); ++i)
  638. DebugRenderer::sInstance->DrawArrow(cDrawScale * (mPositions[outEdges[i].mStartIdx] + mOffset), cDrawScale * (mPositions[outEdges[i].mEndIdx] + mOffset), Color::sWhite, 0.01f);
  639. DrawState();
  640. #endif
  641. }
  642. void ConvexHullBuilder::MergeFaces(Edge *inEdge)
  643. {
  644. // Get the face
  645. Face *face = inEdge->mFace;
  646. // Find the previous and next edge
  647. Edge *next_edge = inEdge->mNextEdge;
  648. Edge *prev_edge = inEdge->GetPreviousEdge();
  649. // Get the other face
  650. Edge *other_edge = inEdge->mNeighbourEdge;
  651. Face *other_face = other_edge->mFace;
  652. // Check if attempting to merge with self
  653. JPH_ASSERT(face != other_face);
  654. #ifdef JPH_CONVEX_BUILDER_DEBUG
  655. DrawWireFace(face, Color::sGreen);
  656. DrawWireFace(other_face, Color::sRed);
  657. DrawState();
  658. #endif
  659. // Loop over the edges of the other face and make them belong to inFace
  660. Edge *edge = other_edge->mNextEdge;
  661. prev_edge->mNextEdge = edge;
  662. for (;;)
  663. {
  664. edge->mFace = face;
  665. if (edge->mNextEdge == other_edge)
  666. {
  667. // Terminate when we are back at other_edge
  668. edge->mNextEdge = next_edge;
  669. break;
  670. }
  671. edge = edge->mNextEdge;
  672. }
  673. // If the first edge happens to be inEdge we need to fix it because this edge is no longer part of the face.
  674. // Note that we replace it with the first edge of the merged face so that if the MergeFace function is called
  675. // from a loop that loops around the face that it will still terminate after visiting all edges once.
  676. if (face->mFirstEdge == inEdge)
  677. face->mFirstEdge = prev_edge->mNextEdge;
  678. // Free the edges
  679. delete inEdge;
  680. delete other_edge;
  681. // Mark the other face as removed
  682. other_face->mFirstEdge = nullptr;
  683. other_face->mRemoved = true;
  684. // Recalculate plane
  685. face->CalculateNormalAndCentroid(mPositions.data());
  686. // Merge conflict lists
  687. if (face->mFurthestPointDistanceSq > other_face->mFurthestPointDistanceSq)
  688. {
  689. // This face has a point that's further away, make sure it remains the last one as we add the other points to this faces list
  690. face->mConflictList.insert(face->mConflictList.end() - 1, other_face->mConflictList.begin(), other_face->mConflictList.end());
  691. }
  692. else
  693. {
  694. // The other face has a point that's furthest away, add that list at the end.
  695. face->mConflictList.insert(face->mConflictList.end(), other_face->mConflictList.begin(), other_face->mConflictList.end());
  696. face->mFurthestPointDistanceSq = other_face->mFurthestPointDistanceSq;
  697. }
  698. other_face->mConflictList.clear();
  699. #ifdef JPH_CONVEX_BUILDER_DEBUG
  700. DrawWireFace(face, Color::sWhite);
  701. DrawState();
  702. #endif
  703. }
  704. void ConvexHullBuilder::MergeDegenerateFace(Face *inFace, Faces &ioAffectedFaces)
  705. {
  706. // Check area of face
  707. if (inFace->mNormal.LengthSq() < cMinTriangleAreaSq)
  708. {
  709. // Find longest edge, since this face is a sliver this should keep the face convex
  710. float max_length_sq = 0.0f;
  711. Edge *longest_edge = nullptr;
  712. Edge *e = inFace->mFirstEdge;
  713. Vec3 p1 = mPositions[e->mStartIdx];
  714. do
  715. {
  716. Edge *next = e->mNextEdge;
  717. Vec3 p2 = mPositions[next->mStartIdx];
  718. float length_sq = (p2 - p1).LengthSq();
  719. if (length_sq >= max_length_sq)
  720. {
  721. max_length_sq = length_sq;
  722. longest_edge = e;
  723. }
  724. p1 = p2;
  725. e = next;
  726. } while (e != inFace->mFirstEdge);
  727. // Merge with face on longest edge
  728. MergeFaces(longest_edge);
  729. // Remove any invalid edges
  730. RemoveInvalidEdges(inFace, ioAffectedFaces);
  731. }
  732. }
  733. void ConvexHullBuilder::MergeCoplanarOrConcaveFaces(Face *inFace, float inCoplanarToleranceSq, Faces &ioAffectedFaces)
  734. {
  735. bool merged = false;
  736. Edge *edge = inFace->mFirstEdge;
  737. do
  738. {
  739. // Store next edge since this edge can be removed
  740. Edge *next_edge = edge->mNextEdge;
  741. // Test if centroid of one face is above plane of the other face by inCoplanarToleranceSq.
  742. // If so we need to merge other face into inFace.
  743. const Face *other_face = edge->mNeighbourEdge->mFace;
  744. Vec3 delta_centroid = other_face->mCentroid - inFace->mCentroid;
  745. float dist_other_face_centroid = inFace->mNormal.Dot(delta_centroid);
  746. float signed_dist_other_face_centroid_sq = abs(dist_other_face_centroid) * dist_other_face_centroid;
  747. float dist_face_centroid = -other_face->mNormal.Dot(delta_centroid);
  748. float signed_dist_face_centroid_sq = abs(dist_face_centroid) * dist_face_centroid;
  749. float face_normal_len_sq = inFace->mNormal.LengthSq();
  750. float other_face_normal_len_sq = other_face->mNormal.LengthSq();
  751. if ((signed_dist_other_face_centroid_sq > -inCoplanarToleranceSq * face_normal_len_sq
  752. || signed_dist_face_centroid_sq > -inCoplanarToleranceSq * other_face_normal_len_sq)
  753. && inFace->mNormal.Dot(other_face->mNormal) > 0.0f) // Never merge faces that are back to back
  754. {
  755. MergeFaces(edge);
  756. merged = true;
  757. }
  758. edge = next_edge;
  759. } while (edge != inFace->mFirstEdge);
  760. if (merged)
  761. RemoveInvalidEdges(inFace, ioAffectedFaces);
  762. }
  763. void ConvexHullBuilder::sMarkAffected(Face *inFace, Faces &ioAffectedFaces)
  764. {
  765. if (find(ioAffectedFaces.begin(), ioAffectedFaces.end(), inFace) == ioAffectedFaces.end())
  766. ioAffectedFaces.push_back(inFace);
  767. }
  768. void ConvexHullBuilder::RemoveInvalidEdges(Face *inFace, Faces &ioAffectedFaces)
  769. {
  770. // This marks that the plane needs to be recalculated (we delay this until the end of the
  771. // function since we don't use the plane and we want to avoid calculating it multiple times)
  772. bool recalculate_plane = false;
  773. // We keep going through this loop until no more edges were removed
  774. bool removed;
  775. do
  776. {
  777. removed = false;
  778. // Loop over all edges in this face
  779. Edge *edge = inFace->mFirstEdge;
  780. Face *neighbour_face = edge->mNeighbourEdge->mFace;
  781. do
  782. {
  783. Edge *next_edge = edge->mNextEdge;
  784. Face *next_neighbour_face = next_edge->mNeighbourEdge->mFace;
  785. if (neighbour_face == inFace)
  786. {
  787. // We only remove 1 edge at a time, check if this edge's next edge is our neighbour.
  788. // If this check fails, we will continue to scan along the edge until we find an edge where this is the case.
  789. if (edge->mNeighbourEdge == next_edge)
  790. {
  791. // This edge leads back to the starting point, this means the edge is interior and needs to be removed
  792. #ifdef JPH_CONVEX_BUILDER_DEBUG
  793. DrawWireFace(inFace, Color::sBlue);
  794. DrawState();
  795. #endif
  796. // Remove edge
  797. Edge *prev_edge = edge->GetPreviousEdge();
  798. prev_edge->mNextEdge = next_edge->mNextEdge;
  799. if (inFace->mFirstEdge == edge || inFace->mFirstEdge == next_edge)
  800. inFace->mFirstEdge = prev_edge;
  801. delete edge;
  802. delete next_edge;
  803. #ifdef JPH_CONVEX_BUILDER_DEBUG
  804. DrawWireFace(inFace, Color::sGreen);
  805. DrawState();
  806. #endif
  807. // Check if inFace now has only 2 edges left
  808. if (RemoveTwoEdgeFace(inFace, ioAffectedFaces))
  809. return; // Bail if face no longer exists
  810. // Restart the loop
  811. recalculate_plane = true;
  812. removed = true;
  813. break;
  814. }
  815. }
  816. else if (neighbour_face == next_neighbour_face)
  817. {
  818. // There are two edges that connect to the same face, we will remove the second one
  819. #ifdef JPH_CONVEX_BUILDER_DEBUG
  820. DrawWireFace(inFace, Color::sYellow);
  821. DrawWireFace(neighbour_face, Color::sRed);
  822. DrawState();
  823. #endif
  824. // First merge the neighbours edges
  825. Edge *neighbour_edge = next_edge->mNeighbourEdge;
  826. Edge *next_neighbour_edge = neighbour_edge->mNextEdge;
  827. if (neighbour_face->mFirstEdge == next_neighbour_edge)
  828. neighbour_face->mFirstEdge = neighbour_edge;
  829. neighbour_edge->mNextEdge = next_neighbour_edge->mNextEdge;
  830. neighbour_edge->mNeighbourEdge = edge;
  831. delete next_neighbour_edge;
  832. // Then merge my own edges
  833. if (inFace->mFirstEdge == next_edge)
  834. inFace->mFirstEdge = edge;
  835. edge->mNextEdge = next_edge->mNextEdge;
  836. edge->mNeighbourEdge = neighbour_edge;
  837. delete next_edge;
  838. #ifdef JPH_CONVEX_BUILDER_DEBUG
  839. DrawWireFace(inFace, Color::sYellow);
  840. DrawWireFace(neighbour_face, Color::sGreen);
  841. DrawState();
  842. #endif
  843. // Check if neighbour has only 2 edges left
  844. if (!RemoveTwoEdgeFace(neighbour_face, ioAffectedFaces))
  845. {
  846. // No, we need to recalculate its plane
  847. neighbour_face->CalculateNormalAndCentroid(mPositions.data());
  848. // Mark neighbour face as affected
  849. sMarkAffected(neighbour_face, ioAffectedFaces);
  850. }
  851. // Check if inFace now has only 2 edges left
  852. if (RemoveTwoEdgeFace(inFace, ioAffectedFaces))
  853. return; // Bail if face no longer exists
  854. // Restart loop
  855. recalculate_plane = true;
  856. removed = true;
  857. break;
  858. }
  859. // This edge is ok, go to the next edge
  860. edge = next_edge;
  861. neighbour_face = next_neighbour_face;
  862. } while (edge != inFace->mFirstEdge);
  863. } while (removed);
  864. // Recalculate plane?
  865. if (recalculate_plane)
  866. inFace->CalculateNormalAndCentroid(mPositions.data());
  867. }
  868. bool ConvexHullBuilder::RemoveTwoEdgeFace(Face *inFace, Faces &ioAffectedFaces) const
  869. {
  870. // Check if this face contains only 2 edges
  871. Edge *edge = inFace->mFirstEdge;
  872. Edge *next_edge = edge->mNextEdge;
  873. JPH_ASSERT(edge != next_edge); // 1 edge faces should not exist
  874. if (next_edge->mNextEdge == edge)
  875. {
  876. #ifdef JPH_CONVEX_BUILDER_DEBUG
  877. DrawWireFace(inFace, Color::sRed);
  878. DrawState();
  879. #endif
  880. // Schedule both neighbours for re-checking
  881. Edge *neighbour_edge = edge->mNeighbourEdge;
  882. Face *neighbour_face = neighbour_edge->mFace;
  883. Edge *next_neighbour_edge = next_edge->mNeighbourEdge;
  884. Face *next_neighbour_face = next_neighbour_edge->mFace;
  885. sMarkAffected(neighbour_face, ioAffectedFaces);
  886. sMarkAffected(next_neighbour_face, ioAffectedFaces);
  887. // Link my neighbours to each other
  888. neighbour_edge->mNeighbourEdge = next_neighbour_edge;
  889. next_neighbour_edge->mNeighbourEdge = neighbour_edge;
  890. // Unlink my edges
  891. edge->mNeighbourEdge = nullptr;
  892. next_edge->mNeighbourEdge = nullptr;
  893. // Mark this face as removed
  894. inFace->mRemoved = true;
  895. return true;
  896. }
  897. return false;
  898. }
  899. #ifdef JPH_ENABLE_ASSERTS
  900. void ConvexHullBuilder::DumpFace(const Face *inFace) const
  901. {
  902. Trace("f:0x%p", inFace);
  903. const Edge *e = inFace->mFirstEdge;
  904. do
  905. {
  906. Trace("\te:0x%p { i:%d e:0x%p f:0x%p }", e, e->mStartIdx, e->mNeighbourEdge, e->mNeighbourEdge->mFace);
  907. e = e->mNextEdge;
  908. } while (e != inFace->mFirstEdge);
  909. }
  910. void ConvexHullBuilder::DumpFaces() const
  911. {
  912. Trace("Dump Faces:");
  913. for (const Face *f : mFaces)
  914. if (!f->mRemoved)
  915. DumpFace(f);
  916. }
  917. void ConvexHullBuilder::ValidateFace(const Face *inFace) const
  918. {
  919. if (inFace->mRemoved)
  920. {
  921. const Edge *e = inFace->mFirstEdge;
  922. if (e != nullptr)
  923. do
  924. {
  925. JPH_ASSERT(e->mNeighbourEdge == nullptr);
  926. e = e->mNextEdge;
  927. } while (e != inFace->mFirstEdge);
  928. }
  929. else
  930. {
  931. int edge_count = 0;
  932. const Edge *e = inFace->mFirstEdge;
  933. do
  934. {
  935. // Count edge
  936. ++edge_count;
  937. // Validate that adjacent faces are all different
  938. if (mFaces.size() > 2)
  939. for (const Edge *other_edge = e->mNextEdge; other_edge != inFace->mFirstEdge; other_edge = other_edge->mNextEdge)
  940. JPH_ASSERT(e->mNeighbourEdge->mFace != other_edge->mNeighbourEdge->mFace);
  941. // Assert that the face is correct
  942. JPH_ASSERT(e->mFace == inFace);
  943. // Assert that we have a neighbour
  944. const Edge *nb_edge = e->mNeighbourEdge;
  945. JPH_ASSERT(nb_edge != nullptr);
  946. if (nb_edge != nullptr)
  947. {
  948. // Assert that our neighbours edge points to us
  949. JPH_ASSERT(nb_edge->mNeighbourEdge == e);
  950. // Assert that it belongs to a different face
  951. JPH_ASSERT(nb_edge->mFace != inFace);
  952. // Assert that the next edge of the neighbour points to the same vertex as this edge's vertex
  953. JPH_ASSERT(nb_edge->mNextEdge->mStartIdx == e->mStartIdx);
  954. // Assert that my next edge points to the same vertex as my neighbours vertex
  955. JPH_ASSERT(e->mNextEdge->mStartIdx == nb_edge->mStartIdx);
  956. }
  957. e = e->mNextEdge;
  958. } while (e != inFace->mFirstEdge);
  959. // Assert that we have 3 or more edges
  960. JPH_ASSERT(edge_count >= 3);
  961. }
  962. }
  963. void ConvexHullBuilder::ValidateFaces() const
  964. {
  965. for (const Face *f : mFaces)
  966. ValidateFace(f);
  967. }
  968. #endif // JPH_ENABLE_ASSERTS
  969. void ConvexHullBuilder::GetCenterOfMassAndVolume(Vec3 &outCenterOfMass, float &outVolume) const
  970. {
  971. // Fourth point is the average of all face centroids
  972. Vec3 v4 = Vec3::sZero();
  973. for (const Face *f : mFaces)
  974. v4 += f->mCentroid;
  975. v4 /= float(mFaces.size());
  976. // Calculate mass and center of mass of this convex hull by summing all tetrahedrons
  977. outVolume = 0.0f;
  978. outCenterOfMass = Vec3::sZero();
  979. for (const Face *f : mFaces)
  980. {
  981. // Get the first vertex that we'll use to create a triangle fan
  982. Edge *e = f->mFirstEdge;
  983. Vec3 v1 = mPositions[e->mStartIdx];
  984. // Get the second vertex
  985. e = e->mNextEdge;
  986. Vec3 v2 = mPositions[e->mStartIdx];
  987. for (e = e->mNextEdge; e != f->mFirstEdge; e = e->mNextEdge)
  988. {
  989. // Fetch the last point of the triangle
  990. Vec3 v3 = mPositions[e->mStartIdx];
  991. // Calculate center of mass and mass of this tetrahedron,
  992. // see: https://en.wikipedia.org/wiki/Tetrahedron#Volume
  993. float volume_tetrahedron = (v1 - v4).Dot((v2 - v4).Cross(v3 - v4)); // Needs to be divided by 6, postpone this until the end of the loop
  994. Vec3 center_of_mass_tetrahedron = v1 + v2 + v3 + v4; // Needs to be divided by 4, postpone this until the end of the loop
  995. // Accumulate results
  996. outVolume += volume_tetrahedron;
  997. outCenterOfMass += volume_tetrahedron * center_of_mass_tetrahedron;
  998. // Update v2 for next triangle
  999. v2 = v3;
  1000. } while (e != f->mFirstEdge);
  1001. }
  1002. // Calculate center of mass, fall back to average point in case there is no volume (everything is on a plane in this case)
  1003. if (outVolume > FLT_EPSILON)
  1004. outCenterOfMass /= 4.0f * outVolume;
  1005. else
  1006. outCenterOfMass = v4;
  1007. outVolume /= 6.0f;
  1008. }
  1009. void ConvexHullBuilder::DetermineMaxError(Face *&outFaceWithMaxError, float &outMaxError, int &outMaxErrorPositionIdx, float &outCoplanarDistance) const
  1010. {
  1011. outCoplanarDistance = DetermineCoplanarDistance();
  1012. // This measures the distance from a polygon to the furthest point outside of the hull
  1013. float max_error = 0.0f;
  1014. Face *max_error_face = nullptr;
  1015. int max_error_point = -1;
  1016. for (int i = 0; i < (int)mPositions.size(); ++i)
  1017. {
  1018. Vec3 v = mPositions[i];
  1019. // This measures the closest edge from all faces to point v
  1020. // Note that we take the min of all faces since there may be multiple near coplanar faces so if we were to test this per face
  1021. // we may find that a point is outside of a polygon and mark it as an error, while it is actually inside a nearly coplanar
  1022. // polygon.
  1023. float min_edge_dist = FLT_MAX;
  1024. Face *min_edge_dist_face = nullptr;
  1025. for (Face *f : mFaces)
  1026. {
  1027. // Check if point is on or in front of plane
  1028. float normal_len = f->mNormal.Length();
  1029. JPH_ASSERT(normal_len > 0.0f);
  1030. float plane_dist = f->mNormal.Dot(v - f->mCentroid) / normal_len;
  1031. if (plane_dist > -outCoplanarDistance)
  1032. {
  1033. bool all_inside = true;
  1034. // Test if it is inside the edges of the polygon
  1035. Edge *edge = f->mFirstEdge;
  1036. Vec3 p1 = mPositions[edge->GetPreviousEdge()->mStartIdx];
  1037. do
  1038. {
  1039. Vec3 p2 = mPositions[edge->mStartIdx];
  1040. if ((p2 - p1).Cross(v - p1).Dot(f->mNormal) < 0.0f)
  1041. {
  1042. // It is outside
  1043. all_inside = false;
  1044. // Measure distance to this edge
  1045. uint32 s;
  1046. float edge_dist = ClosestPoint::GetClosestPointOnLine(p1 - v, p2 - v, s).Length();
  1047. if (edge_dist < min_edge_dist)
  1048. {
  1049. min_edge_dist = edge_dist;
  1050. min_edge_dist_face = f;
  1051. }
  1052. }
  1053. p1 = p2;
  1054. edge = edge->mNextEdge;
  1055. } while (edge != f->mFirstEdge);
  1056. if (all_inside)
  1057. {
  1058. // The point is inside the polygon, reset distance to edge
  1059. min_edge_dist = 0.0f;
  1060. min_edge_dist_face = f;
  1061. // If the point is in front of the plane, measure the distance
  1062. if (plane_dist > max_error)
  1063. {
  1064. max_error = plane_dist;
  1065. max_error_face = f;
  1066. max_error_point = i;
  1067. }
  1068. }
  1069. }
  1070. }
  1071. // If the minimum distance to an edge is further than our current max error, we use that as max error
  1072. if (min_edge_dist_face != nullptr && min_edge_dist > max_error)
  1073. {
  1074. max_error = min_edge_dist;
  1075. max_error_face = min_edge_dist_face;
  1076. max_error_point = i;
  1077. }
  1078. }
  1079. outFaceWithMaxError = max_error_face;
  1080. outMaxError = max_error;
  1081. outMaxErrorPositionIdx = max_error_point;
  1082. }
  1083. #ifdef JPH_CONVEX_BUILDER_DEBUG
  1084. void ConvexHullBuilder::DrawState(bool inDrawConflictList) const
  1085. {
  1086. // Draw origin
  1087. DebugRenderer::sInstance->DrawMarker(cDrawScale * mOffset, Color::sRed, 0.2f);
  1088. int face_idx = 0;
  1089. // Draw faces
  1090. for (const Face *f : mFaces)
  1091. if (!f->mRemoved)
  1092. {
  1093. Color iteration_color = Color::sGetDistinctColor(f->mIteration);
  1094. Color face_color = Color::sGetDistinctColor(face_idx++);
  1095. // First point
  1096. const Edge *e = f->mFirstEdge;
  1097. Vec3 p1 = cDrawScale * (mPositions[e->mStartIdx] + mOffset);
  1098. // Second point
  1099. e = e->mNextEdge;
  1100. Vec3 p2 = cDrawScale * (mPositions[e->mStartIdx] + mOffset);
  1101. // First line
  1102. DebugRenderer::sInstance->DrawLine(p1, p2, Color::sGrey);
  1103. do
  1104. {
  1105. // Third point
  1106. e = e->mNextEdge;
  1107. Vec3 p3 = cDrawScale * (mPositions[e->mStartIdx] + mOffset);
  1108. DebugRenderer::sInstance->DrawTriangle(p1, p2, p3, iteration_color);
  1109. DebugRenderer::sInstance->DrawLine(p2, p3, Color::sGrey);
  1110. p2 = p3;
  1111. }
  1112. while (e != f->mFirstEdge);
  1113. // Draw normal
  1114. Vec3 centroid = cDrawScale * (f->mCentroid + mOffset);
  1115. DebugRenderer::sInstance->DrawArrow(centroid, centroid + f->mNormal.Normalized(), face_color, 0.01f);
  1116. // Draw conflict list
  1117. if (inDrawConflictList)
  1118. for (int idx : f->mConflictList)
  1119. DebugRenderer::sInstance->DrawMarker(cDrawScale * (mOffset + mPositions[idx]), face_color, 0.05f);
  1120. }
  1121. // Offset to the right
  1122. mOffset += mDelta;
  1123. }
  1124. void ConvexHullBuilder::DrawWireFace(const Face *inFace, ColorArg inColor) const
  1125. {
  1126. const Edge *e = inFace->mFirstEdge;
  1127. Vec3 prev = cDrawScale * (mPositions[e->mStartIdx] + mOffset);
  1128. do
  1129. {
  1130. const Edge *next = e->mNextEdge;
  1131. Vec3 cur = cDrawScale * (mPositions[next->mStartIdx] + mOffset);
  1132. DebugRenderer::sInstance->DrawArrow(prev, cur, inColor, 0.01f);
  1133. DebugRenderer::sInstance->DrawText3D(prev, ConvertToString(e->mStartIdx), inColor);
  1134. e = next;
  1135. prev = cur;
  1136. } while (e != inFace->mFirstEdge);
  1137. }
  1138. void ConvexHullBuilder::DrawEdge(const Edge *inEdge, ColorArg inColor) const
  1139. {
  1140. Vec3 p1 = cDrawScale * (mPositions[inEdge->mStartIdx] + mOffset);
  1141. Vec3 p2 = cDrawScale * (mPositions[inEdge->mNextEdge->mStartIdx] + mOffset);
  1142. DebugRenderer::sInstance->DrawArrow(p1, p2, inColor, 0.01f);
  1143. }
  1144. #endif // JPH_CONVEX_BUILDER_DEBUG
  1145. #ifdef JPH_CONVEX_BUILDER_DUMP_SHAPE
  1146. void ConvexHullBuilder::DumpShape() const
  1147. {
  1148. static atomic<int> sShapeNo = 1;
  1149. int shape_no = sShapeNo++;
  1150. ofstream f;
  1151. f.open(StringFormat("dumped_shape%d.cpp", shape_no).c_str(), ofstream::out | ofstream::trunc);
  1152. if (!f.is_open())
  1153. return;
  1154. f << "{\n";
  1155. for (Vec3 v : mPositions)
  1156. f << StringFormat("\tVec3(%.9gf, %.9gf, %.9gf),\n", v.GetX(), v.GetY(), v.GetZ());
  1157. f << "},\n";
  1158. }
  1159. #endif // JPH_CONVEX_BUILDER_DUMP_SHAPE
  1160. JPH_NAMESPACE_END