|
23 | 23 | #include "flat_array_map.h" |
24 | 24 | #include "flat_sparse_map.h" |
25 | 25 | #include "tree_stats.h" |
| 26 | +#include <algorithm> |
26 | 27 | #include <cassert> |
27 | 28 | #include <cmath> |
28 | 29 | #include <functional> |
@@ -150,6 +151,73 @@ class FilterAABB { |
150 | 151 | const CONVERTER converter_; |
151 | 152 | }; |
152 | 153 |
|
| 154 | + |
| 155 | +/* |
| 156 | + * The sphere filter can be used to query a point tree for a sphere. |
| 157 | + */ |
| 158 | +template < |
| 159 | + typename CONVERTER = ConverterIEEE<3>, |
| 160 | + typename DISTANCE = DistanceEuclidean<3>> |
| 161 | +class FilterSphere { |
| 162 | + using KeyExternal = typename CONVERTER::KeyExternal; |
| 163 | + using KeyInternal = typename CONVERTER::KeyInternal; |
| 164 | + using ScalarInternal = typename CONVERTER::ScalarInternal; |
| 165 | + using ScalarExternal = typename CONVERTER::ScalarExternal; |
| 166 | + |
| 167 | + public: |
| 168 | + FilterSphere( |
| 169 | + const KeyExternal& center, |
| 170 | + const ScalarExternal& radius, |
| 171 | + CONVERTER converter = CONVERTER(), |
| 172 | + DISTANCE distance_function = DISTANCE()) |
| 173 | + : center_external_{center} |
| 174 | + , center_internal_{converter.pre(center)} |
| 175 | + , radius_{radius} |
| 176 | + , converter_{converter} |
| 177 | + , distance_function_{distance_function} {}; |
| 178 | + |
| 179 | + template <typename T> |
| 180 | + [[nodiscard]] bool IsEntryValid(const KeyInternal& key, const T& value) const { |
| 181 | + KeyExternal point = converter_.post(key); |
| 182 | + return distance_function_(center_external_, point) <= radius_; |
| 183 | + } |
| 184 | + |
| 185 | + /* |
| 186 | + * Calculate whether AABB encompassing all possible points in the node intersects with the |
| 187 | + * sphere. |
| 188 | + */ |
| 189 | + [[nodiscard]] bool IsNodeValid(const KeyInternal& prefix, int bits_to_ignore) const { |
| 190 | + // we always want to traverse the root node (bits_to_ignore == 64) |
| 191 | + |
| 192 | + if (bits_to_ignore >= (MAX_BIT_WIDTH<ScalarInternal> - 1)) { |
| 193 | + return true; |
| 194 | + } |
| 195 | + |
| 196 | + ScalarInternal node_min_bits = MAX_MASK<ScalarInternal> << bits_to_ignore; |
| 197 | + ScalarInternal node_max_bits = ~node_min_bits; |
| 198 | + |
| 199 | + KeyInternal closest_in_bounds; |
| 200 | + for (size_t i = 0; i < prefix.size(); ++i) { |
| 201 | + // calculate lower and upper bound for dimension for given node |
| 202 | + ScalarInternal lo = prefix[i] & node_min_bits; |
| 203 | + ScalarInternal hi = prefix[i] | node_max_bits; |
| 204 | + |
| 205 | + // choose value closest to center for dimension |
| 206 | + closest_in_bounds[i] = std::clamp(center_internal_[i], lo, hi); |
| 207 | + } |
| 208 | + |
| 209 | + KeyExternal closest_point = converter_.post(closest_in_bounds); |
| 210 | + return distance_function_(center_external_, closest_point) <= radius_; |
| 211 | + } |
| 212 | + |
| 213 | + private: |
| 214 | + const KeyExternal center_external_; |
| 215 | + const KeyExternal center_internal_; |
| 216 | + const ScalarExternal radius_; |
| 217 | + const CONVERTER converter_; |
| 218 | + const DISTANCE distance_function_; |
| 219 | +}; |
| 220 | + |
153 | 221 | } // namespace improbable::phtree |
154 | 222 |
|
155 | 223 | #endif // PHTREE_COMMON_FILTERS_H |
0 commit comments