20 #ifndef GEOMETRY__LOOKUP_TABLE_HPP_
21 #define GEOMETRY__LOOKUP_TABLE_HPP_
34 namespace helper_functions
44 template<
typename T,
typename U>
47 static const geometry::Interval<U> UNIT_INTERVAL(
static_cast<U
>(0),
static_cast<U
>(1));
50 const auto m = (b -
a);
51 const auto offset =
static_cast<U
>(
m) * scaling;
52 return a +
static_cast<T>(offset);
59 T lookup_impl_1d(
const std::vector<T> & domain,
const std::vector<T> & range,
const T value)
61 if (!std::isfinite(value)) {
62 throw std::domain_error{
"Query value is not finite (NAN or INF)"};
64 if (value <= domain.front()) {
66 }
else if (value >= domain.back()) {
73 for (
auto idx = 1U; idx < domain.size(); ++idx) {
74 if (value < domain[idx]) {
80 const auto num =
static_cast<double>(value - domain[second_idx - 1U]);
81 const auto den =
static_cast<double>(domain[second_idx] - domain[second_idx - 1U]);
82 const auto t = num / den;
83 const auto val =
interpolate(range[second_idx - 1U], range[second_idx],
t);
84 return static_cast<T>(val);
89 void check_table_lookup_invariants(
const std::vector<T> & domain,
const std::vector<T> & range)
91 if (domain.size() != range.size()) {
92 throw std::domain_error{
"Domain's size does not match range's"};
95 throw std::domain_error{
"Empty domain or range"};
98 for (
auto idx = 1U; idx < domain.size(); ++idx) {
99 if (domain[idx] <= domain[idx - 1U]) {
100 throw std::domain_error{
"Domain is not sorted"};
119 T lookup_1d(
const std::vector<T> & domain,
const std::vector<T> & range,
const T value)
121 check_table_lookup_invariants(domain, range);
123 return lookup_impl_1d(domain, range, value);
143 check_table_lookup_invariants(m_domain, m_range);
156 check_table_lookup_invariants(m_domain, m_range);
167 return lookup_impl_1d(m_domain, m_range, value);
170 const std::vector<T> &
domain() const noexcept {
return m_domain;}
172 const std::vector<T> &
range() const noexcept {
return m_range;}
175 std::vector<T> m_domain;
176 std::vector<T> m_range;
184 #endif // GEOMETRY__LOOKUP_TABLE_HPP_