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 138 139 140 141 142 143 144 145 146 147
|
/*=========================================================================
Program: Visualization Toolkit
Module: vtkMathUtilities.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/**
* @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
*/
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)"
*/
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
|