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