GteIntpAkimaUniform2.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 <LowLevel/GteArray2.h>
11 #include <LowLevel/GteLogger.h>
12 #include <algorithm>
13 #include <cmath>
14 #include <cstring>
15 
16 // The interpolator is for uniformly spaced (x,y)-values. The input samples
17 // F must be stored in row-major order to represent f(x,y); that is,
18 // F[c + xBound*r] corresponds to f(x,y), where c is the index corresponding
19 // to x and r is the index corresponding to y.
20 
21 namespace gte
22 {
23 
24 template <typename Real>
26 {
27 public:
28  // Construction and destruction.
30  IntpAkimaUniform2(int xBound, int yBound, Real xMin, Real xSpacing,
31  Real yMin, Real ySpacing, Real const* F);
32 
33  // Member access.
34  inline int GetXBound() const;
35  inline int GetYBound() const;
36  inline int GetQuantity() const;
37  inline Real const* GetF() const;
38  inline Real GetXMin() const;
39  inline Real GetXMax() const;
40  inline Real GetXSpacing() const;
41  inline Real GetYMin() const;
42  inline Real GetYMax() const;
43  inline Real GetYSpacing() const;
44 
45  // Evaluate the function and its derivatives. The functions clamp the
46  // inputs to xmin <= x <= xmax and ymin <= y <= ymax. The first operator
47  // is for function evaluation. The second operator is for function or
48  // derivative evaluations. The xOrder argument is the order of the
49  // x-derivative and the yOrder argument is the order of the y-derivative.
50  // Both orders are zero to get the function value itself.
51  Real operator()(Real x, Real y) const;
52  Real operator()(int xOrder, int yOrder, Real x, Real y) const;
53 
54 private:
55  class Polynomial
56  {
57  public:
58  Polynomial();
59 
60  // P(x,y) = (1,x,x^2,x^3)*A*(1,y,y^2,y^3). The matrix term A[ix][iy]
61  // corresponds to the polynomial term x^{ix} y^{iy}.
62  Real& A(int ix, int iy);
63  Real operator()(Real x, Real y) const;
64  Real operator()(int xOrder, int yOrder, Real x, Real y) const;
65 
66  private:
67  Real mCoeff[4][4];
68  };
69 
70  // Support for construction.
71  void GetFX(Array2<Real> const& F, Array2<Real>& FX);
72  void GetFY(Array2<Real> const& F, Array2<Real>& FY);
73  void GetFXY(Array2<Real> const& F, Array2<Real>& FXY);
74  void GetPolynomials(Array2<Real> const& F, Array2<Real> const& FX,
75  Array2<Real> const& FY, Array2<Real> const& FXY);
76  Real ComputeDerivative(Real const* slope) const;
77  void Construct(Polynomial& poly, Real const F[2][2], Real const FX[2][2],
78  Real const FY[2][2], Real const FXY[2][2]);
79 
80  // Support for evaluation.
81  void XLookup(Real x, int& xIndex, Real& dx) const;
82  void YLookup(Real y, int& yIndex, Real& dy) const;
83 
87  Real const* mF;
89 };
90 
91 
92 template <typename Real>
94 {
95 }
96 
97 template <typename Real>
98 IntpAkimaUniform2<Real>::IntpAkimaUniform2(int xBound, int yBound, Real xMin,
99  Real xSpacing, Real yMin, Real ySpacing, Real const* F)
100  :
101  mXBound(xBound),
102  mYBound(yBound),
103  mQuantity(xBound * yBound),
104  mXMin(xMin),
105  mXSpacing(xSpacing),
106  mYMin(yMin),
107  mYSpacing(ySpacing),
108  mF(F),
109  mPoly(xBound - 1, mYBound - 1)
110 {
111  // At least a 3x3 block of data points is needed to construct the
112  // estimates of the boundary derivatives.
113  LogAssert(mXBound >= 3 && mYBound >= 3 && mF, "Invalid input.");
114  LogAssert(mXSpacing > (Real)0 && mYSpacing > (Real)0, "Invalid input.");
115 
116  mXMax = mXMin + mXSpacing * static_cast<Real>(mXBound - 1);
117  mYMax = mYMin + mYSpacing * static_cast<Real>(mYBound - 1);
118 
119  // Create a 2D wrapper for the 1D samples.
120  Array2<Real> Fmap(mXBound, mYBound, const_cast<Real*>(mF));
121 
122  // Construct first-order derivatives.
124  GetFX(Fmap, FX);
125  GetFY(Fmap, FY);
126 
127  // Construct second-order derivatives.
129  GetFXY(Fmap, FXY);
130 
131  // Construct polynomials.
132  GetPolynomials(Fmap, FX, FY, FXY);
133 }
134 
135 template <typename Real> inline
137 {
138  return mXBound;
139 }
140 
141 template <typename Real> inline
143 {
144  return mYBound;
145 }
146 
147 template <typename Real> inline
149 {
150  return mQuantity;
151 }
152 
153 template <typename Real> inline
154 Real const* IntpAkimaUniform2<Real>::GetF() const
155 {
156  return mF;
157 }
158 
159 template <typename Real> inline
161 {
162  return mXMin;
163 }
164 
165 template <typename Real> inline
167 {
168  return mXMax;
169 }
170 
171 template <typename Real> inline
173 {
174  return mXSpacing;
175 }
176 
177 template <typename Real> inline
179 {
180  return mYMin;
181 }
182 
183 template <typename Real> inline
185 {
186  return mYMax;
187 }
188 
189 template <typename Real> inline
191 {
192  return mYSpacing;
193 }
194 
195 template <typename Real>
197 {
198  x = std::min(std::max(x, mXMin), mXMax);
199  y = std::min(std::max(y, mYMin), mYMax);
200  int ix, iy;
201  Real dx, dy;
202  XLookup(x, ix, dx);
203  YLookup(y, iy, dy);
204  return mPoly[iy][ix](dx, dy);
205 }
206 
207 template <typename Real>
208 Real IntpAkimaUniform2<Real>::operator()(int xOrder, int yOrder, Real x,
209  Real y) const
210 {
211  x = std::min(std::max(x, mXMin), mXMax);
212  y = std::min(std::max(y, mYMin), mYMax);
213  int ix, iy;
214  Real dx, dy;
215  XLookup(x, ix, dx);
216  YLookup(y, iy, dy);
217  return mPoly[iy][ix](xOrder, yOrder, dx, dy);
218 }
219 
220 template <typename Real>
222 {
223  Array2<Real> slope(mXBound + 3, mYBound);
224  Real invDX = ((Real)1) / mXSpacing;
225  int ix, iy;
226  for (iy = 0; iy < mYBound; ++iy)
227  {
228  for (ix = 0; ix < mXBound - 1; ++ix)
229  {
230  slope[iy][ix + 2] = (F[iy][ix + 1] - F[iy][ix]) * invDX;
231  }
232 
233  slope[iy][1] = ((Real)2) * slope[iy][2] - slope[iy][3];
234  slope[iy][0] = ((Real)2) * slope[iy][1] - slope[iy][2];
235  slope[iy][mXBound + 1] = ((Real)2) * slope[iy][mXBound] - slope[iy][mXBound - 1];
236  slope[iy][mXBound + 2] = ((Real)2) * slope[iy][mXBound + 1] - slope[iy][mXBound];
237  }
238 
239  for (iy = 0; iy < mYBound; ++iy)
240  {
241  for (ix = 0; ix < mXBound; ++ix)
242  {
243  FX[iy][ix] = ComputeDerivative(slope[iy] + ix);
244  }
245  }
246 }
247 
248 template <typename Real>
250 {
251  Array2<Real> slope(mYBound + 3, mXBound);
252  Real invDY = ((Real)1) / mYSpacing;
253  int ix, iy;
254  for (ix = 0; ix < mXBound; ++ix)
255  {
256  for (iy = 0; iy < mYBound - 1; ++iy)
257  {
258  slope[ix][iy + 2] = (F[iy + 1][ix] - F[iy][ix]) * invDY;
259  }
260 
261  slope[ix][1] = ((Real)2) * slope[ix][2] - slope[ix][3];
262  slope[ix][0] = ((Real)2) * slope[ix][1] - slope[ix][2];
263  slope[ix][mYBound + 1] = ((Real)2) * slope[ix][mYBound] - slope[ix][mYBound - 1];
264  slope[ix][mYBound + 2] = ((Real)2) * slope[ix][mYBound + 1] - slope[ix][mYBound];
265  }
266 
267  for (ix = 0; ix < mXBound; ++ix)
268  {
269  for (iy = 0; iy < mYBound; ++iy)
270  {
271  FY[iy][ix] = ComputeDerivative(slope[ix] + iy);
272  }
273  }
274 }
275 
276 template <typename Real>
278 {
279  int xBoundM1 = mXBound - 1;
280  int yBoundM1 = mYBound - 1;
281  int ix0 = xBoundM1, ix1 = ix0 - 1, ix2 = ix1 - 1;
282  int iy0 = yBoundM1, iy1 = iy0 - 1, iy2 = iy1 - 1;
283  int ix, iy;
284 
285  Real invDXDY = ((Real)1) / (mXSpacing * mYSpacing);
286 
287  // corners
288  FXY[0][0] = ((Real)0.25)*invDXDY*(
289  ((Real)9)*F[0][0]
290  - ((Real)12)*F[0][1]
291  + ((Real)3)*F[0][2]
292  - ((Real)12)*F[1][0]
293  + ((Real)16)*F[1][1]
294  - ((Real)4)*F[1][2]
295  + ((Real)3)*F[2][0]
296  - ((Real)4)*F[2][1]
297  + F[2][2]);
298 
299  FXY[0][xBoundM1] = ((Real)0.25)*invDXDY*(
300  ((Real)9)*F[0][ix0]
301  - ((Real)12)*F[0][ix1]
302  + ((Real)3)*F[0][ix2]
303  - ((Real)12)*F[1][ix0]
304  + ((Real)16)*F[1][ix1]
305  - ((Real)4)*F[1][ix2]
306  + ((Real)3)*F[2][ix0]
307  - ((Real)4)*F[2][ix1]
308  + F[2][ix2]);
309 
310  FXY[yBoundM1][0] = ((Real)0.25)*invDXDY*(
311  ((Real)9)*F[iy0][0]
312  - ((Real)12)*F[iy0][1]
313  + ((Real)3)*F[iy0][2]
314  - ((Real)12)*F[iy1][0]
315  + ((Real)16)*F[iy1][1]
316  - ((Real)4)*F[iy1][2]
317  + ((Real)3)*F[iy2][0]
318  - ((Real)4)*F[iy2][1]
319  + F[iy2][2]);
320 
321  FXY[yBoundM1][xBoundM1] = ((Real)0.25)*invDXDY*(
322  ((Real)9)*F[iy0][ix0]
323  - ((Real)12)*F[iy0][ix1]
324  + ((Real)3)*F[iy0][ix2]
325  - ((Real)12)*F[iy1][ix0]
326  + ((Real)16)*F[iy1][ix1]
327  - ((Real)4)*F[iy1][ix2]
328  + ((Real)3)*F[iy2][ix0]
329  - ((Real)4)*F[iy2][ix1]
330  + F[iy2][ix2]);
331 
332  // x-edges
333  for (ix = 1; ix < xBoundM1; ++ix)
334  {
335  FXY[0][ix] = ((Real)0.25)*invDXDY*(
336  ((Real)3)*(F[0][ix - 1] - F[0][ix + 1])
337  - ((Real)4)*(F[1][ix - 1] - F[1][ix + 1])
338  + (F[2][ix - 1] - F[2][ix + 1]));
339 
340  FXY[yBoundM1][ix] = ((Real)0.25)*invDXDY*(
341  ((Real)3)*(F[iy0][ix - 1] - F[iy0][ix + 1])
342  - ((Real)4)*(F[iy1][ix - 1] - F[iy1][ix + 1])
343  + (F[iy2][ix - 1] - F[iy2][ix + 1]));
344  }
345 
346  // y-edges
347  for (iy = 1; iy < yBoundM1; ++iy)
348  {
349  FXY[iy][0] = ((Real)0.25)*invDXDY*(
350  ((Real)3)*(F[iy - 1][0] - F[iy + 1][0])
351  - ((Real)4)*(F[iy - 1][1] - F[iy + 1][1])
352  + (F[iy - 1][2] - F[iy + 1][2]));
353 
354  FXY[iy][xBoundM1] = ((Real)0.25)*invDXDY*(
355  ((Real)3)*(F[iy - 1][ix0] - F[iy + 1][ix0])
356  - ((Real)4)*(F[iy - 1][ix1] - F[iy + 1][ix1])
357  + (F[iy - 1][ix2] - F[iy + 1][ix2]));
358  }
359 
360  // interior
361  for (iy = 1; iy < yBoundM1; ++iy)
362  {
363  for (ix = 1; ix < xBoundM1; ++ix)
364  {
365  FXY[iy][ix] = ((Real)0.25)*invDXDY*(F[iy - 1][ix - 1] -
366  F[iy - 1][ix + 1] - F[iy + 1][ix - 1] + F[iy + 1][ix + 1]);
367  }
368  }
369 }
370 
371 template <typename Real>
373  Array2<Real> const& FX, Array2<Real> const& FY, Array2<Real> const& FXY)
374 {
375  int xBoundM1 = mXBound - 1;
376  int yBoundM1 = mYBound - 1;
377  for (int iy = 0; iy < yBoundM1; ++iy)
378  {
379  for (int ix = 0; ix < xBoundM1; ++ix)
380  {
381  // Note the 'transposing' of the 2x2 blocks (to match notation
382  // used in the polynomial definition).
383  Real G[2][2] =
384  {
385  { F[iy][ix], F[iy + 1][ix] },
386  { F[iy][ix + 1], F[iy + 1][ix + 1] }
387  };
388 
389  Real GX[2][2] =
390  {
391  { FX[iy][ix], FX[iy + 1][ix] },
392  { FX[iy][ix + 1], FX[iy + 1][ix + 1] }
393  };
394 
395  Real GY[2][2] =
396  {
397  { FY[iy][ix], FY[iy + 1][ix] },
398  { FY[iy][ix + 1], FY[iy + 1][ix + 1] }
399  };
400 
401  Real GXY[2][2] =
402  {
403  { FXY[iy][ix], FXY[iy + 1][ix] },
404  { FXY[iy][ix + 1], FXY[iy + 1][ix + 1] }
405  };
406 
407  Construct(mPoly[iy][ix], G, GX, GY, GXY);
408  }
409  }
410 }
411 
412 template <typename Real>
413 Real IntpAkimaUniform2<Real>::ComputeDerivative(Real const* slope) const
414 {
415  if (slope[1] != slope[2])
416  {
417  if (slope[0] != slope[1])
418  {
419  if (slope[2] != slope[3])
420  {
421  Real ad0 = fabs(slope[3] - slope[2]);
422  Real ad1 = fabs(slope[0] - slope[1]);
423  return (ad0 * slope[1] + ad1 * slope[2]) / (ad0 + ad1);
424  }
425  else
426  {
427  return slope[2];
428  }
429  }
430  else
431  {
432  if (slope[2] != slope[3])
433  {
434  return slope[1];
435  }
436  else
437  {
438  return ((Real)0.5) * (slope[1] + slope[2]);
439  }
440  }
441  }
442  else
443  {
444  return slope[1];
445  }
446 }
447 
448 template <typename Real>
449 void IntpAkimaUniform2<Real>::Construct(Polynomial& poly, Real const F[2][2],
450  Real const FX[2][2], Real const FY[2][2], Real const FXY[2][2])
451 {
452  Real dx = mXSpacing;
453  Real dy = mYSpacing;
454  Real invDX = ((Real)1) / dx, invDX2 = invDX*invDX;
455  Real invDY = ((Real)1) / dy, invDY2 = invDY*invDY;
456  Real b0, b1, b2, b3;
457 
458  poly.A(0, 0) = F[0][0];
459  poly.A(1, 0) = FX[0][0];
460  poly.A(0, 1) = FY[0][0];
461  poly.A(1, 1) = FXY[0][0];
462 
463  b0 = (F[1][0] - poly(0, 0, dx, (Real)0))*invDX2;
464  b1 = (FX[1][0] - poly(1, 0, dx, (Real)0))*invDX;
465  poly.A(2, 0) = ((Real)3)*b0 - b1;
466  poly.A(3, 0) = (-((Real)2)*b0 + b1)*invDX;
467 
468  b0 = (F[0][1] - poly(0, 0, (Real)0, dy))*invDY2;
469  b1 = (FY[0][1] - poly(0, 1, (Real)0, dy))*invDY;
470  poly.A(0, 2) = ((Real)3)*b0 - b1;
471  poly.A(0, 3) = (-((Real)2)*b0 + b1)*invDY;
472 
473  b0 = (FY[1][0] - poly(0, 1, dx, (Real)0))*invDX2;
474  b1 = (FXY[1][0] - poly(1, 1, dx, (Real)0))*invDX;
475  poly.A(2, 1) = ((Real)3)*b0 - b1;
476  poly.A(3, 1) = (-((Real)2)*b0 + b1)*invDX;
477 
478  b0 = (FX[0][1] - poly(1, 0, (Real)0, dy))*invDY2;
479  b1 = (FXY[0][1] - poly(1, 1, (Real)0, dy))*invDY;
480  poly.A(1, 2) = ((Real)3)*b0 - b1;
481  poly.A(1, 3) = (-((Real)2)*b0 + b1)*invDY;
482 
483  b0 = (F[1][1] - poly(0, 0, dx, dy))*invDX2*invDY2;
484  b1 = (FX[1][1] - poly(1, 0, dx, dy))*invDX*invDY2;
485  b2 = (FY[1][1] - poly(0, 1, dx, dy))*invDX2*invDY;
486  b3 = (FXY[1][1] - poly(1, 1, dx, dy))*invDX*invDY;
487  poly.A(2, 2) = ((Real)9)*b0 - ((Real)3)*b1 - ((Real)3)*b2 + b3;
488  poly.A(3, 2) = (-((Real)6)*b0 + ((Real)3)*b1 + ((Real)2)*b2 - b3)*invDX;
489  poly.A(2, 3) = (-((Real)6)*b0 + ((Real)2)*b1 + ((Real)3)*b2 - b3)*invDY;
490  poly.A(3, 3) = (((Real)4)*b0 - ((Real)2)*b1 - ((Real)2)*b2 + b3)*invDX*invDY;
491 }
492 
493 template <typename Real>
494 void IntpAkimaUniform2<Real>::XLookup(Real x, int& xIndex, Real& dx) const
495 {
496  for (xIndex = 0; xIndex + 1 < mXBound; ++xIndex)
497  {
498  if (x < mXMin + mXSpacing*(xIndex + 1))
499  {
500  dx = x - (mXMin + mXSpacing*xIndex);
501  return;
502  }
503  }
504 
505  --xIndex;
506  dx = x - (mXMin + mXSpacing*xIndex);
507 }
508 
509 template <typename Real>
510 void IntpAkimaUniform2<Real>::YLookup(Real y, int& yIndex, Real& dy) const
511 {
512  for (yIndex = 0; yIndex + 1 < mYBound; ++yIndex)
513  {
514  if (y < mYMin + mYSpacing*(yIndex + 1))
515  {
516  dy = y - (mYMin + mYSpacing*yIndex);
517  return;
518  }
519  }
520 
521  yIndex--;
522  dy = y - (mYMin + mYSpacing*yIndex);
523 }
524 
525 template <typename Real>
527 {
528  memset(&mCoeff[0][0], 0, 16 * sizeof(Real));
529 }
530 
531 template <typename Real>
533 {
534  return mCoeff[ix][iy];
535 }
536 
537 template <typename Real>
539 {
540  Real B[4];
541  for (int i = 0; i <= 3; ++i)
542  {
543  B[i] = mCoeff[i][0] + y*(mCoeff[i][1] + y*(mCoeff[i][2] + y*mCoeff[i][3]));
544  }
545 
546  return B[0] + x*(B[1] + x*(B[2] + x*B[3]));
547 }
548 
549 template <typename Real>
551  Real x, Real y) const
552 {
553  Real xPow[4];
554  switch (xOrder)
555  {
556  case 0:
557  xPow[0] = (Real)1;
558  xPow[1] = x;
559  xPow[2] = x * x;
560  xPow[3] = x * x * x;
561  break;
562  case 1:
563  xPow[0] = (Real)0;
564  xPow[1] = (Real)1;
565  xPow[2] = ((Real)2) * x;
566  xPow[3] = ((Real)3) * x * x;
567  break;
568  case 2:
569  xPow[0] = (Real)0;
570  xPow[1] = (Real)0;
571  xPow[2] = (Real)2;
572  xPow[3] = ((Real)6) * x;
573  break;
574  case 3:
575  xPow[0] = (Real)0;
576  xPow[1] = (Real)0;
577  xPow[2] = (Real)0;
578  xPow[3] = (Real)6;
579  break;
580  default:
581  return (Real)0;
582  }
583 
584  Real yPow[4];
585  switch (yOrder)
586  {
587  case 0:
588  yPow[0] = (Real)1;
589  yPow[1] = y;
590  yPow[2] = y * y;
591  yPow[3] = y * y * y;
592  break;
593  case 1:
594  yPow[0] = (Real)0;
595  yPow[1] = (Real)1;
596  yPow[2] = ((Real)2) * y;
597  yPow[3] = ((Real)3) * y * y;
598  break;
599  case 2:
600  yPow[0] = (Real)0;
601  yPow[1] = (Real)0;
602  yPow[2] = (Real)2;
603  yPow[3] = ((Real)6) * y;
604  break;
605  case 3:
606  yPow[0] = (Real)0;
607  yPow[1] = (Real)0;
608  yPow[2] = (Real)0;
609  yPow[3] = (Real)6;
610  break;
611  default:
612  return (Real)0;
613  }
614 
615  Real p = (Real)0;
616  for (int iy = 0; iy <= 3; ++iy)
617  {
618  for (int ix = 0; ix <= 3; ++ix)
619  {
620  p += mCoeff[ix][iy] * xPow[ix] * yPow[iy];
621  }
622  }
623 
624  return p;
625 }
626 
627 }
#define LogAssert(condition, message)
Definition: GteLogger.h:86
GLint GLenum GLint x
Definition: glcorearb.h:404
Real operator()(Real x, Real y) const
void GetFY(Array2< Real > const &F, Array2< Real > &FY)
IntpAkimaUniform2(int xBound, int yBound, Real xMin, Real xSpacing, Real yMin, Real ySpacing, Real const *F)
void XLookup(Real x, int &xIndex, Real &dx) const
void GetFX(Array2< Real > const &F, Array2< Real > &FX)
Real operator()(Real x, Real y) const
Array2< Polynomial > mPoly
Real const * GetF() const
void Construct(Polynomial &poly, Real const F[2][2], Real const FX[2][2], Real const FY[2][2], Real const FXY[2][2])
void GetFXY(Array2< Real > const &F, Array2< Real > &FXY)
Real ComputeDerivative(Real const *slope) const
GLfloat GLfloat p
Definition: glext.h:11668
void GetPolynomials(Array2< Real > const &F, Array2< Real > const &FX, Array2< Real > const &FY, Array2< Real > const &FXY)
GLint y
Definition: glcorearb.h:98
void YLookup(Real y, int &yIndex, Real &dy) const


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