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. defined_ = 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. defined_ = false;
  36. Merge(vertices, count);
  37. }
  38. void Sphere::Define(const BoundingBox& box)
  39. {
  40. const Vector3& min = box.min_;
  41. const Vector3& max = box.max_;
  42. defined_ = false;
  43. Merge(min);
  44. Merge(Vector3(max.x_, min.y_, min.z_));
  45. Merge(Vector3(min.x_, max.y_, min.z_));
  46. Merge(Vector3(max.x_, max.y_, min.z_));
  47. Merge(Vector3(min.x_, min.y_, max.z_));
  48. Merge(Vector3(max.x_, min.y_, max.z_));
  49. Merge(Vector3(min.x_, max.y_, max.z_));
  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.min_;
  72. const Vector3& max = box.max_;
  73. Merge(min);
  74. Merge(Vector3(max.x_, min.y_, min.z_));
  75. Merge(Vector3(min.x_, max.y_, min.z_));
  76. Merge(Vector3(max.x_, max.y_, min.z_));
  77. Merge(Vector3(min.x_, min.y_, max.z_));
  78. Merge(Vector3(max.x_, min.y_, max.z_));
  79. Merge(Vector3(min.x_, max.y_, max.z_));
  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 (!defined_)
  90. {
  91. center_ = sphere.center_;
  92. radius_ = sphere.radius_;
  93. defined_ = true;
  94. return;
  95. }
  96. Vector3 offset = sphere.center_ - center_;
  97. float dist = offset.GetLength();
  98. // If sphere fits inside, do nothing
  99. if (dist + sphere.radius_ < radius_)
  100. return;
  101. // If we fit inside the other sphere, become it
  102. if (dist + radius_ < sphere.radius_)
  103. {
  104. center_ = sphere.center_;
  105. radius_ = sphere.radius_;
  106. }
  107. else
  108. {
  109. Vector3 NormalizedOffset = offset / dist;
  110. Vector3 min = center_ - radius_ * NormalizedOffset;
  111. Vector3 max = sphere.center_ + sphere.radius_ * NormalizedOffset;
  112. center_ = (min + max) * 0.5f;
  113. radius_ = (max - center_).GetLength();
  114. }
  115. }
  116. Intersection Sphere::IsInside(const BoundingBox& box) const
  117. {
  118. float radiusSquared = radius_ * radius_;
  119. float distSquared = 0;
  120. float temp;
  121. Vector3 min = box.min_;
  122. Vector3 max = box.max_;
  123. if (center_.x_ < min.x_)
  124. {
  125. temp = center_.x_ - min.x_;
  126. distSquared += temp * temp;
  127. }
  128. else if (center_.x_ > max.x_)
  129. {
  130. temp = center_.x_ - max.x_;
  131. distSquared += temp * temp;
  132. }
  133. if (center_.y_ < min.y_)
  134. {
  135. temp = center_.y_ - min.y_;
  136. distSquared += temp * temp;
  137. }
  138. else if (center_.y_ > max.y_)
  139. {
  140. temp = center_.y_ - max.y_;
  141. distSquared += temp * temp;
  142. }
  143. if (center_.z_ < min.z_)
  144. {
  145. temp = center_.z_ - min.z_;
  146. distSquared += temp * temp;
  147. }
  148. else if (center_.z_ > max.z_)
  149. {
  150. temp = center_.z_ - max.z_;
  151. distSquared += temp * temp;
  152. }
  153. if (distSquared >= radiusSquared)
  154. return OUTSIDE;
  155. min -= center_;
  156. max -= center_;
  157. Vector3 tempVec = min; // - - -
  158. if (tempVec.GetLengthSquared() >= radiusSquared)
  159. return INTERSECTS;
  160. tempVec.x_ = max.x_; // + - -
  161. if (tempVec.GetLengthSquared() >= radiusSquared)
  162. return INTERSECTS;
  163. tempVec.y_ = max.y_; // + + -
  164. if (tempVec.GetLengthSquared() >= radiusSquared)
  165. return INTERSECTS;
  166. tempVec.x_ = min.x_; // - + -
  167. if (tempVec.GetLengthSquared() >= radiusSquared)
  168. return INTERSECTS;
  169. tempVec.z_ = max.z_; // - + +
  170. if (tempVec.GetLengthSquared() >= radiusSquared)
  171. return INTERSECTS;
  172. tempVec.y_ = min.y_; // - - +
  173. if (tempVec.GetLengthSquared() >= radiusSquared)
  174. return INTERSECTS;
  175. tempVec.x_ = max.x_; // + - +
  176. if (tempVec.GetLengthSquared() >= radiusSquared)
  177. return INTERSECTS;
  178. tempVec.y_ = max.y_; // + + +
  179. if (tempVec.GetLengthSquared() >= radiusSquared)
  180. return INTERSECTS;
  181. return INSIDE;
  182. }
  183. Intersection Sphere::IsInsideFast(const BoundingBox& box) const
  184. {
  185. float radiusSquared = radius_ * radius_;
  186. float distSquared = 0;
  187. float temp;
  188. Vector3 min = box.min_;
  189. Vector3 max = box.max_;
  190. if (center_.x_ < min.x_)
  191. {
  192. temp = center_.x_ - min.x_;
  193. distSquared += temp * temp;
  194. }
  195. else if (center_.x_ > max.x_)
  196. {
  197. temp = center_.x_ - max.x_;
  198. distSquared += temp * temp;
  199. }
  200. if (center_.y_ < min.y_)
  201. {
  202. temp = center_.y_ - min.y_;
  203. distSquared += temp * temp;
  204. }
  205. else if (center_.y_ > max.y_)
  206. {
  207. temp = center_.y_ - max.y_;
  208. distSquared += temp * temp;
  209. }
  210. if (center_.z_ < min.z_)
  211. {
  212. temp = center_.z_ - min.z_;
  213. distSquared += temp * temp;
  214. }
  215. else if (center_.z_ > max.z_)
  216. {
  217. temp = center_.z_ - max.z_;
  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.origin_ - center_;
  228. float squaredRadius = radius_ * radius_;
  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.direction_.DotProduct(ray.direction_);
  234. float b = 2.0f * centeredOrigin.DotProduct(ray.direction_);
  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. }