GteContCapsule3.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 
13 #include <Mathematics/GteCapsule.h>
15 
16 namespace gte
17 {
18 
19 // Compute the axis of the capsule segment using least-squares fitting. The
20 // radius is the maximum distance from the points to the axis. Hemispherical
21 // caps are chosen as close together as possible.
22 template <typename Real>
23 bool GetContainer(int numPoints, Vector3<Real> const* points,
24  Capsule3<Real>& capsule);
25 
26 // Test for containment of a point by a capsule.
27 template <typename Real>
28 bool InContainer(Vector3<Real> const& point, Capsule3<Real> const& capsule);
29 
30 // Test for containment of a sphere by a capsule.
31 template <typename Real>
32 bool InContainer(Sphere3<Real> const& sphere, Capsule3<Real> const& capsule);
33 
34 // Test for containment of a capsule by a capsule.
35 template <typename Real>
36 bool InContainer(Capsule3<Real> const& testCapsule,
37  Capsule3<Real> const& capsule);
38 
39 // Compute a capsule that contains the input capsules. The returned capsule
40 // is not necessarily the one of smallest volume that contains the inputs.
41 template <typename Real>
42 bool MergeContainers(Capsule3<Real> const& capsule0,
43  Capsule3<Real> const& capsule1, Capsule3<Real>& merge);
44 
45 
46 template <typename Real>
47 bool GetContainer(int numPoints, Vector3<Real> const* points,
48  Capsule3<Real>& capsule)
49 {
51  fitter.Fit(numPoints, points);
52  Line3<Real> line = fitter.GetParameters();
53 
55  Real maxRadiusSqr = (Real)0;
56  for (int i = 0; i < numPoints; ++i)
57  {
58  auto result = plQuery(points[i], line);
59  if (result.sqrDistance > maxRadiusSqr)
60  {
61  maxRadiusSqr = result.sqrDistance;
62  }
63  }
64 
65  Vector3<Real> basis[3];
66  basis[0] = line.direction;
68 
69  Real minValue = std::numeric_limits<Real>::max();
70  Real maxValue = -std::numeric_limits<Real>::max();
71  for (int i = 0; i < numPoints; ++i)
72  {
73  Vector3<Real> diff = points[i] - line.origin;
74  Real uDotDiff = Dot(diff, basis[1]);
75  Real vDotDiff = Dot(diff, basis[2]);
76  Real wDotDiff = Dot(diff, basis[0]);
77  Real discr = maxRadiusSqr - (uDotDiff*uDotDiff + vDotDiff*vDotDiff);
78  Real radical = sqrt(std::max(discr, (Real)0));
79 
80  Real test = wDotDiff + radical;
81  if (test < minValue)
82  {
83  minValue = test;
84  }
85 
86  test = wDotDiff - radical;
87  if (test > maxValue)
88  {
89  maxValue = test;
90  }
91  }
92 
93  Vector3<Real> center = line.origin +
94  (((Real)0.5)*(minValue + maxValue))*line.direction;
95 
96  Real extent;
97  if (maxValue > minValue)
98  {
99  // Container is a capsule.
100  extent = ((Real)0.5)*(maxValue - minValue);
101  }
102  else
103  {
104  // Container is a sphere.
105  extent = (Real)0;
106  }
107 
108  capsule.segment = Segment3<Real>(center, line.direction, extent);
109  capsule.radius = sqrt(maxRadiusSqr);
110  return true;
111 }
112 
113 template <typename Real>
114 bool InContainer(Vector3<Real> const& point, Capsule3<Real> const& capsule)
115 {
117  auto result = psQuery(point, capsule.segment);
118  return result.distance <= capsule.radius;
119 }
120 
121 template <typename Real>
122 bool InContainer(Sphere3<Real> const& sphere, Capsule3<Real> const& capsule)
123 {
124  Real rDiff = capsule.radius - sphere.radius;
125  if (rDiff >= (Real)0)
126  {
128  auto result = psQuery(sphere.center, capsule.segment);
129  return result.distance <= rDiff;
130  }
131  return false;
132 }
133 
134 template <typename Real>
135 bool InContainer(Capsule3<Real> const& testCapsule,
136  Capsule3<Real> const& capsule)
137 {
138  Sphere3<Real> spherePosEnd(testCapsule.segment.p[1], testCapsule.radius);
139  Sphere3<Real> sphereNegEnd(testCapsule.segment.p[0], testCapsule.radius);
140  return InContainer<Real>(spherePosEnd, capsule)
141  && InContainer<Real>(sphereNegEnd, capsule);
142 }
143 
144 template <typename Real>
145 bool MergeContainers(Capsule3<Real> const& capsule0,
146  Capsule3<Real> const& capsule1, Capsule3<Real>& merge)
147 {
148  if (InContainer<Real>(capsule0, capsule1))
149  {
150  merge = capsule1;
151  return true;
152  }
153 
154  if (InContainer<Real>(capsule1, capsule0))
155  {
156  merge = capsule0;
157  return true;
158  }
159 
160  Vector3<Real> P0, P1, D0, D1;
161  Real extent0, extent1;
162  capsule0.segment.GetCenteredForm(P0, D0, extent0);
163  capsule1.segment.GetCenteredForm(P1, D1, extent1);
164 
165  // Axis of final capsule.
166  Line3<Real> line;
167 
168  // Axis center is average of input axis centers.
169  line.origin = ((Real)0.5)*(P0 + P1);
170 
171  // Axis unit direction is average of input axis unit directions.
172  if (Dot(D0, D1) >= (Real)0)
173  {
174  line.direction = D0 + D1;
175  }
176  else
177  {
178  line.direction = D0 - D1;
179  }
180  Normalize(line.direction);
181 
182  // Cylinder with axis 'line' must contain the spheres centered at the
183  // endpoints of the input capsules.
185  Vector3<Real> posEnd0 = capsule0.segment.p[1];
186  Real radius = plQuery(posEnd0, line).distance + capsule0.radius;
187 
188  Vector3<Real> negEnd0 = capsule0.segment.p[0];
189  Real tmp = plQuery(negEnd0, line).distance + capsule0.radius;
190 
191  Vector3<Real> posEnd1 = capsule1.segment.p[1];
192  tmp = plQuery(posEnd1, line).distance + capsule1.radius;
193  if (tmp > radius)
194  {
195  radius = tmp;
196  }
197 
198  Vector3<Real> negEnd1 = capsule1.segment.p[0];
199  tmp = plQuery(negEnd1, line).distance + capsule1.radius;
200  if (tmp > radius)
201  {
202  radius = tmp;
203  }
204 
205  // Process sphere <posEnd0,r0>.
206  Real rDiff = radius - capsule0.radius;
207  Real rDiffSqr = rDiff*rDiff;
208  Vector3<Real> diff = line.origin - posEnd0;
209  Real k0 = Dot(diff, diff) - rDiffSqr;
210  Real k1 = Dot(diff, line.direction);
211  Real discr = k1*k1 - k0; // assert: k1*k1-k0 >= 0, guard against anyway
212  Real root = sqrt(std::max(discr, (Real)0));
213  Real tPos = -k1 - root;
214  Real tNeg = -k1 + root;
215 
216  // Process sphere <negEnd0,r0>.
217  diff = line.origin - negEnd0;
218  k0 = Dot(diff, diff) - rDiffSqr;
219  k1 = Dot(diff, line.direction);
220  discr = k1*k1 - k0; // assert: k1*k1-k0 >= 0, guard against anyway
221  root = sqrt(std::max(discr, (Real)0));
222  tmp = -k1 - root;
223  if (tmp > tPos)
224  {
225  tPos = tmp;
226  }
227  tmp = -k1 + root;
228  if (tmp < tNeg)
229  {
230  tNeg = tmp;
231  }
232 
233  // Process sphere <posEnd1,r1>.
234  rDiff = radius - capsule1.radius;
235  rDiffSqr = rDiff*rDiff;
236  diff = line.origin - posEnd1;
237  k0 = Dot(diff, diff) - rDiffSqr;
238  k1 = Dot(diff, line.direction);
239  discr = k1*k1 - k0; // assert: k1*k1-k0 >= 0, guard against anyway
240  root = sqrt(std::max(discr, (Real)0));
241  tmp = -k1 - root;
242  if (tmp > tPos)
243  {
244  tPos = tmp;
245  }
246  tmp = -k1 + root;
247  if (tmp < tNeg)
248  {
249  tNeg = tmp;
250  }
251 
252  // Process sphere <negEnd1,r1>.
253  diff = line.origin - negEnd1;
254  k0 = Dot(diff, diff) - rDiffSqr;
255  k1 = Dot(diff, line.direction);
256  discr = k1*k1 - k0; // assert: k1*k1-k0 >= 0, guard against anyway
257  root = sqrt(std::max(discr, (Real)0));
258  tmp = -k1 - root;
259  if (tmp > tPos)
260  {
261  tPos = tmp;
262  }
263  tmp = -k1 + root;
264  if (tmp < tNeg)
265  {
266  tNeg = tmp;
267  }
268 
269  Vector3<Real> center = line.origin +
270  ((Real)0.5)*(tPos + tNeg)*line.direction;
271 
272  Real extent;
273  if (tPos > tNeg)
274  {
275  // Container is a capsule.
276  extent = ((Real)0.5)*(tPos - tNeg);
277  }
278  else
279  {
280  // Container is a sphere.
281  extent = (Real)0;
282  }
283 
284  merge.segment = Segment3<Real>(center, line.direction, extent);
285  merge.radius = radius;
286  return true;
287 }
288 
289 
290 }
bool GetContainer(int numPoints, Vector3< Real > const *points, Capsule3< Real > &capsule)
bool MergeContainers(Capsule3< Real > const &capsule0, Capsule3< Real > const &capsule1, Capsule3< Real > &merge)
bool InContainer(Vector3< Real > const &point, Capsule3< Real > const &capsule)
Vector< N, Real > direction
Definition: GteLine.h:29
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Segment< N, Real > segment
Definition: GteCapsule.h:29
Real Normalize(GVector< Real > &v, bool robust=false)
Definition: GteGVector.h:454
bool Fit(int numPoints, Vector3< Real > const *points)
Vector< N, Real > origin
Definition: GteLine.h:29
Real ComputeOrthogonalComplement(int numInputs, Vector2< Real > *v, bool robust=false)
Definition: GteVector2.h:123
Vector< N, Real > center
Line3< Real > const & GetParameters() const
GLuint64EXT * result
Definition: glext.h:10003


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