Sphere.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Frustum.h"
  25. void Sphere::define(const std::vector<Vector3>& vertices)
  26. {
  27. mDefined = false;
  28. for (std::vector<Vector3>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
  29. merge(*i);
  30. }
  31. void Sphere::define(const Vector3* vertices, unsigned count)
  32. {
  33. if (!count)
  34. return;
  35. mDefined = false;
  36. merge(vertices, count);
  37. }
  38. void Sphere::define(const BoundingBox& box)
  39. {
  40. const Vector3& min = box.mMin;
  41. const Vector3& max = box.mMax;
  42. mDefined = false;
  43. merge(min);
  44. merge(Vector3(max.mX, min.mY, min.mZ));
  45. merge(Vector3(min.mX, max.mY, min.mZ));
  46. merge(Vector3(max.mX, max.mY, min.mZ));
  47. merge(Vector3(min.mX, min.mY, max.mZ));
  48. merge(Vector3(max.mX, min.mY, max.mZ));
  49. merge(Vector3(min.mX, max.mY, max.mZ));
  50. merge(max);
  51. }
  52. void Sphere::define(const Frustum& frustum)
  53. {
  54. define(frustum.getVertices(), NUM_FRUSTUM_VERTICES);
  55. }
  56. void Sphere::merge(const std::vector<Vector3>& vertices)
  57. {
  58. for (std::vector<Vector3>::const_iterator i = vertices.begin(); i != vertices.end(); ++i)
  59. merge(*i);
  60. }
  61. void Sphere::merge(const Vector3* vertices, unsigned count)
  62. {
  63. while (count--)
  64. {
  65. merge(*vertices);
  66. ++vertices;
  67. }
  68. }
  69. void Sphere::merge(const BoundingBox& box)
  70. {
  71. const Vector3& min = box.mMin;
  72. const Vector3& max = box.mMax;
  73. merge(min);
  74. merge(Vector3(max.mX, min.mY, min.mZ));
  75. merge(Vector3(min.mX, max.mY, min.mZ));
  76. merge(Vector3(max.mX, max.mY, min.mZ));
  77. merge(Vector3(min.mX, min.mY, max.mZ));
  78. merge(Vector3(max.mX, min.mY, max.mZ));
  79. merge(Vector3(min.mX, max.mY, max.mZ));
  80. merge(max);
  81. }
  82. void Sphere::merge(const Frustum& frustum)
  83. {
  84. const Vector3* vertices = frustum.getVertices();
  85. merge(vertices, NUM_FRUSTUM_VERTICES);
  86. }
  87. void Sphere::merge(const Sphere& sphere)
  88. {
  89. if (!mDefined)
  90. {
  91. mCenter = sphere.mCenter;
  92. mRadius = sphere.mRadius;
  93. mDefined = true;
  94. return;
  95. }
  96. Vector3 offset = sphere.mCenter - mCenter;
  97. float dist = offset.getLength();
  98. // If sphere fits inside, do nothing
  99. if (dist + sphere.mRadius < mRadius)
  100. return;
  101. // If we fit inside the other sphere, become it
  102. if (dist + mRadius < sphere.mRadius)
  103. {
  104. mCenter = sphere.mCenter;
  105. mRadius = sphere.mRadius;
  106. }
  107. else
  108. {
  109. Vector3 normalizedOffset = offset / dist;
  110. Vector3 min = mCenter - mRadius * normalizedOffset;
  111. Vector3 max = sphere.mCenter + sphere.mRadius * normalizedOffset;
  112. mCenter = (min + max) * 0.5f;
  113. mRadius = (max - mCenter).getLength();
  114. }
  115. }
  116. Intersection Sphere::isInside(const BoundingBox& box) const
  117. {
  118. float radiusSquared = mRadius * mRadius;
  119. float distSquared = 0;
  120. float temp;
  121. Vector3 min = box.mMin;
  122. Vector3 max = box.mMax;
  123. if (mCenter.mX < min.mX)
  124. {
  125. temp = mCenter.mX - min.mX;
  126. distSquared += temp * temp;
  127. }
  128. else if (mCenter.mX > max.mX)
  129. {
  130. temp = mCenter.mX - max.mX;
  131. distSquared += temp * temp;
  132. }
  133. if (mCenter.mY < min.mY)
  134. {
  135. temp = mCenter.mY - min.mY;
  136. distSquared += temp * temp;
  137. }
  138. else if (mCenter.mY > max.mY)
  139. {
  140. temp = mCenter.mY - max.mY;
  141. distSquared += temp * temp;
  142. }
  143. if (mCenter.mZ < min.mZ)
  144. {
  145. temp = mCenter.mZ - min.mZ;
  146. distSquared += temp * temp;
  147. }
  148. else if (mCenter.mZ > max.mZ)
  149. {
  150. temp = mCenter.mZ - max.mZ;
  151. distSquared += temp * temp;
  152. }
  153. if (distSquared >= radiusSquared)
  154. return OUTSIDE;
  155. min -= mCenter;
  156. max -= mCenter;
  157. Vector3 tempVec = min; // - - -
  158. if (tempVec.getLengthSquared() >= radiusSquared)
  159. return INTERSECTS;
  160. tempVec.mX = max.mX; // + - -
  161. if (tempVec.getLengthSquared() >= radiusSquared)
  162. return INTERSECTS;
  163. tempVec.mY = max.mY; // + + -
  164. if (tempVec.getLengthSquared() >= radiusSquared)
  165. return INTERSECTS;
  166. tempVec.mX = min.mX; // - + -
  167. if (tempVec.getLengthSquared() >= radiusSquared)
  168. return INTERSECTS;
  169. tempVec.mZ = max.mZ; // - + +
  170. if (tempVec.getLengthSquared() >= radiusSquared)
  171. return INTERSECTS;
  172. tempVec.mY = min.mY; // - - +
  173. if (tempVec.getLengthSquared() >= radiusSquared)
  174. return INTERSECTS;
  175. tempVec.mX = max.mX; // + - +
  176. if (tempVec.getLengthSquared() >= radiusSquared)
  177. return INTERSECTS;
  178. tempVec.mY = max.mY; // + + +
  179. if (tempVec.getLengthSquared() >= radiusSquared)
  180. return INTERSECTS;
  181. return INSIDE;
  182. }
  183. Intersection Sphere::isInsideFast(const BoundingBox& box) const
  184. {
  185. float radiusSquared = mRadius * mRadius;
  186. float distSquared = 0;
  187. float temp;
  188. Vector3 min = box.mMin;
  189. Vector3 max = box.mMax;
  190. if (mCenter.mX < min.mX)
  191. {
  192. temp = mCenter.mX - min.mX;
  193. distSquared += temp * temp;
  194. }
  195. else if (mCenter.mX > max.mX)
  196. {
  197. temp = mCenter.mX - max.mX;
  198. distSquared += temp * temp;
  199. }
  200. if (mCenter.mY < min.mY)
  201. {
  202. temp = mCenter.mY - min.mY;
  203. distSquared += temp * temp;
  204. }
  205. else if (mCenter.mY > max.mY)
  206. {
  207. temp = mCenter.mY - max.mY;
  208. distSquared += temp * temp;
  209. }
  210. if (mCenter.mZ < min.mZ)
  211. {
  212. temp = mCenter.mZ - min.mZ;
  213. distSquared += temp * temp;
  214. }
  215. else if (mCenter.mZ > max.mZ)
  216. {
  217. temp = mCenter.mZ - max.mZ;
  218. distSquared += temp * temp;
  219. }
  220. if (distSquared >= radiusSquared)
  221. return OUTSIDE;
  222. else
  223. return INSIDE;
  224. }
  225. float Sphere::getDistance(const Ray& ray) const
  226. {
  227. Vector3 centeredOrigin = ray.mOrigin - mCenter;
  228. float squaredRadius = mRadius * mRadius;
  229. // Check if ray originates inside the sphere
  230. if (centeredOrigin.getLengthSquared() <= squaredRadius)
  231. return 0.0f;
  232. // Calculate intersection by quadratic equation
  233. float a = ray.mDirection.dotProduct(ray.mDirection);
  234. float b = 2.0f * centeredOrigin.dotProduct(ray.mDirection);
  235. float c = centeredOrigin.dotProduct(centeredOrigin) - squaredRadius;
  236. float d = b * b - 4.0f * a * c;
  237. // No solution
  238. if (d < 0.0f)
  239. return M_INFINITY;
  240. // Get the nearer solution
  241. float dSqrt = sqrtf(d);
  242. float dist = (-b - dSqrt) / (2.0f * a);
  243. if (dist >= 0.0f)
  244. return dist;
  245. else
  246. return (-b + dSqrt) / (2.0f * a);
  247. }