Wayverb
vector_look_up_table.h
1 #pragma once
2 
3 #include "core/az_el.h"
4 
5 #include "glm/glm.hpp"
6 
7 #include <algorithm>
8 #include <array>
9 #include <cstdlib>
10 #include <vector>
11 
12 namespace wayverb {
13 namespace core {
14 
15 template <typename U>
16 static constexpr const auto& clamp(const U& x, const U& mini, const U& maxi) {
17  using std::min;
18  using std::max;
19  return max(mini, min(maxi, x));
20 }
21 
22 constexpr float degrees(float radians) { return radians * 180 / M_PI; }
23 constexpr float radians(float degrees) { return degrees * M_PI / 180; }
24 
25 template <typename T, size_t azimuth_divisions, size_t elevation_divisions>
26 struct vector_look_up_table final {
27  static_assert(elevation_divisions % 2, "elevation_divisions must be odd");
28 
29  struct index_pair final {
30  size_t azimuth;
31  size_t elevation;
32  };
33 
34  // look up
35 
36  constexpr auto& at(index_pair i) { return table[i.azimuth][i.elevation]; }
37  constexpr const auto& at(index_pair i) const {
38  return table[i.azimuth][i.elevation];
39  }
40 
41  // data
42 
43  static constexpr auto get_azimuth_angle() {
44  return 360.0 / azimuth_divisions;
45  }
46 
47  static constexpr auto get_elevation_angle() {
48  return 180.0 / (elevation_divisions + 1);
49  }
50 
51  // angles to indices
52 
53  static constexpr size_t azimuth_to_index(double azimuth) {
54  azimuth += get_azimuth_angle() / 2;
55  while (azimuth < 0) {
56  azimuth += 360;
57  }
58  return static_cast<size_t>(azimuth / get_azimuth_angle()) %
59  azimuth_divisions;
60  }
61 
62  static constexpr size_t elevation_to_index(double elevation) {
63  elevation += 90 + (get_elevation_angle() / 2);
64  while (elevation < 0) {
65  elevation += 360;
66  }
67 
68  const auto adjusted =
69  static_cast<size_t>(elevation / get_elevation_angle()) %
70  (2 * (elevation_divisions + 1));
71 
72  if (elevation_divisions + 1 < adjusted) {
73  throw std::runtime_error{"Elevation out of range."};
74  }
75 
76  return clamp(adjusted, 1ul, elevation_divisions) - 1;
77  }
78 
79  static constexpr index_pair angles_to_indices(az_el azel) {
80  return {azimuth_to_index(azel.azimuth),
81  elevation_to_index(azel.elevation)};
82  }
83 
84  // indices to angles
85 
86  static constexpr auto index_to_azimuth(size_t index) {
87  if (azimuth_divisions <= index) {
88  throw std::runtime_error{"Index out of range."};
89  }
90  return (index * get_azimuth_angle());
91  }
92 
93  static constexpr auto index_to_elevation(size_t index) {
94  if (elevation_divisions <= index) {
95  throw std::runtime_error{"Index out of range."};
96  }
97  return ((index + 1) * get_elevation_angle()) - 90;
98  }
99 
100  static constexpr az_el indices_to_angles(index_pair i) {
101  return {index_to_azimuth(i.azimuth), index_to_elevation(i.elevation)};
102  }
103 
104  // vectors and angles
105 
106  static auto pointing(index_pair i) {
107  return compute_pointing(
108  az_el{-radians(index_to_azimuth(i.azimuth)),
109  radians(index_to_elevation(i.elevation))});
110  }
111 
112  static auto index(const glm::vec3& i) {
113  const auto radians = compute_azimuth_elevation(i);
114  return index_pair{azimuth_to_index(degrees(-radians.azimuth)),
115  elevation_to_index(degrees(radians.elevation))};
116  }
117 
119  T table[azimuth_divisions][elevation_divisions]{};
120 };
121 
122 template <typename T, typename Alloc, size_t Az, size_t El>
123 void resize_if_necessary(
124  core::vector_look_up_table<std::vector<T, Alloc>, Az, El>& t,
125  size_t new_size) {
126  for (auto& azimuth : t.table) {
127  for (auto& elevation : azimuth) {
128  if (elevation.size() < new_size) {
129  elevation.resize(new_size);
130  }
131  }
132  }
133 }
134 
135 } // namespace core
136 } // namespace wayverb
Definition: vector_look_up_table.h:29
Definition: traits.cpp:2
Definition: capsule_base.h:9
Definition: az_el.h:10
Definition: vector_look_up_table.h:26
T table[azimuth_divisions][elevation_divisions]
Using a C array because it&#39;s more constexpr-ready than std::array.
Definition: vector_look_up_table.h:119