Sphere.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Math/Frustum.h"
  5. #include "../Math/Polyhedron.h"
  6. #include "../DebugNew.h"
  7. namespace Urho3D
  8. {
  9. void Sphere::Define(const Vector3* vertices, i32 count)
  10. {
  11. assert(count >= 0);
  12. if (!count)
  13. return;
  14. Clear();
  15. Merge(vertices, count);
  16. }
  17. void Sphere::Define(const BoundingBox& box)
  18. {
  19. const Vector3& min = box.min_;
  20. const Vector3& max = box.max_;
  21. Clear();
  22. Merge(min);
  23. Merge(Vector3(max.x_, min.y_, min.z_));
  24. Merge(Vector3(min.x_, max.y_, min.z_));
  25. Merge(Vector3(max.x_, max.y_, min.z_));
  26. Merge(Vector3(min.x_, min.y_, max.z_));
  27. Merge(Vector3(max.x_, min.y_, max.z_));
  28. Merge(Vector3(min.x_, max.y_, max.z_));
  29. Merge(max);
  30. }
  31. void Sphere::Define(const Frustum& frustum)
  32. {
  33. Define(frustum.vertices_, NUM_FRUSTUM_VERTICES);
  34. }
  35. void Sphere::Define(const Polyhedron& poly)
  36. {
  37. Clear();
  38. Merge(poly);
  39. }
  40. void Sphere::Merge(const Vector3* vertices, i32 count)
  41. {
  42. assert(count >= 0);
  43. while (count--)
  44. Merge(*vertices++);
  45. }
  46. void Sphere::Merge(const BoundingBox& box)
  47. {
  48. const Vector3& min = box.min_;
  49. const Vector3& max = box.max_;
  50. Merge(min);
  51. Merge(Vector3(max.x_, min.y_, min.z_));
  52. Merge(Vector3(min.x_, max.y_, min.z_));
  53. Merge(Vector3(max.x_, max.y_, min.z_));
  54. Merge(Vector3(min.x_, min.y_, max.z_));
  55. Merge(Vector3(max.x_, min.y_, max.z_));
  56. Merge(Vector3(min.x_, max.y_, max.z_));
  57. Merge(max);
  58. }
  59. void Sphere::Merge(const Frustum& frustum)
  60. {
  61. const Vector3* vertices = frustum.vertices_;
  62. Merge(vertices, NUM_FRUSTUM_VERTICES);
  63. }
  64. void Sphere::Merge(const Polyhedron& poly)
  65. {
  66. for (const Vector<Vector3>& face : poly.faces_)
  67. {
  68. if (!face.Empty())
  69. Merge(&face[0], face.Size());
  70. }
  71. }
  72. void Sphere::Merge(const Sphere& sphere)
  73. {
  74. if (radius_ < 0.0f)
  75. {
  76. center_ = sphere.center_;
  77. radius_ = sphere.radius_;
  78. return;
  79. }
  80. Vector3 offset = sphere.center_ - center_;
  81. float dist = offset.Length();
  82. // If sphere fits inside, do nothing
  83. if (dist + sphere.radius_ < radius_)
  84. return;
  85. // If we fit inside the other sphere, become it
  86. if (dist + radius_ < sphere.radius_)
  87. {
  88. center_ = sphere.center_;
  89. radius_ = sphere.radius_;
  90. }
  91. else
  92. {
  93. Vector3 NormalizedOffset = offset / dist;
  94. Vector3 min = center_ - radius_ * NormalizedOffset;
  95. Vector3 max = sphere.center_ + sphere.radius_ * NormalizedOffset;
  96. center_ = (min + max) * 0.5f;
  97. radius_ = (max - center_).Length();
  98. }
  99. }
  100. Intersection Sphere::IsInside(const BoundingBox& box) const
  101. {
  102. float radiusSquared = radius_ * radius_;
  103. float distSquared = 0;
  104. float temp;
  105. Vector3 min = box.min_;
  106. Vector3 max = box.max_;
  107. if (center_.x_ < min.x_)
  108. {
  109. temp = center_.x_ - min.x_;
  110. distSquared += temp * temp;
  111. }
  112. else if (center_.x_ > max.x_)
  113. {
  114. temp = center_.x_ - max.x_;
  115. distSquared += temp * temp;
  116. }
  117. if (center_.y_ < min.y_)
  118. {
  119. temp = center_.y_ - min.y_;
  120. distSquared += temp * temp;
  121. }
  122. else if (center_.y_ > max.y_)
  123. {
  124. temp = center_.y_ - max.y_;
  125. distSquared += temp * temp;
  126. }
  127. if (center_.z_ < min.z_)
  128. {
  129. temp = center_.z_ - min.z_;
  130. distSquared += temp * temp;
  131. }
  132. else if (center_.z_ > max.z_)
  133. {
  134. temp = center_.z_ - max.z_;
  135. distSquared += temp * temp;
  136. }
  137. if (distSquared >= radiusSquared)
  138. return OUTSIDE;
  139. min -= center_;
  140. max -= center_;
  141. Vector3 tempVec = min; // - - -
  142. if (tempVec.LengthSquared() >= radiusSquared)
  143. return INTERSECTS;
  144. tempVec.x_ = max.x_; // + - -
  145. if (tempVec.LengthSquared() >= radiusSquared)
  146. return INTERSECTS;
  147. tempVec.y_ = max.y_; // + + -
  148. if (tempVec.LengthSquared() >= radiusSquared)
  149. return INTERSECTS;
  150. tempVec.x_ = min.x_; // - + -
  151. if (tempVec.LengthSquared() >= radiusSquared)
  152. return INTERSECTS;
  153. tempVec.z_ = max.z_; // - + +
  154. if (tempVec.LengthSquared() >= radiusSquared)
  155. return INTERSECTS;
  156. tempVec.y_ = min.y_; // - - +
  157. if (tempVec.LengthSquared() >= radiusSquared)
  158. return INTERSECTS;
  159. tempVec.x_ = max.x_; // + - +
  160. if (tempVec.LengthSquared() >= radiusSquared)
  161. return INTERSECTS;
  162. tempVec.y_ = max.y_; // + + +
  163. if (tempVec.LengthSquared() >= radiusSquared)
  164. return INTERSECTS;
  165. return INSIDE;
  166. }
  167. Intersection Sphere::IsInsideFast(const BoundingBox& box) const
  168. {
  169. float radiusSquared = radius_ * radius_;
  170. float distSquared = 0;
  171. float temp;
  172. Vector3 min = box.min_;
  173. Vector3 max = box.max_;
  174. if (center_.x_ < min.x_)
  175. {
  176. temp = center_.x_ - min.x_;
  177. distSquared += temp * temp;
  178. }
  179. else if (center_.x_ > max.x_)
  180. {
  181. temp = center_.x_ - max.x_;
  182. distSquared += temp * temp;
  183. }
  184. if (center_.y_ < min.y_)
  185. {
  186. temp = center_.y_ - min.y_;
  187. distSquared += temp * temp;
  188. }
  189. else if (center_.y_ > max.y_)
  190. {
  191. temp = center_.y_ - max.y_;
  192. distSquared += temp * temp;
  193. }
  194. if (center_.z_ < min.z_)
  195. {
  196. temp = center_.z_ - min.z_;
  197. distSquared += temp * temp;
  198. }
  199. else if (center_.z_ > max.z_)
  200. {
  201. temp = center_.z_ - max.z_;
  202. distSquared += temp * temp;
  203. }
  204. if (distSquared >= radiusSquared)
  205. return OUTSIDE;
  206. else
  207. return INSIDE;
  208. }
  209. Vector3 Sphere::GetLocalPoint(float theta, float phi) const
  210. {
  211. return Vector3(
  212. radius_ * Sin(theta) * Sin(phi),
  213. radius_ * Cos(phi),
  214. radius_ * Cos(theta) * Sin(phi)
  215. );
  216. }
  217. }