Cone.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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/Logger.h>
  9. #include <Mathematics/Math.h>
  10. #include <Mathematics/Ray.h>
  11. // An infinite cone is defined by a vertex V, a unit-length direction D and an
  12. // angle A with 0 < A < pi/2. A point X is on the cone when
  13. // Dot(D, X - V) = |X - V| * cos(A)
  14. // A solid cone includes points on the cone and in the region that contains
  15. // the cone ray V + h * D for h >= 0. It is defined by
  16. // Dot(D, X - V) >= |X - V| * cos(A)
  17. // The height of any point Y in space relative to the cone is defined by
  18. // h = Dot(D, Y - V), which is the signed length of the projection of X - V
  19. // onto the cone axis. Observe that we have restricted the cone definition to
  20. // an acute angle A, so |X - V| * cos(A) >= 0; therefore, points on or inside
  21. // the cone have nonnegative heights: Dot(D, X - V) >= 0. I will refer to the
  22. // infinite solid cone as the "positive cone," which means that the non-vertex
  23. // points inside the cone have positive heights. Although rare in computer
  24. // graphics, one might also want to consider the "negative cone," which is
  25. // defined by
  26. // -Dot(D, X - V) <= -|X - V| * cos(A)
  27. // The non-vertex points inside this cone have negative heights.
  28. //
  29. // For many of the geometric queries involving cones, we can avoid the square
  30. // root computation implied by |X - V|. The positive cone is defined by
  31. // Dot(D, X - V)^2 >= |X - V|^2 * cos(A)^2,
  32. // which is a quadratic inequality, but the squaring of the terms leads to an
  33. // inequality that includes points X in the negative cone. When using the
  34. // quadratic inequality for the positive cone, we need to include also the
  35. // constraint Dot(D, X - V) >= 0.
  36. //
  37. // I define four different types of cones. They all involve V, D and A. The
  38. // differences are based on restrictions to the heights of the cone points.
  39. // The height range is defined to be the interval of possible heights, say,
  40. // [hmin,hmax] with 0 <= hmin < hmax <= +infinity.
  41. // 1. infinite cone: hmin = 0, hmax = +infinity
  42. // 2. infinite truncated cone: hmin > 0, hmax = +infinity
  43. // 3. finite cone: hmin >= 0, hmax < +infinity
  44. // 4. frustum of a cone: hmin > 0, hmax < +infinity
  45. // The infinite truncated cone is truncated for h-minimum; the radius of the
  46. // disk at h-minimum is rmin = hmin * tan(A). The finite cone is truncated for
  47. // h-maximum; the radius of the disk at h-maximum is rmax = hmax * tan(A).
  48. // The frustum of a cone is truncated both for h-minimum and h-maximum.
  49. //
  50. // A technical problem when creating a data structure to represent a cone is
  51. // deciding how to represent +infinity in the height range. When the template
  52. // type Real is 'float' or 'double', we could represent it as
  53. // std::numeric_limits<Real>::infinity(). The geometric queries must be
  54. // structured properly to conform to the semantics associated with the
  55. // floating-point infinity. We could also use the largest finite
  56. // floating-point number, std::numeric_limits<Real>::max(). Either choice is
  57. // problematic when instead Real is an arbitrary precision type that does not
  58. // have a representation for infinity; this is the case for the types
  59. // BSNumber<T> and BSRational<T>, where T is UIntegerAP or UIntegerFP<N>.
  60. //
  61. // The introduction of representations of infinities for the arbitrary
  62. // precision types would require modifying the arithmetic operations to test
  63. // whether the number is finite or infinite. This leads to a greater
  64. // computational cost for all queries, even when those queries do not require
  65. // manipulating infinities. In the case of a cone, the height manipulations
  66. // are nearly always for comparisons of heights. I choose to represent
  67. // +infinity by setting the maxHeight member to -1. The member functions
  68. // IsFinite() and IsInfinite() compare maxHeight to -1 and report the correct
  69. // state.
  70. //
  71. // My choice of representation has the main consequence that comparisons
  72. // between heights requires extra logic. This can make geometric queries
  73. // cumbersome to implement. For example, the point-in-cone test using the
  74. // quadratic inequality is shown in the pseudocode
  75. // Vector point = <some point>;
  76. // Cone cone = <some cone>;
  77. // Vector delta = point - cone.V;
  78. // Real h = Dot(cone.D, delta);
  79. // bool pointInCone =
  80. // cone.hmin <= h &&
  81. // h <= cone.hmax &&
  82. // h * h >= Dot(delta, delta) * cone.cosAngleSqr;
  83. // In the event the cone is infinite and we choose cone.hmax = -1 to
  84. // represent this, the test 'h <= cone.hmax' must be revised,
  85. // bool pointInCone =
  86. // cone.hmin <= h &&
  87. // (cone.hmax == -1 ? true : (h <= cone.hmax)) &&
  88. // h * h >= Dot(delta, delta) * cone.cosAngleSqr;
  89. // To encapsulate the comparisons against height extremes, use the member
  90. // function HeightInRange(h); that is
  91. // bool pointInCone =
  92. // cone.HeightInRange(h) &&
  93. // h * h >= Dot(delta, delta) * cone.cosAngleSqr;
  94. // The modification is not that complicated here, but consider a more
  95. // sophisticated query such as determining the interval of intersection
  96. // of two height intervals [h0,h1] and [cone.hmin,cone.hmax]. The file
  97. // GteIntrIntervals.h provides implementations for computing the
  98. // intersection of two intervals, where either or both intervals are
  99. // semi-infinite.
  100. namespace WwiseGTE
  101. {
  102. template <int N, typename Real>
  103. class Cone
  104. {
  105. public:
  106. // Create an infinite cone with
  107. // vertex = (0,...,0)
  108. // axis = (0,...,0,1)
  109. // angle = pi/4
  110. // minimum height = 0
  111. // maximum height = +infinity
  112. Cone()
  113. {
  114. ray.origin.MakeZero();
  115. ray.direction.MakeUnit(N - 1);
  116. SetAngle((Real)GTE_C_QUARTER_PI);
  117. MakeInfiniteCone();
  118. }
  119. // Create an infinite cone with the specified vertex, axis direction,
  120. // angle and with heights
  121. // minimum height = 0
  122. // maximum height = +infinity
  123. Cone(Ray<N, Real> const& inRay, Real const& inAngle)
  124. :
  125. ray(inRay)
  126. {
  127. SetAngle(inAngle);
  128. MakeInfiniteCone();
  129. }
  130. // Create an infinite truncated cone with the specified vertex, axis
  131. // direction, angle and positive minimum height. The maximum height
  132. // is +infinity. If you specify a minimum height of 0, you get the
  133. // equivalent of calling the constructor for an infinite cone.
  134. Cone(Ray<N, Real> const& inRay, Real const& inAngle, Real const& inMinHeight)
  135. :
  136. ray(inRay)
  137. {
  138. SetAngle(inAngle);
  139. MakeInfiniteTruncatedCone(inMinHeight);
  140. }
  141. // Create a finite cone or a frustum of a cone with all parameters
  142. // specified. If you specify a minimum height of 0, you get a finite
  143. // cone. If you specify a positive minimum height, you get a frustum
  144. // of a cone.
  145. Cone(Ray<N, Real> const& inRay, Real inAngle, Real inMinHeight, Real inMaxHeight)
  146. :
  147. ray(inRay)
  148. {
  149. SetAngle(inAngle);
  150. MakeConeFrustum(inMinHeight, inMaxHeight);
  151. }
  152. // The angle must be in (0,pi/2). The function sets 'angle' and
  153. // computes 'cosAngle', 'sinAngle', 'tanAngle', 'cosAngleSqr',
  154. // 'sinAngleSqr' and 'invSinAngle'.
  155. void SetAngle(Real const& inAngle)
  156. {
  157. LogAssert((Real)0 < inAngle && inAngle < (Real)GTE_C_HALF_PI, "Invalid angle.");
  158. angle = inAngle;
  159. cosAngle = std::cos(angle);
  160. sinAngle = std::sin(angle);
  161. tanAngle = std::tan(angle);
  162. cosAngleSqr = cosAngle * cosAngle;
  163. sinAngleSqr = sinAngle * sinAngle;
  164. invSinAngle = (Real)1 / sinAngle;
  165. }
  166. // Set the heights to obtain one of the four types of cones. Be aware
  167. // that an infinite cone has maxHeight set to -1. Be careful not to
  168. // use maxHeight without understanding this interpretation.
  169. void MakeInfiniteCone()
  170. {
  171. mMinHeight = (Real)0;
  172. mMaxHeight = (Real)-1;
  173. }
  174. void MakeInfiniteTruncatedCone(Real const& inMinHeight)
  175. {
  176. LogAssert(inMinHeight >= (Real)0, "Invalid minimum height.");
  177. mMinHeight = inMinHeight;
  178. mMaxHeight = (Real)-1;
  179. }
  180. void MakeFiniteCone(Real const& inMaxHeight)
  181. {
  182. LogAssert(inMaxHeight > (Real)0, "Invalid maximum height.");
  183. mMinHeight = (Real)0;
  184. mMaxHeight = inMaxHeight;
  185. }
  186. void MakeConeFrustum(Real const& inMinHeight, Real const& inMaxHeight)
  187. {
  188. LogAssert(inMinHeight >= (Real)0 && inMaxHeight > inMinHeight,
  189. "Invalid minimum or maximum height.");
  190. mMinHeight = inMinHeight;
  191. mMaxHeight = inMaxHeight;
  192. }
  193. // Get the height extremes. For an infinite cone, maxHeight is set
  194. // to -1. For a finite cone, maxHeight is set to a positive number.
  195. // Be careful not to use maxHeight without understanding this
  196. // interpretation.
  197. inline Real GetMinHeight() const
  198. {
  199. return mMinHeight;
  200. }
  201. inline Real GetMaxHeight() const
  202. {
  203. return mMaxHeight;
  204. }
  205. inline bool HeightInRange(Real const& h) const
  206. {
  207. return mMinHeight <= h && (mMaxHeight != (Real)-1 ? h <= mMaxHeight : true);
  208. }
  209. inline bool HeightLessThanMin(Real const& h) const
  210. {
  211. return h < mMinHeight;
  212. }
  213. inline bool HeightGreaterThanMax(Real const& h) const
  214. {
  215. return (mMaxHeight != (Real)-1 ? h > mMaxHeight : false);
  216. }
  217. inline bool IsFinite() const
  218. {
  219. return mMaxHeight != (Real)-1;
  220. }
  221. inline bool IsInfinite() const
  222. {
  223. return mMaxHeight == (Real)-1;
  224. }
  225. // The cone axis direction (ray.direction) must be unit length.
  226. Ray<N, Real> ray;
  227. // The angle must be in (0,pi/2). The other members are derived from
  228. // angle to avoid calling trigonometric functions in geometric queries
  229. // (for speed). You may set the angle and compute these by calling
  230. // SetAngle(inAngle).
  231. Real angle;
  232. Real cosAngle, sinAngle, tanAngle;
  233. Real cosAngleSqr, sinAngleSqr, invSinAngle;
  234. private:
  235. // The heights must satisfy 0 <= minHeight < maxHeight <= +infinity.
  236. // For an infinite cone, maxHeight is set to -1. For a finite cone,
  237. // maxHeight is set to a positive number. Be careful not to use
  238. // maxHeight without understanding this interpretation.
  239. Real mMinHeight, mMaxHeight;
  240. public:
  241. // Comparisons to support sorted containers. These based only on
  242. // 'ray', 'angle', 'minHeight' and 'maxHeight'.
  243. bool operator==(Cone const& cone) const
  244. {
  245. return ray == cone.ray
  246. && angle == cone.angle
  247. && mMinHeight == cone.mMinHeight
  248. && mMaxHeight == cone.mMaxHeight;
  249. }
  250. bool operator!=(Cone const& cone) const
  251. {
  252. return !operator==(cone);
  253. }
  254. bool operator< (Cone const& cone) const
  255. {
  256. if (ray < cone.ray)
  257. {
  258. return true;
  259. }
  260. if (ray > cone.ray)
  261. {
  262. return false;
  263. }
  264. if (angle < cone.angle)
  265. {
  266. return true;
  267. }
  268. if (angle > cone.angle)
  269. {
  270. return false;
  271. }
  272. if (mMinHeight < cone.mMinHeight)
  273. {
  274. return true;
  275. }
  276. if (mMinHeight > cone.mMinHeight)
  277. {
  278. return false;
  279. }
  280. return mMaxHeight < cone.mMaxHeight;
  281. }
  282. bool operator<=(Cone const& cone) const
  283. {
  284. return !cone.operator<(*this);
  285. }
  286. bool operator> (Cone const& cone) const
  287. {
  288. return cone.operator<(*this);
  289. }
  290. bool operator>=(Cone const& cone) const
  291. {
  292. return !operator<(cone);
  293. }
  294. };
  295. // Template alias for convenience.
  296. template <typename Real>
  297. using Cone3 = Cone<3, Real>;
  298. }