Sphere.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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 Vector3* vertices, unsigned count)
  26. {
  27. if (!count)
  28. return;
  29. defined_ = false;
  30. Merge(vertices, count);
  31. }
  32. void Sphere::Define(const BoundingBox& box)
  33. {
  34. const Vector3& min = box.min_;
  35. const Vector3& max = box.max_;
  36. defined_ = false;
  37. Merge(min);
  38. Merge(Vector3(max.x_, min.y_, min.z_));
  39. Merge(Vector3(min.x_, max.y_, min.z_));
  40. Merge(Vector3(max.x_, max.y_, min.z_));
  41. Merge(Vector3(min.x_, min.y_, max.z_));
  42. Merge(Vector3(max.x_, min.y_, max.z_));
  43. Merge(Vector3(min.x_, max.y_, max.z_));
  44. Merge(max);
  45. }
  46. void Sphere::Define(const Frustum& frustum)
  47. {
  48. Define(frustum.vertices_, NUM_FRUSTUM_VERTICES);
  49. }
  50. void Sphere::Merge(const Vector3* vertices, unsigned count)
  51. {
  52. while (count--)
  53. {
  54. Merge(*vertices);
  55. ++vertices;
  56. }
  57. }
  58. void Sphere::Merge(const BoundingBox& box)
  59. {
  60. const Vector3& min = box.min_;
  61. const Vector3& max = box.max_;
  62. Merge(min);
  63. Merge(Vector3(max.x_, min.y_, min.z_));
  64. Merge(Vector3(min.x_, max.y_, min.z_));
  65. Merge(Vector3(max.x_, max.y_, min.z_));
  66. Merge(Vector3(min.x_, min.y_, max.z_));
  67. Merge(Vector3(max.x_, min.y_, max.z_));
  68. Merge(Vector3(min.x_, max.y_, max.z_));
  69. Merge(max);
  70. }
  71. void Sphere::Merge(const Frustum& frustum)
  72. {
  73. const Vector3* vertices = frustum.vertices_;
  74. Merge(vertices, NUM_FRUSTUM_VERTICES);
  75. }
  76. void Sphere::Merge(const Sphere& sphere)
  77. {
  78. if (!defined_)
  79. {
  80. center_ = sphere.center_;
  81. radius_ = sphere.radius_;
  82. defined_ = true;
  83. return;
  84. }
  85. Vector3 offset = sphere.center_ - center_;
  86. float dist = offset.Length();
  87. // If sphere fits inside, do nothing
  88. if (dist + sphere.radius_ < radius_)
  89. return;
  90. // If we fit inside the other sphere, become it
  91. if (dist + radius_ < sphere.radius_)
  92. {
  93. center_ = sphere.center_;
  94. radius_ = sphere.radius_;
  95. }
  96. else
  97. {
  98. Vector3 NormalizedOffset = offset / dist;
  99. Vector3 min = center_ - radius_ * NormalizedOffset;
  100. Vector3 max = sphere.center_ + sphere.radius_ * NormalizedOffset;
  101. center_ = (min + max) * 0.5f;
  102. radius_ = (max - center_).Length();
  103. }
  104. }
  105. Intersection Sphere::IsInside(const BoundingBox& box) const
  106. {
  107. float radiusSquared = radius_ * radius_;
  108. float distSquared = 0;
  109. float temp;
  110. Vector3 min = box.min_;
  111. Vector3 max = box.max_;
  112. if (center_.x_ < min.x_)
  113. {
  114. temp = center_.x_ - min.x_;
  115. distSquared += temp * temp;
  116. }
  117. else if (center_.x_ > max.x_)
  118. {
  119. temp = center_.x_ - max.x_;
  120. distSquared += temp * temp;
  121. }
  122. if (center_.y_ < min.y_)
  123. {
  124. temp = center_.y_ - min.y_;
  125. distSquared += temp * temp;
  126. }
  127. else if (center_.y_ > max.y_)
  128. {
  129. temp = center_.y_ - max.y_;
  130. distSquared += temp * temp;
  131. }
  132. if (center_.z_ < min.z_)
  133. {
  134. temp = center_.z_ - min.z_;
  135. distSquared += temp * temp;
  136. }
  137. else if (center_.z_ > max.z_)
  138. {
  139. temp = center_.z_ - max.z_;
  140. distSquared += temp * temp;
  141. }
  142. if (distSquared >= radiusSquared)
  143. return OUTSIDE;
  144. min -= center_;
  145. max -= center_;
  146. Vector3 tempVec = min; // - - -
  147. if (tempVec.LengthSquared() >= radiusSquared)
  148. return INTERSECTS;
  149. tempVec.x_ = max.x_; // + - -
  150. if (tempVec.LengthSquared() >= radiusSquared)
  151. return INTERSECTS;
  152. tempVec.y_ = max.y_; // + + -
  153. if (tempVec.LengthSquared() >= radiusSquared)
  154. return INTERSECTS;
  155. tempVec.x_ = min.x_; // - + -
  156. if (tempVec.LengthSquared() >= radiusSquared)
  157. return INTERSECTS;
  158. tempVec.z_ = max.z_; // - + +
  159. if (tempVec.LengthSquared() >= radiusSquared)
  160. return INTERSECTS;
  161. tempVec.y_ = min.y_; // - - +
  162. if (tempVec.LengthSquared() >= radiusSquared)
  163. return INTERSECTS;
  164. tempVec.x_ = max.x_; // + - +
  165. if (tempVec.LengthSquared() >= radiusSquared)
  166. return INTERSECTS;
  167. tempVec.y_ = max.y_; // + + +
  168. if (tempVec.LengthSquared() >= radiusSquared)
  169. return INTERSECTS;
  170. return INSIDE;
  171. }
  172. Intersection Sphere::IsInsideFast(const BoundingBox& box) const
  173. {
  174. float radiusSquared = radius_ * radius_;
  175. float distSquared = 0;
  176. float temp;
  177. Vector3 min = box.min_;
  178. Vector3 max = box.max_;
  179. if (center_.x_ < min.x_)
  180. {
  181. temp = center_.x_ - min.x_;
  182. distSquared += temp * temp;
  183. }
  184. else if (center_.x_ > max.x_)
  185. {
  186. temp = center_.x_ - max.x_;
  187. distSquared += temp * temp;
  188. }
  189. if (center_.y_ < min.y_)
  190. {
  191. temp = center_.y_ - min.y_;
  192. distSquared += temp * temp;
  193. }
  194. else if (center_.y_ > max.y_)
  195. {
  196. temp = center_.y_ - max.y_;
  197. distSquared += temp * temp;
  198. }
  199. if (center_.z_ < min.z_)
  200. {
  201. temp = center_.z_ - min.z_;
  202. distSquared += temp * temp;
  203. }
  204. else if (center_.z_ > max.z_)
  205. {
  206. temp = center_.z_ - max.z_;
  207. distSquared += temp * temp;
  208. }
  209. if (distSquared >= radiusSquared)
  210. return OUTSIDE;
  211. else
  212. return INSIDE;
  213. }