OGS
VoxelGridFromLayeredMeshes.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <range/v3/algorithm/fill.hpp>
7
8#include "MeshLib/Mesh.h"
13
14static std::string mat_name = "MaterialIDs";
15
16// returns the AABB of all mesh nodes of layers read so far
17void adjustExtent(std::pair<MathLib::Point3d, MathLib::Point3d>& extent,
18 MeshLib::Mesh const& mesh)
19{
20 auto const& nodes = mesh.getNodes();
21 GeoLib::AABB aabb(nodes.cbegin(), nodes.cend());
22 for (std::size_t i = 0; i < 3; ++i)
23 {
24 extent.first[i] = std::min(extent.first[i], aabb.getMinPoint()[i]);
25 extent.second[i] = std::max(extent.second[i], aabb.getMaxPoint()[i]);
26 }
27}
28
29// creates a voxel grid of the AABB of all layers
30std::unique_ptr<MeshLib::Mesh> generateInitialMesh(
31 std::pair<MathLib::Point3d, MathLib::Point3d>& extent,
32 std::array<double, 3> const& res)
33{
34 INFO("Creating initial mesh...");
35 std::array<double, 3> mesh_range{{extent.second[0] - extent.first[0],
36 extent.second[1] - extent.first[1],
37 extent.second[2] - extent.first[2]}};
38 std::array<std::size_t, 3> const n_cells{
39 {static_cast<std::size_t>(std::ceil(mesh_range[0] / res[0])),
40 static_cast<std::size_t>(std::ceil(mesh_range[1] / res[1])),
41 static_cast<std::size_t>(std::ceil(mesh_range[2] / res[2]))}};
42 for (std::size_t i = 0; i < 3; ++i)
43 {
44 double const ext_range = n_cells[i] * res[i];
45 double const offset = (ext_range - mesh_range[i]) / 2.0;
46 mesh_range[i] = ext_range;
47 extent.first[i] -= offset;
48 extent.second[i] += offset;
49 }
50 std::unique_ptr<MeshLib::Mesh> mesh(
52 mesh_range[0], mesh_range[1], mesh_range[2], n_cells[0], n_cells[1],
53 n_cells[2], extent.first));
54 auto mat_id = mesh->getProperties().createNewPropertyVector<int>(
55 mat_name, MeshLib::MeshItemType::Cell, mesh->getNumberOfElements(), 1);
56 if (!mat_id)
57 {
58 return nullptr;
59 }
60 ranges::fill(*mat_id, -1);
61 return mesh;
62}
63
64// returns the element the given node is projected on (or nullptr otherwise)
66 MeshLib::MeshElementGrid const& grid,
67 MathLib::Point3d const& node,
68 double const max_edge)
69{
70 constexpr double max_val = std::numeric_limits<double>::max();
71 MathLib::Point3d const min_vol{
72 {node[0] - max_edge, node[1] - max_edge, -max_val}};
73 MathLib::Point3d const max_vol{
74 {node[0] + max_edge, node[1] + max_edge, max_val}};
75 auto const& intersection_candidates =
76 grid.getElementsInVolume(min_vol, max_vol);
78 intersection_candidates, node);
79}
80
81// casts vote if the given nodes belongs to lower layer, upper layer or no layer
82// at all
83void voteMatId(MathLib::Point3d const& node,
84 MeshLib::MeshElementGrid const& grid,
85 double const max_edge,
86 std::size_t& nullptr_cnt,
87 std::size_t& upper_layer_cnt,
88 std::size_t& lower_layer_cnt)
89{
90 auto const& proj_elem = getProjectedElement(grid, node, max_edge);
91 if (proj_elem == nullptr)
92 {
93 nullptr_cnt++;
94 return;
95 }
96 if (node[2] >
98 {
99 upper_layer_cnt++;
100 return;
101 }
102 lower_layer_cnt++;
103}
104
105// sets material IDs for all elements depending on the layers they are located
106// between
108 std::vector<MeshLib::Mesh const*> const& layers,
109 bool const dilate)
110{
111 INFO("Setting material properties...");
112 std::size_t const n_layers = layers.size();
113 auto const& elems = mesh.getElements();
114 std::size_t const n_elems = mesh.getNumberOfElements();
115 auto mat_ids = mesh.getProperties().getPropertyVector<int>(mat_name);
116 std::vector<bool> is_set(n_elems, false);
117 for (int i = n_layers - 1; i >= 0; --i)
118 {
119 INFO("-> Layer {:d}", n_layers - i - 1);
120 MeshLib::MeshElementGrid const grid(*layers[i]);
121 auto const edgeLengths = minMaxEdgeLength(layers[i]->getElements());
122 double const max_edge = edgeLengths.second;
123 for (std::size_t j = 0; j < n_elems; ++j)
124 {
125 if (is_set[j])
126 {
127 continue;
128 }
129
130 std::size_t nullptr_cnt(0);
131 std::size_t upper_layer_cnt(0);
132 std::size_t lower_layer_cnt(0);
133
134 auto const& node = MeshLib::getCenterOfGravity(*elems[j]);
135 voteMatId(node, grid, max_edge, nullptr_cnt, upper_layer_cnt,
136 lower_layer_cnt);
137 if (nullptr_cnt)
138 {
139 // if no element was found at centre point, vote via corners
140 for (std::size_t k = 0; k < 8; ++k)
141 {
142 MeshLib::Node const& n = *elems[j]->getNode(k);
143 voteMatId(n, grid, max_edge, nullptr_cnt, upper_layer_cnt,
144 lower_layer_cnt);
145 }
146
147 // If the "dilate"-param is set, a mat ID will be assigned if at
148 // least one node was voting for a specific layer. Without the
149 // "dilate"-param, an absolute majority is needed. In case of a
150 // tie, the lower layer will be favoured.
151 if ((upper_layer_cnt == 0 && lower_layer_cnt == 0) ||
152 (!dilate && nullptr_cnt >= upper_layer_cnt &&
153 nullptr_cnt >= lower_layer_cnt))
154 {
155 continue;
156 }
157 if (upper_layer_cnt > lower_layer_cnt)
158 {
159 (*mat_ids)[j] = n_layers - i - 1;
160 }
161 else
162 {
163 is_set[j] = true;
164 }
165 continue;
166 }
167 if (upper_layer_cnt)
168 {
169 (*mat_ids)[j] = n_layers - i - 1;
170 }
171 else
172 {
173 is_set[j] = true;
174 }
175 }
176 }
177 // set all elements above uppermost layer back to -1 so they are
178 // subsequently cut
179 std::replace(mat_ids->begin(), mat_ids->end(),
180 static_cast<int>(n_layers - 1), -1);
181}
182
183// Removes all elements from mesh that have not been marked as being located
184// between two layers. If all elements remain unmarked, a nullptr is returned.
185std::vector<std::size_t> markSpecificElements(MeshLib::Mesh const& mesh,
186 int const mat_id)
187{
188 std::vector<std::size_t> marked_elems;
189 auto const mat_ids = *MeshLib::materialIDs(mesh);
190 std::size_t const n_elems = mat_ids.size();
191 for (std::size_t i = 0; i < n_elems; ++i)
192 {
193 if (mat_ids[i] == mat_id)
194 {
195 marked_elems.push_back(i);
196 }
197 }
198 return marked_elems;
199}
200
201// Creates a VoxelGrid after extending the AABB for each layer.
202std::unique_ptr<MeshLib::Mesh> MeshToolsLib::MeshGenerators::
204 std::pair<MathLib::Point3d, MathLib::Point3d>& extent,
205 std::vector<MeshLib::Mesh const*> const& layers,
206 std::array<double, 3> const cellsize,
207 bool const dilate)
208{
209 for (auto const& layer : layers)
210 {
211 adjustExtent(extent, *layer);
212 }
213
214 std::unique_ptr<MeshLib::Mesh> mesh(generateInitialMesh(extent, cellsize));
215 if (mesh == nullptr)
216 {
217 return nullptr;
218 }
219 setMaterialIDs(*mesh, layers, dilate);
220 auto const marked_elements = markSpecificElements(*mesh, -1);
221 if (marked_elements.size() == mesh->getNumberOfElements())
222 {
223 return nullptr;
224 }
225 std::unique_ptr<MeshLib::Mesh> new_mesh(
226 MeshToolsLib::removeElements(*mesh, marked_elements, "mesh"));
227 return new_mesh;
228}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
static std::string mat_name
std::vector< std::size_t > markSpecificElements(MeshLib::Mesh const &mesh, int const mat_id)
void voteMatId(MathLib::Point3d const &node, MeshLib::MeshElementGrid const &grid, double const max_edge, std::size_t &nullptr_cnt, std::size_t &upper_layer_cnt, std::size_t &lower_layer_cnt)
MeshLib::Element const * getProjectedElement(MeshLib::MeshElementGrid const &grid, MathLib::Point3d const &node, double const max_edge)
void setMaterialIDs(MeshLib::Mesh &mesh, std::vector< MeshLib::Mesh const * > const &layers, bool const dilate)
std::unique_ptr< MeshLib::Mesh > generateInitialMesh(std::pair< MathLib::Point3d, MathLib::Point3d > &extent, std::array< double, 3 > const &res)
void adjustExtent(std::pair< MathLib::Point3d, MathLib::Point3d > &extent, MeshLib::Mesh const &mesh)
Class AABB is an axis aligned bounding box around a given set of geometric points of (template) type ...
Definition AABB.h:45
Eigen::Vector3d const & getMaxPoint() const
Definition AABB.h:176
Eigen::Vector3d const & getMinPoint() const
Definition AABB.h:169
std::vector< MeshLib::Element const * > getElementsInVolume(POINT const &min, POINT const &max) const
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:97
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:100
Properties & getProperties()
Definition Mesh.h:125
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
PropertyVector< T > const * getPropertyVector(std::string_view name) const
PropertyVector< int > const * materialIDs(Mesh const &mesh)
Definition Mesh.cpp:258
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition Element.cpp:131
MeshLib::Mesh * generateRegularHexMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, const BaseLib::ISubdivision &div_z, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
std::unique_ptr< MeshLib::Mesh > createVoxelFromLayeredMesh(std::pair< MathLib::Point3d, MathLib::Point3d > &extent, std::vector< MeshLib::Mesh const * > const &layers, std::array< double, 3 > const cellsize, bool const dilate)
double getElevation(MeshLib::Element const &element, MathLib::Point3d const &node)
MeshLib::Element const * getProjectedElement(std::vector< const MeshLib::Element * > const &elements, MathLib::Point3d const &node)
MeshLib::Mesh * removeElements(const MeshLib::Mesh &mesh, const std::vector< std::size_t > &removed_element_ids, const std::string &new_mesh_name)