GteIntrOrientedBox2Circle2.h
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 #pragma once
9 
10 #include <Mathematics/GteVector2.h>
13 #include <Mathematics/GteFIQuery.h>
14 #include <Mathematics/GteTIQuery.h>
15 
16 namespace gte
17 {
18 
19 template <typename Real>
20 class TIQuery<Real, OrientedBox2<Real>, Circle2<Real>>
21 {
22 public:
23  // The intersection query considers the box and circle to be solids.
24  // For example, if the circle is strictly inside the box (does not touch
25  // the box edges), the objects intersect.
26  struct Result
27  {
28  bool intersect;
29  };
30 
31  Result operator()(OrientedBox2<Real> const& box,
32  Circle2<Real> const& circle);
33 };
34 
35 template <typename Real>
36 class FIQuery<Real, OrientedBox2<Real>, Circle2<Real>>
37 {
38 public:
39  // Currently, only a dynamic query is supported. The static query must
40  // compute the intersection set of (solid) box and circle.
41  struct Result
42  {
43  bool intersect;
46  };
47 
48  Result operator()(Real maxTime, OrientedBox2<Real> const& box,
49  Vector2<Real> const& boxVelocity, Circle2<Real> const& circle,
50  Vector2<Real> const& circleVelocity);
51 
52 private:
53  // Support for dynamic query. Both functions return -1 if the objects are
54  // initially intersecting, 0 if no intersection, or +1 if they intersect
55  // at some positive time.
56  int TestVertexRegion(Real cx, Real cy, Real vx, Real vy, Real ex,
57  Real ey, Real& ix, Real& iy, Real radius, Real& contactTime);
58 
59  int TestEdgeRegion(Real cx, Real cy, Real vx, Real vy, Real ex, Real ey,
60  Real& ix, Real& iy, Real radius, Real& contactTime);
61 };
62 
63 
64 template <typename Real>
67  OrientedBox2<Real> const& box, Circle2<Real> const& circle)
68 {
70  auto pbResult = pbQuery(circle.center, box);
71  Result result;
72  result.intersect = (pbResult.distance <= circle.radius);
73  return result;
74 }
75 
76 
77 
78 template <typename Real>
81  OrientedBox2<Real> const& box, Vector2<Real> const& boxVelocity,
82  Circle2<Real> const& circle, Vector2<Real> const& circleVelocity)
83 {
84  Result result;
85 
86  // Convert circle center to box coordinates.
87  Vector2<Real> diff = circle.center - box.center;
88  Vector2<Real> relativeVelocity = circleVelocity - boxVelocity;
89  Real cx = Dot(diff, box.axis[0]);
90  Real cy = Dot(diff, box.axis[1]);
91  Real vx = Dot(relativeVelocity, box.axis[0]);
92  Real vy = Dot(relativeVelocity, box.axis[1]);
93  Real ex = box.extent[0];
94  Real ey = box.extent[1];
95  Real ix, iy;
96 
97  int type = 0;
98 
99  if (cx < -ex)
100  {
101  if (cy < -ey)
102  {
103  // region Rmm
104  type = TestVertexRegion(cx, cy, vx, vy, ex, ey, ix, iy,
105  circle.radius, result.contactTime);
106  }
107  else if (cy <= ey)
108  {
109  // region Rmz
110  type = TestEdgeRegion(cx, cy, vx, vy, ex, ey, ix, iy,
111  circle.radius, result.contactTime);
112  }
113  else
114  {
115  // region Rmp
116  type = TestVertexRegion(cx, -cy, vx, -vy, ex, ey, ix, iy,
117  circle.radius, result.contactTime);
118  iy = -iy;
119  }
120  }
121  else if (cx <= ex)
122  {
123  if (cy < -ey)
124  {
125  // region Rzm
126  type = TestEdgeRegion(cy, cx, vy, vx, ey, ex, iy, ix,
127  circle.radius, result.contactTime);
128  }
129  else if (cy <= ey)
130  {
131  // region Rzz: The circle is already intersecting the box. Use
132  // it as the intersection point.
133  result.intersect = true;
134  result.contactTime = (Real)0;
135  result.contactPoint = circle.center;
136  return result;
137  }
138  else
139  {
140  // region Rzp
141  type = TestEdgeRegion(-cy, cx, -vy, vx, ey, ex, iy, ix,
142  circle.radius, result.contactTime);
143  iy = -iy;
144  }
145  }
146  else
147  {
148  if (cy < -ey)
149  {
150  // region Rpm
151  type = TestVertexRegion(-cx, cy, -vx, vy, ex, ey, ix, iy,
152  circle.radius, result.contactTime);
153  ix = -ix;
154  }
155  else if (cy <= ey)
156  {
157  // region Rpz
158  type = TestEdgeRegion(-cx, cy, -vx, vy, ex, ey, ix, iy,
159  circle.radius, result.contactTime);
160  ix = -ix;
161  }
162  else
163  {
164  // region Rpp
165  type = TestVertexRegion(-cx, -cy, -vx, -vy, ex, ey, ix, iy,
166  circle.radius, result.contactTime);
167  ix = -ix;
168  iy = -iy;
169  }
170  }
171 
172  if (type != 1 || result.contactTime > maxTime)
173  {
174  result.intersect = false;
175  return result;
176  }
177 
178  result.intersect = true;
179  result.contactPoint = box.center + ix*box.axis[0] + iy*box.axis[1];
180  return result;
181 }
182 
183 template <typename Real>
185  Real cx, Real cy, Real vx, Real vy, Real ex, Real ey, Real& ix, Real& iy,
186  Real radius, Real& contactTime)
187 {
188  Real dx = cx + ex;
189  Real dy = cy + ey;
190  Real rsqr = radius*radius;
191  Real diff = dx*dx + dy*dy - rsqr;
192  if (diff <= (Real)0)
193  {
194  // Circle is already intersecting the box.
195  contactTime = (Real)0;
196  return -1;
197  }
198 
199  Real dot = vx*dx + vy*dy;
200  if (dot >= (Real)0)
201  {
202  // Circle not moving towards box.
203  return 0;
204  }
205 
206  Real dotPerp = vx*dy - vy*dx;
207  Real vsqr, inv;
208 
209  if (dotPerp >= (Real)0)
210  {
211  // Potential contact on left edge.
212  if (dotPerp <= radius*vy)
213  {
214  // Lower left corner is first point of contact.
215  ix = -ex;
216  iy = -ey;
217  vsqr = vx*vx + vy*vy;
218  inv = ((Real)1) / sqrt(std::abs(dot*dot - vsqr*diff));
219  contactTime = diff*inv / ((Real)1 - dot*inv);
220  return 1;
221  }
222 
223  if (vx <= (Real)0)
224  {
225  // Passed corner, moving away from box.
226  return 0;
227  }
228 
229  vsqr = vx*vx + vy*vy;
230  dy = cy - ey;
231  dotPerp = vx*dy - vy*dx;
232  if (dotPerp >= (Real)0 && dotPerp*dotPerp > rsqr*vsqr)
233  {
234  // Circle misses box.
235  return 0;
236  }
237 
238  // Circle will intersect box. Determine first time and place of
239  // contact with x = xmin.
240  ix = -ex;
241 
242  if (dotPerp <= radius*vy)
243  {
244  // First contact on left edge of box.
245  contactTime = -(dx + radius) / vx;
246  iy = cy + contactTime*vy;
247  }
248  else
249  {
250  // First contact at upper left corner of box.
251  dot = vx*dx + vy*dy;
252  diff = dx*dx + dy*dy - rsqr;
253  inv = ((Real)1) / sqrt(std::abs(dot*dot - vsqr*diff));
254  contactTime = diff*inv / ((Real)1 - dot*inv);
255  iy = ey;
256  }
257  }
258  else
259  {
260  // Potential contact on bottom edge.
261  if (-dotPerp <= radius*vx)
262  {
263  // Lower left corner is first point of contact.
264  ix = -ex;
265  iy = -ey;
266  vsqr = vx*vx + vy*vy;
267  inv = ((Real)1) / sqrt(std::abs(dot*dot - vsqr*diff));
268  contactTime = diff*inv / ((Real)1 - dot*inv);
269  return 1;
270  }
271 
272  if (vy <= (Real)0)
273  {
274  // Passed corner, moving away from box.
275  return 0;
276  }
277 
278  vsqr = vx*vx + vy*vy;
279  dx = cx - ex;
280  dotPerp = vx*dy - vy*dx;
281  if (-dotPerp >= (Real)0 && dotPerp*dotPerp > rsqr*vsqr)
282  {
283  // Circle misses box.
284  return 0;
285  }
286 
287  // Circle will intersect box. Determine first time and place of
288  // contact with y = ymin.
289  iy = -ey;
290 
291  if (-dotPerp <= radius*vx)
292  {
293  // First contact on bottom edge of box.
294  contactTime = -(dy + radius) / vy;
295  ix = cx + contactTime*vx;
296  }
297  else
298  {
299  // First contact at lower right corner of box.
300  dot = vx*dx + vy*dy;
301  diff = dx*dx + dy*dy - rsqr;
302  inv = ((Real)1) / sqrt(std::abs(dot*dot - vsqr*diff));
303  contactTime = diff*inv / ((Real)1 - dot*inv);
304  ix = ex;
305  }
306  }
307 
308  return 1;
309 }
310 
311 template <typename Real>
312 int FIQuery<Real, OrientedBox2<Real>, Circle2<Real>>::TestEdgeRegion(Real cx,
313  Real cy, Real vx, Real vy, Real ex, Real ey, Real& ix, Real& iy,
314  Real radius, Real& contactTime)
315 {
316  Real dx = cx + ex;
317  Real xSignedDist = dx + radius;
318  if (xSignedDist >= (Real)0)
319  {
320  // Circle is already intersecting the box.
321  contactTime = (Real)0;
322  return -1;
323  }
324 
325  if (vx <= (Real)0)
326  {
327  // Circle not moving towards box.
328  return 0;
329  }
330 
331  Real rsqr = radius*radius;
332  Real vsqr = vx*vx + vy*vy;
333  Real dy, dot, dotPerp, diff, inv;
334 
335  if (vy >= (Real)0)
336  {
337  dy = cy - ey;
338  dotPerp = vx*dy - vy*dx;
339  if (dotPerp >= (Real)0 && dotPerp*dotPerp > rsqr*vsqr)
340  {
341  // Circle misses box.
342  return 0;
343  }
344 
345  // Circle will intersect box. Determine first time and place of
346  // contact with x = xmin.
347  ix = -ex;
348 
349  if (dotPerp <= radius*vy)
350  {
351  // First contact on left edge of box.
352  contactTime = -xSignedDist / vx;
353  iy = cy + contactTime*vy;
354  }
355  else
356  {
357  // First contact at corner of box.
358  dot = vx*dx + vy*dy;
359  diff = dx*dx + dy*dy - rsqr;
360  inv = ((Real)1) / sqrt(std::abs(dot*dot - vsqr*diff));
361  contactTime = diff*inv / ((Real)1 - dot*inv);
362  iy = ey;
363  }
364  }
365  else
366  {
367  dy = cy + ey;
368  dotPerp = vx*dy - vy*dx;
369  if (dotPerp <= (Real)0 && dotPerp*dotPerp > rsqr*vsqr)
370  {
371  // Circle misses box.
372  return 0;
373  }
374 
375  // Circle will intersect box. Determine first time and place of
376  // contact with x = xmin.
377  ix = -ex;
378 
379  if (dotPerp >= radius*vy)
380  {
381  // First contact on left edge of box.
382  contactTime = -xSignedDist / vx;
383  iy = cy + contactTime*vy;
384  }
385  else
386  {
387  // First contact at corner of box.
388  dot = vx*dx + vy*dy;
389  diff = dx*dx + dy*dy - rsqr;
390  inv = ((Real)1) / sqrt(std::abs(dot*dot - vsqr*diff));
391  contactTime = diff*inv / ((Real)1 - dot*inv);
392  iy = -ey;
393  }
394  }
395 
396  return 1;
397 }
398 
399 
400 }
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
GLuint64EXT * result
Definition: glext.h:10003
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:103


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:00