VTK  9.6.20260113
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
7
8#ifndef vtkInterpolationMath_h
9#define vtkInterpolationMath_h
10
11#include "vtkEndian.h"
12#include "vtkMath.h"
13
14VTK_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:
76template <class F>
77inline 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
110inline 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
141inline 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
152inline 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
165inline 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
187VTK_ABI_NAMESPACE_END
188#endif
math code for image interpolators
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)
static int Round(double x)
#define VTK_INTERPOLATE_FLOOR_TOL