Tatooine
structured_grid.h
Go to the documentation of this file.
1#ifndef TATOOINE_STRUCTURED_GRID_H
2#define TATOOINE_STRUCTURED_GRID_H
3//==============================================================================
5#include <tatooine/pointset.h>
7#include <tatooine/vtk/xml.h>
8// #include <tatooine/detail/structured_grid/vertex_container.h>
10//==============================================================================
11namespace tatooine {
12//==============================================================================
13template <typename Real, std::size_t NumDimensions,
14 typename IndexOrder = x_fastest>
15struct structured_grid : pointset<Real, NumDimensions>,
16 dynamic_multidim_size<IndexOrder> {
17 //============================================================================
18 // INTERNAL TYPES
19 //============================================================================
20 template <typename T>
22 struct hierarchy_type;
23 //============================================================================
24 // TYPEDEFS
25 //============================================================================
30 template <typename T>
32 pointset_parent_type::template typed_vertex_property_type<T>;
33 using typename pointset_parent_type::pos_type;
34 using typename pointset_parent_type::vec_type;
36 //============================================================================
37 // STATIC METHODS
38 //============================================================================
39 static auto constexpr num_dimensions() { return NumDimensions; }
40 //============================================================================
41 // MEMBERS
42 //============================================================================
43 mutable std::unique_ptr<hierarchy_type> m_hierarchy;
44 //============================================================================
45 // CTORS
46 //============================================================================
47 structured_grid() = default;
49 structured_grid(structured_grid&&) noexcept = default;
50 auto operator=(structured_grid const&) -> structured_grid& = default;
51 auto operator=(structured_grid&&) noexcept -> structured_grid& = default;
52 //----------------------------------------------------------------------------
53 structured_grid(filesystem::path const& path) { read(path); }
54 //----------------------------------------------------------------------------
55 structured_grid(integral auto const... size) {
56 static auto constexpr num_indices = sizeof...(size);
57 static_assert(num_indices == num_dimensions(),
58 "Number of Indices does not match number of dimensions");
59 resize(size...);
60 }
61 //============================================================================
62 // METHODS
63 //============================================================================
64 auto hierarchy() const -> auto const& { return m_hierarchy; }
65 //----------------------------------------------------------------------------
66 auto update_hierarchy() const {
67 if (m_hierarchy != nullptr) {
68 m_hierarchy.reset();
69 }
70 auto const aabb = this->axis_aligned_bounding_box();
71 m_hierarchy =
72 std::make_unique<hierarchy_type>(aabb.min(), aabb.max(), *this, 4);
73 auto it = [&](auto const... is) { m_hierarchy->insert_cell(is...); };
74 auto const s = this->size();
75 if constexpr (NumDimensions == 2) {
76 for_loop(it, s[0] - 1, s[1] - 1);
77 } else if constexpr (NumDimensions == 3) {
78 for_loop(it, s[0] - 1, s[1] - 1, s[2] - 1);
79 }
80 }
81 //----------------------------------------------------------------------------
82 auto insert_vertex(arithmetic auto const... ts) = delete;
83 //============================================================================
84 auto vertex_at(integral auto const... is) const -> auto const& {
85 static auto constexpr num_indices = sizeof...(is);
86 static_assert(num_indices == num_dimensions(),
87 "Number of Indices does not match number of dimensions");
90 }
91 //----------------------------------------------------------------------------
92 auto vertex_at(integral auto const... is) -> auto& {
93 static auto constexpr num_indices = sizeof...(is);
94 static_assert(num_indices == num_dimensions(),
95 "Number of Indices does not match number of dimensions");
98 }
99 //----------------------------------------------------------------------------
100 auto resize(integral auto const... sizes) {
101 static auto constexpr num_indices = sizeof...(sizes);
102 static_assert(num_indices == num_dimensions(),
103 "Number of Indices does not match number of dimensions");
104 this->vertices().resize((sizes * ...));
106 }
107 //----------------------------------------------------------------------------
108 auto write(filesystem::path const& path) -> void;
109 template <typename HeaderType = std::uint64_t>
110 auto write_vts(filesystem::path const& path) -> void;
111 //----------------------------------------------------------------------------
112 auto read(filesystem::path const& path) -> void;
113 auto read_vts(filesystem::path const& path) -> void;
114 //----------------------------------------------------------------------------
115 auto local_cell_coordinates(pos_type const x, integral auto const... is) const
116 -> pos_type {
117 static auto constexpr num_indices = sizeof...(is);
118 static_assert(num_indices == num_dimensions(),
119 "Number of Indices does not match number of dimensions");
120 return local_cell_coordinates(x,
121 std::array{static_cast<std::size_t>(is)...});
122 }
123 //----------------------------------------------------------------------------
125 pos_type const x,
126 std::array<std::size_t, NumDimensions> const& cell) const -> pos_type;
127 //----------------------------------------------------------------------------
128 template <typename T>
130 typed_vertex_property_type<T> const& prop) const {
131 if (m_hierarchy == nullptr) {
133 }
134 return linear_cell_sampler_type<T>{*this, prop};
135 }
136 //----------------------------------------------------------------------------
137 template <typename T>
138 auto linear_vertex_property_sampler(std::string const& name) const {
140 this->template vertex_property<T>(name));
141 }
142};
143//==============================================================================
144template <typename Real, std::size_t NumDimensions, typename IndexOrder>
146 filesystem::path const& path) -> void {
147 if (path.extension() == ".vts") {
148 write_vts(path);
149 } else {
150 throw std::runtime_error{"File extension \"" + path.extension().string() +
151 "\" not recognized by structured grid."};
152 }
153}
154//------------------------------------------------------------------------------
155template <typename Real, std::size_t NumDimensions, typename IndexOrder>
156template <typename HeaderType>
158 filesystem::path const& path) -> void {
160}
161//==============================================================================
162template <typename Real, std::size_t NumDimensions, typename IndexOrder>
164 filesystem::path const& path) -> void {
165 if (path.extension() == ".vts") {
166 read_vts(path);
167 } else {
168 throw std::runtime_error{"File extension \"" + path.extension().string() +
169 "\" not recognized by structured grid."};
170 }
171}
172//------------------------------------------------------------------------------
173template <typename Real, std::size_t NumDimensions, typename IndexOrder>
175 filesystem::path const& path) -> void {
176 // TODO write binary data arrays with number of bytes at the beginning of each
177 // array
178 auto reader = vtk::xml::reader{path};
179 auto const& g = *reader.structured_grid();
180
181 resize(g.whole_extent2[0] - g.whole_extent1[0] + 1,
182 g.whole_extent2[1] - g.whole_extent1[1] + 1,
183 g.whole_extent2[2] - g.whole_extent1[2] + 1);
184 for (auto const& p : g.pieces()) {
185 auto const cur_piece_origin =
186 std::array{p.extent1->at(0) - g.whole_extent1.at(0),
187 p.extent1->at(1) - g.whole_extent1.at(1),
188 p.extent1->at(2) - g.whole_extent1.at(2)};
189 auto const cur_piece_resolution = std::array{
190 p.extent2[0] - p.extent1[0] + 1, p.extent2[1] - p.extent1[1] + 1,
191 p.extent2[2] - p.extent1[2] + 1};
192
193 p.points.visit_data([&](auto const& point_data) {
194 // always 3 components in vtk data array
195 for (std::size_t i = 0; i < point_data.size(); i += 3) {
196 if constexpr (num_dimensions() == 2) {
197 // just omit third component when reading to a 3d line
198 vertex_at(i / 3) = {point_data[i], point_data[i + 1]};
199 } else if constexpr (num_dimensions() == 3) {
200 vertex_at(i / 3) = {point_data[i], point_data[i + 1],
201 point_data[i + 2]};
202 }
203 }
204 });
205 }
206 // auto on_point_data(std::string const& name, float const* v)->void override
207 // {
208 // auto& prop = template vertex_property<float>(name);
209 // for_loop(
210 // [&](auto const... is) mutable {
211 // auto& p = prop[vertex_handle{grid.plain_index(is...)}];
212 // p = *v++;
213 // },
214 // std::pair{cur_piece_origin[0], cur_piece_resolution[0]},
215 // std::pair{cur_piece_origin[1], cur_piece_resolution[1]},
216 // std::pair{cur_piece_origin[2], cur_piece_resolution[2]});
217 //}
218}
219//------------------------------------------------------------------------------
220
221template <typename Real, std::size_t NumDimensions, typename IndexOrder>
223 pos_type const x,
224 std::array<std::size_t, NumDimensions> const& cell_indices) const
225 -> pos_type {
226 auto bary = pos_type::fill(Real(0.5)); // initial
227 auto dx = pos_type::fill(Real(0.1));
228 auto i = std::size_t(0);
229 auto const tol = Real(1e-12);
231 static auto const max_num_iterations = std::size_t(20);
232 if constexpr (NumDimensions == 2) {
233 auto const& v0 = vertex_at(cell_indices[0], cell_indices[1]);
234 auto const& v1 = vertex_at(cell_indices[0] + 1, cell_indices[1]);
235 auto const& v2 = vertex_at(cell_indices[0], cell_indices[1] + 1);
236 auto const& v3 = vertex_at(cell_indices[0] + 1, cell_indices[1] + 1);
237 auto ff = vec_type{};
238 static auto const max_num_iterations = std::size_t(20);
239 for (; i < max_num_iterations && squared_euclidean_length(dx) > tol; ++i) {
240 // apply Newton-Raphson method to solve f(x,y)=0
241 ff = (1 - bary.x()) * (1 - bary.y()) * v0 +
242 bary.x() * (1 - bary.y()) * v1 + (1 - bary.x()) * bary.y() * v2 +
243 bary.x() * bary.y() * v3 - x;
244 Dff(0, 0) = bary.y() * v3.x() - bary.y() * v2.x() +
245 (1 - bary.y()) * v1.x() - (1 - bary.y()) * v0.x();
246 Dff(0, 1) = bary.x() * v3.x() + (1 - bary.x()) * v2.x() -
247 bary.x() * v1.x() - (1 - bary.x()) * v0.x();
248 Dff(1, 0) = bary.y() * v3.y() - bary.y() * v2.y() +
249 (1 - bary.y()) * v1.y() - (1 - bary.y()) * v0.y();
250 Dff(1, 1) = bary.x() * v3.y() + (1 - bary.x()) * v2.y() -
251 bary.x() * v1.y() - (1 - bary.x()) * v0.y();
252 dx = *solve(Dff, -ff);
253 bary += dx;
254 if (squared_euclidean_length(bary) > 100) {
255 i = max_num_iterations; // non convergent: just to save time
256 }
257 }
258 if (i < max_num_iterations) {
259 return bary;
260 }
261 } else if constexpr (NumDimensions == 3) {
262 auto const& v0 =
263 vertex_at(cell_indices[0], cell_indices[1], cell_indices[2]);
264 auto const& v1 =
265 vertex_at(cell_indices[0] + 1, cell_indices[1], cell_indices[2]);
266 auto const& v2 =
267 vertex_at(cell_indices[0], cell_indices[1] + 1, cell_indices[2]);
268 auto const& v3 =
269 vertex_at(cell_indices[0] + 1, cell_indices[1] + 1, cell_indices[2]);
270 auto const& v4 =
271 vertex_at(cell_indices[0], cell_indices[1], cell_indices[2] + 1);
272 auto const& v5 =
273 vertex_at(cell_indices[0] + 1, cell_indices[1], cell_indices[2] + 1);
274 auto const& v6 =
275 vertex_at(cell_indices[0], cell_indices[1] + 1, cell_indices[2] + 1);
276 auto const& v7 = vertex_at(cell_indices[0] + 1, cell_indices[1] + 1,
277 cell_indices[2] + 1);
278 auto const x0 = v0.x();
279 auto const y0 = v0.y();
280 auto const z0 = v0.z();
281 auto const x1 = v1.x();
282 auto const y1 = v1.y();
283 auto const z1 = v1.z();
284 auto const x2 = v2.x();
285 auto const y2 = v2.y();
286 auto const z2 = v2.z();
287 auto const x3 = v3.x();
288 auto const y3 = v3.y();
289 auto const z3 = v3.z();
290 auto const x4 = v4.x();
291 auto const y4 = v4.y();
292 auto const z4 = v4.z();
293 auto const x5 = v5.x();
294 auto const y5 = v5.y();
295 auto const z5 = v5.z();
296 auto const x6 = v6.x();
297 auto const y6 = v6.y();
298 auto const z6 = v6.z();
299 auto const x7 = v7.x();
300 auto const y7 = v7.y();
301 auto const z7 = v7.z();
302
303 auto ff = vec_type{};
304 for (; i < max_num_iterations && squared_euclidean_length(dx) > tol; ++i) {
305 auto const a = bary.x();
306 auto const b = bary.y();
307 auto const c = bary.z();
308 // apply Newton-Raphson method to solve ff(x,y)=x
309 ff = (1 - a) * (1 - b) * (1 - c) * v0;
310 ff += a * (1 - b) * (1 - c) * v1;
311 ff += (1 - a) * b * (1 - c) * v2;
312 ff += a * b * (1 - c) * v3;
313 ff += (1 - a) * (1 - b) * c * v4;
314 ff += a * (1 - b) * c * v5;
315 ff += (1 - a) * b * c * v6;
316 ff += a * b * c * v7;
317 ff -= x;
318
319 Dff(0, 0) = b * c * x7 - b * c * x6 + (1 - b) * c * x5 +
320 (b - 1) * c * x4 + (b - b * c) * x3 + (b * c - b) * x2 +
321 ((b - 1) * c - b + 1) * x1 + ((1 - b) * c + b - 1) * x0;
322 Dff(0, 1) = a * c * x7 + (1 - a) * c * x6 - a * c * x5 +
323 (a - 1) * c * x4 + (a - a * c) * x3 +
324 ((a - 1) * c - a + 1) * x2 + (a * c - a) * x1 +
325 ((1 - a) * c + a - 1) * x0;
326 Dff(0, 2) = a * b * x7 + (1 - a) * b * x6 + (a - a * b) * x5 +
327 ((a - 1) * b - a + 1) * x4 - a * b * x3 + (a - 1) * b * x2 +
328 (a * b - a) * x1 + ((1 - a) * b + a - 1) * x0;
329 Dff(1, 0) = b * c * y7 - b * c * y6 + (1 - b) * c * y5 +
330 (b - 1) * c * y4 + (b - b * c) * y3 + (b * c - b) * y2 +
331 ((b - 1) * c - b + 1) * y1 + ((1 - b) * c + b - 1) * y0;
332 Dff(1, 1) = a * c * y7 + (1 - a) * c * y6 - a * c * y5 +
333 (a - 1) * c * y4 + (a - a * c) * y3 +
334 ((a - 1) * c - a + 1) * y2 + (a * c - a) * y1 +
335 ((1 - a) * c + a - 1) * y0;
336 Dff(1, 2) = a * b * y7 + (1 - a) * b * y6 + (a - a * b) * y5 +
337 ((a - 1) * b - a + 1) * y4 - a * b * y3 + (a - 1) * b * y2 +
338 (a * b - a) * y1 + ((1 - a) * b + a - 1) * y0;
339 Dff(2, 0) = b * c * z7 - b * c * z6 + (1 - b) * c * z5 +
340 (b - 1) * c * z4 + (b - b * c) * z3 + (b * c - b) * z2 +
341 ((b - 1) * c - b + 1) * z1 + ((1 - b) * c + b - 1) * z0;
342 Dff(2, 1) = a * c * z7 + (1 - a) * c * z6 - a * c * z5 +
343 (a - 1) * c * z4 + (a - a * c) * z3 +
344 ((a - 1) * c - a + 1) * z2 + (a * c - a) * z1 +
345 ((1 - a) * c + a - 1) * z0;
346 Dff(2, 2) = a * b * z7 + (1 - a) * b * z6 + (a - a * b) * z5 +
347 ((a - 1) * b - a + 1) * z4 - a * b * z3 + (a - 1) * b * z2 +
348 (a * b - a) * z1 + ((1 - a) * b + a - 1) * z0;
349
350 dx = *solve(Dff, -ff);
351 bary += dx;
352 if (squared_euclidean_length(bary) > 100) {
353 i = max_num_iterations; // non convergent: just to save time
354 }
355 }
356 if (i < max_num_iterations) {
357 return bary;
358 }
359 }
360 return pos_type::fill(Real(0) / Real(0));
361}
362//==============================================================================
363template <std::size_t NumDimensions>
367//==============================================================================
368template <typename Real, std::size_t NumDimensions, typename IndexOrder>
369template <typename T>
370struct structured_grid<Real, NumDimensions,
371 IndexOrder>::linear_cell_sampler_type
372 : field<structured_grid<Real, NumDimensions,
373 IndexOrder>::linear_cell_sampler_type<T>,
374 Real, NumDimensions, T> {
376 using real_type = Real;
379 using property_type = typename grid_type::template typed_vertex_property_type<T>;
382 using typename parent_type::tensor_type;
383
384 private:
387
388 public:
390 : m_grid{&grid}, m_property{&prop} {}
391
392 //----------------------------------------------------------------------------
393 auto grid() const -> auto const& { return *m_grid; }
394 auto property() const -> auto const& { return *m_property; }
395 //----------------------------------------------------------------------------
396 auto evaluate(pos_type const& x, real_type const /*t*/) const -> tensor_type {
397 auto possible_cells = grid().hierarchy()->nearby_cells(x);
398
399 for (auto const& cell : possible_cells) {
400 auto const c = grid().local_cell_coordinates(x, cell);
401 if (std::isnan(c(0))) {
402 continue;
403 }
404 auto is_inside = true;
405 for (size_t i = 0; i < NumDimensions; ++i) {
406 if (c(i) < -1e-10 || c(i) > 1 + 1e-10) {
407 is_inside = false;
408 break;
409 }
410 }
411 if (!is_inside) {
412 continue;
413 }
414 if constexpr (NumDimensions == 2) {
415 return (1 - c(0)) * (1 - c(1)) *
416 property()[vertex_handle{
417 grid().plain_index(cell[0], cell[1])}] +
418 c(0) * (1 - c(1)) *
419 property()[vertex_handle{
420 grid().plain_index(cell[0] + 1, cell[1])}] +
421 (1 - c(0)) * c(1) *
422 property()[vertex_handle{
423 grid().plain_index(cell[0], cell[1] + 1)}] +
424 c(0) * c(1) *
425 property()[vertex_handle{
426 grid().plain_index(cell[0] + 1, cell[1] + 1)}];
427 } else if constexpr (NumDimensions == 3) {
428 return (1 - c(0)) * (1 - c(1)) * (1 - c(2)) *
429 property()[vertex_handle{
430 grid().plain_index(cell[0], cell[1], cell[2])}] +
431 c(0) * (1 - c(1)) * (1 - c(2)) *
432 property()[vertex_handle{
433 grid().plain_index(cell[0] + 1, cell[1], cell[2])}] +
434 (1 - c(0)) * c(1) * (1 - c(2)) *
435 property()[vertex_handle{
436 grid().plain_index(cell[0], cell[1] + 1, cell[2])}] +
437 c(0) * c(1) * (1 - c(2)) *
438 property()[vertex_handle{
439 grid().plain_index(cell[0] + 1, cell[1] + 1, cell[2])}] +
440 (1 - c(0)) * (1 - c(1)) * c(2) *
441 property()[vertex_handle{
442 grid().plain_index(cell[0], cell[1], cell[2] + 1)}] +
443 c(0) * (1 - c(1)) * c(2) *
444 property()[vertex_handle{
445 grid().plain_index(cell[0] + 1, cell[1], cell[2] + 1)}] +
446 (1 - c(0)) * c(1) * c(2) *
447 property()[vertex_handle{
448 grid().plain_index(cell[0], cell[1] + 1, cell[2] + 1)}] +
449 c(0) * c(1) * c(2) *
450 property()[vertex_handle{grid().plain_index(
451 cell[0] + 1, cell[1] + 1, cell[2] + 1)}];
452 }
453 }
454 return this->ood_tensor();
455 }
456};
457//==============================================================================
458template <typename Real, std::size_t NumDimensions, typename IndexOrder>
459struct structured_grid<Real, NumDimensions, IndexOrder>::hierarchy_type
460 : base_uniform_tree_hierarchy<Real, NumDimensions, hierarchy_type> {
461 //============================================================================
462 // TYPEDEFS
463 //============================================================================
465 using real_type = Real;
466 using index_order_t = IndexOrder;
470 using cell_t = std::array<std::size_t, NumDimensions>;
471 //============================================================================
472 // INHERITED TYPES
473 //============================================================================
474 using typename parent_type::pos_type;
475 using typename parent_type::vec_type;
476 //============================================================================
477 // INHERITED METHODS
478 //============================================================================
480 using parent_type::children;
481 using parent_type::extents;
482 using parent_type::is_at_max_depth;
483 using parent_type::is_inside;
484 using parent_type::is_simplex_inside;
485 using parent_type::is_splitted;
486 using parent_type::max;
487 using parent_type::min;
488 using parent_type::split_and_distribute;
489 //============================================================================
490 // STATIC METHODS
491 //============================================================================
492 static constexpr auto num_dimensions() -> std::size_t {
493 return NumDimensions;
494 }
495 //============================================================================
496 // MEMBERS
497 //============================================================================
498 grid_type const* m_grid = nullptr;
499 std::vector<cell_t> m_cell_handles;
500 //============================================================================
501 // CTORS
502 //============================================================================
503 hierarchy_type() = default;
505 hierarchy_type(hierarchy_type&&) noexcept = default;
506 auto operator=(hierarchy_type const&) -> hierarchy_type& = default;
507 auto operator=(hierarchy_type&&) noexcept -> hierarchy_type& = default;
508 virtual ~hierarchy_type() = default;
509
510 explicit hierarchy_type(grid_type const& grid) : m_grid{&grid} {}
512 grid_type const& grid,
513 size_t const max_depth = parent_type::default_max_depth)
514 : parent_type{pos_type::zeros(), pos_type::zeros(), 1, max_depth},
515 m_grid{&grid} {
516 parent_type::operator=(grid.bounding_box());
517 }
518 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
520 grid_type const& grid,
521 size_t const max_depth = parent_type::default_max_depth)
522 : parent_type{min, max, 1, max_depth}, m_grid{&grid} {}
523 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
524 private:
525 hierarchy_type(vec_type const& min, vec_type const& max, size_t const level,
526 size_t const max_depth, grid_type const& grid)
527 : parent_type{min, max, level, max_depth}, m_grid{&grid} {}
528 //============================================================================
529 // METHODS
530 //============================================================================
531 public:
532 auto grid() const -> auto const& { return *m_grid; }
533 auto constexpr holds_cells() const { return !m_cell_handles.empty(); }
534 //----------------------------------------------------------------------------
535 auto num_cell_handles() const { return size(m_cell_handles); }
536 //----------------------------------------------------------------------------
537 constexpr auto is_cell_inside(integral auto const... is) const {
538 if constexpr (NumDimensions == 2) {
539 return is_cell_inside_2(is...);
540 } else if constexpr (NumDimensions == 3) {
541 return is_cell_inside_3(is...);
542 }
543 }
544 //----------------------------------------------------------------------------
545 private:
546 constexpr auto is_cell_inside_2(std::size_t const ix,
547 std::size_t const iy) const
548 requires(NumDimensions == 2)
549 {
550 auto const c = center();
551 auto const e = extents() / 2;
552 auto const us = std::array{vec_type{1, 0}, vec_type{0, 1}};
553 auto const xs = std::array{
554 grid().vertex_at(ix, iy) - c, grid().vertex_at(ix + 1, iy) - c,
555 grid().vertex_at(ix + 1, iy + 1) - c, grid().vertex_at(ix, iy + 1) - c};
556 auto is_separating_axis = [&](auto const& axis) {
557 auto const ps = std::array{dot(xs[0], axis), dot(xs[1], axis),
558 dot(xs[2], axis), dot(xs[3], axis)};
559 auto r = e.x() * std::abs(dot(us[0], axis)) +
560 e.y() * std::abs(dot(us[1], axis));
561 return tatooine::max(-tatooine::max(ps), tatooine::min(ps)) > r;
562 };
563 for (auto const& u : us) {
564 if (is_separating_axis(u)) {
565 return false;
566 }
567 }
568 for (size_t i = 0; i < size(xs); ++i) {
569 auto const j = i == size(xs) - 1 ? 0 : i + 1;
571 vec_type{xs[i].y() - xs[j].y(), xs[j].x() - xs[i].x()})) {
572 return false;
573 }
574 }
575 return true;
576 }
577 //----------------------------------------------------------------------------
578 constexpr auto is_cell_inside_3(std::size_t const ix, std::size_t const iy,
579 std::size_t const iz) const
580 requires(NumDimensions == 3)
581 {
582 auto const c = center();
583 auto const e = extents() / 2;
584
585 // vertices
586 auto xs = std::array{grid().vertex_at(ix, iy, iz) - c,
587 grid().vertex_at(ix + 1, iy, iz) - c,
588 grid().vertex_at(ix, iy + 1, iz) - c,
589 grid().vertex_at(ix + 1, iy + 1, iz) - c,
590 grid().vertex_at(ix, iy, iz + 1) - c,
591 grid().vertex_at(ix + 1, iy, iz + 1) - c,
592 grid().vertex_at(ix, iy + 1, iz + 1) - c,
593 grid().vertex_at(ix + 1, iy + 1, iz + 1) - c};
594
595 // edges
596 auto const es =
597 std::array{xs[1] - xs[0], xs[3] - xs[1], xs[2] - xs[3], xs[0] - xs[2],
598 xs[5] - xs[4], xs[7] - xs[5], xs[6] - xs[7], xs[4] - xs[6],
599 xs[4] - xs[0], xs[5] - xs[1], xs[6] - xs[2], xs[7] - xs[3]};
600 // faces
601 auto const fs = std::array{cross(es[0], es[1]), cross(es[9], es[5]),
602 cross(es[4], -es[5]), cross(es[8], -es[7]),
603 cross(es[11], es[2]), cross(es[0], -es[9])};
604
605 auto constexpr us =
606 std::array{vec_type{1, 0, 0}, vec_type{0, 1, 0}, vec_type{0, 0, 1}};
607
608 auto is_separating_axis = [&](auto const& axis) {
609 auto const dots =
610 std::array{dot(xs[0], axis), dot(xs[1], axis), dot(xs[2], axis),
611 dot(xs[3], axis), dot(xs[4], axis), dot(xs[5], axis),
612 dot(xs[6], axis), dot(xs[7], axis)};
613 auto r = e.x() * std::abs(dot(us[0], axis)) +
614 e.y() * std::abs(dot(us[1], axis)) +
615 e.z() * std::abs(dot(us[2], axis));
616 return tatooine::max(-tatooine::max(dots[0], dots[1], dots[2], dots[3],
617 dots[4], dots[5], dots[6], dots[7]),
618 tatooine::min(dots[0], dots[1], dots[2], dots[3],
619 dots[4], dots[5], dots[6], dots[7])) >
620 r;
621 };
622
623 for (auto const& u : us) {
624 if (is_separating_axis(u)) {
625 return false;
626 }
627 }
628 for (auto const& u : us) {
629 for (auto const& e : es) {
630 if (is_separating_axis(cross(u, e))) {
631 return false;
632 }
633 }
634 }
635 for (auto const& f : fs) {
636 if (is_separating_axis(f)) {
637 return false;
638 }
639 }
640 return true;
641 }
642
643 public:
644 //------------------------------------------------------------------------------
645 template <typename... Indices>
646 auto insert_cell(Indices const... is) -> bool {
647 if (!is_cell_inside(is...)) {
648 return false;
649 }
650 if (holds_cells()) {
651 if (is_at_max_depth()) {
652 m_cell_handles.push_back(cell_t{static_cast<std::size_t>(is)...});
653 } else {
654 split_and_distribute();
655 distribute_cell(is...);
656 }
657 } else {
658 if (is_splitted()) {
659 distribute_cell(is...);
660 } else {
661 m_cell_handles.push_back(cell_t{static_cast<std::size_t>(is)...});
662 }
663 }
664 return true;
665 }
666 //----------------------------------------------------------------------------
667 auto distribute() {
668 if (holds_cells()) {
669 distribute_cell(m_cell_handles.front());
670 m_cell_handles.clear();
671 }
672 }
673 //------------------------------------------------------------------------------
674 auto construct(vec_type const& min, vec_type const& max, size_t const level,
675 size_t const max_depth) const {
676 return std::unique_ptr<this_type>{
677 new this_type{min, max, level, max_depth, grid()}};
678 }
679 //----------------------------------------------------------------------------
680 auto distribute_cell(integral auto const... is) {
681 for (auto& child : children()) {
682 child->insert_cell(is...);
683 }
684 }
685 //----------------------------------------------------------------------------
686 template <std::size_t... Is>
687 auto distribute_cell(std::array<std::size_t, NumDimensions> const& is,
688 std::index_sequence<Is...> /*seq*/) {
689 distribute_cell(is[Is]...);
690 }
691 //----------------------------------------------------------------------------
692 auto distribute_cell(std::array<std::size_t, NumDimensions> const& is) {
693 distribute_cell(is, std::make_index_sequence<NumDimensions>{});
694 }
695 //============================================================================
696 auto collect_nearby_cells(vec_type const& pos, std::set<cell_t>& cells) const
697 -> void {
698 if (is_inside(pos)) {
699 if (is_splitted()) {
700 for (auto const& child : children()) {
701 child->collect_nearby_cells(pos, cells);
702 }
703 } else {
704 if (holds_cells()) {
705 boost::copy(m_cell_handles, std::inserter(cells, end(cells)));
706 }
707 }
708 }
709 }
710 //----------------------------------------------------------------------------
711 auto nearby_cells(pos_type const& pos) const {
712 std::set<cell_t> cells;
713 collect_nearby_cells(pos, cells);
714 return cells;
715 }
716};
717//==============================================================================
718} // namespace tatooine
719//==============================================================================
720#endif
Definition: dynamic_multidim_size.h:16
auto size() const -> auto const &
Definition: dynamic_multidim_size.h:107
auto resize(integral auto const ... size) -> void
Definition: dynamic_multidim_size.h:116
Definition: grid_edge.h:16
Definition: structured_grid.h:16
structured_grid(integral auto const ... size)
Definition: structured_grid.h:55
pointset_parent_type::template typed_vertex_property_type< T > typed_vertex_property_type
Definition: structured_grid.h:32
std::unique_ptr< hierarchy_type > m_hierarchy
Definition: structured_grid.h:43
auto update_hierarchy() const
Definition: structured_grid.h:66
auto write(filesystem::path const &path) -> void
Definition: structured_grid.h:145
auto local_cell_coordinates(pos_type const x, integral auto const ... is) const -> pos_type
Definition: structured_grid.h:115
auto read_vts(filesystem::path const &path) -> void
Definition: structured_grid.h:174
structured_grid(structured_grid const &)=default
auto linear_vertex_property_sampler(std::string const &name) const
Definition: structured_grid.h:138
auto vertex_at(integral auto const ... is) const -> auto const &
Definition: structured_grid.h:84
auto linear_vertex_property_sampler(typed_vertex_property_type< T > const &prop) const
Definition: structured_grid.h:129
auto write_vts(filesystem::path const &path) -> void
Definition: structured_grid.h:157
structured_grid(structured_grid &&) noexcept=default
auto insert_vertex(arithmetic auto const ... ts)=delete
static auto constexpr num_dimensions()
Definition: structured_grid.h:39
auto vertex_at(integral auto const ... is) -> auto &
Definition: structured_grid.h:92
pointset< Real, NumDimensions > pointset_parent_type
Definition: structured_grid.h:27
auto hierarchy() const -> auto const &
Definition: structured_grid.h:64
auto resize(integral auto const ... sizes)
Definition: structured_grid.h:100
auto read(filesystem::path const &path) -> void
Definition: structured_grid.h:163
Definition: concepts.h:33
Definition: concepts.h:21
Definition: algorithm.h:6
constexpr auto squared_euclidean_length(base_tensor< Tensor, T, N > const &t_in)
Definition: length.h:7
auto end(Range &&range)
Definition: iterator_facade.h:322
auto is_separating_axis(vec< Real, 2 > const &n, std::vector< vec< Real, 2 > > const &polygon0, std::vector< vec< Real, 2 > > const &polygon1)
Return true if n is a separating axis of polygon0 and polygon1.
Definition: separating_axis_theorem.h:12
auto solve(polynomial< Real, 1 > const &p) -> std::vector< Real >
solve a + b*x
Definition: polynomial.h:187
constexpr auto max(A &&a, B &&b)
Definition: math.h:20
constexpr auto dot(base_tensor< Tensor0, T0, N > const &lhs, base_tensor< Tensor1, T1, N > const &rhs)
Definition: tensor_operations.h:120
constexpr auto min(A &&a, B &&b)
Definition: math.h:15
constexpr auto for_loop(Iteration &&iteration, execution_policy::sequential_t, Ranges(&&... ranges)[2]) -> void
Use this function for creating a sequential nested loop.
Definition: for_loop.h:336
constexpr auto cross(base_tensor< Tensor0, T0, 3 > const &lhs, base_tensor< Tensor1, T1, 3 > const &rhs)
Definition: cross.h:9
Definition: axis_aligned_bounding_box.h:103
auto constexpr max() const -> auto const &
Definition: axis_aligned_bounding_box.h:156
auto constexpr min() const -> auto const &
Definition: axis_aligned_bounding_box.h:151
vec_type pos_type
Definition: axis_aligned_bounding_box.h:109
For octrees and quadtrees.
Definition: uniform_tree_hierarchy.h:15
typename Line::vertex_property_type vertex_property_type
Definition: vtk_writer.h:20
constexpr auto plain_index() const -> auto const &
Definition: vertex_handle.h:37
auto write(filesystem::path const &path) const
Definition: vts_writer.h:23
Definition: field.h:134
auto read() const
Definition: hdf5.h:614
vec< Real, N > vec_type
Definition: interpolation.h:268
auto vertex_at(std::size_t const i) const -> auto const &
Definition: line.h:146
Definition: mat.h:14
Definition: pointset.h:83
Definition: pointset.h:69
auto axis_aligned_bounding_box() const
Definition: pointset.h:183
auto vertices() const
Definition: pointset.h:226
vec_type pos_type
Definition: pointset.h:78
Definition: structured_grid.h:460
auto construct(vec_type const &min, vec_type const &max, size_t const level, size_t const max_depth) const
Definition: structured_grid.h:674
auto constexpr holds_cells() const
Definition: structured_grid.h:533
constexpr auto is_cell_inside_2(std::size_t const ix, std::size_t const iy) const
Definition: structured_grid.h:546
constexpr auto is_cell_inside(integral auto const ... is) const
Definition: structured_grid.h:537
auto distribute_cell(std::array< std::size_t, NumDimensions > const &is, std::index_sequence< Is... >)
Definition: structured_grid.h:687
hierarchy_type(hierarchy_type &&) noexcept=default
IndexOrder index_order_t
Definition: structured_grid.h:466
hierarchy_type(grid_type const &grid, size_t const max_depth=parent_type::default_max_depth)
Definition: structured_grid.h:511
std::vector< cell_t > m_cell_handles
Definition: structured_grid.h:499
auto insert_cell(Indices const ... is) -> bool
Definition: structured_grid.h:646
auto collect_nearby_cells(vec_type const &pos, std::set< cell_t > &cells) const -> void
Definition: structured_grid.h:696
auto distribute_cell(integral auto const ... is)
Definition: structured_grid.h:680
auto distribute()
Definition: structured_grid.h:667
hierarchy_type(vec_type const &min, vec_type const &max, grid_type const &grid, size_t const max_depth=parent_type::default_max_depth)
Definition: structured_grid.h:519
auto distribute_cell(std::array< std::size_t, NumDimensions > const &is)
Definition: structured_grid.h:692
auto grid() const -> auto const &
Definition: structured_grid.h:532
std::array< std::size_t, NumDimensions > cell_t
Definition: structured_grid.h:470
hierarchy_type(vec_type const &min, vec_type const &max, size_t const level, size_t const max_depth, grid_type const &grid)
Definition: structured_grid.h:525
constexpr auto is_cell_inside_3(std::size_t const ix, std::size_t const iy, std::size_t const iz) const
Definition: structured_grid.h:578
hierarchy_type(hierarchy_type const &)=default
static constexpr auto num_dimensions() -> std::size_t
Definition: structured_grid.h:492
auto num_cell_handles() const
Definition: structured_grid.h:535
Real real_type
Definition: structured_grid.h:465
auto nearby_cells(pos_type const &pos) const
Definition: structured_grid.h:711
typename grid_type::template typed_vertex_property_type< T > property_type
Definition: structured_grid.h:379
auto grid() const -> auto const &
Definition: structured_grid.h:393
auto evaluate(pos_type const &x, real_type const) const -> tensor_type
Definition: structured_grid.h:396
typename grid_type::pos_type pos_type
Definition: structured_grid.h:381
grid_type const * m_grid
Definition: structured_grid.h:385
typename grid_type::vec_type vec_type
Definition: structured_grid.h:380
property_type const * m_property
Definition: structured_grid.h:386
linear_cell_sampler_type(grid_type const &grid, property_type const &prop)
Definition: structured_grid.h:389
auto property() const -> auto const &
Definition: structured_grid.h:394
Real real_type
Definition: structured_grid.h:376
Definition: tags.h:96
auto constexpr x() const -> auto const &requires(N >=1)
Definition: vec.h:102
auto constexpr y() const -> auto const &requires(N >=2)
Definition: vec.h:106
Definition: reader.h:25
auto structured_grid() const -> auto const &
Definition: reader.h:51