Tatooine
unstructured_grid.h
Go to the documentation of this file.
1#ifndef TATOOINE_UNSTRUCTURED_GRID_H
2#define TATOOINE_UNSTRUCTURED_GRID_H
3//==============================================================================
4#include <tatooine/edgeset.h>
5#include <tatooine/pointset.h>
6
7#include <boost/range.hpp>
8#include <boost/range/adaptor/transformed.hpp>
9//==============================================================================
10namespace tatooine {
11//==============================================================================
12template <typename Real, std::size_t NumDimensions>
13struct unstructured_grid : pointset<Real, NumDimensions> {
14 public:
17 using real_type = Real;
18 using typename parent_t::pos_type;
19 using typename parent_t::vertex_handle;
20 template <typename T>
21 using vertex_property_t = typename parent_t::template vertex_property_t<T>;
22 static constexpr auto num_dimensions() -> std::size_t { return NumDimensions; }
23
25 : boost::iterator_facade<cell_vertex_iterator, vertex_handle,
26 boost::bidirectional_traversal_tag,
27 vertex_handle> {
30 cell_vertex_iterator(std::vector<std::size_t>::const_iterator it)
31 : m_it{it} {}
33 : m_it{other.m_it} {}
34
35 private:
36 std::vector<std::size_t>::const_iterator m_it;
37
39
40 auto increment() { ++m_it; }
41 auto decrement() { --m_it; }
42
43 auto equal(cell_vertex_iterator const& other) const {
44 return m_it == other.m_it;
45 }
46 auto dereference() const { return vertex_handle{*m_it}; }
47 };
48 struct cell_iterator;
49 struct cell {
50 public:
51 friend struct cell_iterator;
52 using this_type = cell;
56
57 private:
58 // [number of vertices of cell 0, [vertex indices of cell 0],
59 // [number of vertices of cell 1, [vertex indices of cell 1],
60 // ...,
61 // [number of vertices of cell n-1, [vertex indices of cell n-1],
62 // number of vertices of cell n-1 (this is for getting the last cell
63 // index)
64 grid_t const* m_grid;
65 std::vector<std::size_t>::const_iterator m_cell_begin;
66
67 public:
69 std::vector<std::size_t>::const_iterator cell_begin)
70 : m_grid{grid}, m_cell_begin{cell_begin} {}
71 auto size() const { return *m_cell_begin; }
72 auto at(std::size_t const i) const {
73 return vertex_handle{*next(m_cell_begin, i + 1)};
74 }
75 auto operator[](std::size_t const i) const { return at(i); }
76 auto begin() const { return const_iterator{next(m_cell_begin)}; }
77 auto end() const { return const_iterator{next(m_cell_begin, size() + 1)}; }
78 //----------------------------------------------------------------------------
81 auto is_inside(pos_type const& x) const requires(NumDimensions == 2) {
82 bool c = false;
83 for (std::size_t i = 0, j = size() - 1; i < size(); j = i++) {
84 auto const& xi = m_grid->at(at(i));
85 auto const& xj = m_grid->at(at(j));
86 if (((xi(1) > x(1)) != (xj(1) > x(1))) &&
87 (x(0) < (xj(0) - xi(0)) * (x(1) - xi(1)) / (xj(1) - xi(1)) + xi(0)))
88 c = !c;
89 }
90 return c;
91 }
92 //----------------------------------------------------------------------------
99 auto barycentric_coordinates(pos_type const& query_point) const
100 requires(NumDimensions == 2) {
101 // some typedefs and namespaces
102 using namespace boost;
103 using namespace boost::adaptors;
104 using scalar_list = std::vector<real_type>;
105 using pos_list = std::vector<pos_type>;
106
107 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
108 // create data fields
109 static real_type constexpr eps = 1e-8;
110 auto const num_vertices = size();
111 auto vertex_weights = scalar_list(num_vertices, 0);
112 auto accumulated_vertex_weights = real_type(0);
113 auto triangle_areas = scalar_list(num_vertices, 0);
114 auto dot_products = scalar_list(num_vertices, 0);
115 auto distances_to_vertices = scalar_list(num_vertices, 0);
116 auto direction_to_vertices = pos_list(num_vertices, {0, 0});
117
118 //------------------------------------------------------------------------
119 auto previous_index = [num_vertices](auto const i) -> std::size_t {
120 return i == 0 ? num_vertices - 1 : i - 1;
121 };
122 //------------------------------------------------------------------------
123 auto next_index = [num_vertices](auto const i) -> std::size_t {
124 return i == num_vertices - 1 ? 0 : i + 1;
125 };
126 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127 // create functors
128
129 // Creates a meta functor that iterates and calls its underlying function
130 // f.
131 auto indexed_with_neighbors = [&](auto&& f) -> decltype(auto) {
132 return [&f, i = std::size_t(0), &previous_index,
133 &next_index]() mutable -> decltype(auto) {
134 decltype(auto) ret_val = f(previous_index(i), i, next_index(i));
135 ++i;
136 return ret_val;
137 };
138 };
139
140 // Creates a meta functor that iterates and calls its underlying function
141 // f.
142 auto indexed = [&](auto&& f) -> decltype(auto) {
143 return [&f, i = std::size_t(0)]() mutable -> decltype(auto) {
144 decltype(auto) return_value = f(i);
145 ++i;
146 return return_value;
147 };
148 };
149
150 auto calculate_weight_of_vertex = [&distances_to_vertices,
151 &triangle_areas,
152 &dot_products](auto const prev_idx,
153 auto const cur_idx,
154 auto const next_idx) {
155 auto weight = real_type(0);
156 if (std::abs(triangle_areas[prev_idx]) > eps) /* A != 0 */ {
157 weight += (distances_to_vertices[prev_idx] -
158 dot_products[prev_idx] / distances_to_vertices[cur_idx]) /
159 triangle_areas[prev_idx];
160 }
161 if (std::abs(triangle_areas[cur_idx]) > eps) /* A != 0 */ {
162 weight += (distances_to_vertices[next_idx] -
163 dot_products[cur_idx] / distances_to_vertices[cur_idx]) /
164 triangle_areas[cur_idx];
165 }
166 return weight;
167 };
168
169 auto calculate_and_accumulate_vertex_weight =
170 [&accumulated_vertex_weights, &calculate_weight_of_vertex](
171 auto const prev_idx, auto const cur_idx, auto const next_idx) {
172 auto const weight =
173 calculate_weight_of_vertex(prev_idx, cur_idx, next_idx);
174 accumulated_vertex_weights += weight;
175 return weight;
176 };
177
178 auto calculate_direction_to_vertex = [this, &query_point](auto const i) {
179 return m_grid->at(at(i)) - query_point;
180 };
181
182 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183 // fill actual data
184 generate(direction_to_vertices, indexed(calculate_direction_to_vertex));
185
186 // compute distance to vertex and check if query_point is on a vertex
187 // or on an edge
188 for (std::size_t i = 0; i < num_vertices; ++i) {
189 auto const next_idx = next_index(i);
190 distances_to_vertices[i] = length(direction_to_vertices[i]);
191 if (std::abs(distances_to_vertices[i]) <= eps) {
192 vertex_weights[i] = 1;
193 return vertex_weights;
194 }
195 triangle_areas[i] =
196 (direction_to_vertices[i](0) * direction_to_vertices[next_idx](1) -
197 direction_to_vertices[i](1) * direction_to_vertices[next_idx](0)) /
198 2;
199 dot_products[i] =
200 dot(direction_to_vertices[i], direction_to_vertices[next_idx]);
201
202 if (std::abs(triangle_areas[i]) <= eps && dot_products[i] <= eps) {
203 distances_to_vertices[next_idx] =
204 length(direction_to_vertices[next_idx]);
205 real_type const norm =
206 1 / (distances_to_vertices[i] + distances_to_vertices[next_idx]);
207 vertex_weights[i] = distances_to_vertices[next_idx] * norm;
208 vertex_weights[next_idx] = distances_to_vertices[i] * norm;
209 return vertex_weights;
210 }
211 }
212
213 // if query point is not on a vertex or an edge of the polygon:
214 generate(vertex_weights,
215 indexed_with_neighbors(calculate_and_accumulate_vertex_weight));
216
217 // normalize vertex weights to make the sum of the vertex_weights = 1
218 auto normalize_w = [inverse_accumulated_weights =
219 1 / accumulated_vertex_weights](auto& w) {
220 return w * inverse_accumulated_weights;
221 };
222 copy(vertex_weights | transformed(normalize_w), vertex_weights.begin());
223 return vertex_weights;
224 }
225 };
226 //----------------------------------------------------------------------------
228 : boost::iterator_facade<cell_iterator, cell,
229 boost::forward_traversal_tag, cell const&> {
232 cell_iterator(cell c) : m_cell{std::move(c)} {}
233 cell_iterator(cell_iterator const& other) : m_cell{other.m_cell} {}
234
235 private:
237
239
241
242 auto equal(cell_iterator const& other) const {
243 return m_cell.m_cell_begin == other.m_cell.m_cell_begin;
244 }
245 auto dereference() const -> auto const& { return m_cell; }
246 };
247 //----------------------------------------------------------------------------
252 //--------------------------------------------------------------------------
254 //--------------------------------------------------------------------------
255 auto begin() const {
256 return cell_iterator{cell{m_grid, m_grid->m_cell_indices.begin()}};
257 }
258 //--------------------------------------------------------------------------
259 auto end() const {
261 }
262 //--------------------------------------------------------------------------
263 auto size() const { return m_grid->m_num_cells; }
264 };
265 //----------------------------------------------------------------------------
266 template <typename T>
268 : field<barycentric_coordinates_vertex_property_sampler_t<T>, Real,
269 parent_t::num_dimensions(), T> {
270 private:
273
276 //--------------------------------------------------------------------------
277 public:
279 grid_t const& grid, vertex_property_t<T> const& prop)
280 : m_grid{grid}, m_prop{prop} {}
281 //--------------------------------------------------------------------------
282 auto grid() const -> auto const& { return m_grid; }
283 auto property() const -> auto const& { return m_prop; }
284 //--------------------------------------------------------------------------
285 [[nodiscard]] auto evaluate(pos_type const& x, real_type const /*t*/) const -> T {
286 for (auto const& cell : m_grid.cells()) {
287 if (cell.is_inside(x)) {
288 auto b = cell.barycentric_coordinates(x);
289 T acc = 0;
290 for (std::size_t i = 0; i < b.size(); ++i) {
291 acc += b[i] * property()[cell[i]];
292 }
293 return acc;
294 }
295 }
296 return T{Real(0) / Real(0)};
297 }
298 };
299 using parent_t::at;
300 using parent_t::vertex_data;
302 using parent_t::vertices;
303
304 private:
305 //------------------------------------------------------------------------------
306 std::vector<std::size_t> m_cell_indices{};
307 std::size_t m_num_cells = 0;
308
309 public:
312 : parent_t{std::move(edges)} {
313 m_cell_indices.push_back(0);
314 auto edges_per_vertex =
315 std::unordered_map<vertex_handle,
316 std::unordered_set<typename edgeset<
317 Real, NumDimensions>::edge_handle>> {}
318 for (auto e : edges.edges()) {
319 auto [v0, v1] = edges[e];
320 edges_per_vertex[v0].insert(e);
321 edges_per_vertex[v1].insert(e);
322 }
323 for (auto v:vertices()) {
324 auto const& es = edges_per_vertex.at(v);
325 if (es.size() >= 2) {
326 for (auto e1_it = begin(es), e1_it != end(es); ++e1_it) {
327 auto const e1 = *e1_it;
328 auto const [e1v0, e1v1] = edges[e1];
329 for (auto e0_it = next(e1_it), e0_it != end(es); ++e0_it) {
330 auto const e0 = *e0_it;
331 auto const [e0v0, e0v1] = edges[e0];
332 }
333 }
334 }
335 }
336 }
337 //------------------------------------------------------------------------------
338 auto cells() const { return cell_container{this}; }
339 //------------------------------------------------------------------------------
340 template <typename... Handles>
341 auto insert_cell(Handles const... handles) requires(
342 (sizeof...(Handles) > 2) &&
343 ((is_integral<Handles> || is_same<Handles, vertex_handle>)&&...)) {
344 m_cell_indices.back() = sizeof...(handles);
345 (
346 [this](auto const h) {
347 using handle_t = std::decay_t<decltype(h)>;
348 if constexpr (is_same<vertex_handle, handle_t>) {
349 m_cell_indices.push_back(h.i);
350 } else if constexpr (is_integral<handle_t>) {
351 m_cell_indices.push_back(h);
352 }
353 }(handles),
354 ...);
355 m_cell_indices.push_back(sizeof...(handles));
356 ++m_num_cells;
357 // for (auto& [key, prop] : m_cell_properties) {
358 // prop->push_back();
359 //}
360 // return cell_handle{cells().size() - 1};
361 }
362 //------------------------------------------------------------------------------
363 auto insert_cell(std::vector<vertex_handle> const& handles) {
364 using boost::copy;
365 using boost::adaptors::transformed;
366 m_cell_indices.back() = size(handles);
367 copy(handles | transformed([](auto const handle) { return handle.i; }),
368 std::back_inserter(m_cell_indices));
369 m_cell_indices.push_back(size(handles));
370 ++m_num_cells;
371 // for (auto& [key, prop] : m_cell_properties) {
372 // prop->push_back();
373 //}
374 return cell{this, prev(m_cell_indices.end(), m_cell_indices.back() + 2)};
375 }
376 //------------------------------------------------------------------------------
377 auto write(filesystem::path const& path) const {
378 if (path.extension() == ".vtk") {
379 write_vtk(path);
380 return;
381 }
382 throw std::runtime_error{
383 "[unstructured_grid::write()]\n unknown file extension: " +
384 path.extension().string()};
385 }
386 //----------------------------------------------------------------------------
387 template <typename T, typename... Ts, typename Prop, typename Name,
388 typename Writer>
389 auto write_vtk_vertex_property(Prop const& prop, Name const& name,
390 Writer& writer) const {
391 if (prop->type() == typeid(T)) {
392 auto const& casted_prop = *dynamic_cast<
393 typename parent_t::template vertex_property_t<T> const*>(prop.get());
394 writer.write_scalars(name, casted_prop.data());
395 return;
396 }
397 if constexpr (sizeof...(Ts) > 0) {
398 write_vtk_vertex_property<Ts...>(prop, name, writer);
399 }
400 }
401 //----------------------------------------------------------------------------
402 auto write_vtk(filesystem::path const& path) const {
403 using boost::copy;
404 using boost::make_iterator_range;
405 using boost::adaptors::transformed;
406 auto writer =
408 if (writer.is_open()) {
409 writer.set_title("");
410 writer.write_header();
411 if constexpr (num_dimensions() == 2) {
412 auto three_dims = [this](auto const handle) {
413 auto const& v2 = this->at(handle);
414 return vec<Real, 3>{v2(0), v2(1), 0};
415 };
416 auto v3s = std::vector<vec<Real, 3>>(vertices().size());
417 copy(vertices() | transformed(three_dims), begin(v3s));
418 writer.write_points(v3s);
419
420 } else if constexpr (num_dimensions() == 3) {
421 writer.write_points(vertex_data());
422 }
423
424 std::vector<std::vector<std::size_t>> vertices_per_cell;
425 // vertices_per_cell.reserve(cells().size());
426 std::vector<vtk::cell_type> cell_types(cells().size(),
428 for (auto const& cell : cells()) {
429 auto const num_vertices_of_cell = cell.size();
430 auto& polygon = vertices_per_cell.emplace_back();
431 polygon.reserve(num_vertices_of_cell);
432 copy(cell | transformed([](auto const handle) { return handle.i; }),
433 std::back_inserter(polygon));
434 }
435 writer.write_cells(vertices_per_cell);
436 writer.write_cell_types(cell_types);
437
438 // write vertex data
439 writer.write_point_data(vertices().size());
440 for (auto const& [name, prop] : vertex_properties()) {
442 vec3d, vec4d>(prop, name, writer);
443 }
444
445 writer.close();
446 return true;
447 }
448 return false;
449 }
450
451 //----------------------------------------------------------------------------
452 template <typename T>
453 auto sampler(vertex_property_t<T> const& prop) const {
455 }
456 //--------------------------------------------------------------------------
457 template <typename T>
458 auto vertex_property_sampler(std::string const& name) const {
459 return sampler<T>(this->template vertex_property<T>(name));
460 }
461};
462//==============================================================================
463template <std::size_t NumDimensions>
465template <std::size_t NumDimensions>
467template <std::size_t NumDimensions>
475//==============================================================================
476} // namespace tatooine
477//==============================================================================
478#endif
Definition: grid_edge.h:16
Definition: vtk_legacy.h:448
Definition: solver.h:9
Definition: algorithm.h:6
VecF< 3 > vec3f
Definition: vec_typedefs.h:40
auto begin(Range &&range)
Definition: iterator_facade.h:318
auto advance(Iter &iter)
Definition: iterator_facade.h:360
auto end(Range &&range)
Definition: iterator_facade.h:322
VecD< 3 > vec3d
Definition: vec_typedefs.h:51
constexpr auto norm(base_tensor< Tensor, T, N > const &t, unsigned p=2) -> T
Definition: norm.h:23
VecD< 2 > vec2d
Definition: vec_typedefs.h:50
VecF< 4 > vec4f
Definition: vec_typedefs.h:41
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
constexpr auto dot(base_tensor< Tensor0, T0, N > const &lhs, base_tensor< Tensor1, T1, N > const &rhs)
Definition: tensor_operations.h:120
auto next(Iter iter)
Definition: iterator_facade.h:325
auto prev(Iter iter)
Definition: iterator_facade.h:343
VecF< 2 > vec2f
Definition: vec_typedefs.h:39
vec_type pos_type
Definition: axis_aligned_bounding_box.h:109
Definition: edgeset.h:9
Definition: field.h:134
Definition: handle.h:14
Int i
Definition: handle.h:21
auto vertex_properties() const -> auto const &
Definition: line.h:450
Definition: pointset.h:83
Definition: pointset.h:69
auto num_vertices() const
Definition: pointset.h:229
auto at(vertex_handle const v) -> auto &
Definition: pointset.h:198
auto vertices() const
Definition: pointset.h:226
auto vertex_properties() const -> auto const &
Definition: pointset.h:191
type_list_at< this_type, I > at
Definition: type_list.h:269
vertex_property_t< T > const & m_prop
Definition: unstructured_grid.h:275
auto grid() const -> auto const &
Definition: unstructured_grid.h:282
barycentric_coordinates_vertex_property_sampler_t(grid_t const &grid, vertex_property_t< T > const &prop)
Definition: unstructured_grid.h:278
auto evaluate(pos_type const &x, real_type const) const -> T
Definition: unstructured_grid.h:285
auto property() const -> auto const &
Definition: unstructured_grid.h:283
Definition: unstructured_grid.h:248
auto end() const
Definition: unstructured_grid.h:259
auto begin() const
Definition: unstructured_grid.h:255
grid_t const * m_grid
Definition: unstructured_grid.h:253
auto size() const
Definition: unstructured_grid.h:263
Definition: unstructured_grid.h:229
auto equal(cell_iterator const &other) const
Definition: unstructured_grid.h:242
cell_iterator(cell_iterator const &other)
Definition: unstructured_grid.h:233
auto dereference() const -> auto const &
Definition: unstructured_grid.h:245
cell_iterator(cell c)
Definition: unstructured_grid.h:232
auto increment()
Definition: unstructured_grid.h:240
friend class boost::iterator_core_access
Definition: unstructured_grid.h:238
cell m_cell
Definition: unstructured_grid.h:236
Definition: unstructured_grid.h:27
auto equal(cell_vertex_iterator const &other) const
Definition: unstructured_grid.h:43
auto decrement()
Definition: unstructured_grid.h:41
auto dereference() const
Definition: unstructured_grid.h:46
cell_vertex_iterator(cell_vertex_iterator const &other)
Definition: unstructured_grid.h:32
std::vector< std::size_t >::const_iterator m_it
Definition: unstructured_grid.h:36
friend class boost::iterator_core_access
Definition: unstructured_grid.h:38
cell_vertex_iterator(std::vector< std::size_t >::const_iterator it)
Definition: unstructured_grid.h:30
auto increment()
Definition: unstructured_grid.h:40
Definition: unstructured_grid.h:49
cell(grid_t const *grid, std::vector< std::size_t >::const_iterator cell_begin)
Definition: unstructured_grid.h:68
auto end() const
Definition: unstructured_grid.h:77
auto size() const
Definition: unstructured_grid.h:71
auto begin() const
Definition: unstructured_grid.h:76
cell_vertex_iterator iterator
Definition: unstructured_grid.h:54
auto barycentric_coordinates(pos_type const &query_point) const
Computes generalized barycentric coordinates for arbitrary polygons.
Definition: unstructured_grid.h:99
std::vector< std::size_t >::const_iterator m_cell_begin
Definition: unstructured_grid.h:65
auto at(std::size_t const i) const
Definition: unstructured_grid.h:72
auto is_inside(pos_type const &x) const
Definition: unstructured_grid.h:81
grid_t const * m_grid
Definition: unstructured_grid.h:64
auto operator[](std::size_t const i) const
Definition: unstructured_grid.h:75
Definition: unstructured_grid.h:13
std::size_t m_num_cells
Definition: unstructured_grid.h:307
unstructured_grid()
Definition: unstructured_grid.h:310
auto sampler(vertex_property_t< T > const &prop) const
Definition: unstructured_grid.h:453
unstructured_grid(edgeset< Real, NumDimensions > &&edges)
Definition: unstructured_grid.h:311
auto write_vtk_vertex_property(Prop const &prop, Name const &name, Writer &writer) const
Definition: unstructured_grid.h:389
auto cells() const
Definition: unstructured_grid.h:338
Real real_type
Definition: unstructured_grid.h:17
std::vector< std::size_t > m_cell_indices
Definition: unstructured_grid.h:306
pointset< Real, NumDimensions > parent_t
Definition: unstructured_grid.h:16
auto insert_cell(std::vector< vertex_handle > const &handles)
Definition: unstructured_grid.h:363
auto insert_cell(Handles const ... handles)
Definition: unstructured_grid.h:341
static constexpr auto num_dimensions() -> std::size_t
Definition: unstructured_grid.h:22
typename parent_t::template vertex_property_t< T > vertex_property_t
Definition: unstructured_grid.h:21
auto vertex_property_sampler(std::string const &name) const
Definition: unstructured_grid.h:458
auto write(filesystem::path const &path) const
Definition: unstructured_grid.h:377
auto write_vtk(filesystem::path const &path) const
Definition: unstructured_grid.h:402
auto at(simplex_handle t) const -> auto
Definition: unstructured_simplicial_grid.h:300
std::map< std::string, data_array > vertices
Definition: piece.h:26