morton-arithmetic 0.1.0
Fast Morton (Z-order) codes with O(1) arithmetic
Loading...
Searching...
No Matches
iterate.hpp
Go to the documentation of this file.
1
13
14#ifndef MORTON_ITERATE_HPP
15#define MORTON_ITERATE_HPP
16
17#include <array>
18
19#include "morton/morton.hpp"
20
21namespace morton {
22
26template <unsigned Dim, unsigned Bits, typename Fn>
27void for_each_in_box(const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& lo,
28 const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& hi, Fn&& fn) {
29 using M = Morton<Dim, Bits>;
30 using coord = typename M::coord_type;
31
32 for (unsigned d = 0; d < Dim; ++d)
33 if (hi[d] < lo[d])
34 return; // empty box
35
36 M cur = M::encode(lo);
37 std::array<coord, Dim> idx = lo; // track coords without decoding
38
39 for (;;) {
40 fn(cur);
41 unsigned d = 0;
42 for (; d < Dim; ++d) {
43 if (idx[d] < hi[d]) {
44 ++idx[d];
45 cur.inc(d);
46 break;
47 }
48 // axis d exhausted: reset to lo[d] and carry into the next axis
49 cur.set(d, lo[d]);
50 idx[d] = lo[d];
51 }
52 if (d == Dim)
53 break; // every axis wrapped -> finished
54 }
55}
56
57namespace detail {
58
59// Tropf-Herzog BIGMIN: given the Z-order range corners [zmin, zmax] (raw codes
60// of the box's lower/upper corners) and a probe code `z` that lies outside the
61// box, return the smallest code strictly greater than `z` that is inside the
62// box. See H. Tropf & H. Herzog, "Multidimensional Range Search in
63// Dynamically Balanced Trees" (1981).
64template <unsigned Dim, unsigned Bits>
66 typename Morton<Dim, Bits>::code_type zmax,
68 using M = Morton<Dim, Bits>;
69 using code = typename M::code_type;
70
71 code result = 0;
72 for (int i = int(M::code_bits) - 1; i >= 0; --i) {
73 const unsigned d = unsigned(i) % Dim;
74 const code bit = code(1) << i;
75 const code same_dim_below = M::axis_mask(d) & (bit - 1);
76
77 const int zb = int((z >> i) & 1);
78 const int lb = int((zmin >> i) & 1);
79 const int hb = int((zmax >> i) & 1);
80
81 if (!zb && !lb && !hb) {
82 continue;
83 } else if (!zb && !lb && hb) {
84 result = (zmin & ~same_dim_below) | bit; // LOAD(zmin, i, 1)
85 zmax = (zmax & ~bit) | same_dim_below; // LOAD(zmax, i, 0)
86 } else if (!zb && lb && hb) {
87 return zmin;
88 } else if (zb && !lb && !hb) {
89 return result;
90 } else if (zb && !lb && hb) {
91 zmin = (zmin & ~same_dim_below) | bit; // LOAD(zmin, i, 1)
92 } else { // (1,1,1)
93 continue;
94 }
95 }
96 return result;
97}
98
99// Tropf-Herzog combined LITMAX/BIGMIN. Given Z-order box corners
100// [zmin, zmax] and a probe `z`, computes:
101// bigmin = smallest in-box code strictly greater than z, and
102// litmax = largest in-box code strictly less than z.
103// (When the respective value does not exist the result is clamped to a box
104// corner; callers that have already established z is outside the box on the
105// relevant side get the meaningful answer.)
106template <unsigned Dim, unsigned Bits>
108 typename Morton<Dim, Bits>::code_type zmax,
110 typename Morton<Dim, Bits>::code_type& litmax,
112 using M = Morton<Dim, Bits>;
113 using code = typename M::code_type;
114
115 litmax = zmin;
116 bigmin = zmax;
117 for (int i = int(M::code_bits) - 1; i >= 0; --i) {
118 const unsigned d = unsigned(i) % Dim;
119 const code bit = code(1) << i;
120 const code below = M::axis_mask(d) & (bit - 1); // same-dim bits below i
121
122 const int zb = int((z >> i) & 1);
123 const int lb = int((zmin >> i) & 1);
124 const int hb = int((zmax >> i) & 1);
125 const int v = (zb << 2) | (lb << 1) | hb;
126
127 switch (v) {
128 case 0b000:
129 case 0b111:
130 break;
131 case 0b001:
132 bigmin = (zmin & ~below) | bit; // LOAD(zmin, i, 1)
133 zmax = (zmax & ~bit) | below; // LOAD(zmax, i, 0)
134 break;
135 case 0b011:
136 bigmin = zmin;
137 return;
138 case 0b100:
139 litmax = zmax;
140 return;
141 case 0b101:
142 litmax = (zmax & ~bit) | below; // LOAD(zmax, i, 0)
143 zmin = (zmin & ~below) | bit; // LOAD(zmin, i, 1)
144 break;
145 default: // 010, 110 are impossible for zmin <= zmax
146 break;
147 }
148 }
149}
150
151} // namespace detail
152
155template <unsigned Dim, unsigned Bits>
156bool bigmin_in_box(const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& lo,
157 const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& hi,
159 using M = Morton<Dim, Bits>;
160 const auto zmin = M::encode(lo).code();
161 const auto zmax = M::encode(hi).code();
162 if (probe.code() >= zmax)
163 return false;
164 typename M::code_type lm, bm;
165 detail::litmax_bigmin<Dim, Bits>(zmin, zmax, probe.code(), lm, bm);
166 out = M::from_code(bm);
167 return true;
168}
169
172template <unsigned Dim, unsigned Bits>
173bool litmax_in_box(const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& lo,
174 const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& hi,
176 using M = Morton<Dim, Bits>;
177 const auto zmin = M::encode(lo).code();
178 const auto zmax = M::encode(hi).code();
179 if (probe.code() <= zmin)
180 return false;
181 typename M::code_type lm, bm;
182 detail::litmax_bigmin<Dim, Bits>(zmin, zmax, probe.code(), lm, bm);
183 out = M::from_code(lm);
184 return true;
185}
186
188template <unsigned Dim, unsigned Bits>
189MORTON_HD bool in_box(const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& lo,
190 const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& hi,
192 for (unsigned d = 0; d < Dim; ++d) {
193 auto c = m.get(d);
194 if (c < lo[d] || c > hi[d])
195 return false;
196 }
197 return true;
198}
199
202template <unsigned Dim, unsigned Bits, typename Fn>
203void for_each_in_box_zorder(const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& lo,
204 const std::array<typename Morton<Dim, Bits>::coord_type, Dim>& hi,
205 Fn&& fn) {
206 using M = Morton<Dim, Bits>;
207 using code = typename M::code_type;
208
209 for (unsigned d = 0; d < Dim; ++d)
210 if (hi[d] < lo[d])
211 return;
212
213 const code zmin = M::encode(lo).code();
214 const code zmax = M::encode(hi).code();
215
216 code z = zmin;
217 for (;;) {
218 M m = M::from_code(z);
219 if (in_box<Dim, Bits>(lo, hi, m)) {
220 fn(m);
221 if (z == zmax)
222 break;
223 ++z;
224 } else {
225 code lm, next;
226 detail::litmax_bigmin<Dim, Bits>(zmin, zmax, z, lm, next);
227 if (next <= z)
228 break; // safety: guarantee forward progress
229 z = next;
230 }
231 }
232}
233
234} // namespace morton
235
236#endif // MORTON_ITERATE_HPP
A Morton (Z-order) code interleaving Dim unsigned coordinates of Bits bits each.
Definition morton.hpp:203
detail::uint_for_t< Bits > coord_type
Definition morton.hpp:215
MORTON_HD constexpr code_type code() const noexcept
Definition morton.hpp:265
detail::uint_for_t< Dim *Bits > code_type
Definition morton.hpp:214
MORTON_HD constexpr coord_type get(unsigned d) const
Decode coordinate of a single axis.
Definition morton.hpp:268
#define MORTON_HD
Definition hd.hpp:27
Core Morton<Dim,Bits> type — Z-order codes with O(1) arithmetic in Morton space.
MORTON_HD Morton< Dim, Bits >::code_type bigmin(typename Morton< Dim, Bits >::code_type zmin, typename Morton< Dim, Bits >::code_type zmax, typename Morton< Dim, Bits >::code_type z)
Definition iterate.hpp:65
MORTON_HD void litmax_bigmin(typename Morton< Dim, Bits >::code_type zmin, typename Morton< Dim, Bits >::code_type zmax, typename Morton< Dim, Bits >::code_type z, typename Morton< Dim, Bits >::code_type &litmax, typename Morton< Dim, Bits >::code_type &bigmin)
Definition iterate.hpp:107
Definition batch.hpp:26
bool litmax_in_box(const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &lo, const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &hi, Morton< Dim, Bits > probe, Morton< Dim, Bits > &out)
Largest Morton code in the inclusive box [lo, hi] that is strictly less than probe.
Definition iterate.hpp:173
void for_each_in_box_zorder(const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &lo, const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &hi, Fn &&fn)
Visit every cell of the inclusive box [lo, hi] in Z-order (increasing Morton code),...
Definition iterate.hpp:203
void for_each_in_box(const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &lo, const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &hi, Fn &&fn)
Visit every cell of the inclusive box [lo, hi] in row-major order (axis 0 varies fastest).
Definition iterate.hpp:27
bool bigmin_in_box(const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &lo, const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &hi, Morton< Dim, Bits > probe, Morton< Dim, Bits > &out)
Smallest Morton code in the inclusive box [lo, hi] that is strictly greater than probe.
Definition iterate.hpp:156
MORTON_HD bool in_box(const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &lo, const std::array< typename Morton< Dim, Bits >::coord_type, Dim > &hi, Morton< Dim, Bits > m)
Test whether m lies inside the inclusive box [lo, hi].
Definition iterate.hpp:189