File: vtkMathUtilities.h

package info (click to toggle)
vtk9 9.5.2%2Bdfsg3-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 205,916 kB
  • sloc: cpp: 2,336,565; ansic: 327,116; python: 111,200; yacc: 4,104; java: 3,977; sh: 3,032; xml: 2,771; perl: 2,189; lex: 1,787; makefile: 178; javascript: 165; objc: 153; tcl: 59
file content (137 lines) | stat: -rw-r--r-- 3,585 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause

/**
 * @class   vtkMathUtilities
 * @brief   templated utility math functions intended for
 * internal use in tests etc.
 *
 *
 * Provide a set of inline, lightweight templated math utility functions.
 * The initial motivation is to provide a few lightweight functions to help in
 * testing and internal implementation files.
 */

#ifndef vtkMathUtilities_h
#define vtkMathUtilities_h

#include "vtkABINamespace.h"

#include <cmath>
#include <limits>
#include <tuple>
#include <type_traits>

namespace vtkMathUtilities
{
VTK_ABI_NAMESPACE_BEGIN

/**
 * Perform a fuzzy compare of floats/doubles, specify the allowed tolerance
 * NB: this uses an absolute tolerance.
 */
template <class A>
bool FuzzyCompare(A a, A b, A epsilon = std::numeric_limits<A>::epsilon())
{
  return fabs(a - b) < epsilon;
}

/**
 * Performs safe division that catches overflow and underflow.
 */
template <class A>
A SafeDivision(A a, A b)
{
  // Avoid overflow
  if ((b < static_cast<A>(1)) && (a > b * std::numeric_limits<A>::max()))
  {
    return std::numeric_limits<A>::max();
  }

  // Avoid underflow
  if ((a == static_cast<A>(0)) ||
    ((b > static_cast<A>(1)) && (a < b * std::numeric_limits<A>::min())))
  {
    return static_cast<A>(0);
  }

  // safe to do the division
  return (a / b);
}

/**
 * A slightly different fuzzy comparator that checks if two values are
 * "nearly" equal based on Knuth, "The Art of Computer Programming (vol II)"
 * NB: this uses a relative tolerance.
 */
template <class A>
bool NearlyEqual(A a, A b, A tol = std::numeric_limits<A>::epsilon())
{
  A absdiff = fabs(a - b);
  A d1 = vtkMathUtilities::SafeDivision<A>(absdiff, fabs(a));
  A d2 = vtkMathUtilities::SafeDivision<A>(absdiff, fabs(b));

  return ((d1 <= tol) || (d2 <= tol));
}

/**
 * Update an existing min - max range with a new prospective value.  If the
 * value is non NaN then the appropriate range comparisons are made and
 * updated, otherwise the original min - max values are set.
 *
 * Examples:
 *
 *   No change:
 *   UpdateRange(-100, 100, 20) -> (-100, 100)
 *
 *   Update min:
 *   UpdateRange(-100, 100, -200) -> (-200, 100)
 *
 *   Update max:
 *   UpdateRange(-100, 100, 200) -> (-100, 200)
 *
 *   Input min and max are inverted creating an invalid range so a new range
 *   with the specified value is set:
 *   UpdateRange(100, -100, 20) -> (20, 20)
 *
 *   Input value is NaN so the original range is set
 *   UpdateRange(-100, 100, NaN) -> (-100, 100)
 */
template <class A>
void UpdateRangeImpl(A& min0, A& max0, const A& value)
{
  // need temporaries to handle const/non const ref mismatch
  if (value < min0)
  {
    min0 = value;
    max0 = max0 < value ? value : max0;
  }
  else if (value > max0)
  {
    min0 = min0 > value ? value : min0;
    max0 = value;
  }
}

template <class A> // Non floating point implementation not caring about NaN
void UpdateRange(A& min0, A& max0, const A& value,
  typename std::enable_if<!std::is_floating_point<A>::value>::type* = nullptr)
{
  UpdateRangeImpl<A>(min0, max0, value);
}

template <class A> // Floating point implementation specifically considering NaN
void UpdateRange(A& min0, A& max0, const A& value,
  typename std::enable_if<std::is_floating_point<A>::value>::type* = nullptr)
{
  if (!std::isnan(value))
  {
    UpdateRangeImpl<A>(min0, max0, value);
  }
}

VTK_ABI_NAMESPACE_END
} // End vtkMathUtilities namespace.

#endif // vtkMathUtilities_h
// VTK-HeaderTest-Exclude: vtkMathUtilities.h