VTK  9.7.1
vtkInterpolationMath.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2 // SPDX-License-Identifier: BSD-3-Clause
8 #ifndef vtkInterpolationMath_h
9 #define vtkInterpolationMath_h
10 
11 #include "vtkEndian.h"
12 #include "vtkMath.h"
13 
14 VTK_ABI_NAMESPACE_BEGIN
15 // The internal math functions for the interpolators
17 {
18  // floor with remainder (remainder can be double or float),
19  // includes a small tolerance for values just under an integer
20  template <class F>
21  static int Floor(double x, F& f);
22 
23  // round function optimized for various architectures
24  static int Round(double x);
25 
26  // border-handling functions for keeping index a with in bounds b, c
27  static int Clamp(int a, int b, int c);
28  static int Wrap(int a, int b, int c);
29  static int Mirror(int a, int b, int c);
30 };
31 
32 //--------------------------------------------------------------------------
33 // The 'floor' function is slow, so we want a faster replacement.
34 // The goal is to cast double to integer, but round down instead of
35 // rounding towards zero. In other words, we want -0.1 to become -1.
36 
37 // The easiest way to do this is to add a large value (a bias)
38 // to the input of our 'fast floor' in order to ensure that the
39 // double that we cast to integer is positive. This ensures the
40 // cast will round the value down. After the cast, we can subtract
41 // the bias from the integer result.
42 
43 // We choose a bias of 103079215104 because it has a special property
44 // with respect to ieee-754 double-precision floats. It uses 37 bits
45 // of the 53 significant bits available, leaving 16 bits of precision
46 // after the radix. And the same is true for any number in the range
47 // [-34359738368,34359738367] when added to this bias. This is a
48 // very large range, 16 times the range of a 32-bit int. Essentially,
49 // this bias allows us to use the mantissa of a 'double' as a 52-bit
50 // (36.16) fixed-point value. Hence, we can use our floating-point
51 // hardware for fixed-point math, with float-to-fixed and vice-versa
52 // conversions achieved by simply by adding or subtracting the bias.
53 // See http://www.stereopsis.com/FPU.html for further explanation.
54 
55 // The advantage of fixed (absolute) precision over float (relative)
56 // precision is that when we do math on a coordinate (x,y,z) in the
57 // image, the available precision will be the same regardless of
58 // whether x, y, z are close to (0,0,0) or whether they are far away.
59 // This protects against a common problem in computer graphics where
60 // there is lots of available precision near the origin, but less
61 // precision far from the origin. Instead of relying on relative
62 // precision, we have enforced the use of fixed precision. As a
63 // trade-off, we are limited to the range [-34359738368,34359738367].
64 
65 // The value 2^-17 (around 7.6e-6) is exactly half the value of the
66 // 16th bit past the decimal, so it is a useful tolerance to apply in
67 // our calculations. For our 'fast floor', floating-point values
68 // that are within this tolerance from the closest integer will always
69 // be rounded to the integer, even when the value is less than the
70 // integer. Values further than this tolerance from an integer will
71 // always be rounded down.
72 
73 #define VTK_INTERPOLATE_FLOOR_TOL 7.62939453125e-06
74 
75 // A fast replacement for 'floor' that provides fixed precision:
76 template <class F>
77 inline int vtkInterpolationMath::Floor(double x, F& f)
78 {
79 #if VTK_SIZEOF_VOID_P >= 8
80  // add the bias and then subtract it to achieve the desired result
81  x += (103079215104.0 + VTK_INTERPOLATE_FLOOR_TOL);
82  long long i = static_cast<long long>(x);
83  f = static_cast<F>(x - i);
84  return static_cast<int>(i - 103079215104LL);
85 #elif !defined VTK_WORDS_BIGENDIAN
86  // same as above, but avoid doing any 64-bit integer arithmetic
87  union
88  {
89  double d;
90  unsigned short s[4];
91  unsigned int i[2];
92  } dual;
93  dual.d = x + 103079215104.0; // (2**(52-16))*1.5
94  f = dual.s[0] * 0.0000152587890625; // 2**(-16)
95  return static_cast<int>((dual.i[1] << 16) | ((dual.i[0]) >> 16));
96 #else
97  // and again for big-endian architectures
98  union
99  {
100  double d;
101  unsigned short s[4];
102  unsigned int i[2];
103  } dual;
104  dual.d = x + 103079215104.0; // (2**(52-16))*1.5
105  f = dual.s[3] * 0.0000152587890625; // 2**(-16)
106  return static_cast<int>((dual.i[0] << 16) | ((dual.i[1]) >> 16));
107 #endif
108 }
109 
110 inline int vtkInterpolationMath::Round(double x)
111 {
112 #if VTK_SIZEOF_VOID_P >= 8
113  // add the bias and then subtract it to achieve the desired result
114  x += (103079215104.5 + VTK_INTERPOLATE_FLOOR_TOL);
115  long long i = static_cast<long long>(x);
116  return static_cast<int>(i - 103079215104LL);
117 #elif !defined VTK_WORDS_BIGENDIAN
118  // same as above, but avoid doing any 64-bit integer arithmetic
119  union
120  {
121  double d;
122  unsigned int i[2];
123  } dual;
124  dual.d = x + 103079215104.5; // (2**(52-16))*1.5
125  return static_cast<int>((dual.i[1] << 16) | ((dual.i[0]) >> 16));
126 #else
127  // and again for big-endian architectures
128  union
129  {
130  double d;
131  unsigned int i[2];
132  } dual;
133  dual.d = x + 103079215104.5; // (2**(52-16))*1.5
134  return static_cast<int>((dual.i[0] << 16) | ((dual.i[1]) >> 16));
135 #endif
136 }
137 
138 //----------------------------------------------------------------------------
139 // Perform a clamp to limit an index to [b, c] and subtract b.
140 
141 inline int vtkInterpolationMath::Clamp(int a, int b, int c)
142 {
143  a = (a <= c ? a : c);
144  a -= b;
145  a = (a >= 0 ? a : 0);
146  return a;
147 }
148 
149 //----------------------------------------------------------------------------
150 // Perform a wrap to limit an index to [b, c] and subtract b.
151 
152 inline int vtkInterpolationMath::Wrap(int a, int b, int c)
153 {
154  int range = c - b + 1;
155  a -= b;
156  a %= range;
157  // required for some % implementations
158  a = (a >= 0 ? a : a + range);
159  return a;
160 }
161 
162 //----------------------------------------------------------------------------
163 // Perform a mirror to limit an index to [b, c] and subtract b.
164 
165 inline int vtkInterpolationMath::Mirror(int a, int b, int c)
166 {
167 #ifndef VTK_IMAGE_BORDER_LEGACY_MIRROR
168  int range = c - b;
169  int ifzero = (range == 0);
170  int range2 = 2 * range + ifzero;
171  a -= b;
172  a = (a >= 0 ? a : -a);
173  a %= range2;
174  a = (a <= range ? a : range2 - a);
175  return a;
176 #else
177  int range = c - b + 1;
178  int range2 = 2 * range;
179  a -= b;
180  a = (a >= 0 ? a : -a - 1);
181  a %= range2;
182  a = (a < range ? a : range2 - a - 1);
183  return a;
184 #endif
185 }
186 
187 VTK_ABI_NAMESPACE_END
188 #endif
#define VTK_INTERPOLATE_FLOOR_TOL
static int Round(double x)
static int Mirror(int a, int b, int c)
static int Clamp(int a, int b, int c)
static int Wrap(int a, int b, int c)
math code for image interpolators
static int Floor(double x, F &f)