OGS
AddFaultToVoxelGrid.cpp
Go to the documentation of this file.
1
10#include <algorithm>
11#include <memory>
12#include <string>
13#include <vector>
14
15// ThirdParty
16#include <tclap/CmdLine.h>
17
18#include <Eigen/Geometry>
19
20#include "GeoLib/AABB.h"
21#include "InfoLib/GitInfo.h"
22#include "MathLib/Point3d.h"
26#include "MeshLib/Mesh.h"
27#include "MeshLib/Node.h"
29
30namespace
31{
32// tests if a plane and an AABB are intersecting
33// (based on Christer Ericson "Real Time Collision Detection" 5.2.3)
34bool testAABBIntersectingPlane(Eigen::Vector3d const& aabb_centre,
35 Eigen::Vector3d const& aabb_extent,
36 Eigen::Vector3d const& plane_normal,
37 double const pd)
38{
39 double const r = aabb_extent.dot(plane_normal.cwiseAbs());
40 double const s = plane_normal.dot(aabb_centre) - pd;
41 return std::abs(s) > r;
42}
43// tests if a triangle and an AABB are intersecting
44// (based on Christer Ericson "Real Time Collision Detection" 5.2.9)
46 MeshLib::Node const& n1,
47 MeshLib::Node const& n2,
48 Eigen::Vector3d const& c,
49 Eigen::Vector3d const& e)
50{
51 // Translate triangle as conceptually moving AABB to origin
52 Eigen::Matrix3d v;
53 v << n0.asEigenVector3d() - c, n1.asEigenVector3d() - c,
54 n2.asEigenVector3d() - c;
55
56 // Test the three axes corresponding to the face normals of AABB b
57 if (((v.rowwise().minCoeff() - e).array() > 0).any() ||
58 ((v.rowwise().maxCoeff() + e).array() < 0).any())
59 {
60 return false;
61 }
62
63 // separating axes
64 std::array<Eigen::Vector3d, 3> tri_edge{
65 {v.col(1) - v.col(0), v.col(2) - v.col(1), v.col(0) - v.col(2)}};
66 std::array<Eigen::Vector3d, 9> const axx{
67 {Eigen::Vector3d({0, -tri_edge[0].z(), tri_edge[0].y()}),
68 Eigen::Vector3d({0, -tri_edge[1].z(), tri_edge[1].y()}),
69 Eigen::Vector3d({0, -tri_edge[2].z(), tri_edge[2].y()}),
70 Eigen::Vector3d({tri_edge[0].z(), 0, -tri_edge[0].x()}),
71 Eigen::Vector3d({tri_edge[1].z(), 0, -tri_edge[1].x()}),
72 Eigen::Vector3d({tri_edge[2].z(), 0, -tri_edge[2].x()}),
73 Eigen::Vector3d({-tri_edge[0].y(), tri_edge[0].x(), 0}),
74 Eigen::Vector3d({-tri_edge[1].y(), tri_edge[1].x(), 0}),
75 Eigen::Vector3d({-tri_edge[2].y(), tri_edge[2].x(), 0})}};
76
77 // Separating axis tests to check if there's a plane separating the
78 // projections of the AABB and the triangle according to the Separating Axis
79 // Theorem (see C. Ericson "Real Time Collision Detection" for details)
80 for (auto const& a : axx)
81 {
82 Eigen::Vector3d p = v.transpose() * a;
83 double const r = e.dot(a.cwiseAbs());
84 if (std::max(-p.maxCoeff(), p.minCoeff()) > r)
85 {
86 return false;
87 }
88 }
89
90 // Test separating axis corresponding to triangle face normal
91 Eigen::Vector3d const plane_normal(tri_edge[0].cross(tri_edge[1]));
92 double const pd = plane_normal.dot(v.row(0));
93 return testAABBIntersectingPlane(c, e, plane_normal, pd);
94}
95// mark all cells of the voxel grid that intersect with fault
96void markFaults(MeshLib::Mesh& mesh, MeshLib::Mesh const& fault,
97 int const fault_id, Eigen::Vector3d const& half_cell_size)
98{
99 auto const& elems = mesh.getElements();
100 std::size_t const n_elems = mesh.getNumberOfElements();
101 auto mat_ids = MeshLib::materialIDs(mesh);
102 auto const& fnodes = fault.getNodes();
103 auto const& felems = fault.getElements();
104 GeoLib::AABB const fault_aabb(fnodes.cbegin(), fnodes.cend());
105 auto [min_pnt, max_pnt] = fault_aabb.getMinMaxPoints();
106
107 // get bounding box of fault + voxel extent
108 min_pnt -= half_cell_size;
109 max_pnt += half_cell_size;
110
111 std::array<Eigen::Vector3d, 2> const fault_extent{{min_pnt, max_pnt}};
112 GeoLib::AABB const fault_aabb_ext(fault_extent.cbegin(),
113 fault_extent.cend());
114
115 // test each voxel grid element vs each fault triangle
116 Eigen::Vector3d const extent{half_cell_size};
117 for (std::size_t j = 0; j < n_elems; ++j)
118 {
119 // test if bounding box of fault is intersecting voxel
120 auto const& centre_pnt = MeshLib::getCenterOfGravity(*elems[j]);
121 if (!fault_aabb_ext.containsPoint(centre_pnt, 0))
122 {
123 continue;
124 }
125
126 // test if voxel is intersecting triangle
127 auto const& c(centre_pnt.asEigenVector3d());
128 for (auto const* const fault_elem : felems)
129 {
130 if (fault_elem->getDimension() != 2)
131 {
132 continue;
133 }
134
136 *fault_elem->getNode(0), *fault_elem->getNode(1),
137 *fault_elem->getNode(2), c, extent))
138 {
139 (*mat_ids)[j] = fault_id;
140 break;
141 }
142
143 if (fault_elem->getGeomType() == MeshLib::MeshElemType::QUAD)
144 {
146 *fault_elem->getNode(0), *fault_elem->getNode(2),
147 *fault_elem->getNode(3), c, extent))
148 {
149 (*mat_ids)[j] = fault_id;
150 break;
151 }
152 }
153 }
154 }
155}
156} // namespace
158{
159bool isVoxelGrid(MeshLib::Mesh const& mesh)
160{
161 auto const& elements = mesh.getElements();
162 if (std::any_of(elements.cbegin(), elements.cend(),
163 [&](auto const& e) {
164 return (e->getGeomType() !=
165 MeshLib::MeshElemType::HEXAHEDRON);
166 }))
167 {
168 return false;
169 }
170 auto is_voxel = [](auto const& e)
171 {
172 auto const n = e->getNodes();
173 return ((*n[0])[2] != (*n[1])[2] || (*n[1])[2] != (*n[2])[2] ||
174 (*n[4])[2] != (*n[5])[2] || (*n[5])[2] != (*n[6])[2] ||
175 (*n[1])[0] != (*n[2])[0] || (*n[2])[0] != (*n[5])[0] ||
176 (*n[0])[0] != (*n[3])[0] || (*n[3])[0] != (*n[7])[0]);
177 };
178
179 if (std::any_of(elements.cbegin(), elements.cend(), is_voxel))
180 {
181 ERR("Input mesh needs to be voxel grid (i.e. equally sized axis "
182 "aligned hexahedra).");
183 return false;
184 }
185 return true;
186}
187} // namespace MeshToolsLib::MeshGenerator::AddFaultToVoxelGrid
189{
191 MeshLib::Mesh const* fault,
192 int const fault_id)
193{
194 if (mesh == nullptr)
195 {
196 ERR("Input mesh not found...");
197 return false;
198 }
199 if (!isVoxelGrid(*mesh))
200 {
201 ERR("The input mesh is not a voxel grid. The input mesh must be "
202 "a voxel grid (i.e. an equally sized axis "
203 "aligned hexahedra mesh).");
204 return false;
205 }
206
207 if (fault == nullptr)
208 {
209 ERR("Fault mesh not found...");
210 return false;
211 }
212 if (fault->getDimension() != 2)
213 {
214 ERR("Fault needs to be a 2D mesh.");
215 return false;
216 }
217
218 Eigen::Vector3d half_cell_size;
219 {
220 auto const n = *mesh->getElement(0)->getNode(0);
221 auto const c = MeshLib::getCenterOfGravity(*mesh->getElement(0));
222 half_cell_size[0] = std::abs(c[0] - n[0]);
223 half_cell_size[1] = std::abs(c[1] - n[1]);
224 half_cell_size[2] = std::abs(c[2] - n[2]);
225 }
226
227 markFaults(*mesh, *fault, fault_id, half_cell_size);
228
229 return true;
230}
231} // namespace MeshToolsLib::MeshGenerator::AddFaultToVoxelGrid
Definition of the AABB class.
Definition of the Element class.
Git information.
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
Definition of the Mesh class.
Definition of the Node class.
Definition of the Point3d class.
Implementation of the VtuInterface class.
Class AABB is an axis aligned bounding box around a given set of geometric points of (template) type ...
Definition AABB.h:56
bool containsPoint(T const &pnt, double eps) const
Definition AABB.h:143
MinMaxPoints getMinMaxPoints() const
Definition AABB.h:174
Eigen::Vector3d const & asEigenVector3d() const
Definition Point3d.h:63
virtual const Node * getNode(unsigned idx) const =0
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:106
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:109
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:88
const Element * getElement(std::size_t idx) const
Get the element with the given index.
Definition Mesh.h:94
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
PropertyVector< int > const * materialIDs(Mesh const &mesh)
Definition Mesh.cpp:268
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition Element.cpp:124
bool addFaultToVoxelGrid(MeshLib::Mesh *mesh, MeshLib::Mesh const *fault, int const fault_id)
bool testAABBIntersectingPlane(Eigen::Vector3d const &aabb_centre, Eigen::Vector3d const &aabb_extent, Eigen::Vector3d const &plane_normal, double const pd)
void markFaults(MeshLib::Mesh &mesh, MeshLib::Mesh const &fault, int const fault_id, Eigen::Vector3d const &half_cell_size)
bool testTriangleIntersectingAABB(MeshLib::Node const &n0, MeshLib::Node const &n1, MeshLib::Node const &n2, Eigen::Vector3d const &c, Eigen::Vector3d const &e)
Definition of readMeshFromFile function.