IntrAlignedBox3Cone3.h 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/AlignedBox.h>
  9. #include <Mathematics/Cone.h>
  10. #include <Mathematics/IntrRay3AlignedBox3.h>
  11. #include <Mathematics/IntrSegment3AlignedBox3.h>
  12. // Test for intersection of a box and a cone. The cone can be infinite
  13. // 0 <= minHeight < maxHeight = std::numeric_limits<Real>::max()
  14. // or finite (cone frustum)
  15. // 0 <= minHeight < maxHeight < std::numeric_limits<Real>::max().
  16. // The algorithm is described in
  17. // https://www.geometrictools.com/Documentation/IntersectionBoxCone.pdf
  18. // and reports an intersection only when the intersection set has positive
  19. // volume. For example, let the box be outside the cone. If the box is
  20. // below the minHeight plane at the cone vertex and just touches the cone
  21. // vertex, no intersection is reported. If the box is above the maxHeight
  22. // plane and just touches the disk capping the cone, either at a single
  23. // point, a line segment of points or a polygon of points, no intersection
  24. // is reported.
  25. // TODO: These queries were designed when an infinite cone was defined
  26. // by choosing maxHeight of std::numeric_limits<Real>::max(). The Cone<N,Real>
  27. // class has been redesigned not to use std::numeric_limits to allow for
  28. // arithmetic systems that do not have representations for infinities
  29. // (such as BSNumber and BSRational). The intersection queries need to be
  30. // rewritten for the new class design. FOR NOW, the queries will work with
  31. // float/double when you create a cone using the cone-frustum constructor
  32. // Cone(ray, angle, minHeight, std::numeric_limits<Real>::max()).
  33. namespace WwiseGTE
  34. {
  35. template <typename Real>
  36. class TIQuery<Real, AlignedBox<3, Real>, Cone<3, Real>>
  37. {
  38. public:
  39. struct Result
  40. {
  41. bool intersect;
  42. };
  43. TIQuery()
  44. :
  45. mNumCandidateEdges(0)
  46. {
  47. // An edge is { v0, v1 }, where v0 and v1 are relative to mVertices
  48. // with v0 < v1.
  49. mEdges[0] = { 0, 1 };
  50. mEdges[1] = { 1, 3 };
  51. mEdges[2] = { 2, 3 };
  52. mEdges[3] = { 0, 2 };
  53. mEdges[4] = { 4, 5 };
  54. mEdges[5] = { 5, 7 };
  55. mEdges[6] = { 6, 7 };
  56. mEdges[7] = { 4, 6 };
  57. mEdges[8] = { 0, 4 };
  58. mEdges[9] = { 1, 5 };
  59. mEdges[10] = { 3, 7 };
  60. mEdges[11] = { 2, 6 };
  61. // A face is { { v0, v1, v2, v3 }, { e0, e1, e2, e3 } }, where
  62. // { v0, v1, v2, v3 } are relative to mVertices with
  63. // v0 = min(v0,v1,v2,v3) and where { e0, e1, e2, e3 } are relative
  64. // to mEdges. For example, mFaces[0] has vertices { 0, 4, 6, 2 }.
  65. // The edge { 0, 4 } is mEdges[8], the edge { 4, 6 } is mEdges[7],
  66. // the edge { 6, 2 } is mEdges[11] and the edge { 2, 0 } is
  67. // mEdges[3]; thus, the edge indices are { 8, 7, 11, 3 }.
  68. mFaces[0] = { { 0, 4, 6, 2 }, { 8, 7, 11, 3 } };
  69. mFaces[1] = { { 1, 3, 7, 5 }, { 1, 10, 5, 9 } };
  70. mFaces[2] = { { 0, 1, 5, 4 }, { 0, 9, 4, 8 } };
  71. mFaces[3] = { { 2, 6, 7, 3 }, { 11, 6, 10, 2 } };
  72. mFaces[4] = { { 0, 2, 3, 1 }, { 3, 2, 1, 0 } };
  73. mFaces[5] = { { 4, 5, 7, 6 }, { 4, 5, 6, 7 } };
  74. // Clear the edges.
  75. std::array<size_t, 2> ezero = { 0, 0 };
  76. mCandidateEdges.fill(ezero);
  77. for (size_t r = 0; r < MAX_VERTICES; ++r)
  78. {
  79. mAdjacencyMatrix[r].fill(0);
  80. }
  81. mConfiguration[0] = &TIQuery::NNNN_0;
  82. mConfiguration[1] = &TIQuery::NNNZ_1;
  83. mConfiguration[2] = &TIQuery::NNNP_2;
  84. mConfiguration[3] = &TIQuery::NNZN_3;
  85. mConfiguration[4] = &TIQuery::NNZZ_4;
  86. mConfiguration[5] = &TIQuery::NNZP_5;
  87. mConfiguration[6] = &TIQuery::NNPN_6;
  88. mConfiguration[7] = &TIQuery::NNPZ_7;
  89. mConfiguration[8] = &TIQuery::NNPP_8;
  90. mConfiguration[9] = &TIQuery::NZNN_9;
  91. mConfiguration[10] = &TIQuery::NZNZ_10;
  92. mConfiguration[11] = &TIQuery::NZNP_11;
  93. mConfiguration[12] = &TIQuery::NZZN_12;
  94. mConfiguration[13] = &TIQuery::NZZZ_13;
  95. mConfiguration[14] = &TIQuery::NZZP_14;
  96. mConfiguration[15] = &TIQuery::NZPN_15;
  97. mConfiguration[16] = &TIQuery::NZPZ_16;
  98. mConfiguration[17] = &TIQuery::NZPP_17;
  99. mConfiguration[18] = &TIQuery::NPNN_18;
  100. mConfiguration[19] = &TIQuery::NPNZ_19;
  101. mConfiguration[20] = &TIQuery::NPNP_20;
  102. mConfiguration[21] = &TIQuery::NPZN_21;
  103. mConfiguration[22] = &TIQuery::NPZZ_22;
  104. mConfiguration[23] = &TIQuery::NPZP_23;
  105. mConfiguration[24] = &TIQuery::NPPN_24;
  106. mConfiguration[25] = &TIQuery::NPPZ_25;
  107. mConfiguration[26] = &TIQuery::NPPP_26;
  108. mConfiguration[27] = &TIQuery::ZNNN_27;
  109. mConfiguration[28] = &TIQuery::ZNNZ_28;
  110. mConfiguration[29] = &TIQuery::ZNNP_29;
  111. mConfiguration[30] = &TIQuery::ZNZN_30;
  112. mConfiguration[31] = &TIQuery::ZNZZ_31;
  113. mConfiguration[32] = &TIQuery::ZNZP_32;
  114. mConfiguration[33] = &TIQuery::ZNPN_33;
  115. mConfiguration[34] = &TIQuery::ZNPZ_34;
  116. mConfiguration[35] = &TIQuery::ZNPP_35;
  117. mConfiguration[36] = &TIQuery::ZZNN_36;
  118. mConfiguration[37] = &TIQuery::ZZNZ_37;
  119. mConfiguration[38] = &TIQuery::ZZNP_38;
  120. mConfiguration[39] = &TIQuery::ZZZN_39;
  121. mConfiguration[40] = &TIQuery::ZZZZ_40;
  122. mConfiguration[41] = &TIQuery::ZZZP_41;
  123. mConfiguration[42] = &TIQuery::ZZPN_42;
  124. mConfiguration[43] = &TIQuery::ZZPZ_43;
  125. mConfiguration[44] = &TIQuery::ZZPP_44;
  126. mConfiguration[45] = &TIQuery::ZPNN_45;
  127. mConfiguration[46] = &TIQuery::ZPNZ_46;
  128. mConfiguration[47] = &TIQuery::ZPNP_47;
  129. mConfiguration[48] = &TIQuery::ZPZN_48;
  130. mConfiguration[49] = &TIQuery::ZPZZ_49;
  131. mConfiguration[50] = &TIQuery::ZPZP_50;
  132. mConfiguration[51] = &TIQuery::ZPPN_51;
  133. mConfiguration[52] = &TIQuery::ZPPZ_52;
  134. mConfiguration[53] = &TIQuery::ZPPP_53;
  135. mConfiguration[54] = &TIQuery::PNNN_54;
  136. mConfiguration[55] = &TIQuery::PNNZ_55;
  137. mConfiguration[56] = &TIQuery::PNNP_56;
  138. mConfiguration[57] = &TIQuery::PNZN_57;
  139. mConfiguration[58] = &TIQuery::PNZZ_58;
  140. mConfiguration[59] = &TIQuery::PNZP_59;
  141. mConfiguration[60] = &TIQuery::PNPN_60;
  142. mConfiguration[61] = &TIQuery::PNPZ_61;
  143. mConfiguration[62] = &TIQuery::PNPP_62;
  144. mConfiguration[63] = &TIQuery::PZNN_63;
  145. mConfiguration[64] = &TIQuery::PZNZ_64;
  146. mConfiguration[65] = &TIQuery::PZNP_65;
  147. mConfiguration[66] = &TIQuery::PZZN_66;
  148. mConfiguration[67] = &TIQuery::PZZZ_67;
  149. mConfiguration[68] = &TIQuery::PZZP_68;
  150. mConfiguration[69] = &TIQuery::PZPN_69;
  151. mConfiguration[70] = &TIQuery::PZPZ_70;
  152. mConfiguration[71] = &TIQuery::PZPP_71;
  153. mConfiguration[72] = &TIQuery::PPNN_72;
  154. mConfiguration[73] = &TIQuery::PPNZ_73;
  155. mConfiguration[74] = &TIQuery::PPNP_74;
  156. mConfiguration[75] = &TIQuery::PPZN_75;
  157. mConfiguration[76] = &TIQuery::PPZZ_76;
  158. mConfiguration[77] = &TIQuery::PPZP_77;
  159. mConfiguration[78] = &TIQuery::PPPN_78;
  160. mConfiguration[79] = &TIQuery::PPPZ_79;
  161. mConfiguration[80] = &TIQuery::PPPP_80;
  162. }
  163. Result operator()(AlignedBox<3, Real> const& box, Cone<3, Real> const& cone)
  164. {
  165. Result result;
  166. // Quick-rejectance test. Determine whether the box is outside
  167. // the slab bounded by the minimum and maximum height planes.
  168. // When outside the slab, the box vertices are not required by the
  169. // cone-box intersection query, so the vertices are not yet
  170. // computed.
  171. Real boxMinHeight(0), boxMaxHeight(0);
  172. ComputeBoxHeightInterval(box, cone, boxMinHeight, boxMaxHeight);
  173. // TODO: See the comments at the beginning of this file.
  174. Real coneMaxHeight = (cone.IsFinite() ? cone.GetMaxHeight() : std::numeric_limits<Real>::max());
  175. if (boxMaxHeight <= cone.GetMinHeight() || boxMinHeight >= coneMaxHeight)
  176. {
  177. // There is no volumetric overlap of the box and the cone. The
  178. // box is clipped entirely.
  179. result.intersect = false;
  180. return result;
  181. }
  182. // Quick-acceptance test. Determine whether the cone axis
  183. // intersects the box.
  184. if (ConeAxisIntersectsBox(box, cone))
  185. {
  186. result.intersect = true;
  187. return result;
  188. }
  189. // Test for box fully inside the slab. When inside the slab, the
  190. // box vertices are required by the cone-box intersection query,
  191. // so they are computed here; they are also required in the
  192. // remaining cases. Also when inside the slab, the box edges are
  193. // the candidates, so they are copied to mCandidateEdges.
  194. if (BoxFullyInConeSlab(box, boxMinHeight, boxMaxHeight, cone))
  195. {
  196. result.intersect = CandidatesHavePointInsideCone(cone);
  197. return result;
  198. }
  199. // Clear the candidates array and adjacency matrix.
  200. ClearCandidates();
  201. // The box intersects at least one plane. Compute the box-plane
  202. // edge-interior intersection points. Insert the box subedges into
  203. // the array of candidate edges.
  204. ComputeCandidatesOnBoxEdges(cone);
  205. // Insert any relevant box face-interior clipped edges into the array
  206. // of candidate edges.
  207. ComputeCandidatesOnBoxFaces();
  208. result.intersect = CandidatesHavePointInsideCone(cone);
  209. return result;
  210. }
  211. protected:
  212. // The constants here are described in the comments below.
  213. enum
  214. {
  215. NUM_BOX_VERTICES = 8,
  216. NUM_BOX_EDGES = 12,
  217. NUM_BOX_FACES = 6,
  218. MAX_VERTICES = 32,
  219. VERTEX_MIN_BASE = 8,
  220. VERTEX_MAX_BASE = 20,
  221. MAX_CANDIDATE_EDGES = 496,
  222. NUM_CONFIGURATIONS = 81
  223. };
  224. // The box topology is that of a cube whose vertices have components
  225. // in {0,1}. The cube vertices are indexed by
  226. // 0: (0,0,0), 1: (1,0,0), 2: (1,1,0), 3: (0,1,0)
  227. // 4: (0,0,1), 5: (1,0,1), 6: (1,1,1), 7: (0,1,1)
  228. // The first 8 vertices are the box corners, the next 12 vertices are
  229. // reserved for hmin-edge points and the final 12 vertices are reserved
  230. // for the hmax-edge points. The conservative upper bound of the number
  231. // of vertices is 8 + 12 + 12 = 32.
  232. std::array<Vector3<Real>, MAX_VERTICES> mVertices;
  233. // The box has 12 edges stored in mEdges. An edge is mEdges[i] =
  234. // { v0, v1 }, where the indices v0 and v1 are relative to mVertices
  235. // with v0 < v1.
  236. std::array<std::array<size_t, 2>, NUM_BOX_EDGES> mEdges;
  237. // The box has 6 faces stored in mFaces. A face is mFaces[i] =
  238. // { { v0, v1, v2, v3 }, { e0, e1, e2, e3 } }, where the face corner
  239. // vertices are { v0, v1, v2, v3 }. These indices are relative to
  240. // mVertices. The indices { e0, e1, e2, e3 } are relative to mEdges.
  241. // The index e0 refers to edge { v0, v1 }, the index e1 refers to edge
  242. // { v1, v2 }, the index e2 refers to edge { v2, v3 } and the index e3
  243. // refers to edge { v3, v0 }. The ordering of vertices for the faces
  244. // is/ counterclockwise when viewed from outside the box. The choice
  245. // of initial vertex affects how you implement the graph data
  246. // structure. In this implementation, the initial vertex has minimum
  247. // index for all vertices of that face. The faces themselves are
  248. // listed as -x face, +x face, -y face, +y face, -z face and +z face.
  249. struct Face
  250. {
  251. std::array<size_t, 4> v, e;
  252. };
  253. std::array<Face, NUM_BOX_FACES> mFaces;
  254. // Store the signed distances from the minimum and maximum height
  255. // planes for the cone to the projection of the box vertices onto the
  256. // cone axis.
  257. std::array<Real, NUM_BOX_VERTICES> mProjectionMin, mProjectionMax;
  258. // The mCandidateEdges array stores the edges of the clipped box that
  259. // are candidates for containing the optimizing point. The maximum
  260. // number of candidate edges is 1 + 2 + ... + 31 = 496, which is a
  261. // conservative bound because not all pairs of vertices form edges on
  262. // box faces. The candidate edges are stored as (v0,v1) with v0 < v1.
  263. // The implementation is designed so that during a single query, the
  264. // number of candidate edges can only grow.
  265. size_t mNumCandidateEdges;
  266. std::array<std::array<size_t, 2>, MAX_CANDIDATE_EDGES> mCandidateEdges;
  267. // The mAdjancencyMatrix is a simple representation of edges in the
  268. // graph G = (V,E) that represents the (wireframe) clipped box. An
  269. // edge (r,c) does not exist when mAdjancencyMatrix[r][c] = 0. If an
  270. // edge (r,c) does exist, it is appended to mCandidateEdges at index k
  271. // and the adjacency matrix is set to mAdjacencyMatrix[r][c] = 1.
  272. // This allows for a fast edge-in-graph test and a fast and efficient
  273. // clear of mCandidateEdges and mAdjacencyMatrix.
  274. std::array<std::array<size_t, MAX_VERTICES>, MAX_VERTICES> mAdjacencyMatrix;
  275. typedef void (TIQuery::* ConfigurationFunction)(size_t, Face const&);
  276. std::array<ConfigurationFunction, NUM_CONFIGURATIONS> mConfiguration;
  277. static void ComputeBoxHeightInterval(AlignedBox<3, Real> const& box, Cone<3, Real> const& cone,
  278. Real& boxMinHeight, Real& boxMaxHeight)
  279. {
  280. Vector<3, Real> C, e;
  281. box.GetCenteredForm(C, e);
  282. Vector<3, Real> const& V = cone.ray.origin;
  283. Vector<3, Real> const& U = cone.ray.direction;
  284. Vector<3, Real> CmV = C - V;
  285. Real DdCmV = Dot(U, CmV);
  286. Real radius = e[0] * std::abs(U[0]) + e[1] * std::abs(U[1]) + e[2] * std::abs(U[2]);
  287. boxMinHeight = DdCmV - radius;
  288. boxMaxHeight = DdCmV + radius;
  289. }
  290. static bool ConeAxisIntersectsBox(AlignedBox<3, Real> const& box, Cone<3, Real> const& cone)
  291. {
  292. if (cone.IsFinite())
  293. {
  294. Segment<3, Real> segment;
  295. segment.p[0] = cone.ray.origin + cone.GetMinHeight() * cone.ray.direction;
  296. segment.p[1] = cone.ray.origin + cone.GetMaxHeight() * cone.ray.direction;
  297. auto sbResult = TIQuery<Real, Segment<3, Real>, AlignedBox<3, Real>>()(segment, box);
  298. if (sbResult.intersect)
  299. {
  300. return true;
  301. }
  302. }
  303. else
  304. {
  305. Ray<3, Real> ray;
  306. ray.origin = cone.ray.origin + cone.GetMinHeight() * cone.ray.direction;
  307. ray.direction = cone.ray.direction;
  308. auto rbResult = TIQuery<Real, Ray<3, Real>, AlignedBox<3, Real>>()(ray, box);
  309. if (rbResult.intersect)
  310. {
  311. return true;
  312. }
  313. }
  314. return false;
  315. }
  316. bool BoxFullyInConeSlab(AlignedBox<3, Real> const& box, Real boxMinHeight, Real boxMaxHeight, Cone<3, Real> const& cone)
  317. {
  318. // Compute the box vertices relative to cone vertex as origin.
  319. mVertices[0] = { box.min[0], box.min[1], box.min[2] };
  320. mVertices[1] = { box.max[0], box.min[1], box.min[2] };
  321. mVertices[2] = { box.min[0], box.max[1], box.min[2] };
  322. mVertices[3] = { box.max[0], box.max[1], box.min[2] };
  323. mVertices[4] = { box.min[0], box.min[1], box.max[2] };
  324. mVertices[5] = { box.max[0], box.min[1], box.max[2] };
  325. mVertices[6] = { box.min[0], box.max[1], box.max[2] };
  326. mVertices[7] = { box.max[0], box.max[1], box.max[2] };
  327. for (int i = 0; i < NUM_BOX_VERTICES; ++i)
  328. {
  329. mVertices[i] -= cone.ray.origin;
  330. }
  331. Real coneMaxHeight = (cone.IsFinite() ? cone.GetMaxHeight() : std::numeric_limits<Real>::max());
  332. if (cone.GetMinHeight() <= boxMinHeight && boxMaxHeight <= coneMaxHeight)
  333. {
  334. // The box is fully inside, so no clipping is necessary.
  335. std::copy(mEdges.begin(), mEdges.end(), mCandidateEdges.begin());
  336. mNumCandidateEdges = 12;
  337. return true;
  338. }
  339. return false;
  340. }
  341. static bool HasPointInsideCone(Vector<3, Real> const& P0, Vector<3, Real> const& P1,
  342. Cone<3, Real> const& cone)
  343. {
  344. // Define F(X) = Dot(U,X - V)/|X - V|, where U is the unit-length
  345. // cone axis direction and V is the cone vertex. The incoming
  346. // points P0 and P1 are relative to V; that is, the original
  347. // points are X0 = P0 + V and X1 = P1 + V. The segment <P0,P1>
  348. // and cone intersect when a segment point X is inside the cone;
  349. // that is, when F(X) > cosAngle. The comparison is converted to
  350. // an equivalent one that does not involve divisions in order to
  351. // avoid a division by zero if a vertex or edge contain (0,0,0).
  352. // The function is G(X) = Dot(U,X-V) - cosAngle*Length(X-V).
  353. Vector<3, Real> const& U = cone.ray.direction;
  354. // Test whether P0 or P1 is inside the cone.
  355. Real g = Dot(U, P0) - cone.cosAngle * Length(P0);
  356. if (g > (Real)0)
  357. {
  358. // X0 = P0 + V is inside the cone.
  359. return true;
  360. }
  361. g = Dot(U, P1) - cone.cosAngle * Length(P1);
  362. if (g > (Real)0)
  363. {
  364. // X1 = P1 + V is inside the cone.
  365. return true;
  366. }
  367. // Test whether an interior segment point is inside the cone.
  368. Vector<3, Real> E = P1 - P0;
  369. Vector<3, Real> crossP0U = Cross(P0, U);
  370. Vector<3, Real> crossP0E = Cross(P0, E);
  371. Real dphi0 = Dot(crossP0E, crossP0U);
  372. if (dphi0 > (Real)0)
  373. {
  374. Vector3<Real> crossP1U = Cross(P1, U);
  375. Real dphi1 = Dot(crossP0E, crossP1U);
  376. if (dphi1 < (Real)0)
  377. {
  378. Real t = dphi0 / (dphi0 - dphi1);
  379. Vector<3, Real> PMax = P0 + t * E;
  380. g = Dot(U, PMax) - cone.cosAngle * Length(PMax);
  381. if (g > (Real)0)
  382. {
  383. // The edge point XMax = Pmax + V is inside the cone.
  384. return true;
  385. }
  386. }
  387. }
  388. return false;
  389. }
  390. bool CandidatesHavePointInsideCone(Cone<3, Real> const& cone) const
  391. {
  392. for (size_t i = 0; i < mNumCandidateEdges; ++i)
  393. {
  394. auto const& edge = mCandidateEdges[i];
  395. Vector<3, Real> const& P0 = mVertices[edge[0]];
  396. Vector<3, Real> const& P1 = mVertices[edge[1]];
  397. if (HasPointInsideCone(P0, P1, cone))
  398. {
  399. return true;
  400. }
  401. }
  402. return false;
  403. }
  404. void ComputeCandidatesOnBoxEdges(Cone<3, Real> const& cone)
  405. {
  406. for (size_t i = 0; i < NUM_BOX_VERTICES; ++i)
  407. {
  408. Real h = Dot(cone.ray.direction, mVertices[i]);
  409. Real coneMaxHeight = (cone.IsFinite() ? cone.GetMaxHeight() : std::numeric_limits<Real>::max());
  410. mProjectionMin[i] = cone.GetMinHeight() - h;
  411. mProjectionMax[i] = h - coneMaxHeight;
  412. }
  413. size_t v0 = VERTEX_MIN_BASE, v1 = VERTEX_MAX_BASE;
  414. for (size_t i = 0; i < NUM_BOX_EDGES; ++i, ++v0, ++v1)
  415. {
  416. auto const& edge = mEdges[i];
  417. // In the next blocks, the sign comparisons can be expressed
  418. // instead as "s0 * s1 < 0". The multiplication could lead to
  419. // floating-point underflow where the product becomes 0, so I
  420. // avoid that approach.
  421. // Process the hmin-plane.
  422. Real p0Min = mProjectionMin[edge[0]];
  423. Real p1Min = mProjectionMin[edge[1]];
  424. bool clipMin = (p0Min < (Real)0 && p1Min >(Real)0) || (p0Min > (Real)0 && p1Min < (Real)0);
  425. if (clipMin)
  426. {
  427. mVertices[v0] = (p1Min * mVertices[edge[0]] - p0Min * mVertices[edge[1]]) / (p1Min - p0Min);
  428. }
  429. // Process the hmax-plane.
  430. Real p0Max = mProjectionMax[edge[0]];
  431. Real p1Max = mProjectionMax[edge[1]];
  432. bool clipMax = (p0Max < (Real)0 && p1Max >(Real)0) || (p0Max > (Real)0 && p1Max < (Real)0);
  433. if (clipMax)
  434. {
  435. mVertices[v1] = (p1Max * mVertices[edge[0]] - p0Max * mVertices[edge[1]]) / (p1Max - p0Max);
  436. }
  437. // Get the candidate edges that are contained by the box edges.
  438. if (clipMin)
  439. {
  440. if (clipMax)
  441. {
  442. InsertEdge(v0, v1);
  443. }
  444. else
  445. {
  446. if (p0Min < (Real)0)
  447. {
  448. InsertEdge(edge[0], v0);
  449. }
  450. else // p1Min < 0
  451. {
  452. InsertEdge(edge[1], v0);
  453. }
  454. }
  455. }
  456. else if (clipMax)
  457. {
  458. if (p0Max < (Real)0)
  459. {
  460. InsertEdge(edge[0], v1);
  461. }
  462. else // p1Max < 0
  463. {
  464. InsertEdge(edge[1], v1);
  465. }
  466. }
  467. else
  468. {
  469. // No clipping has occurred. If the edge is inside the box,
  470. // it is a candidate edge. To be inside the box, the p*min
  471. // and p*max values must be nonpositive.
  472. if (p0Min <= (Real)0 && p1Min <= (Real)0 && p0Max <= (Real)0 && p1Max <= (Real)0)
  473. {
  474. InsertEdge(edge[0], edge[1]);
  475. }
  476. }
  477. }
  478. }
  479. void ComputeCandidatesOnBoxFaces()
  480. {
  481. Real p0, p1, p2, p3;
  482. size_t b0, b1, b2, b3, index;
  483. for (size_t i = 0; i < NUM_BOX_FACES; ++i)
  484. {
  485. auto const& face = mFaces[i];
  486. // Process the hmin-plane.
  487. p0 = mProjectionMin[face.v[0]];
  488. p1 = mProjectionMin[face.v[1]];
  489. p2 = mProjectionMin[face.v[2]];
  490. p3 = mProjectionMin[face.v[3]];
  491. b0 = (p0 < (Real)0 ? 0 : (p0 > (Real)0 ? 2 : 1));
  492. b1 = (p1 < (Real)0 ? 0 : (p1 > (Real)0 ? 2 : 1));
  493. b2 = (p2 < (Real)0 ? 0 : (p2 > (Real)0 ? 2 : 1));
  494. b3 = (p3 < (Real)0 ? 0 : (p3 > (Real)0 ? 2 : 1));
  495. index = b3 + 3 * (b2 + 3 * (b1 + 3 * b0));
  496. (this->*mConfiguration[index])(VERTEX_MIN_BASE, face);
  497. // Process the hmax-plane.
  498. p0 = mProjectionMax[face.v[0]];
  499. p1 = mProjectionMax[face.v[1]];
  500. p2 = mProjectionMax[face.v[2]];
  501. p3 = mProjectionMax[face.v[3]];
  502. b0 = (p0 < (Real)0 ? 0 : (p0 > (Real)0 ? 2 : 1));
  503. b1 = (p1 < (Real)0 ? 0 : (p1 > (Real)0 ? 2 : 1));
  504. b2 = (p2 < (Real)0 ? 0 : (p2 > (Real)0 ? 2 : 1));
  505. b3 = (p3 < (Real)0 ? 0 : (p3 > (Real)0 ? 2 : 1));
  506. index = b3 + 3 * (b2 + 3 * (b1 + 3 * b0));
  507. (this->*mConfiguration[index])(VERTEX_MAX_BASE, face);
  508. }
  509. }
  510. void ClearCandidates()
  511. {
  512. for (size_t i = 0; i < mNumCandidateEdges; ++i)
  513. {
  514. auto const& edge = mCandidateEdges[i];
  515. mAdjacencyMatrix[edge[0]][edge[1]] = 0;
  516. mAdjacencyMatrix[edge[1]][edge[0]] = 0;
  517. }
  518. mNumCandidateEdges = 0;
  519. }
  520. void InsertEdge(size_t v0, size_t v1)
  521. {
  522. if (mAdjacencyMatrix[v0][v1] == 0)
  523. {
  524. mAdjacencyMatrix[v0][v1] = 1;
  525. mAdjacencyMatrix[v1][v0] = 1;
  526. mCandidateEdges[mNumCandidateEdges] = { v0, v1 };
  527. ++mNumCandidateEdges;
  528. }
  529. }
  530. // The 81 possible configurations for a box face. The N stands for a
  531. // '-', the Z stands for '0' and the P stands for '+'. These are
  532. // listed in the order that maps to the array mConfiguration. Thus,
  533. // NNNN maps to mConfiguration[0], NNNZ maps to mConfiguration[1], and
  534. // so on.
  535. void NNNN_0(size_t, Face const&)
  536. {
  537. }
  538. void NNNZ_1(size_t, Face const&)
  539. {
  540. }
  541. void NNNP_2(size_t base, Face const& face)
  542. {
  543. InsertEdge(base + face.e[2], base + face.e[3]);
  544. }
  545. void NNZN_3(size_t, Face const&)
  546. {
  547. }
  548. void NNZZ_4(size_t, Face const&)
  549. {
  550. }
  551. void NNZP_5(size_t base, Face const& face)
  552. {
  553. InsertEdge(face.v[2], base + face.e[3]);
  554. }
  555. void NNPN_6(size_t base, Face const& face)
  556. {
  557. InsertEdge(base + face.e[1], base + face.e[2]);
  558. }
  559. void NNPZ_7(size_t base, Face const& face)
  560. {
  561. InsertEdge(base + face.e[1], face.v[3]);
  562. }
  563. void NNPP_8(size_t base, Face const& face)
  564. {
  565. InsertEdge(base + face.e[1], base + face.e[3]);
  566. }
  567. void NZNN_9(size_t, Face const&)
  568. {
  569. }
  570. void NZNZ_10(size_t, Face const&)
  571. {
  572. }
  573. void NZNP_11(size_t base, Face const& face)
  574. {
  575. InsertEdge(base + face.e[2], face.v[3]);
  576. InsertEdge(base + face.e[3], face.v[3]);
  577. }
  578. void NZZN_12(size_t, Face const&)
  579. {
  580. }
  581. void NZZZ_13(size_t, Face const&)
  582. {
  583. }
  584. void NZZP_14(size_t base, Face const& face)
  585. {
  586. InsertEdge(face.v[2], face.v[3]);
  587. InsertEdge(base + face.e[3], face.v[3]);
  588. }
  589. void NZPN_15(size_t base, Face const& face)
  590. {
  591. InsertEdge(base + face.e[2], face.v[1]);
  592. }
  593. void NZPZ_16(size_t, Face const& face)
  594. {
  595. InsertEdge(face.v[1], face.v[3]);
  596. }
  597. void NZPP_17(size_t base, Face const& face)
  598. {
  599. InsertEdge(base + face.e[3], face.v[1]);
  600. }
  601. void NPNN_18(size_t base, Face const& face)
  602. {
  603. InsertEdge(base + face.e[0], base + face.e[1]);
  604. }
  605. void NPNZ_19(size_t base, Face const& face)
  606. {
  607. InsertEdge(base + face.e[0], face.v[1]);
  608. InsertEdge(base + face.e[1], face.v[1]);
  609. }
  610. void NPNP_20(size_t base, Face const& face)
  611. {
  612. InsertEdge(base + face.e[0], face.v[1]);
  613. InsertEdge(base + face.e[1], face.v[1]);
  614. InsertEdge(base + face.e[2], face.v[3]);
  615. InsertEdge(base + face.e[3], face.v[3]);
  616. }
  617. void NPZN_21(size_t base, Face const& face)
  618. {
  619. InsertEdge(base + face.e[0], face.v[2]);
  620. }
  621. void NPZZ_22(size_t base, Face const& face)
  622. {
  623. InsertEdge(base + face.e[0], face.v[1]);
  624. InsertEdge(face.v[1], face.v[2]);
  625. }
  626. void NPZP_23(size_t base, Face const& face)
  627. {
  628. InsertEdge(base + face.e[0], face.v[1]);
  629. InsertEdge(face.v[1], face.v[2]);
  630. InsertEdge(base + face.e[3], face.v[2]);
  631. InsertEdge(face.v[2], face.v[3]);
  632. }
  633. void NPPN_24(size_t base, Face const& face)
  634. {
  635. InsertEdge(base + face.e[0], base + face.e[2]);
  636. }
  637. void NPPZ_25(size_t base, Face const& face)
  638. {
  639. InsertEdge(base + face.e[0], face.v[3]);
  640. }
  641. void NPPP_26(size_t base, Face const& face)
  642. {
  643. InsertEdge(base + face.e[0], base + face.e[3]);
  644. }
  645. void ZNNN_27(size_t, Face const&)
  646. {
  647. }
  648. void ZNNZ_28(size_t, Face const&)
  649. {
  650. }
  651. void ZNNP_29(size_t base, Face const& face)
  652. {
  653. InsertEdge(base + face.e[2], face.v[0]);
  654. }
  655. void ZNZN_30(size_t, Face const&)
  656. {
  657. }
  658. void ZNZZ_31(size_t, Face const&)
  659. {
  660. }
  661. void ZNZP_32(size_t, Face const& face)
  662. {
  663. InsertEdge(face.v[0], face.v[2]);
  664. }
  665. void ZNPN_33(size_t base, Face const& face)
  666. {
  667. InsertEdge(base + face.e[1], face.v[2]);
  668. InsertEdge(base + face.e[2], face.v[2]);
  669. }
  670. void ZNPZ_34(size_t base, Face const& face)
  671. {
  672. InsertEdge(base + face.e[1], face.v[2]);
  673. InsertEdge(face.v[2], face.v[3]);
  674. }
  675. void ZNPP_35(size_t base, Face const& face)
  676. {
  677. InsertEdge(face.v[0], base + face.e[1]);
  678. }
  679. void ZZNN_36(size_t, Face const&)
  680. {
  681. }
  682. void ZZNZ_37(size_t, Face const&)
  683. {
  684. }
  685. void ZZNP_38(size_t base, Face const& face)
  686. {
  687. InsertEdge(face.v[0], face.v[3]);
  688. InsertEdge(face.v[3], base + face.e[2]);
  689. }
  690. void ZZZN_39(size_t, Face const&)
  691. {
  692. }
  693. void ZZZZ_40(size_t, Face const&)
  694. {
  695. }
  696. void ZZZP_41(size_t, Face const& face)
  697. {
  698. InsertEdge(face.v[0], face.v[3]);
  699. InsertEdge(face.v[3], face.v[2]);
  700. }
  701. void ZZPN_42(size_t base, Face const& face)
  702. {
  703. InsertEdge(face.v[1], face.v[2]);
  704. InsertEdge(face.v[2], base + face.e[2]);
  705. }
  706. void ZZPZ_43(size_t, Face const& face)
  707. {
  708. InsertEdge(face.v[1], face.v[2]);
  709. InsertEdge(face.v[2], face.v[3]);
  710. }
  711. void ZZPP_44(size_t, Face const&)
  712. {
  713. }
  714. void ZPNN_45(size_t base, Face const& face)
  715. {
  716. InsertEdge(face.v[0], base + face.e[1]);
  717. }
  718. void ZPNZ_46(size_t base, Face const& face)
  719. {
  720. InsertEdge(face.v[0], face.v[1]);
  721. InsertEdge(face.v[1], base + face.e[1]);
  722. }
  723. void ZPNP_47(size_t base, Face const& face)
  724. {
  725. InsertEdge(face.v[0], face.v[1]);
  726. InsertEdge(face.v[1], base + face.e[1]);
  727. InsertEdge(base + face.e[2], face.v[3]);
  728. InsertEdge(face.v[3], face.v[0]);
  729. }
  730. void ZPZN_48(size_t, Face const& face)
  731. {
  732. InsertEdge(face.v[0], face.v[2]);
  733. }
  734. void ZPZZ_49(size_t, Face const& face)
  735. {
  736. InsertEdge(face.v[0], face.v[1]);
  737. InsertEdge(face.v[1], face.v[2]);
  738. }
  739. void ZPZP_50(size_t, Face const&)
  740. {
  741. }
  742. void ZPPN_51(size_t base, Face const& face)
  743. {
  744. InsertEdge(face.v[0], base + face.e[2]);
  745. }
  746. void ZPPZ_52(size_t, Face const&)
  747. {
  748. }
  749. void ZPPP_53(size_t, Face const&)
  750. {
  751. }
  752. void PNNN_54(size_t base, Face const& face)
  753. {
  754. InsertEdge(base + face.e[3], base + face.e[0]);
  755. }
  756. void PNNZ_55(size_t base, Face const& face)
  757. {
  758. InsertEdge(face.v[3], base + face.e[0]);
  759. }
  760. void PNNP_56(size_t base, Face const& face)
  761. {
  762. InsertEdge(base + face.e[2], base + face.e[0]);
  763. }
  764. void PNZN_57(size_t base, Face const& face)
  765. {
  766. InsertEdge(base + face.e[3], face.v[0]);
  767. InsertEdge(face.v[0], base + face.e[0]);
  768. }
  769. void PNZZ_58(size_t base, Face const& face)
  770. {
  771. InsertEdge(face.v[3], face.v[0]);
  772. InsertEdge(face.v[0], base + face.e[0]);
  773. }
  774. void PNZP_59(size_t base, Face const& face)
  775. {
  776. InsertEdge(face.v[2], base + face.e[0]);
  777. }
  778. void PNPN_60(size_t base, Face const& face)
  779. {
  780. InsertEdge(base + face.e[3], face.v[0]);
  781. InsertEdge(face.v[0], base + face.e[0]);
  782. InsertEdge(base + face.e[1], face.v[2]);
  783. InsertEdge(face.v[2], base + face.e[2]);
  784. }
  785. void PNPZ_61(size_t base, Face const& face)
  786. {
  787. InsertEdge(face.v[3], face.v[0]);
  788. InsertEdge(face.v[0], base + face.e[0]);
  789. InsertEdge(base + face.e[1], face.v[2]);
  790. InsertEdge(face.v[2], face.v[3]);
  791. }
  792. void PNPP_62(size_t base, Face const& face)
  793. {
  794. InsertEdge(base + face.e[0], base + face.e[1]);
  795. }
  796. void PZNN_63(size_t base, Face const& face)
  797. {
  798. InsertEdge(base + face.e[3], face.v[1]);
  799. }
  800. void PZNZ_64(size_t, Face const& face)
  801. {
  802. InsertEdge(face.v[3], face.v[1]);
  803. }
  804. void PZNP_65(size_t base, Face const& face)
  805. {
  806. InsertEdge(base + face.e[2], face.v[1]);
  807. }
  808. void PZZN_66(size_t base, Face const& face)
  809. {
  810. InsertEdge(base + face.e[3], face.v[0]);
  811. InsertEdge(face.v[0], face.v[1]);
  812. }
  813. void PZZZ_67(size_t, Face const&)
  814. {
  815. }
  816. void PZZP_68(size_t, Face const&)
  817. {
  818. }
  819. void PZPN_69(size_t base, Face const& face)
  820. {
  821. InsertEdge(base + face.e[3], face.v[0]);
  822. InsertEdge(face.v[0], face.v[1]);
  823. InsertEdge(face.v[1], face.v[2]);
  824. InsertEdge(face.v[2], base + face.e[2]);
  825. }
  826. void PZPZ_70(size_t, Face const&)
  827. {
  828. }
  829. void PZPP_71(size_t, Face const&)
  830. {
  831. }
  832. void PPNN_72(size_t base, Face const& face)
  833. {
  834. InsertEdge(base + face.e[3], base + face.e[1]);
  835. }
  836. void PPNZ_73(size_t base, Face const& face)
  837. {
  838. InsertEdge(face.v[3], base + face.e[1]);
  839. }
  840. void PPNP_74(size_t base, Face const& face)
  841. {
  842. InsertEdge(base + face.e[2], base + face.e[1]);
  843. }
  844. void PPZN_75(size_t base, Face const& face)
  845. {
  846. InsertEdge(base + face.e[2], face.v[2]);
  847. }
  848. void PPZZ_76(size_t, Face const&)
  849. {
  850. }
  851. void PPZP_77(size_t, Face const&)
  852. {
  853. }
  854. void PPPN_78(size_t base, Face const& face)
  855. {
  856. InsertEdge(base + face.e[3], base + face.e[2]);
  857. }
  858. void PPPZ_79(size_t, Face const&)
  859. {
  860. }
  861. void PPPP_80(size_t, Face const&)
  862. {
  863. }
  864. };
  865. // Template alias for convenience.
  866. template <typename Real>
  867. using TIAlignedBox3Cone3 = TIQuery<Real, AlignedBox<3, Real>, Cone<3, Real>>;
  868. }