OGS
SurfaceGrid.cpp
Go to the documentation of this file.
1/*
2 * \date 2012-09-22
3 * \brief Definition of the SurfaceGrid class.
4 *
5 * \file
6 * \copyright
7 * Copyright (c) 2012-2022, OpenGeoSys Community (http://www.opengeosys.org)
8 * Distributed under a Modified BSD License.
9 * See accompanying file LICENSE.txt or
10 */
11
12#include "SurfaceGrid.h"
13
14#include <algorithm>
15#include <bitset>
16
17#include "BaseLib/Error.h"
18#include "BaseLib/Logging.h"
19#include "MathLib/Point3d.h"
20#include "Surface.h"
21#include "Triangle.h"
22
23namespace GeoLib
24{
26 : AABB(sfc->getAABB()), _n_steps({{1, 1, 1}})
27{
28 auto min_point{getMinPoint()};
29 auto max_point{getMaxPoint()};
30 // enlarge the bounding, such that the points with maximal coordinates
31 // fits into the grid
32 for (std::size_t k(0); k < 3; ++k)
33 {
34 max_point[k] += std::abs(max_point[k]) * 1e-6;
35 if (std::abs(max_point[k]) < std::numeric_limits<double>::epsilon())
36 {
37 max_point[k] = (max_point[k] - min_point[k]) * (1.0 + 1e-6);
38 }
39 }
40
41 Eigen::Vector3d delta = max_point - min_point;
42
43 if (delta[0] < std::numeric_limits<double>::epsilon())
44 {
45 const double max_delta(std::max(delta[1], delta[2]));
46 min_point[0] -= max_delta * 0.5e-3;
47 max_point[0] += max_delta * 0.5e-3;
48 delta[0] = max_point[0] - min_point[0];
49 }
50
51 if (delta[1] < std::numeric_limits<double>::epsilon())
52 {
53 const double max_delta(std::max(delta[0], delta[2]));
54 min_point[1] -= max_delta * 0.5e-3;
55 max_point[1] += max_delta * 0.5e-3;
56 delta[1] = max_point[1] - min_point[1];
57 }
58
59 if (delta[2] < std::numeric_limits<double>::epsilon())
60 {
61 const double max_delta(std::max(delta[0], delta[1]));
62 min_point[2] -= max_delta * 0.5e-3;
63 max_point[2] += max_delta * 0.5e-3;
64 delta[2] = max_point[2] - min_point[2];
65 }
66
67 update(min_point);
68 update(max_point);
69
70 const std::size_t n_tris(sfc->getNumberOfTriangles());
71 const std::size_t n_tris_per_cell(5);
72
73 Eigen::Matrix<bool, 3, 1> dim =
74 delta.array() >= std::numeric_limits<double>::epsilon();
75
76 // *** condition: n_tris / n_cells < n_tris_per_cell
77 // where n_cells = _n_steps[0] * _n_steps[1] * _n_steps[2]
78 // *** with _n_steps[0] =
79 // ceil(pow(n_tris*delta[0]*delta[0]/(n_tris_per_cell*delta[1]*delta[2]),
80 // 1/3.)));
81 // _n_steps[1] = _n_steps[0] * delta[1]/delta[0],
82 // _n_steps[2] = _n_steps[0] * delta[2]/delta[0]
83 auto sc_ceil = [](double v)
84 { return static_cast<std::size_t>(std::ceil(v)); };
85 switch (dim.count())
86 {
87 case 3: // 3d case
88 _n_steps[0] =
89 sc_ceil(std::cbrt(n_tris * delta[0] * delta[0] /
90 (n_tris_per_cell * delta[1] * delta[2])));
91 _n_steps[1] =
92 sc_ceil(_n_steps[0] * std::min(delta[1] / delta[0], 100.0));
93 _n_steps[2] =
94 sc_ceil(_n_steps[0] * std::min(delta[2] / delta[0], 100.0));
95 break;
96 case 2: // 2d cases
97 if (dim[0] && dim[2])
98 { // 2d case: xz plane, y = const
99 _n_steps[0] = sc_ceil(std::sqrt(n_tris * delta[0] /
100 (n_tris_per_cell * delta[2])));
101 _n_steps[2] = sc_ceil(_n_steps[0] * delta[2] / delta[0]);
102 }
103 else if (dim[0] && dim[1])
104 { // 2d case: xy plane, z = const
105 _n_steps[0] = sc_ceil(std::sqrt(n_tris * delta[0] /
106 (n_tris_per_cell * delta[1])));
107 _n_steps[1] = sc_ceil(_n_steps[0] * delta[1] / delta[0]);
108 }
109 else if (dim[1] && dim[2])
110 { // 2d case: yz plane, x = const
111 _n_steps[1] = sc_ceil(std::sqrt(n_tris * delta[1] /
112 (n_tris_per_cell * delta[2])));
113 _n_steps[2] =
114 sc_ceil(n_tris * delta[2] / (n_tris_per_cell * delta[1]));
115 }
116 break;
117 case 1: // 1d cases
118 for (std::size_t k(0); k < 3; ++k)
119 {
120 if (dim[k])
121 {
122 _n_steps[k] =
123 sc_ceil(static_cast<double>(n_tris) / n_tris_per_cell);
124 }
125 }
126 }
127
128 // some frequently used expressions to fill the grid vectors
129 for (std::size_t k(0); k < 3; k++)
130 {
131 _step_sizes[k] = delta[k] / _n_steps[k];
132 if (delta[k] > std::numeric_limits<double>::epsilon())
133 {
134 _inverse_step_sizes[k] = 1.0 / _step_sizes[k];
135 }
136 else
137 {
138 _inverse_step_sizes[k] = 0;
139 }
140 }
141
142 _triangles_in_grid_box.resize(_n_steps[0] * _n_steps[1] * _n_steps[2]);
143 sortTrianglesInGridCells(sfc);
144}
145
147{
148 for (std::size_t l(0); l < sfc->getNumberOfTriangles(); l++)
149 {
150 if (!sortTriangleInGridCells((*sfc)[l]))
151 {
152 Point const& p0(*((*sfc)[l]->getPoint(0)));
153 Point const& p1(*((*sfc)[l]->getPoint(1)));
154 Point const& p2(*((*sfc)[l]->getPoint(2)));
155 auto const& min{getMinPoint()};
156 auto const& max{getMaxPoint()};
157 OGS_FATAL(
158 "Sorting triangle {:d} [({:f},{:f},{:f}), ({:f},{:f},{:f}), "
159 "({:f},{:f},{:f}) into grid. Bounding box is [{:f}, {:f}] x "
160 "[{:f}, {:f}] x [{:f}, {:f}].",
161 l, p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1],
162 p2[2], min[0], max[0], min[1], max[1], min[2], max[2]);
163 }
164 }
165}
166
168{
169 // compute grid coordinates for each triangle point
170 std::optional<std::array<std::size_t, 3> const> c_p0(
171 getGridCellCoordinates(*(triangle->getPoint(0))));
172 if (!c_p0)
173 {
174 return false;
175 }
176 std::optional<std::array<std::size_t, 3> const> c_p1(
177 getGridCellCoordinates(*(triangle->getPoint(1))));
178 if (!c_p1)
179 {
180 return false;
181 }
182 std::optional<std::array<std::size_t, 3> const> c_p2(
183 getGridCellCoordinates(*(triangle->getPoint(2))));
184 if (!c_p2)
185 {
186 return false;
187 }
188
189 // determine interval in grid (grid cells the triangle will be inserted)
190 std::size_t const i_min(
191 std::min(std::min((*c_p0)[0], (*c_p1)[0]), (*c_p2)[0]));
192 std::size_t const i_max(
193 std::max(std::max((*c_p0)[0], (*c_p1)[0]), (*c_p2)[0]));
194 std::size_t const j_min(
195 std::min(std::min((*c_p0)[1], (*c_p1)[1]), (*c_p2)[1]));
196 std::size_t const j_max(
197 std::max(std::max((*c_p0)[1], (*c_p1)[1]), (*c_p2)[1]));
198 std::size_t const k_min(
199 std::min(std::min((*c_p0)[2], (*c_p1)[2]), (*c_p2)[2]));
200 std::size_t const k_max(
201 std::max(std::max((*c_p0)[2], (*c_p1)[2]), (*c_p2)[2]));
202
203 const std::size_t n_plane(_n_steps[0] * _n_steps[1]);
204
205 // insert the triangle into the grid cells
206 for (std::size_t i(i_min); i <= i_max; i++)
207 {
208 for (std::size_t j(j_min); j <= j_max; j++)
209 {
210 for (std::size_t k(k_min); k <= k_max; k++)
211 {
212 _triangles_in_grid_box[i + j * _n_steps[0] + k * n_plane]
213 .push_back(triangle);
214 }
215 }
216 }
217
218 return true;
219}
220
221std::optional<std::array<std::size_t, 3>> SurfaceGrid::getGridCellCoordinates(
222 MathLib::Point3d const& p) const
223{
224 auto const& min_point{getMinPoint()};
225 std::array<std::size_t, 3> coords{
226 {static_cast<std::size_t>((p[0] - min_point[0]) *
228 static_cast<std::size_t>((p[1] - min_point[1]) *
230 static_cast<std::size_t>((p[2] - min_point[2]) *
232
233 if (coords[0] >= _n_steps[0] || coords[1] >= _n_steps[1] ||
234 coords[2] >= _n_steps[2])
235 {
236 DBUG(
237 "Computed indices ({:d},{:d},{:d}), max grid cell indices "
238 "({:d},{:d},{:d})",
239 coords[0], coords[1], coords[2], _n_steps[0], _n_steps[1],
240 _n_steps[2]);
241 return std::optional<std::array<std::size_t, 3>>();
242 }
243 return std::optional<std::array<std::size_t, 3>>(coords);
244}
245
247 double eps) const
248{
249 std::optional<std::array<std::size_t, 3>> optional_c(
251 if (!optional_c)
252 {
253 return false;
254 }
255 std::array<std::size_t, 3> const c(optional_c.value());
256
257 std::size_t const grid_cell_idx(c[0] + c[1] * _n_steps[0] +
258 c[2] * _n_steps[0] * _n_steps[1]);
259 std::vector<Triangle const*> const& triangles(
260 _triangles_in_grid_box[grid_cell_idx]);
261 auto const it = std::find_if(triangles.begin(), triangles.end(),
262 [eps, pnt](auto const* triangle)
263 { return triangle->containsPoint(pnt, eps); });
264 return it != triangles.end();
265}
266
267} // end namespace GeoLib
#define OGS_FATAL(...)
Definition: Error.h:26
void DBUG(char const *fmt, Args const &... args)
Definition: Logging.h:29
Definition of the Point3d class.
Class AABB is an axis aligned bounding box around a given set of geometric points of (template) type ...
Definition: AABB.h:49
Eigen::Vector3d const & getMaxPoint() const
Definition: AABB.h:179
Eigen::Vector3d const & getMinPoint() const
Definition: AABB.h:172
void sortTrianglesInGridCells(GeoLib::Surface const *const sfc)
std::vector< std::vector< GeoLib::Triangle const * > > _triangles_in_grid_box
Definition: SurfaceGrid.h:43
bool isPointInSurface(MathLib::Point3d const &pnt, double eps=std::numeric_limits< double >::epsilon()) const
std::array< std::size_t, 3 > _n_steps
Definition: SurfaceGrid.h:42
std::array< double, 3 > _inverse_step_sizes
Definition: SurfaceGrid.h:41
bool sortTriangleInGridCells(GeoLib::Triangle const *const triangle)
SurfaceGrid(GeoLib::Surface const *const sfc)
Definition: SurfaceGrid.cpp:25
std::optional< std::array< std::size_t, 3 > > getGridCellCoordinates(MathLib::Point3d const &p) const
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
Definition: Surface.h:34
std::size_t getNumberOfTriangles() const
Definition: Surface.cpp:82
Class Triangle consists of a reference to a point vector and a vector that stores the indices in the ...
Definition: Triangle.h:26
const Point * getPoint(std::size_t i) const
const access operator to access the i-th triangle Point
Definition: Triangle.h:49
static const double v