Tatooine
isolines.h
Go to the documentation of this file.
1#ifndef TATOOINE_ISOLINES_H
2#define TATOOINE_ISOLINES_H
3//==============================================================================
4#include <cassert>
5#include <string>
6#include <vector>
7#ifndef NDEBUG
8#include <mutex>
9#endif
10
11#include <tatooine/field.h>
12#include <tatooine/for_loop.h>
14#include <tatooine/tensor.h>
15#include <tatooine/utility.h>
16#include <tatooine/edgeset.h>
18//==============================================================================
19namespace tatooine {
20//==============================================================================
23template <typename XDomain, typename YDomain>
26 std::size_t, std::size_t,
28 get_scalars,
30 arithmetic auto const isolevel) {
32 using edgeset_type = Edgeset2<real_type>;
33 auto isolines = edgeset_type{};
34
35#ifdef NDEBUG
36 std::mutex mutex;
37#endif
38 auto process_cell = [&](auto ix, auto iy) {
39 auto iso_positions = std::vector<typename edgeset_type::vertex_handle>{};
40 auto p =
41 std::array{g.vertex_at(ix, iy), g.vertex_at(ix + 1, iy), g.vertex_at(ix + 1, iy + 1), g.vertex_at(ix, iy + 1)};
42
43 auto s = std::array{
44 get_scalars(ix, iy, p[0]), get_scalars(ix + 1, iy, p[1]),
45 get_scalars(ix + 1, iy + 1, p[2]), get_scalars(ix, iy + 1, p[3])};
46 if (s[0] > isolevel && s[1] > isolevel && s[2] > isolevel &&
47 s[3] > isolevel) {
48 return;
49 }
50 if (s[0] < isolevel && s[1] < isolevel && s[2] < isolevel &&
51 s[3] < isolevel) {
52 return;
53 }
54
55 auto check_edge = [&](std::size_t const i, std::size_t const j) {
56 if ((s[i] > isolevel && s[j] < isolevel) ||
57 (s[i] < isolevel && s[j] > isolevel)) {
58 auto const t = (isolevel - s[i]) / (-s[i] + s[j]);
59 iso_positions.push_back(isolines.insert_vertex(p[i] * (1 - t) + p[j] * t));
60 }
61 };
62 check_edge(0, 1);
63 check_edge(1, 2);
64 check_edge(2, 3);
65 check_edge(3, 0);
66 for (std::size_t i = 0; i < 4; ++i) {
67 if (s[i] == isolevel) {
68 iso_positions.push_back(isolines.insert_vertex(p[i]));
69 }
70 }
71
72 if (size(iso_positions) == 2) {
73#ifdef NDEBUG
74 {
75 std::lock_guard lock{mutex};
76#endif
77 isolines.insert_edge(iso_positions[0], iso_positions[1]);
78#ifdef NDEBUG
79 }
80#endif
81 }
82 if (size(iso_positions) == 4) {
83 auto const scalar_center = (s[0] + s[1] + s[2] + s[3]) / 4;
84#ifdef NDEBUG
85 {
86 std::lock_guard lock{mutex};
87#endif
88 if (scalar_center > isolevel && s[0] > isolevel) {
89 isolines.insert_edge(iso_positions[0], iso_positions[1]);
90 isolines.insert_edge(iso_positions[2], iso_positions[3]);
91 } else {
92 isolines.insert_edge(iso_positions[0], iso_positions[3]);
93 isolines.insert_edge(iso_positions[2], iso_positions[1]);
94 }
95#ifdef NDEBUG
96 }
97#endif
98 }
99 };
100 auto execution =
101#ifdef NDEBUG
103#else
105#endif
106 for_loop(process_cell, execution, g.size(0) - 1, g.size(1) - 1);
107 return isolines;
108}
109//------------------------------------------------------------------------------
110template <typename Grid, arithmetic T, bool HasNonConstReference>
112 Grid, T, HasNonConstReference> const& data,
113 arithmetic auto const isolevel) {
114 return isolines(
115 [&](auto ix, auto iy, auto const& /*ps*/) -> auto const& {
116 return data(ix, iy);
117 },
118 data.grid(), isolevel);
119}
120//------------------------------------------------------------------------------
121template <arithmetic Real, typename Indexing, arithmetic BBReal>
124 arithmetic auto const isolevel) {
125 assert(data.num_dimensions() == 2);
126 return isolines(
127 [&](auto ix, auto iy, auto const& /*ps*/) -> auto const& {
128 return data(ix, iy);
129 },
130 rectilinear_grid{linspace{bb.min(0), bb.max(0), data.size(0)},
131 linspace{bb.min(1), bb.max(1), data.size(1)}},
132 isolevel);
133}
134//------------------------------------------------------------------------------
135template <arithmetic Real, arithmetic BBReal, typename Indexing,
136 typename MemLoc, std::size_t XRes, std::size_t YRes>
140 arithmetic auto const isolevel) {
141 return isolines(
142 [&](auto ix, auto iy, auto const& /*ps*/) -> auto const& {
143 return data(ix, iy);
144 },
145 rectilinear_grid{linspace{bb.min(0), bb.max(0), data.size(0)},
146 linspace{bb.min(1), bb.max(1), data.size(1)}},
147 isolevel);
148}
149//------------------------------------------------------------------------------
150template <typename Field, typename FieldReal,
151 floating_point_range XDomain,
152 floating_point_range YDomain,
153 arithmetic TReal = FieldReal>
156 arithmetic auto const isolevel, TReal const t = 0) {
157 auto eval = [&](auto const /*ix*/, auto const /*iy*/, auto const& pos) {
158 return sf(pos, t);
159 };
160 return isolines(eval, g, isolevel);
161}
162//==============================================================================
163} // namespace tatooine
164//==============================================================================
165#endif
Definition: dynamic_multidim_array.h:18
auto size() const -> auto const &
Definition: dynamic_multidim_size.h:107
auto num_dimensions() const
Definition: dynamic_multidim_size.h:105
Definition: rectilinear_grid.h:38
constexpr auto size(std::index_sequence< Seq... >) const
Definition: rectilinear_grid.h:347
auto vertex_at(std::index_sequence< DIs... >, std::array< Int, num_dimensions()> const &is) const -> vec< real_type, num_dimensions()>
Definition: rectilinear_grid.h:640
common_type< typename Dimensions::value_type... > real_type
Definition: rectilinear_grid.h:46
Definition: static_multidim_array.h:19
static auto constexpr size()
Definition: static_multidim_array.h:30
Definition: concepts.h:33
Definition: concepts.h:121
static constexpr sequential_t sequential
Definition: tags.h:63
Definition: algorithm.h:6
auto isolines(invocable< std::size_t, std::size_t, Vec2< typename rectilinear_grid< XDomain, YDomain >::real_type > > auto &&get_scalars, rectilinear_grid< XDomain, YDomain > const &g, arithmetic auto const isolevel)
Indexing and lookup map from http://paulbourke.net/geometry/polygonise/.
Definition: isolines.h:24
void eval(base_tensor< Tensor, GiNaC::ex, Dims... > &m)
Definition: tensor_symbolic.h:53
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
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
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
Definition: edgeset.h:9
Definition: field.h:134
Definition: linspace.h:26
Definition: vec.h:12