GteBoundingSphere.cpp
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #include <GTEnginePCH.h>
10 using namespace gte;
11 
12 
14 {
15 }
16 
18  :
19  mTuple({ 0.0f, 0.0f, 0.0f, 0.0f })
20 {
21 }
22 
24  :
25  mTuple(sphere.mTuple)
26 {
27 }
28 
30 {
31  mTuple = sphere.mTuple;
32  return *this;
33 }
34 
35 int BoundingSphere::WhichSide(CullingPlane const& plane) const
36 {
37  float signedDistance = plane.DistanceTo(GetCenter());
38  float radius = GetRadius();
39 
40  if (signedDistance <= -radius)
41  {
42  return -1;
43  }
44 
45  if (signedDistance >= radius)
46  {
47  return +1;
48  }
49 
50  return 0;
51 }
52 
54 {
55  float radius1 = sphere.GetRadius();
56  if (radius1 == 0.0f)
57  {
58  // The incoming bound is invalid and cannot affect growth.
59  return;
60  }
61 
62  float radius0 = GetRadius();
63  if (radius0 == 0.0f)
64  {
65  // The current bound is invalid, so just assign the incoming bound.
66  mTuple = sphere.mTuple;
67  return;
68  }
69 
70  Vector4<float> center0 = GetCenter(), center1 = sphere.GetCenter();
71  Vector4<float> centerDiff = center1 - center0;
72  float lengthSqr = Dot(centerDiff, centerDiff);
73  float radiusDiff = radius1 - radius0;
74  float radiusDiffSqr = radiusDiff*radiusDiff;
75 
76  if (radiusDiffSqr >= lengthSqr)
77  {
78  if (radiusDiff >= 0.0f)
79  {
80  mTuple = sphere.mTuple;
81  }
82  return;
83  }
84 
85  float length = sqrt(lengthSqr);
86  if (length > 0.0f)
87  {
88  float coeff = (length + radiusDiff) / (2.0f*length);
89  SetCenter(center0 + coeff*centerDiff);
90  }
91 
92  SetRadius(0.5f*(length + radius0 + radius1));
93 }
94 
96  BoundingSphere& sphere) const
97 {
98 #if defined (GTE_USE_MAT_VEC)
99  sphere.SetCenter(transform * GetCenter());
100 #else
101  sphere.SetCenter(GetCenter() * transform);
102 #endif
103  sphere.SetRadius(transform.GetNorm() * GetRadius());
104 }
105 
106 void BoundingSphere::ComputeFromData(int numVertices, int vertexSize,
107  char const* data)
108 {
109  // The center is the average of the positions.
110  float sum[3] = { 0.0f, 0.0f, 0.0f };
111  int i;
112  for (i = 0; i < numVertices; ++i)
113  {
114  float const* position = (float const*)(data + i*vertexSize);
115  sum[0] += position[0];
116  sum[1] += position[1];
117  sum[2] += position[2];
118  }
119  float invNumVertices = 1.0f / (float)numVertices;
120  mTuple[0] = sum[0] * invNumVertices;
121  mTuple[1] = sum[1] * invNumVertices;
122  mTuple[2] = sum[2] * invNumVertices;
123 
124  // The radius is the largest distance from the center to the positions.
125  mTuple[3] = 0.0f;
126  for (i = 0; i < numVertices; ++i)
127  {
128  float const* position = (const float*)(data + i*vertexSize);
129  float diff[3] =
130  {
131  position[0] - mTuple[0],
132  position[1] - mTuple[1],
133  position[2] - mTuple[2]
134  };
135  float radiusSqr = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
136  if (radiusSqr > mTuple[3])
137  {
138  mTuple[3] = radiusSqr;
139  }
140  }
141 
142  mTuple[3] = sqrt(mTuple[3]);
143 }
144 
146  Vector4<float> const& direction, float tmin, float tmax) const
147 {
148  float radius = GetRadius();
149  if (radius == 0.0f)
150  {
151  // The bound is invalid and cannot be intersected.
152  LogWarning(
153  "Invalid bound. Did you forget to call UpdateModelBound()?");
154  return false;
155  }
156 
157  Vector4<float> center = GetCenter();
158  float const infinity = std::numeric_limits<float>::max();
159  Vector4<float> diff;
160  float a0, a1, discr;
161 
162  if (tmin == -infinity)
163  {
164  LogAssert(tmax == infinity, "tmax must be infinity for a line.");
165 
166  // Test for sphere-line intersection.
167  diff = origin - center;
168  a0 = Dot(diff, diff) - radius*radius;
169  a1 = Dot(direction, diff);
170  discr = a1*a1 - a0;
171  return discr >= 0.0f;
172  }
173 
174  if (tmax == infinity)
175  {
176  LogAssert(tmin == 0.0f, "tmin must be zero for a ray.");
177 
178  // Test for sphere-ray intersection.
179  diff = origin - center;
180  a0 = Dot(diff, diff) - radius*radius;
181  if (a0 <= 0.0f)
182  {
183  // The ray origin is inside the sphere.
184  return true;
185  }
186  // else: The ray origin is outside the sphere.
187 
188  a1 = Dot(direction, diff);
189  if (a1 >= 0.0f)
190  {
191  // The ray forms an acute angle with diff, and so the ray is
192  // directed from the sphere. Thus, the ray origin is outside
193  // the sphere, and points P+t*D for t >= 0 are even farther
194  // away from the sphere.
195  return false;
196  }
197 
198  discr = a1*a1 - a0;
199  return discr >= 0.0f;
200  }
201 
202  LogAssert(tmax > tmin, "tmin < tmax is required for a segment.");
203 
204  // Test for sphere-segment intersection.
205  float taverage = 0.5f*(tmin + tmax);
206  Vector4<float> segOrigin = origin + taverage * direction;
207  float segExtent = 0.5f * (tmax - tmin);
208 
209  diff = segOrigin - GetCenter();
210  a0 = Dot(diff, diff) - radius*radius;
211  if (a0 <= 0.0f)
212  {
213  // The segment center is inside the sphere.
214  return true;
215  }
216 
217  a1 = Dot(direction, diff);
218  discr = a1 * a1 - a0;
219  if (discr <= 0.0f)
220  {
221  // The line is outside the sphere, which implies the segment is also.
222  return false;
223  }
224 
225  // See "3D Game Engine Design (2nd edition)", Section 15.4.3 for the
226  // details of the test-intersection query for a segment and a sphere.
227  // In the book, 'qval' is the same as '(segment.e - |a1|)^2 - discr'.
228  float absA1 = fabs(a1);
229  float tmp = segExtent - absA1;
230  return tmp * tmp <= discr || segExtent >= absA1;
231 }
232 
234 {
235  if (sphere.GetRadius() == 0.0f || GetRadius() == 0.0f)
236  {
237  // One of the bounds is invalid and cannot be intersected.
238  LogWarning(
239  "Invalid bound. Did you forget to call UpdateModelBound()?");
240  return false;
241  }
242 
243  // Test for staticSphere-staticSphere intersection.
244  Vector4<float> diff = GetCenter() - sphere.GetCenter();
245  float rSum = GetRadius() + sphere.GetRadius();
246  return Dot(diff, diff) <= rSum*rSum;
247 }
248 
250  float tmax, Vector4<float> const& velocity0,
251  Vector4<float> const& velocity1) const
252 {
253  if (sphere.GetRadius() == 0.0f || GetRadius() == 0.0f)
254  {
255  // One of the bounds is invalid and cannot be intersected.
256  LogWarning(
257  "Invalid bound. Did you forget to call UpdateModelBound()?");
258  return false;
259  }
260 
261  // Test for movingSphere-movingSphere intersection.
262  Vector4<float> relVelocity = velocity1 - velocity0;
263  Vector4<float> cenDiff = sphere.GetCenter() - GetCenter();
264  float a = Dot(relVelocity, relVelocity);
265  float c = Dot(cenDiff, cenDiff);
266  float rSum = sphere.GetRadius() + GetRadius();
267  float rSumSqr = rSum*rSum;
268 
269  if (a > 0.0f)
270  {
271  float b = Dot(cenDiff, relVelocity);
272  if (b <= 0.0f)
273  {
274  if (-tmax*a <= b)
275  {
276  return a*c - b*b <= a*rSumSqr;
277  }
278  else
279  {
280  return tmax*(tmax*a + 2.0f*b) + c <= rSumSqr;
281  }
282  }
283  }
284 
285  return c <= rSumSqr;
286 }
287 
int WhichSide(CullingPlane const &plane) const
BoundingSphere & operator=(BoundingSphere const &sphere)
float GetRadius() const
float GetNorm() const
#define LogAssert(condition, message)
Definition: GteLogger.h:86
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1217
const GLubyte * c
Definition: glext.h:11671
void SetRadius(float radius)
GLboolean * data
Definition: glcorearb.h:126
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Vector4< float > GetCenter() const
#define LogWarning(message)
Definition: GteLogger.h:95
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1217
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:790
bool TestIntersection(Vector4< float > const &origin, Vector4< float > const &direction, float tmin, float tmax) const
GLfloat f
Definition: glcorearb.h:1921
void ComputeFromData(int numVertices, int vertexSize, char const *data)
GLuint GLenum GLenum transform
Definition: glext.h:10574
void GrowToContain(BoundingSphere const &sphere)
void TransformBy(Transform const &transform, BoundingSphere &sphere) const
Vector4< float > mTuple
float DistanceTo(Vector4< float > const &P) const
void SetCenter(Vector4< float > const &center)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59