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