MRPTree v0.5.0.0 lib 0.5.0.0
MR 2^P Trees (MRPTree)
Loading...
Searching...
No Matches
MR_rect_tree.hpp
Go to the documentation of this file.
1// -*- Mode:C++; Coding:us-ascii-unix; fill-column:158 -*-
2/*******************************************************************************************************************************************************.H.S.**/
3/**
4 @file MR_rect_tree.hpp
5 @author Mitch Richling http://www.mitchr.me/
6 @date 2024-06-13
7 @brief Implimentation of the MR_rect_tree class.@EOL
8 @keywords quadtree octree lod
9 @std C++23
10 @see MR_rt_to_cc.hpp, MR_cell_cplx.hpp
11 @copyright
12 @parblock
13 Copyright (c) 2024, Mitchell Jay Richling <http://www.mitchr.me/> All rights reserved.
14
15 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
16
17 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer.
18
19 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, and the following disclaimer in the documentation
20 and/or other materials provided with the distribution.
21
22 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software
23 without specific prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30 DAMAGE.
31 @endparblock
32*/
33/*******************************************************************************************************************************************************.H.E.**/
34
35////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
36#ifndef MJR_INCLUDE_MR_rect_tree
37
38////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
39#include <algorithm> /* STL algorithm C++11 */
40#include <array> /* array template C++11 */
41#include <bit> /* STL bit manipulation C++20 */
42#include <climits> /* std:: C limits.h C++11 */
43#include <cmath> /* std:: C math.h C++11 */
44#include <complex> /* Complex Numbers C++11 */
45#include <concepts> /* Concepts library C++20 */
46#include <cstdint> /* std:: C stdint.h C++11 */
47#include <cstring> /* std:: C string.h C++11 */
48#include <fstream> /* C++ fstream C++98 */
49#include <functional> /* STL funcs C++98 */
50#include <iomanip> /* C++ stream formatting C++11 */
51#include <iostream> /* C++ iostream C++11 */
52#include <limits> /* C++ Numeric limits C++11 */
53#include <set> /* STL set C++98 */
54#include <span> /* STL spans C++20 */
55#include <sstream> /* C++ string stream C++ */
56#include <string> /* C++ strings C++11 */
57#include <tuple> /* STL tuples C++11 */
58#include <type_traits> /* C++ metaprogramming C++11 */
59#include <unordered_map> /* STL hash map C++11 */
60#include <map> /* STL map C++11 */
61#include <utility> /* STL Misc Utilities C++11 */
62#include <vector> /* STL vector C++11 */
63
64////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
65#include "MRMathCPP.hpp"
66
67////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
68// Put everything in the mjr namespace
69namespace mjr {
70/** @brief Template Class used to house an MR_rect_tree.
71
72 Overview
73 ========
74
75 This class forms the primary component of the MR @f$2^P\mathrm{-Tree}@f$ library (also known as "MRPTree"). In terms of this library, a quadtree is a
76 @f$2^2\mathrm{-Tree}@f$ and an octree is a @f$2^3\mathrm{-Tree}@f$ -- in essence this class implements a universal data structure capable of holding such
77 trees of any dimension. Contrary to the name, this is all achieved without using any tree-like data structures at all!
78
79 The `dom_dim` template parameter corresponds to the "@f$P@f$" in the exponent. If one wishes to implement a quadtree, then dom_dim should be set to 2.
80 For octrees the value of dom_dim should be set to 3. We are not limited to dimensions 2 & 3 -- for example, we could make 1D "bitrees" or a 4D "space
81 time trees".
82
83 This class makes the unusual assumption that the sampled data stored in the tree is a finite, real vector space. So instead of using a template parameter
84 to specify the type of the sampled data, we provide 1) a type for the vector space scalar (spc_real_t) and 2) a dimension (rng_dim). In other words these
85 trees are optimized to model model functions @f$f:\mathbb{R}^d\rightarrow\mathbb{R}^r@f$ where @f$d@f$ and @f$r@f$ *are* template parameters(`dom_dim` &
86 `rng_dim` respectively).
87
88 The `max_level` parameter will seem odd for anyone who has used a traditional quadtree/octree library. As a practical matter trees in traditional
89 libraries are limited to a shallow depths (say 10 or 12 levels); however, the code bases themselves don't usually place an explicit limit on depth. In
90 this library the maximum depth must be specified from the start.
91
92 As an example, suppose we have a function @f$f:\mathbb{R}^2\rightarrow\mathbb{R}^3@f$ we wish to sample. For this application we might use the following values:
93 - `spc_real_t = double`
94 - `dom_dim = 2`
95 - `rng_dim = 3`
96 - `max_level = 15`
97
98 We could use an alternate value for `max_level`, but I think 15 is a good balance. We can do quadtrees at this depth using 32-bit integer keys, and we
99 can do octrees with 64-bit integer keys.
100
101 Naming Conventions
102 ==================
103
104 - Methods for numeric computation on coordinate tuples (::diti_t types). These methods have nothing to do with cell sample status -- just coordinates!
105 - ccc_ -- Cell Coordinate Computation: Coordinates are interpreted as cell coordinate centers
106 - cuc_ -- Coordinate Utility Computation: Coordinate are not necessarily cell coordinate centers
107 - Type Naming Conventions
108 - Coordinates
109 - ::dic_t (domain Integer Coordinate) -- A single integer
110 - ::src_t (domain/range space Real Coordinate) -- Floating point
111 - Domain Integer Coordinate Tuples
112 - ::diti_t (domain int tuple Integer) -- Encoded as a packed integer
113 - ::dita_t (domain int tuple Array) -- As a dom_dim element std::array
114 - ::ditv_t (domain int tuple Vector) -- As a dom_dim element std::vector
115 - Domain/range real Coordinate tuples
116 - ::rrta_t & ::drta_t (range/domain real tuple Array) -- As a `dom_dim` or `rng_dim` element std::array
117 - ::rrtv_t & ::drtv_t (range/domain real tuple Vector) -- As a `dom_dim` or `rng_dim` element std::vector
118 - ::rrpt_t & ::drpt_t (range/domain real psudo-tuple) -- As a ::src_t when `dim==1`, and an array otherwise
119 Function arguments of type "`foo_t`" are frequently called "`foo`".
120
121 Details
122 =======
123
124 @tparam max_level The maximum depth of the tree -- use one minus a power of two for highest performance.
125 @tparam spc_real_t The base floating type to use for both domain & range.
126 @tparam dom_dim Domain dimension.
127 @tparam rng_dim Range dimension. */
128 template <int max_level, class spc_real_t, int dom_dim, int rng_dim>
129 requires ((max_level>0) &&
130 (dom_dim>0) &&
131 (rng_dim>0) &&
132 (dom_dim*max_level<=CHAR_BIT*sizeof(uint64_t)) &&
133 (std::is_floating_point<spc_real_t>::value))
135 public:
136
137 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
138 /** @name Template Parameter Constants */
139 //@{
140 //--------------------------------------------------------------------------------------------------------------------------------------------------------
141 constexpr static int domain_dimension = dom_dim; //!< The value of the template parameter dom_dim
142 //--------------------------------------------------------------------------------------------------------------------------------------------------------
143 constexpr static int range_dimension = rng_dim; //!< The value of the template parameter rng_dim
144 //--------------------------------------------------------------------------------------------------------------------------------------------------------
145 constexpr static int maximum_level = max_level; //!< The value of the template parameter max_level
146 //@}
147
148 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
149 /** @name Template Parameter Types */
150 //@{
151 //--------------------------------------------------------------------------------------------------------------------------------------------------------
152 /** Externally exposed typedef for spc_real_t */
154 //--------------------------------------------------------------------------------------------------------------------------------------------------------
155 /** Externally exposed typedef for spc_real_t */
156 typedef spc_real_t src_t;
157 //@}
158
159 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160 /** @name Domain Real Coordinates */
161 //@{
162 //--------------------------------------------------------------------------------------------------------------------------------------------------------
163 /** std::vector for values in the domain space. */
164 typedef std::vector<src_t> drtv_t;
165 //--------------------------------------------------------------------------------------------------------------------------------------------------------
166 /** An std::array for points in the domain space. */
167 typedef std::array<src_t, dom_dim> drta_t;
168 //--------------------------------------------------------------------------------------------------------------------------------------------------------
169 /** For values in the domain space.
170 - When dom_dim==1, this will be src_t
171 - When dom_dim!=1, this will be drta_t (an std::array) */
172 typedef typename std::conditional<std::cmp_equal(dom_dim, 1), src_t, drta_t>::type drpt_t;
173 //--------------------------------------------------------------------------------------------------------------------------------------------------------
174 /** A nicely descriptive typedef for drpt_t. */
176 //@}
177
178 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
179 /** @name Range Real Coordinates */
180 //@{
181 //--------------------------------------------------------------------------------------------------------------------------------------------------------
182 /** std::vector for values in the range space. */
183 typedef std::vector<src_t> rrtv_t;
184 //--------------------------------------------------------------------------------------------------------------------------------------------------------
185 /** An std::array for points in the range space. */
186 typedef std::array<src_t, rng_dim> rrta_t;
187 //--------------------------------------------------------------------------------------------------------------------------------------------------------
188 /** For values in the range space.
189 - When rng_dim==1, this will be src_t
190 - When rng_dim!=1, this will be a rrta_t (an std::array) */
191 typedef typename std::conditional<std::cmp_equal(rng_dim, 1), src_t, rrta_t>::type rrpt_t;
192 //--------------------------------------------------------------------------------------------------------------------------------------------------------
193 /** A nicely descriptive typedef for rrpt_t */
195 //@}
196
197 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
198 /** @name Domain Integer Coordinates */
199 //@{
200 //--------------------------------------------------------------------------------------------------------------------------------------------------------
201 /** The number of bits used by a single component of an integer coordinate tuple.
202 @warning dic_bits >= sizeof(dic_t), but it might not be equal. */
203 constexpr static int dic_bits = max_level+1;
204 //--------------------------------------------------------------------------------------------------------------------------------------------------------
205 /** The number of bits used by an entire integer coordinate tuple.
206 @warning diti_bits >= sizeof(diti_t), but it might not be equal. */
207 constexpr static int diti_bits = dic_bits * dom_dim;
208 //@}
209
210 private:
211
212 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
213 /** @name Domain Integer Coordinates */
214 //@{
215 //--------------------------------------------------------------------------------------------------------------------------------------------------------
216 /* Private to keep it undocumented in doxygen because the typedef definition is too large */
217 typedef typename std::conditional<std::cmp_greater_equal(CHAR_BIT*sizeof(int8_t), dic_bits), uint8_t,
218 typename std::conditional<std::cmp_greater_equal(CHAR_BIT*sizeof(int16_t), dic_bits), uint16_t,
219 typename std::conditional<std::cmp_greater_equal(CHAR_BIT*sizeof(int32_t), dic_bits), uint32_t,
220 uint64_t
221 >::type>::type>::type priv_dic_t;
222 //--------------------------------------------------------------------------------------------------------------------------------------------------------
223 /* Private to keep it undocumented in doxygen because the typedef definition is too large */
224 typedef typename std::conditional<std::cmp_greater_equal(CHAR_BIT*sizeof(int8_t), diti_bits), uint8_t,
225 typename std::conditional<std::cmp_greater_equal(CHAR_BIT*sizeof(int16_t), diti_bits), uint16_t,
226 typename std::conditional<std::cmp_greater_equal(CHAR_BIT*sizeof(int32_t), diti_bits), uint32_t,
227 uint64_t
228 >::type>::type>::type priv_diti_t;
229 //@}
230
231 public:
232
233 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
234 /** @name Domain Integer Coordinates */
235 //@{
236 //--------------------------------------------------------------------------------------------------------------------------------------------------------
237 /** Unsigned integer type large large enough to hold an integer coordiante component */
239 //--------------------------------------------------------------------------------------------------------------------------------------------------------
240 /** Unsigned integer type large large enough to hold an integer coordiante tuple */
242 //--------------------------------------------------------------------------------------------------------------------------------------------------------
243 /** Domain point given as an std::array integer tuple. */
244 typedef std::array<dic_t, 3> dita_t;
245 //--------------------------------------------------------------------------------------------------------------------------------------------------------
246 /** Domain point given as an std::vector integer tuple. */
247 typedef std::vector<dic_t> ditv_t;
248 //--------------------------------------------------------------------------------------------------------------------------------------------------------
249 /** A std::vector used to pass lists of diti_t types around. */
250 typedef std::vector<diti_t> diti_list_t;
251 //--------------------------------------------------------------------------------------------------------------------------------------------------------
252 constexpr static dic_t dic_max = (static_cast<dic_t>(1) << max_level); //!< Maximum allowd for a dic_t
253 //--------------------------------------------------------------------------------------------------------------------------------------------------------
254 constexpr static dic_t dic_ctr = (static_cast<dic_t>(1) << (max_level-1)); //!< Center value for a dic_t
255 //--------------------------------------------------------------------------------------------------------------------------------------------------------
256 constexpr static dic_t dic_min = 0; //!< Minimum allowd for a dic_t
257 //@}
258
259 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
260 /** @name Function Types */
261 //@{
262 //--------------------------------------------------------------------------------------------------------------------------------------------------------
263 /** Real input sample function */
264 typedef std::function<rrpt_t(drpt_t)> drpt2rrpt_func_t; // dr2rr (Sample Function)
265 //--------------------------------------------------------------------------------------------------------------------------------------------------------
266 /** Integer input predicate function */
267 typedef std::function<bool(diti_t)> diti2bool_func_t; // di2b (Domain Index Predicate)
268 //--------------------------------------------------------------------------------------------------------------------------------------------------------
269 /** Real input predicate function */
270 typedef std::function<bool(drpt_t)> drpt2bool_func_t; // dr2b (Domain Point Predicate)
271 //--------------------------------------------------------------------------------------------------------------------------------------------------------
272 /** Real input, single real variable output function */
273 typedef std::function<src_t(drpt_t)> drpt2real_func_t; // dr2r (Domain Point SDF)
274 //@}
275
276 private:
277
278 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
279 /** @name Domain Integer Coordinates */
280 //@{
281 //--------------------------------------------------------------------------------------------------------------------------------------------------------
282 constexpr static diti_t diti_ones = ~static_cast<diti_t>(0); // diti_t int with all ones
283 //--------------------------------------------------------------------------------------------------------------------------------------------------------
284 constexpr static diti_t diti_msk0 = static_cast<diti_t>(~(diti_ones << dic_bits)); // diti_t int with ones on 0th coord
285 //@}
286
287 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
288 /** @name Data Members */
289 //@{
290 //--------------------------------------------------------------------------------------------------------------------------------------------------------
291 drpt_t bbox_min; //!< Holds the minimal point for the real domain range
292 drpt_t bbox_max; //!< Holds the maximal point for the real domain range
293 drpt_t bbox_delta; //!< The wdith of the real domain range
294 //--------------------------------------------------------------------------------------------------------------------------------------------------------
295 std::unordered_map<diti_t, rrpt_t> samples; //!< Holds the sampled data
296 //@}
297
298 public:
299
300 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
301 /** @name Constructors */
302 //@{
303 //--------------------------------------------------------------------------------------------------------------------------------------------------------
304 /** Set real coordinates to defaults. see: set_bbox_default(). */
305 MR_rect_tree() { set_bbox_default(); }
306 //--------------------------------------------------------------------------------------------------------------------------------------------------------
307 /** Set real coordinate as specified.
308 @param new_bbox_min Value to use for bounding box minimum point
309 @param new_bbox_max Value to use for bounding box maximum point */
310 MR_rect_tree(drpt_t new_bbox_min, drpt_t new_bbox_max) { set_bbox(new_bbox_min, new_bbox_max); }
311 //@}
312
313 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
314 /** @name Construction Helpers */
315 //@{
316 //--------------------------------------------------------------------------------------------------------------------------------------------------------
317 /** Update the value of bbox_delta.
318 Use this after modifying the value of bbox_min or bbox_max. */
320 if constexpr (dom_dim == 1) {
321 bbox_delta = (bbox_max - bbox_min) / ((dic_t(1) << max_level));
322 if (bbox_max <= bbox_min) {
323 std::cerr << "ERROR(update_bbox_delta): bbox_min must be less than bbox_max!" << std::endl;
324 exit(1);
325 }
326 } else {
327 for(int i=0; i<dom_dim; i++) {
328 bbox_delta[i] = (bbox_max[i] - bbox_min[i]) / ((dic_t(1) << max_level));
329 if (bbox_max[i] <= bbox_min[i]) {
330 std::cerr << "ERROR(update_bbox_delta): Corrisponding elements of bbox_min must be less than bbox_max!" << std::endl;
331 exit(1);
332 }
333 }
334 }
335 }
336 //--------------------------------------------------------------------------------------------------------------------------------------------------------
337 /** Set the bounding box
338 @param new_bbox_min Value to use for bounding box minimum point
339 @param new_bbox_max Value to use for bounding box maximum point */
340 void set_bbox(drpt_t new_bbox_min, drpt_t new_bbox_max) {
341 bbox_min = new_bbox_min;
342 bbox_max = new_bbox_max;
343 update_bbox_delta();
344 }
345 //--------------------------------------------------------------------------------------------------------------------------------------------------------
346 /** Set the bounding box to the default: -1 for all minimum components and +1 for all maximum components. */
348 if constexpr (dom_dim == 1) {
349 bbox_min = static_cast<src_t>(-1.0);
350 bbox_max = static_cast<src_t>( 1.0);
351 } else {
352 bbox_min.fill(static_cast<src_t>(-1.0));
353 bbox_max.fill(static_cast<src_t>( 1.0));
354 }
355 update_bbox_delta();
356 }
357 //--------------------------------------------------------------------------------------------------------------------------------------------------------
358 /** Set the bounding box minimum.
359 @param new_bbox_min Value to use for bounding box minimum point*/
360 void set_bbox_min(drpt_t new_bbox_min) { set_bbox(new_bbox_min, bbox_max); };
361 //--------------------------------------------------------------------------------------------------------------------------------------------------------
362 /** Set the bounding box max_level.
363 @param new_bbox_max Value to use for bounding box maximum point*/
364 void set_bbox_max(drpt_t new_bbox_max) { set_bbox(bbox_min, new_bbox_max); };
365 //@}
366
367 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
368 /** @name Basic Class Info */
369 //@{
370 //--------------------------------------------------------------------------------------------------------------------------------------------------------
371 /** Return the bounding box minimum point */
372 inline drpt_t get_bbox_min() const { return (bbox_min); }
373 //--------------------------------------------------------------------------------------------------------------------------------------------------------
374 /** Return the bounding box minimum point */
375 inline drpt_t get_bbox_max() const { return (bbox_max); }
376 //--------------------------------------------------------------------------------------------------------------------------------------------------------
377 /** Return the bounding box minimum point */
378 inline drpt_t get_bbox_delta() const { return (bbox_delta); }
379 //--------------------------------------------------------------------------------------------------------------------------------------------------------
380 /** Return the sample value for vertex.
381 @param vertex Input vertex */
382 inline rrpt_t get_sample(diti_t vertex) const { return samples.at(vertex); }
383 //--------------------------------------------------------------------------------------------------------------------------------------------------------
384 /** Return the sample value for vertex as an rrta_t (an std::array)
385 @param vertex Input vertex */
386 inline rrta_t get_sample_rrta(diti_t vertex) const {
387 rrta_t ret;
388 if constexpr (rng_dim == 1)
389 ret[0] = get_sample(vertex);
390 else
391 ret = get_sample(vertex);
392 return ret;
393 }
394 //--------------------------------------------------------------------------------------------------------------------------------------------------------
395 /** Provide a constant forward iterator for the sample data.
396 Sample data is stored as a pair with the first element being the packed integer domain coordinates and the second being the sampled data. */
397 inline std::unordered_map<diti_t, rrpt_t>::const_iterator cbegin_samples() { return samples.cbegin(); }
398 //--------------------------------------------------------------------------------------------------------------------------------------------------------
399 /** Provide a constant end iterator for the sample data.
400 see: cbegin_samples(). */
401 inline std::unordered_map<diti_t, rrpt_t>::const_iterator cend_samples() { return samples.cend(); }
402 //@}
403
404 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
405 /** @name Cell Oriented Coordinate Computation
406 These functions compute theoretical values based on a given cell center coordinate, and have nothing to do with sample state.
407
408 For example, the ccc_get_top_cell() function returns the coordinates that would be used to identify the tree's top cell; however, this function tells us
409 nothing about if that cell exists (as been sampled) in the tree.
410
411 In general these routines are optimized for performance, and do not preform any error checking.
412
413 - Many functions require a valid cell coordinate (that is a coordinate that could be the center of a cell). For example, if one of these
414 functions is given 0, then erroneous results are likely because 0 represents the coordinate for the corner of a tree which can never the the
415 center of a cell.
416
417 - When possible, the fewest coordinate components are used. For example ccc_cell_level() uses just the first coordinate in it's computation. */
418 //@{
419 //--------------------------------------------------------------------------------------------------------------------------------------------------------
420 /** Compute the top cell coordinates for the tree
421 @warning Just returns the coordinates regardless of if the top cell exists (is sampled).
422 @return Top cell coordinate for the tree. */
423 inline diti_t ccc_get_top_cell() const { return cuc_set_all_crd(dic_ctr); }
424 //--------------------------------------------------------------------------------------------------------------------------------------------------------
425 /** Compute cell level
426 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
427 @warning Only uses the last dic in the cell to compute value. Thus inconsistant components will not be detected.
428 @param cell Input cell
429 @return The level of the given cell. */
430 inline dic_t ccc_cell_level(diti_t cell) const { return static_cast<dic_t>(max_level-static_cast<diti_t>(1)-std::countr_zero(cell)); }
431 //--------------------------------------------------------------------------------------------------------------------------------------------------------
432 /** Compute cell quarter width
433 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
434 @param cell Input cell
435 @return Quarter width of the given cell. */
436 inline dic_t ccc_cell_quarter_width(diti_t cell) const { return static_cast<dic_t>(ccc_cell_half_width(cell) >> static_cast<dic_t>(1)); }
437 //--------------------------------------------------------------------------------------------------------------------------------------------------------
438 /** Compute cell half width
439 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
440 @param cell Input cell
441 @return Half width of the given cell. */
442 inline dic_t ccc_cell_half_width(diti_t cell) const { return static_cast<dic_t>(cell & (~cell+static_cast<diti_t>(1))); }
443 //--------------------------------------------------------------------------------------------------------------------------------------------------------
444 /** Compute cell full width
445 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
446 @param cell Input cell
447 @return Full width of the given cell. */
448 inline dic_t ccc_cell_full_width(diti_t cell) const { return static_cast<dic_t>(ccc_cell_half_width(cell) << static_cast<dic_t>(1)); }
449 //--------------------------------------------------------------------------------------------------------------------------------------------------------
450 /** Cell first corner
451 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
452 @param cell Input cell
453 @return First corner of given cell */
454 inline diti_t ccc_cell_get_corner_min(diti_t cell) const { return (cuc_dec_all_crd(cell, ccc_cell_half_width(cell))); }
455 //--------------------------------------------------------------------------------------------------------------------------------------------------------
456 /** Cell last corner
457 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
458 @param cell Input cell
459 @return Last corner of given cell */
460 inline diti_t ccc_cell_get_corner_max(diti_t cell) const { return (cuc_inc_all_crd(cell, ccc_cell_half_width(cell))); }
461 //--------------------------------------------------------------------------------------------------------------------------------------------------------
462 /** Return a list of the corners of the given cell
463 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
464 @param cell Input cell */
465 diti_list_t ccc_get_corners(diti_t cell) const { return cuc_two_cross(cell, ccc_cell_half_width(cell)); }
466 //--------------------------------------------------------------------------------------------------------------------------------------------------------
467 /** Return a list of the corners of the given cell
468 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
469 @param cell Input cell
470 @param index The index of the axis. Must be in [0, dom_dim-1]. No error checking.
471 @param direction The direction on the given index. Must be 1 or -1. No error checking. */
472 diti_list_t ccc_get_corners(diti_t cell, int index, int direction) const { return cuc_two_cross(cell, ccc_cell_half_width(cell), index, direction); }
473 //--------------------------------------------------------------------------------------------------------------------------------------------------------
474 /** Return a list of potential neighbor cells of the specified cell
475 Note the cells are not in canonical order!
476 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
477 @param cell Input cell */
478 diti_list_t ccc_get_neighbors(diti_t cell) const { return cuc_axis_cross(cell, ccc_cell_full_width(cell)); }
479 //--------------------------------------------------------------------------------------------------------------------------------------------------------
480 /** Return the potential neighbor cell along the given axis in the specified direction.
481 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
482 @param cell Input cell
483 @param index The index of the axis. Must be in [0, dom_dim-1]. No error checking.
484 @param direction The direction on the given index. Must be 1 or -1. No error checking.
485 @return A neighbor cell coordinate or 0 if no neighbor exists. Note 0 is a valid coordinate, but not the center of any cell. */
486 diti_t ccc_get_neighbor(diti_t cell, int index, int direction) const {
487 dic_t tmp = cuc_get_crd(cell, index);
488 dic_t delta = ccc_cell_full_width(cell);
489 if (direction == 1) {
490 if ((dic_max-tmp) >= delta)
491 return cuc_inc_crd(cell, index, delta);
492 } else {
493 if (tmp >= delta)
494 return cuc_dec_crd(cell, index, delta);
495 }
496 return 0;
497 }
498 //--------------------------------------------------------------------------------------------------------------------------------------------------------
499 /** Return a list of child cells of the specified cell
500 @warning No error checking -- cell must be a valid center coordinate. See: cell_good_cords()
501 If cell can't have children because it is at max_level, then an empty vector is returned.
502 @warning This isn't a check for existing, sampled children -- it simply returns the coordinates of potential children.
503 @param cell Input cell */
505 if (ccc_cell_level(cell) < (max_level-1)) {
506 return cuc_two_cross(cell, ccc_cell_quarter_width(cell));
507 } else {
508 return diti_list_t();
509 }
510 }
511 //--------------------------------------------------------------------------------------------------------------------------------------------------------
512 /** Return a list of child cells of the specified cell
513 An empty vector is returned if no children are possible.
514 @warning This isn't a check for existing, sampled children -- it simply returns the coordinates of potential children.
515 @param cell Input cell
516 @param index The index of the axis. Must be in [0, dom_dim-1]. No error checking.
517 @param direction The direction on the given index. Must be 1 or -1. No error checking.
518 */
519 diti_list_t ccc_get_children(diti_t cell, int index, int direction) const {
520 if (ccc_cell_level(cell) < (max_level-1)) {
521 return cuc_two_cross(cell, ccc_cell_quarter_width(cell), index, direction);
522 } else {
523 return diti_list_t();
524 }
525 }
526 //--------------------------------------------------------------------------------------------------------------------------------------------------------
527 /** Return a list of the vertexes (corners and center) of the given cell
528 @param cell Input cell */
530 diti_list_t rv = ccc_get_corners(cell);
531 rv.push_back(cell);
532 return rv;
533 }
534 //@}
535
536 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
537 /** @name Low Level Integer Tuple Computation
538 These functions encapsulate various coordinate computations.
539
540 In general these routines are optimized for performance, and do not preform any error checking. For example it is possible to underflow/overflow
541 with inappropriate values. */
542 //@{
543 //--------------------------------------------------------------------------------------------------------------------------------------------------------
544 /** Extract a component from a tuple
545 @param diti The input tuple
546 @param index Which component to extract
547 @return The component at index position */
548 inline dic_t cuc_get_crd(diti_t diti, int index) const { return static_cast<dic_t>(diti_msk0 & static_cast<diti_t>(diti >> (dic_bits * index))); }
549 //--------------------------------------------------------------------------------------------------------------------------------------------------------
550 /** Incriment a component in a a tuple
551 @param diti The input tuple
552 @param index Which component to incriment
553 @param value Amout by which to increment the component
554 @return New tuple with the specified component incrimented */
555 inline diti_t cuc_inc_crd(diti_t diti, int index, dic_t value) const { return (diti + (static_cast<diti_t>(static_cast<diti_t>(value) << (dic_bits*index)))); }
556 //--------------------------------------------------------------------------------------------------------------------------------------------------------
557 /** Decriment a component in a a tuple
558 @param diti The input tuple
559 @param index Which component to incriment
560 @param value Amout by which to decrement the component
561 @return New tuple with the specified component decrimented */
562 inline diti_t cuc_dec_crd(diti_t diti, int index, dic_t value) const { return (diti - (static_cast<diti_t>(static_cast<diti_t>(value) << (dic_bits*index)))); }
563 //--------------------------------------------------------------------------------------------------------------------------------------------------------
564 /** Decriment all components in a a tuple
565 @param diti The input tuple
566 @param value Amout by which to decrement each component
567 @return New tuple with decrimented components */
568 inline diti_t cuc_dec_all_crd(diti_t diti, dic_t value) const {
569 if constexpr (dom_dim == 1) {
570 return (diti - value);
571 } else {
572 diti_t rv = diti;
573 diti_t tmp = value;
574 for(int i=0; i<dom_dim; i++) {
575 rv -= tmp;
576 tmp = static_cast<diti_t>(tmp << dic_bits);
577 }
578 return rv;
579 }
580 }
581 //--------------------------------------------------------------------------------------------------------------------------------------------------------
582 /** Incriment all components in a a tuple
583 @param diti The input tuple
584 @param value Amout by which to increment each component
585 @return New tuple with incrimented components */
586 inline diti_t cuc_inc_all_crd(diti_t diti, dic_t value) const {
587 if constexpr (dom_dim == 1) {
588 return (diti + value);
589 } else {
590 diti_t rv = diti;
591 diti_t tmp = value;
592 for(int i=0; i<dom_dim; i++) {
593 rv += tmp;
594 tmp = static_cast<diti_t>(tmp << dic_bits);
595 }
596 return rv;
597 }
598 }
599 //--------------------------------------------------------------------------------------------------------------------------------------------------------
600 /** Set all components in a a tuple to a constant
601 @param value The value for each component
602 @return New tuple */
603 inline diti_t cuc_set_all_crd(dic_t value) const {
604 if constexpr (dom_dim == 1) {
605 return value;
606 } else {
607 diti_t tmp = value;
608 diti_t rv = 0;
609 for(int i=0; i<dom_dim; i++)
610 rv |= (tmp << (i * dic_bits));
611 return rv;
612 }
613 }
614 //--------------------------------------------------------------------------------------------------------------------------------------------------------
615 /** Compute cross product points centered at diti and delta away
616 Examples:
617 - dom_dom==1 => {diti-delta, diti+delta}
618 - dom_dom==2 => {diti+[-delta, -delta], diti+[-delta, +delta], diti+[+delta, -delta], diti+[+delta, +delta]}
619 - dom_dom==3 => {diti+[-delta, -delta, -delta], ..., diti+[+delta, +delta, +delta]} -- this list will have 8 points
620 @param diti Center coordinates for the cross product points
621 @param delta The Distance for the cross product points
622 @return Last of cross product points */
624 // MJR TODO NOTE <2024-07-11T11:50:36-0500> cuc_two_cross: If diti is close to an corner, some result points may be out of range.
625 diti_list_t rv;
626 for(int i=0; i<(1 << dom_dim); i++) {
627 diti_t tmp = diti;
628 for(int j=0; j<dom_dim; j++) {
629 if (i & (1 << j)) {
630 tmp = cuc_inc_crd(tmp, j, delta);
631 } else {
632 tmp = cuc_dec_crd(tmp, j, delta);
633 }
634 }
635 rv.push_back(tmp);
636 }
637 return rv;
638 }
639 //--------------------------------------------------------------------------------------------------------------------------------------------------------
640 /** Compute directional cross product points centered at diti and delta away
641 @warning If diti is close to an corner, then some of the cross product points may be out of range!
642 Examples:
643 - dom_dom==1, index==0, direction==-1 => {diti-delta}
644 - dom_dom==1, index==0, direction== 1 => {diti+delta}
645 - dom_dom==2, index==0, direction==-1 => {diti+[-delta, -delta], diti+[-delta, +delta] }
646 - dom_dom==2, index==0, direction== 1 => { diti+[+delta, -delta], diti+[+delta, +delta]}
647 - dom_dom==2, index==1, direction==-1 => {diti+[-delta, -delta], diti+[+delta, -delta] }
648 - dom_dom==2, index==1, direction== 1 => { diti+[-delta, +delta], diti+[+delta, +delta]}
649 @param diti Center coordinates for the cross product points
650 @param delta The Distance for the cross product points.
651 @param index The index to hold constant. Must be in [0, dom_dom-1]. No error checking.
652 @param direction The direction on the given index. Must be 1 or -1. No error checking.
653 @return List of cross product points */
654 diti_list_t cuc_two_cross(diti_t diti, dic_t delta, int index, int direction) const {
655 diti_list_t rv;
656 if (direction != 1)
657 direction = 0;
658 for(int i=0; i<(1 << dom_dim); i++) {
659 if (((i >> index) & 1) == direction) {
660 diti_t tmp = diti;
661 for(int j=0; j<dom_dim; j++) {
662 if ((i >> j) & 1) {
663 tmp = cuc_inc_crd(tmp, j, delta);
664 } else {
665 tmp = cuc_dec_crd(tmp, j, delta);
666 }
667 }
668 rv.push_back(tmp);
669 }
670 }
671 return rv;
672 }
673 //--------------------------------------------------------------------------------------------------------------------------------------------------------
674 /** Compute axis aligned cross points centered at diti and delta away
675 Axis aligned cross points that fall outside of the domain will not be returned. For example, if diti=0, then we get no points to the left.
676 Examples:
677 - dom_dom==1 => {diti-delta, diti+delta}
678 - dom_dom==2 => {diti+[0, -delta], diti+[0, +delta], diti+[-delta, 0], diti+[+delta, 0]}
679 - dom_dom==3 => {diti+[0, 0, -delta], diti+[0, 0, +delta],
680 diti+[0, -delta, 0], diti+[0, +delta, 0],
681 diti+[-delta, 0, 0], diti+[+delta, 0, 0]}
682 @param diti Center coordinates for the cross
683 @param delta The Distance for the cross points
684 @return Last of cross product points */
686 diti_list_t rv;
687 for(int idx=0; idx<dom_dim; idx++) {
688 for(int up=0; up<2; up++) {
689 dic_t tmp = cuc_get_crd(diti, idx);
690 if (up) {
691 if ((dic_max-tmp) >= delta)
692 rv.push_back(cuc_inc_crd(diti, idx, delta));
693 } else {
694 if (tmp >= delta)
695 rv.push_back(cuc_dec_crd(diti, idx, delta));
696 }
697 }
698 }
699 return rv;
700 }
701 //@}
702
703 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
704 /** @name Easy way to treat rrpt_t & drpt_t types as indexable regardless of dom_dim & rng_dim. */
705 //@{
706 //--------------------------------------------------------------------------------------------------------------------------------------------------------
707 /* Helper to index range values. */
708 inline src_t rng_at(rrpt_t value, int index) const {
709 if constexpr (rng_dim == 1) {
710 return value;
711 } else {
712 return value[index];
713 }
714 }
715 //--------------------------------------------------------------------------------------------------------------------------------------------------------
716 /* Helper to index domain values. */
717 inline src_t dom_at(drpt_t value, int index) const {
718 if constexpr (dom_dim == 1) {
719 return value;
720 } else {
721 return value[index];
722 }
723 }
724 //@}
725
726 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
727 /** @name Packed Integer Tuple <-> std::array of Integer Tuple Conversions */
728 //@{
729 //--------------------------------------------------------------------------------------------------------------------------------------------------------
730 /** Convert an std::array of integer coordinate tuple to an packed integer coordinate tuple.
731 @param dita The std::array of integer coordinate
732 @return New packed integer tuple. */
733 inline diti_t dita_to_diti(const dita_t& dita) const {
734 if constexpr (dom_dim == 1) {
735 return (dita[0]);
736 } else {
737 diti_t rv = 0;
738 for(int i=0; i<dom_dim; i++)
739 rv |= (dita[i] << (i * dic_bits));
740 return rv;
741 }
742 }
743 //--------------------------------------------------------------------------------------------------------------------------------------------------------
744 /** Convert a packed integer coordinate tuple to an std::array of integer coordinate tuple
745 Note dita_t is *always* an std::array even when dom_dim==1.
746 @param diti Packed integer coordinate tuple
747 @return New std::array of integer coordinate tuple */
748 inline dita_t diti_to_dita(diti_t diti) const {
749 if constexpr (dom_dim == 1) {
750 return (dita_t({diti}));
751 } else {
752 dita_t rv;
753 for(int i=0; i<dom_dim; i++)
754 rv[i] = (diti >> ((dom_dim-1-i) * dic_bits)) & diti_msk0;
755 return rv;
756 }
757 }
758 //@}
759
760 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
761 /** @name Integer Tuple to Domain Space Tuple Conversion */
762 //@{
763 //--------------------------------------------------------------------------------------------------------------------------------------------------------
764 /** Convert a packed integer coordinate tuple to the coorisponding coordinate in drpt_t
765 Note this function might return a scalar (float, double, etc...) or a std::array!
766 @param diti Input integer tuple
767 @return domain space value. */
768 inline drpt_t diti_to_drpt(diti_t diti) const {
769 if constexpr (dom_dim == 1) {
770 return (bbox_min + bbox_delta * diti);
771 } else {
772 drpt_t rv;
773 rv.fill(static_cast<src_t>(0.0));
774 for(int i=0; i<dom_dim; i++) {
775 rv[i] = (bbox_min[i] + bbox_delta[i] * cuc_get_crd(diti, i));
776 }
777 return rv;
778 }
779 }
780 //--------------------------------------------------------------------------------------------------------------------------------------------------------
781 /** Convert a packed integer coordinate tuple to the coorisponding std::array tuple of src_t
782 Unlike diti_to_drpt, this function ALWAYS returns an std::array!
783 @param diti Input integer tuple
784 @return domain space value. */
785 inline drta_t diti_to_drta(diti_t diti) const {
786 drta_t rv;
787 rv.fill(static_cast<src_t>(0.0));
788 if constexpr (dom_dim == 1) {
789 rv[0] = (bbox_min + bbox_delta * diti);
790 } else {
791 for(int i=0; i<dom_dim; i++) {
792 rv[i] = (bbox_min[i] + bbox_delta[i] * cuc_get_crd(diti, i));
793 }
794 }
795 return rv;
796 }
797 //@}
798
799 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
800 /** @name Function Sampleing
801
802 Note that refine_grid() is a hybrid in that it can be used for both refinement and for sampling. */
803 //--------------------------------------------------------------------------------------------------------------------------------------------------------
804 /** Sample a cell.
805 @param cell Cell to sample
806 @param func Function to use for samples */
808 if (sample_point_maybe(cell, func)) {
809 for(auto const e: ccc_get_corners(cell)) {
810 sample_point_maybe(e, func);
811 }
812 }
813 }
814 //--------------------------------------------------------------------------------------------------------------------------------------------------------
815 /** @overload */
817 sample_cell(ccc_get_top_cell(), func);
818 }
819 //--------------------------------------------------------------------------------------------------------------------------------------------------------
820 /** Sample a point if it has not already been sampled.
821 @param diti Point at which to sample
822 @param func Function to sample
823 @return true if we sampled the point, and false otherwise. */
825 if ( !(vertex_exists(diti))) {
826 drpt_t xvec = diti_to_drpt(diti);
827 rrpt_t val = func(xvec);
828 samples[diti] = val;
829 return true;
830 } else {
831 return false;
832 }
833 }
834 //--------------------------------------------------------------------------------------------------------------------------------------------------------
835 /** Sample, or resample, a point.
836 @param diti Point at which to sample
837 @param func Function to sample */
838 inline void sample_point(diti_t diti, drpt2rrpt_func_t func) {
839 drpt_t xvec = diti_to_drpt(diti);
840 rrpt_t val = func(xvec);
841 samples[diti] = val;
842 }
843 //@}
844
845 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
846 /** @name Real Range Space Computation */
847 //@{
848 //--------------------------------------------------------------------------------------------------------------------------------------------------------
849 /** Test if a point in the range space contains a NaN coordinate value
850 @param val Value in space */
851 inline bool rrpt_is_nan(rrpt_t val) const {
852 if constexpr (rng_dim == 1) {
853 return std::isnan(val);
854 } else {
855 return (std::any_of(val.cbegin(), val.cend(), [](src_t v) { return (std::isnan(v)); }));
856 }
857 }
858 //--------------------------------------------------------------------------------------------------------------------------------------------------------
859 /** Distance between two points in the range space using the infinity norm (max absolute value)
860 @param val1 Value in range space
861 @param val2 Value in range space */
862 inline src_t rrpt_distance_inf(rrpt_t val1, rrpt_t val2) const {
863 if constexpr (rng_dim == 1) {
864 return std::abs(val1-val2);
865 } else {
866 src_t ret = 0;
867 for(int i=0; i<rng_dim; ++i)
868 ret = std::max(ret, std::abs(val1[i]-val2[i]));
869 return ret;
870 }
871 }
872 //@}
873
874 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
875 /** @name Real Domain Space Computation */
876 //@{
877 //--------------------------------------------------------------------------------------------------------------------------------------------------------
878 /** Distance between two points in the domain space using the infinity norm (max absolute value)
879 @param val1 Value in domain space
880 @param val2 Value in domain space */
881 inline src_t drpt_distance_inf(drpt_t val1, drpt_t val2) const {
882 if constexpr (dom_dim == 1) {
883 return std::abs(val1-val2);
884 } else {
885 src_t ret = 0;
886 for(int i=0; i<dom_dim; ++i)
887 ret = std::max(ret, std::abs(val1[i]-val2[i]));
888 return ret;
889 }
890 }
891 //--------------------------------------------------------------------------------------------------------------------------------------------------------
892 /** Return the midpoint between two points in the domain space
893 @param val1 Value in domain space
894 @param val2 Value in domain space */
895 inline drpt_t drpt_midpoint(drpt_t val1, drpt_t val2) const {
896 if constexpr (dom_dim == 1) {
897 return (val1+val2)/static_cast<src_t>(2.0);
898 } else {
899 drpt_t ret;
900 for(int i=0; i<dom_dim; ++i)
901 ret[i] = (val1[i] + val2[i])/static_cast<src_t>(2.0);
902 return ret;
903 }
904 }
905 //@}
906
907 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
908 /** @name Tree/Cell Refinement
909
910 Three general function smalpling stratigies are provided:
911 - Manual: refine_once()
912 - Uniformly sample a cell: refine_grid() & refine_recursive()
913 - Recine recursively on a predicate: refine_recursive_cell_pred()
914 - Refine leaves with a predicate:
915 - Once: refine_leaves_once_if_cell_pred()
916 - Repeatedly atomically: refine_leaves_atomically_if_cell_pred
917 - Recursively: refine_leaves_recursive_cell_pred()
918 */
919 //@{
920 //--------------------------------------------------------------------------------------------------------------------------------------------------------
921 /** Refine a cell if possible.
922 @param cell Cell to refine -- no error checking!!
923 @param func Function to use for samples
924 @return 1 if cell was refined, and 0 otherwise -- i.e. the number of cells refined. */
926 auto children = ccc_get_children(cell);
927 if (children.empty()) {
928 return 0;
929 } else {
930 for(auto const c : children) // ccc_get_children returns an empty list if the cell is too small to refine.
931 sample_cell(c, func);
932 return 1;
933 }
934 }
935 //--------------------------------------------------------------------------------------------------------------------------------------------------------
936 /** Sample a function uniformly across given cell to the given level.
937 The given cell need not exist in the tree yet.
938
939 @warning Will resample previously sampled points in the cell.
940
941 @param cell The cell to sample within
942 @param level_delta The relative level at which to sample
943 level_delta=0 is equivalent to calling sample_cell(cell, func).
944 level_delta=1 is equivalent to calling sample_cell(cell, func) followed by refine_once(cell, func).
945 @param func Function to use for samples */
946 void refine_grid(diti_t cell, int level_delta, drpt2rrpt_func_t func) {
947 diti_t tmp = ccc_cell_get_corner_min(cell);
948 if constexpr (dom_dim == 1) {
949 dic_t del = ccc_cell_half_width(cell) >> level_delta;
950 for(int i=0; i<(1 << (1+level_delta))+1; i++) {
951 sample_point(tmp, func);
952 tmp += del;
953 }
954 } else if constexpr (dom_dim == 2) {
955 dic_t del = static_cast<dic_t>(ccc_cell_full_width(cell) >> level_delta);
956 // Corners
957 for(dic_t i=0; i<(1 << level_delta)+1; i++) {
958 diti_t tmp2 = cuc_inc_crd(tmp, 0, i*del);
959 for(dic_t j=0; j<(1 << level_delta)+1; j++) {
960 diti_t tmp3 = cuc_inc_crd(tmp2, 1, j*del);
961 sample_point(tmp3, func);
962 }
963 }
964 // Centers
965 tmp = cuc_inc_all_crd(tmp, del/2);
966 for(dic_t i=0; i<(1 << level_delta); i++) {
967 diti_t tmp2 = cuc_inc_crd(tmp, 0, i*del);
968 for(dic_t j=0; j<(1 << level_delta); j++) {
969 diti_t tmp3 = cuc_inc_crd(tmp2, 1, j*del);
970 sample_point(tmp3, func);
971 }
972 }
973 } else if constexpr (dom_dim == 3) {
974 dic_t del = static_cast<dic_t>(ccc_cell_full_width(cell) >> level_delta);
975 // Corners
976 for(dic_t i=0; i<(1 << level_delta)+1; i++) {
977 diti_t tmp2 = cuc_inc_crd(tmp, 0, i*del);
978 for(dic_t j=0; j<(1 << level_delta)+1; j++) {
979 diti_t tmp3 = cuc_inc_crd(tmp2, 1, j*del);
980 for(dic_t k=0; k<(1 << level_delta)+1; k++) {
981 diti_t tmp4 = cuc_inc_crd(tmp3, 2, k*del);
982 sample_point(tmp4, func);
983 }
984 }
985 }
986 // Centers
987 tmp = cuc_inc_all_crd(tmp, del/2);
988 for(dic_t i=0; i<(1 << level_delta); i++) {
989 diti_t tmp2 = cuc_inc_crd(tmp, 0, i*del);
990 for(dic_t j=0; j<(1 << level_delta); j++) {
991 diti_t tmp3 = cuc_inc_crd(tmp2, 1, j*del);
992 for(dic_t k=0; k<(1 << level_delta); k++) {
993 diti_t tmp4 = cuc_inc_crd(tmp3, 2, k*del);
994 sample_point(tmp4, func);
995 }
996 }
997 }
998 } else {
999 std::cout << "ERROR: refine_grid with dom_dim>3 not supported (use refine_recursive)!" << std::endl;
1000 }
1001 }
1002 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1003 /** @overload */
1004 void refine_grid(int level_delta, drpt2rrpt_func_t func) {
1005 refine_grid(ccc_get_top_cell(), level_delta, func);
1006 }
1007 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1008 /** Refine a cell until refined cells reach specified level
1009
1010 @note Unlike most of the other refine functions, this one will sample the given cell. i.e. the provided cell need not be already sampled. This
1011 difference is because this function is frequently called to initially sample a tree.
1012
1013 @param cell Cell to refine
1014 @param level Maximum level of refined cells. -1 means refine to the limit.
1015 @param func Function to use for samples */
1016 void refine_recursive(diti_t cell, int level, drpt2rrpt_func_t func) {
1017 sample_cell(cell, func);
1018 if ((level < 0) || (ccc_cell_level(cell) < level)) {
1019 for(auto const c : ccc_get_children(cell)) {
1020 sample_cell(c, func);
1021 refine_recursive(c, level, func);
1022 }
1023 }
1024 }
1025 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1026 /** @overload */
1027 void refine_recursive(int level, drpt2rrpt_func_t func) {
1028 refine_recursive(ccc_get_top_cell(), level, func);
1029 }
1030 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1031 /** Refine a cells matching predicate until refined cells reach specified level
1032
1033 @warning cell must exist (i.e. must be sampled)
1034
1035 @note Nothing happens if pred isn't true for cell. i.e. this is a worker function to refine a cell with a known condition until the condition is
1036 no longer true, or a maximum level has been reached. This is normally the wrong function to call with the ccc_get_top_cell(). If you wish to
1037 refine recursively all cells in a tree that match a predicate, then use refine_leaves_recursive_cell_pred().
1038
1039 @param cell Cell to refine
1040 @param level Maximum level of refinded cells. -1 means refine to the limit.
1041 @param func Function to use for samples
1042 @param pred Predicate function. */
1044 if ((level < 0) || (ccc_cell_level(cell) < level)) {
1045 if (pred(cell)) {
1046 refine_once(cell, func);
1047 for(auto const c : ccc_get_children(cell)) {
1048 refine_recursive_cell_pred(c, level, func, pred);
1049 }
1050 }
1051 }
1052 }
1053 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1054 /** Refine a cells matching predicate until refined cells reach specified level
1055 @warning cell must exist (i.e. must be sampled)
1056 @param cell Cell to refine
1057 @param level Maximum level of refinded cells. -1 means refine to the limit.
1058 @param func Function to use for samples
1059 @param pred Predicate function. */
1061 for(auto c: get_leaf_cells(cell))
1062 refine_recursive_cell_pred(c, level, func, pred);
1063 }
1064 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1065 /** @overload */
1067 refine_leaves_recursive_cell_pred(ccc_get_top_cell(), level, func, pred);
1068 }
1069 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1070 /** Refine each leaf cell if pred returns true and the cell level is less than the given level value.
1071
1072 All leaf cells are tested with the predicate first. Then the list of cells requiring refinement are refined. This guarantees that no leaf cell
1073 will be refined more than once even if the refinement process would impact the value of the predicate. This can produce qualitatively different
1074 behavior than refine_leaves_recursive_cell_pred() when used with predicates like cell_is_unbalanced().
1075
1076 @param cell Input cell. Must be a valid cell. -- no error checking.
1077 @param level Maximum level of refinded cells. -1 means refine to the limit.
1078 @param func Function to sample
1079 @param pred Predicate function. */
1081 diti_list_t cells_to_check = get_leaf_cells(cell);
1082 diti_list_t cells_to_refine;
1083 for(auto c: cells_to_check)
1084 if (pred(c))
1085 if ((level < 0) || (ccc_cell_level(c) < level))
1086 cells_to_refine.push_back(c);
1087 int refined_count = 0;
1088 for(auto c: cells_to_refine)
1089 refined_count += refine_once(c, func);
1090 return refined_count;
1091 }
1092 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1093 /** @overload */
1095 return refine_leaves_once_if_cell_pred(ccc_get_top_cell(), level, func, pred);
1096 }
1097 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1098 /** Repeatedly refine leaves of the given cell for which pred is true.
1099
1100 Apply refine_leaves_once_if_cell_pred() repeatedly untill no new cells are refined.
1101
1102 @param cell Input cell. Must be a valid cell. -- no error checking.
1103 @param level Maximum level of refinded cells. -1 means refine to the limit.
1104 @param func Function to sample
1105 @param pred Predicate function. */
1107 int refined_count = 0;
1108 while (0 < (refined_count = refine_leaves_once_if_cell_pred(cell, level, func, pred)))
1109 ;
1110 return refined_count;
1111 }
1112 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1113 /** @overload */
1115 return refine_leaves_atomically_if_cell_pred(ccc_get_top_cell(), level, func, pred);
1116 }
1117 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1118 /** Refine a cells with NaNs until refined cells reach specified level
1119
1120 This is a convenience function combining refine_recursive_cell_pred(), cell_vertex_is_nan(), & ccc_get_top_cell().
1121
1122 @param level Maximum level of refinded cells. -1 means refine to the limit.
1123 @param func Function to use for samples */
1125 refine_leaves_recursive_cell_pred(level, func, std::bind_front(&MR_rect_tree::cell_vertex_is_nan, this));
1126 }
1127 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1128 /** Refine leaf cells if they are unbalanced at the given level.
1129
1130 This is a convenience function combining refine_leaves_atomically_if_cell_pred(), cell_is_unbalanced(), & ccc_get_top_cell().
1131
1132 The primary use case is to demonstrate the step wise balancing of a tree.
1133
1134 @param level_delta The Level.
1135 @param func Function to sample */
1137 return refine_leaves_once_if_cell_pred(ccc_get_top_cell(), -1, func, std::bind_front(&cell_is_unbalanced, this, level_delta));
1138 }
1139 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1140 /** Balance the cell to the given level.
1141
1142 This is a convenience function combining refine_leaves_atomically_if_cell_pred(), cell_is_unbalanced(), & ccc_get_top_cell().
1143
1144 @param level_delta The Level.
1145 @param func Function to sample */
1146 void balance_tree(int level_delta, drpt2rrpt_func_t func) {
1147 refine_leaves_atomically_if_cell_pred(ccc_get_top_cell(), -1, func, std::bind_front(&this_t::cell_is_unbalanced, this, level_delta));
1148 }
1149 //@}
1150
1151
1152 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1153 /** @name Cell Predicates */
1154 //@{
1155 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1156 /** Check if cell coordinates are in range to be a cell center
1157 @param cell Input cell
1158 @return True if cell is in bounds, false otherwise */
1159 inline bool cell_good_cords(diti_t cell) const {
1160 if constexpr (dom_dim == 1) {
1161 return ((0 < cell) && (dic_max > cell));
1162 } else {
1163 diti_t working_tuple = cell;
1164 for(int i=0; i<dom_dim; i++) {
1165 dic_t cur_dic = diti_msk0 & working_tuple;
1166 if ((cur_dic <= 0) || (cur_dic >= dic_max)) {
1167 return false;
1168 }
1169 working_tuple = working_tuple >> dic_bits;
1170 }
1171 return true;
1172 }
1173 }
1174 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1175 /** Test if a cell has been sampled.
1176 @warning Simply checks that cell has been sampled -- identical to vertex_exists().
1177 @param cell Input cell*/
1178 inline bool cell_exists(diti_t cell) const {
1179 return (vertex_exists(cell));
1180 }
1181 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1182 /** Test if a cell has been sampled.
1183 @warning Simply checks that cell has been sampled -- identical to vertex_exists().
1184 @param cell Input cell*/
1185 inline bool cell_is_sampled(diti_t cell) const {
1186 diti_list_t verts = ccc_get_vertexes(cell);
1187 return (std::all_of(verts.cbegin(), verts.cend(), [this](diti_t i) { return (vertex_exists(i)); }));
1188 }
1189 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1190 /** Test if a cell has a vertex with a NaN value for a sample
1191 @param cell Input cell */
1192 inline bool cell_vertex_is_nan(diti_t cell) {
1193 diti_list_t verts = ccc_get_vertexes(cell);
1194 return (std::any_of(verts.cbegin(), verts.cend(), [this](diti_t i) { return (vertex_is_nan(i)); }));
1195 }
1196 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1197 /** Test if a cell has an corner with a NaN value for a sample
1198 @param cell Input cell */
1199 inline bool cell_corner_is_nan(diti_t cell) {
1200 diti_list_t corners = ccc_get_corners(cell);
1201 return (std::any_of(corners.cbegin(), corners.cend(), [this](diti_t i) { return (vertex_is_nan(i)); }));
1202 }
1203 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1204 /** Test if a cell has children
1205 @warning Assumes the tree is well formed, and only checks that the "lower left" child's center been sampled!
1206 @param cell Input cell */
1207 inline bool cell_has_child(diti_t cell) const {
1208 return (cell_can_have_children(cell) && cell_exists(cuc_dec_all_crd(cell, ccc_cell_quarter_width(cell))));
1209 }
1210 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1211 /** Test if a cell has no children
1212 @warning Assumes the tree is well formed, and only checks that the "lower left" child's center been sampled!
1213 @param cell Input cell */
1214 inline bool cell_has_no_child(diti_t cell) const {
1215 return ( !(cell_has_child(cell)));
1216 }
1217 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1218 /** Test if a cell can have children (it not of minimal size)
1219 @param cell Input cell */
1220 inline bool cell_can_have_children(diti_t cell) const {
1221 return (ccc_cell_level(cell) < (max_level - 1));
1222 }
1223 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1224 /** Test if the specified neighbor cell exixts (is smapled).
1225 @param index The index of the axis. Must be in [0, dom_dim-1]. No error checking.
1226 @param direction The direction on the given index. Must be 1 or -1. No error checking.
1227 @param cell Input cell */
1228 inline bool cell_has_neighbor(diti_t cell, int index, int direction) {
1229 diti_t tmp = ccc_get_neighbor(cell, index, direction);
1230 if (tmp)
1231 return cell_is_sampled(cell);
1232 else
1233 return false;
1234 }
1235 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1236 /** Test if a cell crosses, or is on, a signed distance function boundry.
1237 "Crossing" is defined as: The center is zero or any corner has a diffrent sign from the center.
1238 @warning Incorrect result if ALL vertexes of the cell are zero.
1239 @param cell Input Cell
1240 @param sdf Signed distance function
1241 @return true if the cell crosses, or is on, the signed distance function boundry. */
1242 inline bool cell_cross_sdf(diti_t cell, drpt2real_func_t sdf) {
1243 /* The algorithm below directly expresses the RHS of the following iff which is equivalent to the LHS (and the statement in the documentation).
1244 @f[
1245 (\mathrm{sgn}(\vec{\mathbf{c}})=0)\lor(\exists \vec{\mathbf{v}}\in E(\vec{\mathbf{c}})\,\mathrm{st}\,\mathrm{sgn}(\vec{\mathbf{c}})\ne\mathrm{sgn}(\vec{\mathbf{v}}))
1246 \Longleftrightarrow
1247 (\exists \vec{\mathbf{v}}\in E(\vec{\mathbf{c}})\,\mathrm{st}\,\mathrm{sgn}(\vec{\mathbf{v}})=0)
1248 \lor
1249 (\exists \vec{\mathbf{v_1}},\vec{\mathbf{v_2}}\in E(\vec{\mathbf{c}})\,\mathrm{st}\,\mathrm{sgn}(\vec{\mathbf{v1}})\ne\mathrm{sgn}(\vec{\mathbf{v2}}))
1250 @f]
1251 */
1252 int center_sign = mjr::math::sfun::sgn(sdf(diti_to_drpt(cell)));
1253 if (center_sign == 0)
1254 return true;
1255 for(diti_t& v: ccc_get_corners(cell))
1256 if (center_sign != mjr::math::sfun::sgn(sdf(diti_to_drpt(v))))
1257 return true;
1258 return false;
1259 }
1260 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1261 /** Test if a cell contains, or is close to, a point in the domain.
1262 @param domain_point The point in the domain
1263 @param epsilon How close the point must be
1264 @param cell Input Cell
1265 @return true if a cell contains, or is close to, a domain_point. */
1266 inline bool cell_near_domain_point(drpt_t domain_point, src_t epsilon, diti_t cell) {
1267 drpt_t min_drpt = diti_to_drpt(ccc_cell_get_corner_min(cell));
1268 for(int i=0; i<dom_dim; i++)
1269 if (dom_at(min_drpt, i)-epsilon > dom_at(domain_point, i))
1270 return false;
1271 drpt_t max_drpt = diti_to_drpt(ccc_cell_get_corner_max(cell));
1272 for(int i=0; i<dom_dim; i++)
1273 if (dom_at(max_drpt, i)+epsilon < dom_at(domain_point, i))
1274 return false;
1275 return true;
1276 }
1277 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1278 /** Test if a cell crosses the given domain component value
1279 @param cell Input Cell
1280 @param domain_index The index of the domain component we are testing
1281 @param domain_level The level, or value, of the domain component we are testing
1282 @param epsilon Used to fuzz floating point comparisons
1283 @return true if the cell crosses the domain level. */
1284 inline bool cell_near_domain_level(diti_t cell, int domain_index, src_t domain_level, src_t epsilon) {
1285 return ( (dom_at(diti_to_drpt(ccc_cell_get_corner_min(cell)), domain_index) < domain_level+epsilon) &&
1286 (dom_at(diti_to_drpt(ccc_cell_get_corner_max(cell)), domain_index) > domain_level-epsilon) );
1287 }
1288 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1289 /** Test if a cell is below the given domain component value
1290 @param cell Input Cell
1291 @param domain_index The index of the domain component we are testing
1292 @param domain_level The level, or value, of the domain component we are testing
1293 @return true if the cell below the domain level. */
1294 inline bool cell_below_domain_level(diti_t cell, int domain_index, src_t domain_level) {
1295 return (dom_at(diti_to_drpt(ccc_cell_get_corner_max(cell)), domain_index) < domain_level);
1296 }
1297 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1298 /** Test if a cell above the given domain component value
1299 @param cell Input Cell
1300 @param domain_index The index of the domain component we are testing
1301 @param domain_level The level, or value, of the domain component we are testing
1302 @return true if the cell above the domain level. */
1303 inline bool cell_above_domain_level(diti_t cell, int domain_index, src_t domain_level) {
1304 return ((dom_at(diti_to_drpt(ccc_cell_get_corner_min(cell)), domain_index) > domain_level));
1305 }
1306 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1307 /** Test if a cell crosses the given range component value.
1308 See ::cell_cross_sdf for algorithm notes.
1309 @param cell Input Cell
1310 @param range_index The index of the range component we are testing
1311 @param range_level The level, or value, of the range component we are testing
1312 @return true if the cell crosses the range level. */
1313 inline bool cell_cross_range_level(diti_t cell, int range_index, src_t range_level) {
1314 int center_sign = mjr::math::sfun::sgn(rng_at(samples[cell], range_index)-range_level);
1315 if (center_sign == 0)
1316 return true;
1317 for(diti_t& v: ccc_get_corners(cell))
1318 if (center_sign != mjr::math::sfun::sgn(rng_at(samples[v], range_index)-range_level))
1319 return true;
1320 return false;
1321 }
1322 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1323 /** Test if a cell is below given range component value
1324 @param cell Input Cell
1325 @param range_index The index of the range component we are testing
1326 @param range_level The level, or value, of the range component we are testing
1327 @return true if the cell is below the range level. */
1328 inline bool cell_below_range_level(diti_t cell, int range_index, src_t range_level) {
1329 diti_list_t verts = ccc_get_vertexes(cell);
1330 return std::all_of(verts.cbegin(), verts.cend(), [this, range_index, range_level](int i) { return (rng_at(samples[i], range_index) < range_level); });
1331 }
1332 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1333 /** Test if a cell is above given range component value
1334 @param cell Input Cell
1335 @param range_index The index of the range component we are testing
1336 @param range_level The level, or value, of the range component we are testing
1337 @return true if the cell is above the range level. */
1338 inline bool cell_above_range_level(diti_t cell, int range_index, src_t range_level) {
1339 diti_list_t verts = ccc_get_vertexes(cell);
1340 return std::all_of(verts.cbegin(), verts.cend(), [this, range_index, range_level](int i) { return (rng_at(samples[i], range_index) > range_level); });
1341 }
1342 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1343 /** Test if a cell is unbalanced at the given level
1344 @param cell Input Cell
1345 @param level_delta Signed distance function
1346 @return true if the cell is unbalanced at the given level. */
1347 bool cell_is_unbalanced(int level_delta, diti_t cell) {
1348 // MJR TODO NOTE <2024-07-11T16:04:10-0500> cell_is_unbalanced: Optimize run time (nix the use of get_smallest_neighbor_level)
1349 int max_level_neighbor = get_smallest_neighbor_level(cell);
1350 int current_ccc_cell_level = ccc_cell_level(cell);
1351 if (max_level_neighbor > current_ccc_cell_level+level_delta)
1352 return true;
1353 else
1354 return false;
1355 }
1356 //@}
1357
1358 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1359 /** @name Vertex Predicates */
1360 //@{
1361 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1362 /** Test if a vertex is NaN or, when it is an std::array, if it contains a NaN element
1363 @param vertex Input vertex */
1364 inline bool vertex_is_nan(diti_t vertex) {
1365 if constexpr (rng_dim == 1) {
1366 return std::isnan(samples[vertex]);
1367 } else {
1368 return (std::any_of(samples[vertex].cbegin(), samples[vertex].cend(), [this](src_t v) { return (std::isnan(v)); }));
1369 }
1370 }
1371 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1372 /** Point has been sampled.
1373 @param vertex Input vertex */
1374 inline bool vertex_exists(diti_t vertex) const {
1375 return (samples.contains(vertex));
1376 }
1377 //@}
1378
1379 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1380 /** @name Extract Cells */
1381 //@{
1382 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1383 /** Extract a list of all leaf cells starting from the given cell
1384 @param cell Starting cell */
1386 diti_list_t rv;
1387 if (cell_has_child(cell)) {
1388 for(auto const c : ccc_get_children(cell)) {
1389 auto mv = get_leaf_cells(c);
1390 std::move(mv.begin(), mv.end(), std::back_inserter(rv));
1391 }
1392 } else {
1393 rv.push_back(cell);
1394 }
1395 return rv;
1396 }
1397 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1398 /** @overload */
1400 return get_leaf_cells(ccc_get_top_cell());
1401 }
1402 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1403 /** Extract a list of all leaf cells starting from the given cell that match the given predicate
1404 @warning The given cell need not match the predicate.
1405 @param cell Starting cell
1406 @param pred Predicate function. */
1408 diti_list_t cells_to_return;
1409 for(auto c: get_leaf_cells(cell))
1410 if (pred(c))
1411 cells_to_return.push_back(c);
1412 return cells_to_return;
1413 }
1414 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1415 /** Extract a list of all leaf cells starting from the given cell
1416 @param cell Input cell. Must be a valid cell. -- no error checking.
1417 @param index The index of the axis. Must be in [0, dom_dim-1]. No error checking.
1418 @param direction The direction on the given index. Must be 1 or -1. No error checking. */
1419 diti_list_t get_leaf_cells(diti_t cell, int index, int direction) const {
1420 diti_list_t rv;
1421 if (cell_has_child(cell)) {
1422 for(auto const c : ccc_get_children(cell, index, direction)) {
1423 auto mv = get_leaf_cells(c, index, direction);
1424 std::move(mv.begin(), mv.end(), std::back_inserter(rv));
1425 }
1426 } else {
1427 rv.push_back(cell);
1428 }
1429 return rv;
1430 }
1431 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1432 /** Count the number of leaf cells starting from the given cell
1433 @param cell Starting cell */
1434 int count_leaf_cells(diti_t cell) const {
1435 int rv=0;
1436 if (cell_has_child(cell)) {
1437 for(auto const c : ccc_get_children(cell)) {
1438 int mv = count_leaf_cells(c);
1439 rv+=mv;
1440 }
1441 } else {
1442 rv++;
1443 }
1444 return rv;
1445 }
1446 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1447 /** Return a list of sampled neighbors to the given cell.
1448 @warning Unlike ccc_get_neighbor(), this member returns a *list* of *existing* (sampled) cell centers.
1449 @param cell Input cell. Must be a valid cell. -- no error checking.
1450 @param index The index of the axis. Must be in [0, dom_dim-1]. No error checking.
1451 @param direction The direction on the given index. Must be 1 or -1. No error checking.
1452 @return List of existing neighbors. */
1453 diti_list_t get_existing_neighbor(diti_t cell, int index, int direction) const {
1454 diti_t tmp = ccc_get_neighbor(cell, index, direction);
1455 if ( (tmp!=0) && cell_exists(tmp)) {
1456 if (cell_has_child(tmp)) {
1457 return get_leaf_cells(tmp, index, -direction);
1458 } else {
1459 return diti_list_t({tmp});
1460 }
1461 }
1462 return diti_list_t();
1463 }
1464 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1465 /** Return the level of the smallest, existing neighbor.
1466 Returns -1 if no neighbors exist.
1467 @param cell Input cell. Must be a valid cell. -- no error checking. */
1469 int maximum_level = -1;
1470 int start_level = ccc_cell_level(cell);
1471 for(int aix=0; aix<dom_dim; aix++) {
1472 for(int dir=-1; dir<2; dir+=2) {
1473 diti_t nbr0 = ccc_get_neighbor(cell, aix, dir);
1474 if ( (nbr0!=0) && cell_exists(nbr0)) {
1475 if (cell_has_child(nbr0)) {
1476 diti_list_t nbr_leafs = get_leaf_cells(nbr0, aix, -dir);
1477 for(auto nbr_leaf: nbr_leafs) {
1478 int nbr_leaf_lvl = ccc_cell_level(nbr_leaf);
1479 if (nbr_leaf_lvl > maximum_level)
1480 maximum_level = nbr_leaf_lvl;
1481 }
1482 } else {
1483 if (start_level > maximum_level)
1484 maximum_level = start_level;
1485 }
1486 }
1487 }
1488 }
1489 return maximum_level;
1490 }
1491 //@}
1492
1493 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1494 /** @name Debug */
1495 //@{
1496 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1497 /** Convert a diti_t to a string representation
1498 @param diti The diti_t to convert
1499 @param do_hex Print hex if true
1500 @param include_domain When true, also include the real coordinates in the string representation. */
1501 std::string diti_to_string(diti_t diti, bool include_domain, bool do_hex) const {
1502 std::ostringstream convert;
1503 int pwid = (do_hex ? (max_level+1)/4+1 : (max_level+1)/2+1);
1504 dita_t tmp1 = diti_to_dita(diti);
1505 for(int i=0; i<dom_dim; i++)
1506 convert << std::setw(pwid) << std::setfill('0') << (do_hex ? std::hex : std::dec ) << (uint32_t)tmp1[dom_dim-1-i] << std::dec << std::setw(0) << std::setfill('\0') << " ";
1507 if (include_domain) {
1508 drta_t tmp3 = diti_to_drta(diti);
1509 convert << "[ ";
1510 for (const auto tmp4 : tmp3)
1511 convert << std::setprecision(5) << static_cast<src_t>(tmp4) << " ";
1512 convert << "] ";
1513 }
1514 return(convert.str());
1515 }
1516 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1517 std::string diti_to_string(diti_t diti, bool include_domain) const { return diti_to_string(diti, include_domain, true); }
1518 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1519 std::string diti_to_string(diti_t diti) const { return diti_to_string(diti, true, true); }
1520 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1521 /** Convert a drpt_t to a string representation */
1522 std::string drpt_to_string(drpt_t x) const {
1523 std::ostringstream convert;
1524 if constexpr (dom_dim == 1) {
1525 convert << "[ " << x << " ]";
1526 } else {
1527 convert << "[ ";
1528 for(auto c: x)
1529 convert << std::setprecision(5) << static_cast<src_t>(c) << " ";
1530 convert << "]";
1531 }
1532 return(convert.str());
1533 }
1534 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1535 /** Convert rrpt value to a string representation */
1536 std::string rrpt_to_string(rrpt_t x) const {
1537 std::ostringstream convert;
1538 if constexpr (rng_dim == 1) {
1539 convert << "[ " << x << " ]";
1540 } else {
1541 convert << "[ ";
1542 for(auto c: x)
1543 convert << std::setprecision(5) << static_cast<src_t>(c) << " ";
1544 convert << "]";
1545 }
1546 return(convert.str());
1547 }
1548 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1549 /** Dump tree to STDOUT
1550 @param max_num_print Maximum number of samples to print. Use 0 to print all samples. */
1551 void dump_tree(int max_num_print) const {
1552 std::cout << "Meta Data" << std::endl;
1553 std::cout << " get_bbox_min ... " << drpt_to_string(get_bbox_min()) << std::endl;
1554 std::cout << " get_bbox_max ... " << drpt_to_string(get_bbox_max()) << std::endl;
1555 std::cout << " dom_dim ........ " << dom_dim << std::endl;
1556 std::cout << " rng_dim ........ " << rng_dim << std::endl;
1557 std::cout << " max_level ...... " << max_level << std::endl;
1558 std::cout << " size icrd Cmp .. " << sizeof(dic_t) << std::endl;
1559 std::cout << " size icrd Tup .. " << sizeof(diti_t) << std::endl;
1560 std::cout << " Samples ........ " << samples.size() << std::endl;
1561 std::cout << " Leaf Cells ..... " << count_leaf_cells(ccc_get_top_cell()) << std::endl;
1562 std::cout << "Samples" << std::endl;
1563 int num_printed = 0;
1564 for (const auto& kvp : samples) {
1565 std::cout << " c=" << diti_to_string(kvp.first, true);
1566 std::cout << " v=" << rrpt_to_string(kvp.second) << std::endl;
1567 num_printed++;
1568 if ((max_num_print > 0) && (num_printed >= max_num_print)) {
1569 std::cout << "Maximum number of samples reached. Halting tree dump." << std::endl;
1570 break;
1571 }
1572 }
1573 }
1574 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1575 /** Dump tree points to file -- one tuple per line with domain coordinates followed by range values. */
1576 int dump_tree_datafile(std::string file_name) const {
1577 std::ofstream out_stream;
1578 out_stream.open(file_name, std::ios::out | std::ios::binary | std::ios::trunc);
1579 if (out_stream.is_open()) {
1580 out_stream.imbue(std::locale::classic());
1581 } else {
1582 std::cout << "ERROR(write_xml_vtk): Could not open file!" << std::endl;
1583 return 1;
1584 }
1585 for (const auto& kvp : samples) {
1586 for(int i=0; i<dom_dim; i++)
1587 out_stream << std::setprecision(5) << dom_at(diti_to_drpt(kvp.first), i) << " ";
1588 for(int i=0; i<rng_dim; i++)
1589 out_stream << std::setprecision(5) << rng_at(kvp.second, i) << " ";
1590 out_stream << std::endl;
1591 }
1592 out_stream.close();
1593 return 0;
1594 }
1595
1596 //@}
1597
1598 };
1599
1600 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1601 /* 7-bit per coordinate */
1607
1612
1617
1622
1623
1624 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1625 /* 15-bit per coordinate */
1626
1627 typedef mjr::MR_rect_tree<15, double, 1, 1> tree15b1d1rT; // Curve defined by [x, f(x)]
1628 typedef mjr::MR_rect_tree<15, double, 2, 1> tree15b2d1rT; // Surface defined by [x, y, f(x, y)]
1629 // Monochrome image defined by [x, y] and colored by f(x, y)
1630 // 2D scalar field
1633
1634 typedef mjr::MR_rect_tree<15, double, 1, 2> tree15b1d2rT; // Parametric Plane Curve defined by [x(t), y(t)]
1635 typedef mjr::MR_rect_tree<15, double, 2, 2> tree15b2d2rT; // Complex function magnutude surface defined by [Re(z), Im(z), mag(z)]
1638
1639 typedef mjr::MR_rect_tree<15, double, 1, 3> tree15b1d3rT; // Parametric Space Curve defined by [x(t), y(t), z(t)]
1640 typedef mjr::MR_rect_tree<15, double, 2, 3> tree15b2d3rT; // Parametric Surface defined by [x(u, v), y(u, v), z(u, v)]
1641 // RGB image defined by [x, y] and colored by [f_1(x, y), f_2(x, y), f_3(x, y)]
1644
1645 typedef mjr::MR_rect_tree<15, double, 1, 4> tree15b1d4rT; // curve defined by [x, f(x)] with point color
1646 // Parametric Plane Curve defined by [x(t), y(t)] with velocity vector
1647 // 3D scalar field with piont color
1648 typedef mjr::MR_rect_tree<15, double, 2, 4> tree15b2d4rT; // Complex function magnutude surface defined by [Re(z), Im(z), mag(z)] with point color XOR surface normals
1649 // Surface defined by [x, y, f(x, y)] with surface normal XOR point color
1650 // 2D scalar field with point color
1653
1654 typedef mjr::MR_rect_tree<15, double, 1, 5> tree15b1d5rT; // Parametric Plane Curve defined by [x(t), y(t)] with point color
1658
1659 typedef mjr::MR_rect_tree<15, double, 1, 6> tree15b1d6rT; // Parametric Space Curve defined by [x(t), y(t), z(t)] with velocity vector XOR point color
1660 typedef mjr::MR_rect_tree<15, double, 2, 6> tree15b2d6rT; // Parametric Surface defined by [x(u, v), y(u, v), z(u, v)] with surface normal XOR point color
1663
1664 typedef mjr::MR_rect_tree<15, double, 1, 7> tree15b1d7rT; // Parametric Plane Curve defined by [x(t), y(t)] with velocity vector AND point color
1665 typedef mjr::MR_rect_tree<15, double, 2, 7> tree15b2d7rT; // Surface defined by [x, y, f(x, y)] with surface normal AND point color
1666 // Complex function magnutude surface defined by [Re(z), Im(z), mag(z)] with point color AND surface normals
1669
1674
1675 typedef mjr::MR_rect_tree<15, double, 1, 9> tree15b1d9rT; // Parametric Space Curve defined by [x(t), y(t), z(t)] with velocity vector AND point color
1676 typedef mjr::MR_rect_tree<15, double, 2, 9> tree15b2d9rT; // Parametric Surface defined by [x(u, v), y(u, v), z(u, v)] with surface normal AND point color
1679
1684
1689
1694
1699
1704
1709
1710 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1711 /* 31-bit per coordinate */
1714
1717
1720
1723
1724 //--------------------------------------------------------------------------------------------------------------------------------------------------------
1725 /* 63-bit per coordinate */
1726
1731}
1732
1733#define MJR_INCLUDE_MR_rect_tree
1734#endif
Template Class used to house an MR_rect_tree.
dic_t ccc_cell_level(diti_t cell) const
Compute cell level.
diti_list_t ccc_get_vertexes(diti_t cell) const
Return a list of the vertexes (corners and center) of the given cell.
drpt_t get_bbox_delta() const
Return the bounding box minimum point.
dic_t ccc_cell_full_width(diti_t cell) const
Compute cell full width.
void refine_recursive_if_cell_vertex_is_nan(int level, drpt2rrpt_func_t func)
Refine a cells with NaNs until refined cells reach specified level.
src_t rrpt_distance_inf(rrpt_t val1, rrpt_t val2) const
Distance between two points in the range space using the infinity norm (max absolute value)
bool cell_above_range_level(diti_t cell, int range_index, src_t range_level)
Test if a cell is above given range component value.
bool cell_above_domain_level(diti_t cell, int domain_index, src_t domain_level)
Test if a cell above the given domain component value.
diti_t ccc_get_top_cell() const
Compute the top cell coordinates for the tree.
std::array< src_t, rng_dim > rrta_t
An std::array for points in the range space.
std::unordered_map< diti_t, rrpt_t > samples
Holds the sampled data.
diti_list_t get_existing_neighbor(diti_t cell, int index, int direction) const
Return a list of sampled neighbors to the given cell.
void set_bbox_min(drpt_t new_bbox_min)
Set the bounding box minimum.
std::string drpt_to_string(drpt_t x) const
Convert a drpt_t to a string representation.
bool cell_cross_range_level(diti_t cell, int range_index, src_t range_level)
Test if a cell crosses the given range component value.
rrta_t get_sample_rrta(diti_t vertex) const
Return the sample value for vertex as an rrta_t (an std::array)
dita_t diti_to_dita(diti_t diti) const
Convert a packed integer coordinate tuple to an std::array of integer coordinate tuple Note dita_t is...
MR_rect_tree(drpt_t new_bbox_min, drpt_t new_bbox_max)
Set real coordinate as specified.
bool cell_near_domain_level(diti_t cell, int domain_index, src_t domain_level, src_t epsilon)
Test if a cell crosses the given domain component value.
std::function< bool(diti_t)> diti2bool_func_t
Integer input predicate function.
void refine_leaves_recursive_cell_pred(int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool cell_has_neighbor(diti_t cell, int index, int direction)
Test if the specified neighbor cell exixts (is smapled).
std::function< rrpt_t(drpt_t)> drpt2rrpt_func_t
Real input sample function.
int refine_leaves_once_if_unbalanced(int level_delta, drpt2rrpt_func_t func)
Refine leaf cells if they are unbalanced at the given level.
bool cell_cross_sdf(diti_t cell, drpt2real_func_t sdf)
Test if a cell crosses, or is on, a signed distance function boundry.
bool vertex_exists(diti_t vertex) const
Point has been sampled.
void balance_tree(int level_delta, drpt2rrpt_func_t func)
Balance the cell to the given level.
diti_list_t ccc_get_children(diti_t cell, int index, int direction) const
Return a list of child cells of the specified cell An empty vector is returned if no children are pos...
void refine_recursive(diti_t cell, int level, drpt2rrpt_func_t func)
Refine a cell until refined cells reach specified level.
bool cell_corner_is_nan(diti_t cell)
Test if a cell has an corner with a NaN value for a sample.
diti_t cuc_set_all_crd(dic_t value) const
Set all components in a a tuple to a constant.
void refine_leaves_recursive_cell_pred(diti_t cell, int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
Refine a cells matching predicate until refined cells reach specified level.
diti_t ccc_get_neighbor(diti_t cell, int index, int direction) const
Return the potential neighbor cell along the given axis in the specified direction.
std::string diti_to_string(diti_t diti, bool include_domain) const
bool vertex_is_nan(diti_t vertex)
Test if a vertex is NaN or, when it is an std::array, if it contains a NaN element.
std::conditional< std::cmp_greater_equal(CHAR_BIT *sizeof(int8_t), diti_bits), uint8_t, typenamestd::conditional< std::cmp_greater_equal(CHAR_BIT *sizeof(int16_t), diti_bits), uint16_t, typenamestd::conditional< std::cmp_greater_equal(CHAR_BIT *sizeof(int32_t), diti_bits), uint32_t, uint64_t >::type >::type >::type priv_diti_t
diti_t ccc_cell_get_corner_min(diti_t cell) const
Cell first corner.
bool cell_vertex_is_nan(diti_t cell)
Test if a cell has a vertex with a NaN value for a sample.
diti_t dita_to_diti(const dita_t &dita) const
Convert an std::array of integer coordinate tuple to an packed integer coordinate tuple.
bool cell_can_have_children(diti_t cell) const
Test if a cell can have children (it not of minimal size)
void set_bbox_default()
Set the bounding box to the default: -1 for all minimum components and +1 for all maximum components.
void refine_grid(int level_delta, drpt2rrpt_func_t func)
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::function< src_t(drpt_t)> drpt2real_func_t
Real input, single real variable output function.
drpt_t bbox_max
Holds the maximal point for the real domain range.
std::unordered_map< diti_t, rrpt_t >::const_iterator cbegin_samples()
Provide a constant forward iterator for the sample data.
diti_list_t cuc_axis_cross(diti_t diti, dic_t delta) const
Compute axis aligned cross points centered at diti and delta away Axis aligned cross points that fall...
bool cell_good_cords(diti_t cell) const
Check if cell coordinates are in range to be a cell center.
void refine_recursive(int level, drpt2rrpt_func_t func)
This is an overloaded member function, provided for convenience. It differs from the above function o...
MR_rect_tree< max_level, spc_real_t, dom_dim, rng_dim > this_t
Externally exposed typedef for spc_real_t.
priv_diti_t diti_t
Unsigned integer type large large enough to hold an integer coordiante tuple.
diti_t cuc_dec_crd(diti_t diti, int index, dic_t value) const
Decriment a component in a a tuple.
diti_t ccc_cell_get_corner_max(diti_t cell) const
Cell last corner.
diti_t cuc_inc_all_crd(diti_t diti, dic_t value) const
Incriment all components in a a tuple.
diti_list_t ccc_get_children(diti_t cell) const
Return a list of child cells of the specified cell.
bool cell_is_sampled(diti_t cell) const
Test if a cell has been sampled.
std::function< bool(drpt_t)> drpt2bool_func_t
Real input predicate function.
bool cell_near_domain_point(drpt_t domain_point, src_t epsilon, diti_t cell)
Test if a cell contains, or is close to, a point in the domain.
bool cell_has_no_child(diti_t cell) const
Test if a cell has no children.
bool cell_below_range_level(diti_t cell, int range_index, src_t range_level)
Test if a cell is below given range component value.
src_t dom_at(drpt_t value, int index) const
drpt_t real_domain_t
A nicely descriptive typedef for drpt_t.
bool cell_has_child(diti_t cell) const
Test if a cell has children.
std::conditional< std::cmp_equal(dom_dim, 1), src_t, drta_t >::type drpt_t
For values in the domain space.
bool sample_point_maybe(diti_t diti, drpt2rrpt_func_t func)
Sample a point if it has not already been sampled.
std::string rrpt_to_string(rrpt_t x) const
Convert rrpt value to a string representation.
void sample_point(diti_t diti, drpt2rrpt_func_t func)
Sample, or resample, a point.
priv_dic_t dic_t
Unsigned integer type large large enough to hold an integer coordiante component.
std::array< dic_t, 3 > dita_t
Domain point given as an std::array integer tuple.
bool cell_below_domain_level(diti_t cell, int domain_index, src_t domain_level)
Test if a cell is below the given domain component value.
int refine_leaves_atomically_if_cell_pred(int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
This is an overloaded member function, provided for convenience. It differs from the above function o...
drpt_t drpt_midpoint(drpt_t val1, drpt_t val2) const
Return the midpoint between two points in the domain space.
src_t drpt_distance_inf(drpt_t val1, drpt_t val2) const
Distance between two points in the domain space using the infinity norm (max absolute value)
drta_t diti_to_drta(diti_t diti) const
Convert a packed integer coordinate tuple to the coorisponding std::array tuple of src_t Unlike diti_...
rrpt_t real_range_t
A nicely descriptive typedef for rrpt_t.
diti_t cuc_dec_all_crd(diti_t diti, dic_t value) const
Decriment all components in a a tuple.
diti_list_t get_leaf_cells() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::unordered_map< diti_t, rrpt_t >::const_iterator cend_samples()
Provide a constant end iterator for the sample data.
std::conditional< std::cmp_equal(rng_dim, 1), src_t, rrta_t >::type rrpt_t
For values in the range space.
diti_list_t cuc_two_cross(diti_t diti, dic_t delta, int index, int direction) const
Compute directional cross product points centered at diti and delta away.
dic_t ccc_cell_quarter_width(diti_t cell) const
Compute cell quarter width.
diti_t cuc_inc_crd(diti_t diti, int index, dic_t value) const
Incriment a component in a a tuple.
int count_leaf_cells(diti_t cell) const
Count the number of leaf cells starting from the given cell.
void refine_grid(diti_t cell, int level_delta, drpt2rrpt_func_t func)
Sample a function uniformly across given cell to the given level.
std::vector< diti_t > diti_list_t
A std::vector used to pass lists of diti_t types around.
diti_list_t ccc_get_corners(diti_t cell, int index, int direction) const
Return a list of the corners of the given cell.
int get_smallest_neighbor_level(diti_t cell) const
Return the level of the smallest, existing neighbor.
void set_bbox(drpt_t new_bbox_min, drpt_t new_bbox_max)
Set the bounding box.
std::string diti_to_string(diti_t diti) const
drpt_t get_bbox_max() const
Return the bounding box minimum point.
void update_bbox_delta()
Update the value of bbox_delta.
bool cell_is_unbalanced(int level_delta, diti_t cell)
Test if a cell is unbalanced at the given level.
std::string diti_to_string(diti_t diti, bool include_domain, bool do_hex) const
Convert a diti_t to a string representation.
dic_t ccc_cell_half_width(diti_t cell) const
Compute cell half width.
drpt_t bbox_min
Holds the minimal point for the real domain range.
rrpt_t get_sample(diti_t vertex) const
Return the sample value for vertex.
spc_real_t src_t
Externally exposed typedef for spc_real_t.
int refine_leaves_atomically_if_cell_pred(diti_t cell, int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
Repeatedly refine leaves of the given cell for which pred is true.
std::vector< dic_t > ditv_t
Domain point given as an std::vector integer tuple.
diti_list_t get_leaf_cells(diti_t cell, int index, int direction) const
Extract a list of all leaf cells starting from the given cell.
void dump_tree(int max_num_print) const
Dump tree to STDOUT.
bool cell_exists(diti_t cell) const
Test if a cell has been sampled.
int refine_leaves_once_if_cell_pred(int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
This is an overloaded member function, provided for convenience. It differs from the above function o...
std::vector< src_t > drtv_t
std::vector for values in the domain space.
diti_list_t get_leaf_cells_pred(diti_t cell, diti2bool_func_t pred) const
Extract a list of all leaf cells starting from the given cell that match the given predicate.
int dump_tree_datafile(std::string file_name) const
Dump tree points to file – one tuple per line with domain coordinates followed by range values.
drpt_t bbox_delta
The wdith of the real domain range.
void set_bbox_max(drpt_t new_bbox_max)
Set the bounding box max_level.
drpt_t diti_to_drpt(diti_t diti) const
Convert a packed integer coordinate tuple to the coorisponding coordinate in drpt_t Note this functio...
drpt_t get_bbox_min() const
Return the bounding box minimum point.
int refine_leaves_once_if_cell_pred(diti_t cell, int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
Refine each leaf cell if pred returns true and the cell level is less than the given level value.
bool refine_once(diti_t cell, drpt2rrpt_func_t func)
Refine a cell if possible.
diti_list_t get_leaf_cells(diti_t cell) const
Extract a list of all leaf cells starting from the given cell.
diti_list_t cuc_two_cross(diti_t diti, dic_t delta) const
Compute cross product points centered at diti and delta away Examples:
std::vector< src_t > rrtv_t
std::vector for values in the range space.
void refine_recursive_cell_pred(diti_t cell, int level, drpt2rrpt_func_t func, diti2bool_func_t pred)
Refine a cells matching predicate until refined cells reach specified level.
dic_t cuc_get_crd(diti_t diti, int index) const
Extract a component from a tuple.
std::conditional< std::cmp_greater_equal(CHAR_BIT *sizeof(int8_t), dic_bits), uint8_t, typenamestd::conditional< std::cmp_greater_equal(CHAR_BIT *sizeof(int16_t), dic_bits), uint16_t, typenamestd::conditional< std::cmp_greater_equal(CHAR_BIT *sizeof(int32_t), dic_bits), uint32_t, uint64_t >::type >::type >::type priv_dic_t
void sample_cell(drpt2rrpt_func_t func)
This is an overloaded member function, provided for convenience. It differs from the above function o...
src_t rng_at(rrpt_t value, int index) const
diti_list_t ccc_get_corners(diti_t cell) const
Return a list of the corners of the given cell.
diti_list_t ccc_get_neighbors(diti_t cell) const
Return a list of potential neighbor cells of the specified cell Note the cells are not in canonical o...
bool rrpt_is_nan(rrpt_t val) const
Test if a point in the range space contains a NaN coordinate value.
MR_rect_tree()
Set real coordinates to defaults.
void sample_cell(diti_t cell, drpt2rrpt_func_t func)
Sample a cell.
std::array< src_t, dom_dim > drta_t
An std::array for points in the domain space.
mjr::MR_rect_tree< 15, double, 4, 1 > tree15b4d1rT
mjr::MR_rect_tree< 15, double, 3, 3 > tree15b3d3rT
mjr::MR_rect_tree< 7, double, 4, 2 > tree7b4d2rT
mjr::MR_rect_tree< 31, double, 2, 4 > tree31b2d4rT
mjr::MR_rect_tree< 15, double, 3, 9 > tree15b3d9rT
mjr::MR_rect_tree< 31, double, 2, 3 > tree31b2d3rT
mjr::MR_rect_tree< 7, double, 3, 3 > tree7b3d3rT
mjr::MR_rect_tree< 15, double, 1, 1 > tree15b1d1rT
mjr::MR_rect_tree< 15, double, 3, 12 > tree15b3d12rT
mjr::MR_rect_tree< 15, double, 1, 14 > tree15b1d14rT
mjr::MR_rect_tree< 15, double, 2, 7 > tree15b2d7rT
mjr::MR_rect_tree< 7, double, 4, 1 > tree7b4d1rT
mjr::MR_rect_tree< 7, double, 2, 1 > tree7b2d1rT
mjr::MR_rect_tree< 15, double, 2, 9 > tree15b2d9rT
mjr::MR_rect_tree< 15, double, 3, 2 > tree15b3d2rT
mjr::MR_rect_tree< 15, double, 1, 9 > tree15b1d9rT
mjr::MR_rect_tree< 7, double, 2, 2 > tree7b2d2rT
mjr::MR_rect_tree< 15, double, 3, 13 > tree15b3d13rT
mjr::MR_rect_tree< 15, double, 2, 1 > tree15b2d1rT
mjr::MR_rect_tree< 15, double, 1, 6 > tree15b1d6rT
mjr::MR_rect_tree< 31, double, 2, 2 > tree31b2d2rT
mjr::MR_rect_tree< 15, double, 4, 5 > tree15b4d5rT
mjr::MR_rect_tree< 15, double, 1, 5 > tree15b1d5rT
mjr::MR_rect_tree< 15, double, 1, 15 > tree15b1d15rT
mjr::MR_rect_tree< 15, double, 3, 1 > tree15b3d1rT
mjr::MR_rect_tree< 15, double, 2, 4 > tree15b2d4rT
mjr::MR_rect_tree< 15, double, 1, 11 > tree15b1d11rT
mjr::MR_rect_tree< 7, double, 1, 1 > tree7b1d1rT
mjr::MR_rect_tree< 63, double, 1, 3 > tree63b1d3rT
mjr::MR_rect_tree< 15, double, 1, 13 > tree15b1d13rT
mjr::MR_rect_tree< 7, double, 3, 2 > tree7b3d2rT
mjr::MR_rect_tree< 15, double, 4, 12 > tree15b4d12rT
mjr::MR_rect_tree< 7, double, 1, 4 > tree7b1d4rT
mjr::MR_rect_tree< 15, double, 3, 4 > tree15b3d4rT
mjr::MR_rect_tree< 15, double, 4, 4 > tree15b4d4rT
mjr::MR_rect_tree< 7, double, 4, 3 > tree7b4d3rT
mjr::MR_rect_tree< 63, double, 1, 4 > tree63b1d4rT
mjr::MR_rect_tree< 15, double, 2, 5 > tree15b2d5rT
mjr::MR_rect_tree< 15, double, 2, 13 > tree15b2d13rT
mjr::MR_rect_tree< 63, double, 1, 2 > tree63b1d2rT
mjr::MR_rect_tree< 15, double, 3, 6 > tree15b3d6rT
mjr::MR_rect_tree< 31, double, 2, 1 > tree31b2d1rT
mjr::MR_rect_tree< 15, double, 3, 15 > tree15b3d15rT
mjr::MR_rect_tree< 15, double, 3, 5 > tree15b3d5rT
mjr::MR_rect_tree< 15, double, 2, 12 > tree15b2d12rT
mjr::MR_rect_tree< 31, double, 1, 2 > tree31b1d2rT
mjr::MR_rect_tree< 7, double, 5, 1 > tree7b5d1rT
mjr::MR_rect_tree< 15, double, 1, 8 > tree15b1d8rT
mjr::MR_rect_tree< 15, double, 4, 7 > tree15b4d7rT
mjr::MR_rect_tree< 7, double, 3, 4 > tree7b3d4rT
mjr::MR_rect_tree< 15, double, 2, 6 > tree15b2d6rT
mjr::MR_rect_tree< 15, double, 4, 10 > tree15b4d10rT
mjr::MR_rect_tree< 7, double, 3, 1 > tree7b3d1rT
mjr::MR_rect_tree< 7, double, 1, 3 > tree7b1d3rT
mjr::MR_rect_tree< 15, double, 2, 2 > tree15b2d2rT
mjr::MR_rect_tree< 7, double, 1, 2 > tree7b1d2rT
mjr::MR_rect_tree< 15, double, 3, 11 > tree15b3d11rT
mjr::MR_rect_tree< 15, double, 4, 13 > tree15b4d13rT
mjr::MR_rect_tree< 15, double, 4, 8 > tree15b4d8rT
mjr::MR_rect_tree< 15, double, 4, 11 > tree15b4d11rT
mjr::MR_rect_tree< 15, double, 4, 6 > tree15b4d6rT
mjr::MR_rect_tree< 15, double, 2, 3 > tree15b2d3rT
mjr::MR_rect_tree< 15, double, 2, 11 > tree15b2d11rT
mjr::MR_rect_tree< 31, double, 1, 4 > tree31b1d4rT
mjr::MR_rect_tree< 15, double, 2, 15 > tree15b2d15rT
mjr::MR_rect_tree< 15, double, 2, 10 > tree15b2d10rT
mjr::MR_rect_tree< 15, double, 3, 14 > tree15b3d14rT
mjr::MR_rect_tree< 15, double, 1, 7 > tree15b1d7rT
mjr::MR_rect_tree< 15, double, 4, 14 > tree15b4d14rT
mjr::MR_rect_tree< 31, double, 1, 1 > tree31b1d1rT
mjr::MR_rect_tree< 15, double, 3, 7 > tree15b3d7rT
mjr::MR_rect_tree< 15, double, 1, 12 > tree15b1d12rT
mjr::MR_rect_tree< 15, double, 2, 8 > tree15b2d8rT
mjr::MR_rect_tree< 31, double, 1, 3 > tree31b1d3rT
mjr::MR_rect_tree< 15, double, 1, 10 > tree15b1d10rT
mjr::MR_rect_tree< 15, double, 4, 9 > tree15b4d9rT
mjr::MR_rect_tree< 15, double, 3, 8 > tree15b3d8rT
mjr::MR_rect_tree< 7, double, 2, 3 > tree7b2d3rT
mjr::MR_rect_tree< 7, double, 2, 4 > tree7b2d4rT
mjr::MR_rect_tree< 15, double, 1, 3 > tree15b1d3rT
mjr::MR_rect_tree< 15, double, 4, 15 > tree15b4d15rT
mjr::MR_rect_tree< 15, double, 4, 2 > tree15b4d2rT
mjr::MR_rect_tree< 15, double, 4, 3 > tree15b4d3rT
mjr::MR_rect_tree< 15, double, 1, 4 > tree15b1d4rT
mjr::MR_rect_tree< 15, double, 1, 2 > tree15b1d2rT
mjr::MR_rect_tree< 15, double, 3, 10 > tree15b3d10rT
mjr::MR_rect_tree< 63, double, 1, 1 > tree63b1d1rT
mjr::MR_rect_tree< 7, double, 4, 4 > tree7b4d4rT
mjr::MR_rect_tree< 15, double, 2, 14 > tree15b2d14rT