39#include "../basic_types/datatype_structure.hpp"
66 const IntT n_pts =
static_cast<IntT>(x.size());
68 std::vector<IntT> perm(n_pts);
69 std::iota(perm.begin(), perm.end(), 0);
70 std::sort(perm.begin(), perm.end(),
71 [&x, &y](
const auto i,
const auto j) { return x[i] != x[j] ? x[i] < x[j] : y[i] < y[j]; });
73 auto reorder = [n_pts, &perm](
const auto& v) {
75 for (
IntT i = 0; i < n_pts; ++i) {
83 std::vector<IntT> inv_perm(n_pts);
84 for (
IntT i = 0; i < n_pts; ++i) {
85 inv_perm[perm[i]] = i;
87 for (
IntT i = 0; i < static_cast<IntT>(triangles.
rows()); ++i) {
88 for (
IntT j = 0; j < 3; ++j) {
89 triangles(i, j) = inv_perm[triangles(i, j)];
99 std::vector<std::array<IntT, 3>> edges;
102 for (
IntT i_tri = 0; i_tri < static_cast<IntT>(triangles.
rows()); ++i_tri) {
103 for (
IntT i = 0; i < 3; ++i) {
104 const IntT j = (i + 1) % 3;
105 const IntT i_pt = std::min(triangles(i_tri, i), triangles(i_tri, j));
106 const IntT j_pt = std::max(triangles(i_tri, i), triangles(i_tri, j));
107 edges[3 * i_tri + i] = {i_pt, j_pt, i_tri};
112 std::sort(edges.begin(), edges.end(),
113 [](
const auto& a,
const auto& b) { return a[0] != b[0] ? (a[0] < b[0]) : (a[1] < b[1]); });
115 auto is_equal = [](
const auto& a,
const auto& b) {
return a[0] == b[0] && a[1] == b[1]; };
118 for (
IntT i = 1; i < static_cast<IntT>(edges.size()); ++i) {
119 n_edges +=
static_cast<IntT>(!is_equal(edges[i], edges[i - 1]));
122 edge_pts.
resize(n_edges, 2);
123 edge_faces.
resize(n_edges, 2);
126 auto new_edge = [&](
const auto& edge) {
127 edge_pts(pos, 0) = edge[0];
128 edge_pts(pos, 1) = edge[1];
129 edge_faces(pos, 0) = edge[2];
130 edge_faces(pos, 1) = -1;
135 for (
IntT i = 1; i < static_cast<IntT>(edges.size()); ++i) {
136 if (is_equal(edges[i], edges[i - 1])) {
137 edge_faces(pos - 1, 1) = edges[i][2];
150 if (max_bands <= 0) {
151 max_bands = std::min(
IntT{5000},
static_cast<IntT>(4.0 * std::sqrt(
static_cast<double>(x.size()))));
155 for (
IntT i = 1; i < static_cast<IntT>(x.size()); ++i) {
156 if (x[i] != x[i - 1]) n_unique++;
159 if (n_unique <= max_bands) {
160 const IntT n_bands = n_unique - 1;
164 for (
IntT i = 1; i < static_cast<IntT>(x.size()); ++i) {
165 if (x[i] != x_bands[pos]) {
166 x_bands[++pos] = x[i];
169 return std::make_tuple(n_bands, std::move(x_bands));
172 const RealT x_min = x.front();
173 const RealT x_max = x.back();
174 const RealT band_width = (x_max - x_min) / max_bands;
177 for (
IntT i = 0; i <= max_bands; ++i) {
178 x_bands[i] = x_min + i * band_width;
180 x_bands[max_bands] = x_max;
182 return std::make_tuple(max_bands, std::move(x_bands));
193 auto& edge_y = map.
edge_y;
195 auto clear_map = [&]() {
203 x_bands = std::move(bands);
210 auto find_band = [&x_bands, n_bands = n_bands](
RealT x_val) ->
IntT {
211 auto it = std::lower_bound(x_bands.begin(), x_bands.end(), x_val);
212 const IntT idx =
static_cast<IntT>(it - x_bands.begin());
213 return std::min(std::max(
IntT{0}, idx - 1), n_bands - 1);
218 auto& counts = offsets;
220 counts.resize(n_bands + 1, 0);
222 for (
IntT i = 0; i < static_cast<IntT>(edge_pts.
rows()); ++i) {
223 const IntT band_0 = find_band(x[edge_pts(i, 0)]);
224 const IntT band_1 = find_band(x[edge_pts(i, 1)]);
226 for (
IntT j = std::min(band_0, band_1); j <= std::max(band_0, band_1); ++j) {
232 for (
IntT i = 2; i < static_cast<IntT>(offsets.size()); ++i) {
233 offsets[i] += offsets[i - 1];
237 const size_t memory_mb =
static_cast<size_t>(offsets.back()) * (
sizeof(
IntT) +
sizeof(
RealT)) / (1024 * 1024);
238 if (memory_mb > 2048) {
243 edge_id.resize(offsets.back());
244 edge_y.resize(offsets.back());
247 for (
IntT i_edge = 0; i_edge < static_cast<IntT>(edge_pts.
rows()); ++i_edge) {
248 const IntT pt_0 = edge_pts(i_edge, 0);
249 const IntT pt_1 = edge_pts(i_edge, 1);
250 const RealT x_0 = x[pt_0], y_0 = y[pt_0];
251 const RealT x_1 = x[pt_1], y_1 = y[pt_1];
253 const IntT band_0 = find_band(x_0);
254 const IntT band_1 = find_band(x_1);
256 const RealT dx = x_1 - x_0;
258 const RealT dy_dx = vertical ?
RealT{0} : (y_1 - y_0) / dx;
260 for (
IntT j = std::min(band_0, band_1); j <= std::max(band_0, band_1); ++j) {
261 edge_id[pos[j]] = i_edge;
262 const RealT x_mid = (x_bands[j] + x_bands[j + 1]) / 2;
263 edge_y[pos[j]] = vertical ?
RealT((y_0 + y_1) / 2) :
RealT(y_0 + dy_dx * (x_mid - x_0));
269 std::vector<std::pair<IntT, RealT>> tmp;
270 for (
IntT i = 0; i < n_bands; ++i) {
271 const IntT begin = offsets[i];
272 const IntT end = offsets[i + 1];
273 if (begin >= end)
continue;
275 tmp.resize(end - begin);
276 for (
auto k = begin; k < end; ++k) {
277 tmp[k - begin] = {edge_id[k], edge_y[k]};
279 std::sort(tmp.begin(), tmp.end(), [](
const auto& a,
const auto& b) { return a.second < b.second; });
280 for (
auto k = begin; k < end; ++k) {
281 edge_id[k] = tmp[k - begin].first;
282 edge_y[k] = tmp[k - begin].second;
294 return std::make_pair(
IntT{-1},
IntT{-1});
297 const auto& x_bands = map.
x_bands;
298 const IntT n_bands =
static_cast<IntT>(x_bands.size()) - 1;
299 auto it = std::lower_bound(x_bands.begin(), x_bands.end(), x);
300 const IntT d =
static_cast<IntT>(it - x_bands.begin());
301 const IntT band_idx = std::min(std::max(
IntT{0}, d - 1), n_bands - 1);
303 RealT best_y_below = -1e300;
304 RealT best_y_above = 1e300;
305 IntT edge_below = -1;
306 IntT edge_above = -1;
311 for (
IntT k = begin; k < end; ++k) {
314 const IntT p0 = edge_pts(e_id, 0);
315 const IntT p1 = edge_pts(e_id, 1);
316 const RealT x0 = x_coords[p0], y0 = y_coords[p0];
317 const RealT x1 = x_coords[p1], y1 = y_coords[p1];
319 if (x < std::min(x0, x1) - 1e-10 || x > std::max(x0, x1) + 1e-10) {
325 const RealT dx = x1 - x0;
327 edge_y_at_x = (y0 + y1) / 2.0;
329 edge_y_at_x = y0 + (x - x0) / dx * (y1 - y0);
332 if (edge_y_at_x <= y + 1e-10 && edge_y_at_x > best_y_below) {
333 best_y_below = edge_y_at_x;
336 if (edge_y_at_x >= y - 1e-10 && edge_y_at_x < best_y_above) {
337 best_y_above = edge_y_at_x;
342 return std::make_pair(edge_below, edge_above);
349 std::array<IntT, 3> tris = {-1, -1, -1};
352 auto insert = [&tris, &pos](
const IntT t) {
354 for (
IntT i = 0; i < pos; ++i) {
355 if (t == tris[i])
return;
360 auto get_tris = [&edge_faces](
const IntT e) {
361 if (e < 0)
return std::array{
IntT{-1},
IntT{-1}};
362 return std::array{edge_faces(e, 0), edge_faces(e, 1)};
365 for (
const auto e : {edge_0, edge_1}) {
366 for (
const auto t : get_tris(e)) {
378 const IntT p0 = triangles(i_tri, 0);
379 const IntT p1 = triangles(i_tri, 1);
380 const IntT p2 = triangles(i_tri, 2);
382 const RealT x0 = x[p0], y0 = y[p0];
383 const RealT x1 = x[p1], y1 = y[p1];
384 const RealT x2 = x[p2], y2 = y[p2];
386 const RealT dx1 = x1 - x0, dy1 = y1 - y0;
387 const RealT dx2 = x2 - x0, dy2 = y2 - y0;
389 auto cross = [](
const RealT ux,
const RealT uy,
const RealT vx,
const RealT vy) {
return ux * vy - uy * vx; };
391 const RealT det = cross(dx1, dy1, dx2, dy2);
396 const RealT inv_det = 1.0 / det;
397 const RealT a = (cross(x_q, y_q, dx2, dy2) - cross(x0, y0, dx2, dy2)) * inv_det;
398 const RealT b = (cross(x0, y0, dx1, dy1) - cross(x_q, y_q, dx1, dy1)) * inv_det;
400 return std::array<RealT, 3>{1 - a - b, a, b};
407 return coords[0] >= -tol && coords[1] >= -tol && coords[2] >= -tol;
415 const RealT y_q, std::array<RealT, 3>& bary_out) {
419 const RealT tol = 1e-12;
420 for (
const auto t : candidates) {
430 bary_out = {0.0, 0.0, 0.0};
448 unsigned long n_points = 0;
449 unsigned long n_triangles = 0;
459 const unsigned long* connectivity) {
460 n_points = num_points;
461 n_triangles = num_triangles;
463 if (num_points == 0 || num_triangles == 0)
return false;
465 x_coords.assign(x, x + num_points);
466 y_coords.assign(y, y + num_points);
468 triangles.
resize(num_triangles, 3);
469 for (
size_t i = 0; i < 3 * num_triangles; ++i) {
485 std::array<su2double, 3>& bary_coords)
const {
486 if (n_triangles == 0 || n_points == 0 || map.
x_bands.empty()) {
487 bary_coords = {0.0, 0.0, 0.0};
491 std::array<su2_lut::RealT, 3> bary;
495 if (tri_id < 0)
return false;
497 triangle_id =
static_cast<unsigned long>(tri_id);
498 bary_coords = {bary[0], bary[1], bary[2]};
510 return double(bytes) / (1024.0 * 1024.0);
A templated vector/matrix object.
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
C2DContainer & resize(const Index_t size1, const Index_t size2=1) noexcept
Request a change of size.
Definition C2DContainer.hpp:541
size_t size() const noexcept
Definition C2DContainer.hpp:222
Index_t rows() const noexcept
Definition C2DContainer.hpp:222
Trapezoidal map for finding the triangle containing a query point in a 2D triangulation.
Definition CTrapezoidalMap.hpp:441
double GetMemoryFootprint() const
Get the memory footprint of the map in MB.
Definition CTrapezoidalMap.hpp:505
bool Build(unsigned long num_points, unsigned long num_triangles, const su2double *x, const su2double *y, const unsigned long *connectivity)
Build the trapezoidal map from a triangulation.
Definition CTrapezoidalMap.hpp:458
bool FindTriangle(su2double val_x, su2double val_y, unsigned long &triangle_id, std::array< su2double, 3 > &bary_coords) const
Find the triangle containing a query point.
Definition CTrapezoidalMap.hpp:484
CTrapezoidalMap()=default
Scalar_t * data() noexcept
Definition C2DContainer.hpp:222
passivedouble su2double
Definition code_config.hpp:181
passivedouble GetValue(const su2double &data)
Get the (primitive) value of the datatype (needs to be specialized for active types).
Definition datatype_structure.hpp:113
Definition CTrapezoidalMap.hpp:42
void ReorderPoints(Matrix3i &triangles, VectorReal &x, VectorReal &y)
Orders points by ascending x coordinates and updates triangle indices.
Definition CTrapezoidalMap.hpp:65
su2double RealT
Definition CTrapezoidalMap.hpp:45
auto TriangleCoords(const IntT i_tri, const Matrix3i &triangles, const VectorReal &x, const VectorReal &y, const RealT x_q, const RealT y_q)
Computes the barycentric coordinates of point (x_q, y_q) in a triangle.
Definition CTrapezoidalMap.hpp:376
void BuildTrapezoidalMap(const Matrix2i &edge_pts, const VectorReal &x, const VectorReal &y, TrapezoidalMap &map)
Builds the trapezoidal map for a set of edges (points must be ordered by x).
Definition CTrapezoidalMap.hpp:188
auto QueryTrapezoidalMap(const TrapezoidalMap &map, const Matrix2i &edge_pts, const VectorReal &x_coords, const VectorReal &y_coords, const RealT &x, const RealT &y)
Returns the IDs of the edges directly below and above a query point (either ID can be -1 if the point...
Definition CTrapezoidalMap.hpp:291
int32_t IntT
Definition CTrapezoidalMap.hpp:44
auto DetectBands(const VectorReal &x, IntT max_bands=0)
Detects the x bands of the map. One band per unique x coordinate is used unless that would exceed max...
Definition CTrapezoidalMap.hpp:149
std::vector< IntT > VectorInt
Definition CTrapezoidalMap.hpp:52
IntT FindTriangle(const TrapezoidalMap &map, const Matrix3i &triangles, const Matrix2i &edge_pts, const Matrix2i &edge_faces, const VectorReal &x, const VectorReal &y, const RealT x_q, const RealT y_q, std::array< RealT, 3 > &bary_out)
Finds the triangle containing a point using the trapezoidal map.
Definition CTrapezoidalMap.hpp:413
auto AdjacentTriangles(const IntT edge_0, const IntT edge_1, const Matrix2i &edge_faces)
Returns the IDs of the triangles adjacent to two query edges (up to 3 triangles).
Definition CTrapezoidalMap.hpp:348
bool InTriangle(const std::array< RealT, 3 > &coords, const RealT tol=0.0)
Checks if a point is inside a triangle based on its barycentric coordinates.
Definition CTrapezoidalMap.hpp:406
std::vector< RealT > VectorReal
Definition CTrapezoidalMap.hpp:53
void ExtractEdges(const Matrix3i &triangles, Matrix2i &edge_pts, Matrix2i &edge_faces)
Extracts unique edges from triangles. Edges are defined by two point IDs and up to two adjacent trian...
Definition CTrapezoidalMap.hpp:98
Definition CTrapezoidalMap.hpp:57
VectorInt offsets
Definition CTrapezoidalMap.hpp:58
VectorReal x_bands
Definition CTrapezoidalMap.hpp:59
VectorReal edge_y
Definition CTrapezoidalMap.hpp:59
VectorInt edge_id
Definition CTrapezoidalMap.hpp:58