GteDistPointHyperellipsoid.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/GteVector.h>
14 
15 // Compute the distance from a point to a hyperellipsoid. In 2D, this is a
16 // point-ellipse distance query. In 3D, this is a point-ellipsoid distance
17 // query. The following document describes the algorithm.
18 // http://www.geometrictools.com/Documentation/DistancePointEllipseEllipsoid.pdf
19 // The hyperellipsoid can have arbitrary center and orientation; that is, it
20 // does not have to be axis-aligned with center at the origin.
21 //
22 // For the 2D query,
23 // Vector2<Real> point; // initialized to something
24 // Ellipse2<Real> ellipse; // initialized to something
25 // DCPPoint2Ellipse2<Real> query;
26 // auto result = query(point, ellipse);
27 // Real distance = result.distance;
28 // Vector2<Real> closestEllipsePoint = result.closest;
29 //
30 // For the 3D query,
31 // Vector3<Real> point; // initialized to something
32 // Ellipsoid3<Real> ellipsoid; // initialized to something
33 // DCPPoint3Ellipsoid3<Real> query;
34 // auto result = query(point, ellipsoid);
35 // Real distance = result.distance;
36 // Vector3<Real> closestEllipsoidPoint = result.closest;
37 
38 namespace gte
39 {
40 
41 template <int N, typename Real>
42 class DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>
43 {
44 public:
45  struct Result
46  {
49  };
50 
51  // The query for any hyperellipsoid.
52  Result operator()(Vector<N, Real> const& point,
53  Hyperellipsoid<N, Real> const& hyperellipsoid);
54 
55  // The 'hyperellipsoid' is assumed to be axis-aligned and centered at the
56  // origin , so only the extent[] values are used.
57  Result operator()(Vector<N, Real> const& point,
58  Vector<N, Real> const& extent);
59 
60 private:
61  // The hyperellipsoid is sum_{d=0}^{N-1} (x[d]/e[d])^2 = 1 with no
62  // constraints on the orderind of the e[d]. The query point is
63  // (y[0],...,y[N-1]) with no constraints on the signs of the components.
64  // The function returns the squared distance from the query point to the
65  // hyperellipsoid. It also computes the hyperellipsoid point
66  // (x[0],...,x[N-1]) that is closest to (y[0],...,y[N-1]).
67  Real SqrDistance(Vector<N, Real> const& e,
69 
70  // The hyperellipsoid is sum_{d=0}^{N-1} (x[d]/e[d])^2 = 1 with the e[d]
71  // positive and nonincreasing: e[d] >= e[d + 1] for all d. The query
72  // point is (y[0],...,y[N-1]) with y[d] >= 0 for all d. The function
73  // returns the squared distance from the query point to the
74  // hyperellipsoid. It also computes the hyperellipsoid point
75  // (x[0],...,x[N-1]) that is closest to (y[0],...,y[N-1]), where
76  // x[d] >= 0 for all d.
77  Real SqrDistanceSpecial(Vector<N, Real> const& e,
79 
80  // The bisection algorithm to find the unique root of F(t).
81  Real Bisector(int numComponents, Vector<N, Real> const& e,
83 };
84 
85 // Template aliases for convenience.
86 template <int N, typename Real>
89 
90 template <typename Real>
92 
93 template <typename Real>
95 
96 
97 template <int N, typename Real>
98 typename DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::Result
99 DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::operator()(
100  Vector<N, Real> const& point,
101  Hyperellipsoid<N, Real> const& hyperellipsoid)
102 {
103  Result result;
104 
105  // Compute the coordinates of Y in the hyperellipsoid coordinate system.
106  Vector<N, Real> diff = point - hyperellipsoid.center;
108  for (int i = 0; i < N; ++i)
109  {
110  y[i] = Dot(diff, hyperellipsoid.axis[i]);
111  }
112 
113  // Compute the closest hyperellipsoid point in the axis-aligned
114  // coordinate system.
116  result.sqrDistance = SqrDistance(hyperellipsoid.extent, y, x);
117  result.distance = sqrt(result.sqrDistance);
118 
119  // Convert back to the original coordinate system.
120  result.closest = hyperellipsoid.center;
121  for (int i = 0; i < N; ++i)
122  {
123  result.closest += x[i] * hyperellipsoid.axis[i];
124  }
125 
126  return result;
127 }
128 
129 template <int N, typename Real>
130 typename DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::Result
131 DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::operator()(
132  Vector<N, Real> const& point, Vector<N, Real> const& extent)
133 {
134  Result result;
135  result.sqrDistance = SqrDistance(extent, point, result.closest);
136  result.distance = sqrt(result.sqrDistance);
137  return result;
138 }
139 
140 template <int N, typename Real>
141 Real DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::SqrDistance(
143 {
144  // Determine negations for y to the first octant.
145  std::array<bool, N> negate;
146  int i, j;
147  for (i = 0; i < N; ++i)
148  {
149  negate[i] = (y[i] < (Real)0);
150  }
151 
152  // Determine the axis order for decreasing extents.
153  std::array<std::pair<Real, int>, N> permute;
154  for (i = 0; i < N; ++i)
155  {
156  permute[i].first = -e[i];
157  permute[i].second = i;
158  }
159  std::sort(permute.begin(), permute.end());
160 
161  std::array<int, N> invPermute;
162  for (i = 0; i < N; ++i)
163  {
164  invPermute[permute[i].second] = i;
165  }
166 
167  Vector<N, Real> locE, locY;
168  for (i = 0; i < N; ++i)
169  {
170  j = permute[i].second;
171  locE[i] = e[j];
172  locY[i] = std::abs(y[j]);
173  }
174 
175  Vector<N, Real> locX;
176  Real sqrDistance = SqrDistanceSpecial(locE, locY, locX);
177 
178  // Restore the axis order and reflections.
179  for (i = 0; i < N; ++i)
180  {
181  j = invPermute[i];
182  if (negate[i])
183  {
184  locX[j] = -locX[j];
185  }
186  x[i] = locX[j];
187  }
188 
189  return sqrDistance;
190 }
191 
192 template <int N, typename Real>
193 Real DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::
194 SqrDistanceSpecial(Vector<N, Real> const& e, Vector<N, Real> const& y,
196 {
197  Real sqrDistance = (Real)0;
198 
199  Vector<N, Real> ePos, yPos, xPos;
200  int numPos = 0;
201  int i;
202  for (i = 0; i < N; ++i)
203  {
204  if (y[i] >(Real)0)
205  {
206  ePos[numPos] = e[i];
207  yPos[numPos] = y[i];
208  ++numPos;
209  }
210  else
211  {
212  x[i] = (Real)0;
213  }
214  }
215 
216  if (y[N - 1] > (Real)0)
217  {
218  sqrDistance = Bisector(numPos, ePos, yPos, xPos);
219  }
220  else // y[N-1] = 0
221  {
222  Vector<N - 1, Real> numer, denom;
223  Real eNm1Sqr = e[N - 1] * e[N - 1];
224  for (i = 0; i < numPos; ++i)
225  {
226  numer[i] = ePos[i] * yPos[i];
227  denom[i] = ePos[i] * ePos[i] - eNm1Sqr;
228  }
229 
230  bool inSubHyperbox = true;
231  for (i = 0; i < numPos; ++i)
232  {
233  if (numer[i] >= denom[i])
234  {
235  inSubHyperbox = false;
236  break;
237  }
238  }
239 
240  bool inSubHyperellipsoid = false;
241  if (inSubHyperbox)
242  {
243  // yPos[] is inside the axis-aligned bounding box of the
244  // subhyperellipsoid. This intermediate test is designed to guard
245  // against the division by zero when ePos[i] == e[N-1] for some i.
246  Vector<N - 1, Real> xde;
247  Real discr = (Real)1;
248  for (i = 0; i < numPos; ++i)
249  {
250  xde[i] = numer[i] / denom[i];
251  discr -= xde[i] * xde[i];
252  }
253  if (discr >(Real)0)
254  {
255  // yPos[] is inside the subhyperellipsoid. The closest
256  // hyperellipsoid point has x[N-1] > 0.
257  sqrDistance = (Real)0;
258  for (i = 0; i < numPos; ++i)
259  {
260  xPos[i] = ePos[i] * xde[i];
261  Real diff = xPos[i] - yPos[i];
262  sqrDistance += diff*diff;
263  }
264  x[N - 1] = e[N - 1] * sqrt(discr);
265  sqrDistance += x[N - 1] * x[N - 1];
266  inSubHyperellipsoid = true;
267  }
268  }
269 
270  if (!inSubHyperellipsoid)
271  {
272  // yPos[] is outside the subhyperellipsoid. The closest
273  // hyperellipsoid point has x[N-1] == 0 and is on the
274  // domain-boundary hyperellipsoid.
275  x[N - 1] = (Real)0;
276  sqrDistance = Bisector(numPos, ePos, yPos, xPos);
277  }
278  }
279 
280  // Fill in those x[] values that were not zeroed out initially.
281  for (i = 0, numPos = 0; i < N; ++i)
282  {
283  if (y[i] >(Real)0)
284  {
285  x[i] = xPos[numPos];
286  ++numPos;
287  }
288  }
289 
290  return sqrDistance;
291 }
292 
293 template <int N, typename Real>
294 Real DCPQuery<Real, Vector<N, Real>, Hyperellipsoid<N, Real>>::Bisector(
295  int numComponents, Vector<N, Real> const& e, Vector<N, Real> const& y,
297 {
299  Real sumZSqr = (Real)0;
300  int i;
301  for (i = 0; i < numComponents; ++i)
302  {
303  z[i] = y[i] / e[i];
304  sumZSqr += z[i] * z[i];
305  }
306 
307  if (sumZSqr == (Real)1)
308  {
309  // The point is on the hyperellipsoid.
310  for (i = 0; i < numComponents; ++i)
311  {
312  x[i] = y[i];
313  }
314  return (Real)0;
315  }
316 
317  Real emin = e[numComponents - 1];
319  for (i = 0; i < numComponents; ++i)
320  {
321  Real p = e[i] / emin;
322  pSqr[i] = p * p;
323  numerator[i] = pSqr[i] * z[i];
324  }
325 
326  Real s = (Real)0, smin = z[numComponents - 1] - (Real)1, smax;
327  if (sumZSqr < (Real)1)
328  {
329  // The point is strictly inside the hyperellipsoid.
330  smax = (Real)0;
331  }
332  else
333  {
334  // The point is strictly outside the hyperellipsoid.
335  smax = Length(numerator, true) - (Real)1;
336  }
337 
338  // The use of 'double' is intentional in case Real is a BSNumber or
339  // BSRational type. We want the bisections to terminate in a reasonable
340  // amount of time.
341  unsigned int const jmax = Function<double>::GetMaxBisections();
342  for (unsigned int j = 0; j < jmax; ++j)
343  {
344  s = (smin + smax) * (Real)0.5;
345  if (s == smin || s == smax)
346  {
347  break;
348  }
349 
350  Real g = (Real)-1;
351  for (i = 0; i < numComponents; ++i)
352  {
353  Real ratio = numerator[i] / (s + pSqr[i]);
354  g += ratio * ratio;
355  }
356 
357  if (g >(Real)0)
358  {
359  smin = s;
360  }
361  else if (g < (Real)0)
362  {
363  smax = s;
364  }
365  else
366  {
367  break;
368  }
369  }
370 
371  Real sqrDistance = (Real)0;
372  for (i = 0; i < numComponents; ++i)
373  {
374  x[i] = pSqr[i] * y[i] / (s + pSqr[i]);
375  Real diff = x[i] - y[i];
376  sqrDistance += diff*diff;
377  }
378  return sqrDistance;
379 }
380 
381 
382 }
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
static unsigned int GetMaxBisections()
GLsizei GLsizei GLfloat distance
Definition: glext.h:9704
GLint GLenum GLint x
Definition: glcorearb.h:404
GLboolean GLboolean g
Definition: glcorearb.h:1217
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
INT32 * numerator
Definition: wglext.h:821
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:843
DualQuaternion< Real > Length(DualQuaternion< Real > const &d, bool robust=false)
GLdouble s
Definition: glext.h:231
GLfloat GLfloat p
Definition: glext.h:11668
GLuint64EXT * result
Definition: glext.h:10003
GLint y
Definition: glcorearb.h:98


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