Loading [MathJax]/extensions/tex2jax.js
MeshKernel
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages Concepts
Utils.hpp
1//---- GPL ---------------------------------------------------------------------
2//
3// Copyright (C) Stichting Deltares, 2011-2021.
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation version 3.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//
17// contact: delft3d.support@deltares.nl
18// Stichting Deltares
19// P.O. Box 177
20// 2600 MH Delft, The Netherlands
21//
22// All indications and logos of, and references to, "Delft3D" and "Deltares"
23// are registered trademarks of Stichting Deltares, and remain the property of
24// Stichting Deltares. All rights reserved.
25//
26//------------------------------------------------------------------------------
27
28#pragma once
29
30#include <MeshKernel/Constants.hpp>
31#include <MeshKernel/CurvilinearGrid/CurvilinearGrid.hpp>
32#include <MeshKernel/Entities.hpp>
33#include <MeshKernel/Exceptions.hpp>
34#include <MeshKernel/Mesh1D.hpp>
35#include <MeshKernel/Mesh2D.hpp>
36#include <MeshKernel/MeshEdgeCenters.hpp>
37#include <MeshKernel/Operations.hpp>
38#include <MeshKernel/Splines.hpp>
39
40#include <MeshKernelApi/GeometryList.hpp>
41#include <MeshKernelApi/GriddedSamples.hpp>
42#include <MeshKernelApi/Mesh1D.hpp>
43#include <MeshKernelApi/Mesh2D.hpp>
44
45#include "MeshKernel/BilinearInterpolationOnGriddedSamples.hpp"
46#include <MeshKernel/CurvilinearGrid/CurvilinearGridRectangular.hpp>
47
48#include "MeshKernelApi/CurvilinearGrid.hpp"
49
50#include <optional>
51#include <span>
52#include <stdexcept>
53#include <vector>
54
55namespace meshkernelapi
56{
57
61 static std::vector<meshkernel::Point> ConvertGeometryListToPointVector(const GeometryList& geometryListIn)
62 {
63 std::vector<meshkernel::Point> result;
64 if (geometryListIn.num_coordinates == 0)
65 {
66 return result;
67 }
68 result.reserve(geometryListIn.num_coordinates);
69 result.emplace_back(geometryListIn.coordinates_x[0], geometryListIn.coordinates_y[0]);
70 // remove consecutive duplicated point leading to 0 edge length
71 for (auto i = 1; i < geometryListIn.num_coordinates; ++i)
72 {
73 if (meshkernel::IsEqual(geometryListIn.coordinates_x[i], result.back().x) &&
74 meshkernel::IsEqual(geometryListIn.coordinates_y[i], result.back().y))
75 {
76 continue;
77 }
78 result.emplace_back(geometryListIn.coordinates_x[i], geometryListIn.coordinates_y[i]);
79 }
80 return result;
81 }
82
87 static std::vector<std::vector<meshkernel::Point>> ConvertGeometryListToVectorOfPointVectors(GeometryList const& geometryListIn)
88 {
89 std::vector<std::vector<meshkernel::Point>> result;
90 std::vector<meshkernel::Point> chunk;
91 chunk.reserve(geometryListIn.num_coordinates);
92 for (auto i = 0; i < geometryListIn.num_coordinates; ++i)
93 {
94
95 if (meshkernel::IsEqual(geometryListIn.coordinates_x[i], geometryListIn.geometry_separator))
96 {
97 result.emplace_back(chunk);
98 chunk.clear();
99 }
100 else
101 {
102 chunk.emplace_back(geometryListIn.coordinates_x[i], geometryListIn.coordinates_y[i]);
103 }
104 }
105
106 if (!chunk.empty())
107 {
108 result.emplace_back(chunk);
109 }
110
111 return result;
112 }
113
118 template <typename T>
119 static std::vector<std::vector<T>> ConvertVectorToVectorOfVectors(const std::vector<T> input, T separator)
120 {
121 std::vector<std::vector<T>> result;
122 std::vector<T> chunk;
123 for (size_t i = 0; i < input.size(); ++i)
124 {
125 if (meshkernel::IsEqual(input[i], separator))
126 {
127 result.emplace_back(chunk);
128 chunk.clear();
129 }
130 else
131 {
132 chunk.emplace_back(input[i]);
133 }
134 }
135 if (!chunk.empty())
136 {
137 result.emplace_back(chunk);
138 }
139 return result;
140 }
141
146 static std::vector<bool> ConvertIntegerArrayToBoolVector(const int inputArray[], size_t inputSize)
147 {
148 std::vector<bool> result(inputSize);
149 for (size_t i = 0; i < inputSize; ++i)
150 {
151 switch (inputArray[i])
152 {
153 case 0:
154 result[i] = false;
155 break;
156 case 1:
157 result[i] = true;
158 break;
159 default:
160 throw std::invalid_argument("MeshKernel: Invalid 1D mask.");
161 }
162 }
163 return result;
164 }
165
169 static std::vector<meshkernel::Sample> ConvertGeometryListToSampleVector(const GeometryList& geometryListIn)
170 {
171 if (geometryListIn.num_coordinates == 0)
172 {
173 throw std::invalid_argument("MeshKernel: The samples are empty.");
174 }
175 std::vector<meshkernel::Sample> result;
176 result.reserve(geometryListIn.num_coordinates);
177
178 for (auto i = 0; i < geometryListIn.num_coordinates; ++i)
179 {
180 result.push_back({geometryListIn.coordinates_x[i], geometryListIn.coordinates_y[i], geometryListIn.values[i]});
181 }
182 return result;
183 }
184
188 static void ConvertPointVectorToGeometryList(std::vector<meshkernel::Point> const& pointVector, GeometryList& result)
189 {
190 if (pointVector.size() < static_cast<size_t>(result.num_coordinates))
191 {
192 throw std::invalid_argument("MeshKernel: Invalid memory allocation, the point-vector size is smaller than the number of coordinates in the result vector.");
193 }
194
195 for (auto i = 0; i < result.num_coordinates; ++i)
196 {
197 result.coordinates_x[i] = pointVector[i].x;
198 result.coordinates_y[i] = pointVector[i].y;
199 }
200 }
201
206 static void ConvertSampleVectorToGeometryList(std::vector<meshkernel::Point> const& valuesCoordinates, std::vector<double> const& values, GeometryList& result)
207 {
208 if (valuesCoordinates.size() != values.size())
209 {
210 throw std::invalid_argument("MeshKernel: The size of the valuesCoordinates-vector is not equal to the size of the values-vector");
211 }
212
213 if (values.size() < static_cast<size_t>(result.num_coordinates))
214 {
215 throw std::invalid_argument("MeshKernel: Invalid memory allocation, the value-vector size is smaller than the number of coordinates in the result vector.");
216 }
217
218 for (auto i = 0; i < result.num_coordinates; ++i)
219 {
220 result.coordinates_x[i] = valuesCoordinates[i].x;
221 result.coordinates_y[i] = valuesCoordinates[i].y;
222 result.values[i] = values[i];
223 }
224 }
225
229 template <meshkernel::InterpolatableType T>
230 static std::vector<meshkernel::Sample> ComputeGriddedDataSamples(const GriddedSamples& griddedSamples)
231 {
232 std::vector<meshkernel::Sample> result;
233 meshkernel::Point origin{griddedSamples.x_origin, griddedSamples.y_origin};
234 const auto numSamples = static_cast<size_t>(griddedSamples.num_x * griddedSamples.num_y);
235 result.resize(numSamples);
236 const T* valuePtr = static_cast<T*>(griddedSamples.values);
237 if (griddedSamples.x_coordinates == nullptr || griddedSamples.y_coordinates == nullptr)
238 {
239 meshkernel::UInt index = 0;
240
241 for (int j = 0; j < griddedSamples.num_x; ++j)
242 {
243 for (int i = griddedSamples.num_y - 1; i >= 0; --i)
244 {
245 const auto griddedIndex = griddedSamples.num_x * i + j;
246 result[index].x = origin.x + j * griddedSamples.cell_size;
247 result[index].y = origin.y + i * griddedSamples.cell_size;
248 result[index].value = static_cast<double>(valuePtr[griddedIndex]);
249 index++;
250 }
251 }
252 return result;
253 }
254
255 meshkernel::UInt index = 0;
256 for (int j = 0; j < griddedSamples.num_x; ++j)
257 {
258 for (int i = griddedSamples.num_y - 1; i >= 0; --i)
259 {
260 const auto griddedIndex = griddedSamples.num_x * i + j;
261 result[index].x = origin.x + griddedSamples.x_coordinates[griddedIndex];
262 result[index].y = origin.y + griddedSamples.y_coordinates[griddedIndex];
263 result[index].value = static_cast<double>(valuePtr[griddedIndex]);
264 index++;
265 }
266 }
267 return result;
268 }
269
273 static std::vector<meshkernel::Sample> ConvertGriddedData(const GriddedSamples& griddedSamples)
274 {
275 std::vector<meshkernel::Sample> result;
276 if (griddedSamples.num_x <= 0 || griddedSamples.num_y <= 0)
277 {
278 return result;
279 }
280
281 if (griddedSamples.value_type == static_cast<int>(meshkernel::InterpolationDataTypes::Short))
282 {
283 return ComputeGriddedDataSamples<short>(griddedSamples);
284 }
285 if (griddedSamples.value_type == static_cast<int>(meshkernel::InterpolationDataTypes::Float))
286 {
287 return ComputeGriddedDataSamples<float>(griddedSamples);
288 }
289 if (griddedSamples.value_type == static_cast<int>(meshkernel::InterpolationDataTypes::Double))
290 {
291 return ComputeGriddedDataSamples<double>(griddedSamples);
292 }
293 if (griddedSamples.value_type == static_cast<int>(meshkernel::InterpolationDataTypes::Int))
294 {
295 return ComputeGriddedDataSamples<int>(griddedSamples);
296 }
297 throw meshkernel::MeshKernelError("The value type for the gridded data samples is invalid.");
298 }
299
303 static void SetSplines(const GeometryList& geometryListIn, meshkernel::Splines& spline)
304 {
305 if (geometryListIn.num_coordinates == 0)
306 {
307 return;
308 }
309
310 const auto splineCornerPoints = ConvertGeometryListToPointVector(geometryListIn);
311
312 const auto indices = FindIndices(splineCornerPoints,
313 0,
314 static_cast<meshkernel::UInt>(splineCornerPoints.size()),
315 meshkernel::constants::missing::doubleValue);
316
317 for (const auto& index : indices)
318 {
319 const auto& [startIndex, endIndex] = index;
320 const auto size = endIndex - startIndex + 1;
321 if (size > 0)
322 {
323 spline.AddSpline(splineCornerPoints, startIndex, size);
324 }
325 }
326 }
327
331 static void SetMesh2dApiDimensions(const meshkernel::Mesh& mesh2d, Mesh2D& mesh2dApi)
332 {
333 size_t num_face_nodes = 0;
334 for (size_t f = 0; f < mesh2d.GetNumFaces(); f++)
335 {
336 num_face_nodes += mesh2d.m_facesNodes[f].size();
337 }
338
339 mesh2dApi.num_face_nodes = static_cast<int>(num_face_nodes);
340 mesh2dApi.num_faces = static_cast<int>(mesh2d.GetNumFaces());
341 mesh2dApi.num_nodes = static_cast<int>(mesh2d.GetNumNodes());
342 mesh2dApi.num_valid_nodes = static_cast<int>(mesh2d.GetNumValidNodes());
343 mesh2dApi.num_edges = static_cast<int>(mesh2d.GetNumEdges());
344 mesh2dApi.num_valid_edges = static_cast<int>(mesh2d.GetNumValidEdges());
345 }
346
350 static void SetMesh2dApiNodeEdgeData(meshkernel::Mesh2D& mesh2d, Mesh2D& mesh2dApi)
351 {
352 if (mesh2dApi.num_nodes != static_cast<int>(mesh2d.GetNumNodes()))
353 {
354 throw meshkernel::ConstraintError("The number of nodes in the mesh2d api structure does not equal the number of nodes in the grid, {} /= {}",
355 mesh2dApi.num_nodes, mesh2d.GetNumNodes());
356 }
357
358 if (mesh2dApi.num_edges != static_cast<int>(mesh2d.GetNumEdges()))
359 {
360 throw meshkernel::ConstraintError("The number of edges in the mesh2d api structure does not equal the number of edges in the grid, {} /= {}",
361 mesh2dApi.num_edges, mesh2d.GetNumEdges());
362 }
363
364 for (meshkernel::UInt n = 0; n < mesh2d.GetNumNodes(); ++n)
365 {
366 mesh2dApi.node_x[n] = mesh2d.Node(n).x;
367 mesh2dApi.node_y[n] = mesh2d.Node(n).y;
368 }
369
370 for (meshkernel::UInt edgeIndex = 0; edgeIndex < mesh2d.GetNumEdges(); ++edgeIndex)
371 {
372 mesh2dApi.edge_nodes[edgeIndex * 2] = static_cast<int>(mesh2d.GetEdge(edgeIndex).first);
373 mesh2dApi.edge_nodes[edgeIndex * 2 + 1] = static_cast<int>(mesh2d.GetEdge(edgeIndex).second);
374 }
375 SetMesh2dApiDimensions(mesh2d, mesh2dApi);
376 }
377
381 static void SetMesh2dApiData(meshkernel::Mesh2D& mesh2d, Mesh2D& mesh2dApi)
382 {
383 std::vector<meshkernel::Point> edgeCentres = meshkernel::algo::ComputeEdgeCentres(mesh2d);
384
385 for (meshkernel::UInt n = 0; n < mesh2d.GetNumNodes(); n++)
386 {
387 mesh2dApi.node_x[n] = mesh2d.Node(n).x;
388 mesh2dApi.node_y[n] = mesh2d.Node(n).y;
389 }
390
391 for (meshkernel::UInt edgeIndex = 0; edgeIndex < mesh2d.GetNumEdges(); edgeIndex++)
392 {
393 mesh2dApi.edge_x[edgeIndex] = edgeCentres[edgeIndex].x;
394 mesh2dApi.edge_y[edgeIndex] = edgeCentres[edgeIndex].y;
395 mesh2dApi.edge_nodes[edgeIndex * 2] = static_cast<int>(mesh2d.GetEdge(edgeIndex).first);
396 mesh2dApi.edge_nodes[edgeIndex * 2 + 1] = static_cast<int>(mesh2d.GetEdge(edgeIndex).second);
397
398 const auto& firstEdgeFace = mesh2d.m_edgesFaces[edgeIndex][0];
399 mesh2dApi.edge_faces[edgeIndex * 2] = firstEdgeFace == meshkernel::constants::missing::uintValue ? -1 : static_cast<int>(firstEdgeFace);
400 const auto& secondEdgeFace = mesh2d.m_edgesFaces[edgeIndex][1];
401 mesh2dApi.edge_faces[edgeIndex * 2 + 1] = secondEdgeFace == meshkernel::constants::missing::uintValue ? -1 : static_cast<int>(secondEdgeFace);
402 }
403
404 int faceIndex = 0;
405 for (size_t f = 0; f < mesh2d.GetNumFaces(); f++)
406 {
407 mesh2dApi.face_x[f] = mesh2d.m_facesMassCenters[f].x;
408 mesh2dApi.face_y[f] = mesh2d.m_facesMassCenters[f].y;
409 mesh2dApi.nodes_per_face[f] = static_cast<int>(mesh2d.m_facesNodes[f].size());
410 for (size_t n = 0; n < mesh2d.m_facesNodes[f].size(); ++n)
411 {
412 mesh2dApi.face_nodes[faceIndex] = static_cast<int>(mesh2d.m_facesNodes[f][n]);
413 mesh2dApi.face_edges[faceIndex] = static_cast<int>(mesh2d.m_facesEdges[f][n]);
414 faceIndex++;
415 }
416 }
417 SetMesh2dApiDimensions(mesh2d, mesh2dApi);
418 }
419
423 static void SetCurvilinearGridApiData(const meshkernel::CurvilinearGrid& curvilinearGrid,
424 CurvilinearGrid& curvilinearGridApi)
425 {
426 if (curvilinearGridApi.num_n != static_cast<int>(curvilinearGrid.NumN()))
427 {
428 throw meshkernel::ConstraintError("The number of rows in the api structure does not equal the number of rows in the grid, {} /= {}",
429 curvilinearGridApi.num_n, curvilinearGrid.NumN());
430 }
431
432 if (curvilinearGridApi.num_m != static_cast<int>(curvilinearGrid.NumM()))
433 {
434 throw meshkernel::ConstraintError("The number of columns in the api structure does not equal the number of columns in the grid, {} /= {}",
435 curvilinearGridApi.num_m, curvilinearGrid.NumM());
436 }
437
438 int count = 0;
439
440 for (meshkernel::UInt n = 0; n < curvilinearGrid.NumN(); n++)
441 {
442 for (meshkernel::UInt m = 0; m < curvilinearGrid.NumM(); m++)
443 {
444 curvilinearGridApi.node_x[count] = curvilinearGrid.GetNode(n, m).x;
445 curvilinearGridApi.node_y[count] = curvilinearGrid.GetNode(n, m).y;
446 ++count;
447 }
448 }
449 }
450
454 static void SetMesh1dApiDimension(const meshkernel::Mesh1D& mesh1d,
455 Mesh1D& mesh1dApi)
456 {
457 mesh1dApi.num_nodes = static_cast<int>(mesh1d.GetNumNodes());
458 mesh1dApi.num_valid_nodes = static_cast<int>(mesh1d.GetNumValidNodes());
459 mesh1dApi.num_edges = static_cast<int>(mesh1d.GetNumEdges());
460 mesh1dApi.num_valid_edges = static_cast<int>(mesh1d.GetNumValidEdges());
461 }
462
466 static void SetMesh1dApiData(const meshkernel::Mesh1D& mesh1d,
467 Mesh1D& mesh1dApi)
468 {
469 for (meshkernel::UInt n = 0; n < mesh1d.GetNumNodes(); n++)
470 {
471 mesh1dApi.node_x[n] = mesh1d.Node(n).x;
472 mesh1dApi.node_y[n] = mesh1d.Node(n).y;
473 }
474
475 size_t edgeIndex = 0;
476 for (meshkernel::UInt e = 0; e < mesh1d.GetNumEdges(); e++)
477 {
478 mesh1dApi.edge_nodes[edgeIndex] = static_cast<int>(mesh1d.GetEdge(e).first);
479 edgeIndex++;
480 mesh1dApi.edge_nodes[edgeIndex] = static_cast<int>(mesh1d.GetEdge(e).second);
481 edgeIndex++;
482 }
483 SetMesh1dApiDimension(mesh1d, mesh1dApi);
484 }
485
490 static std::unique_ptr<meshkernel::CurvilinearGrid> CreateRectangularCurvilinearGrid(const meshkernel::MakeGridParameters& makeGridParameters,
491 const meshkernel::Projection& projection)
492 {
493 meshkernel::CurvilinearGridRectangular grid(projection);
494 return grid.Compute(makeGridParameters.num_columns,
495 makeGridParameters.num_rows,
496 makeGridParameters.origin_x,
497 makeGridParameters.origin_y,
498 makeGridParameters.angle,
499 makeGridParameters.block_size_x,
500 makeGridParameters.block_size_y);
501 }
502
508 static std::unique_ptr<meshkernel::CurvilinearGrid> CreateRectangularCurvilinearGridFromPolygons(const meshkernel::MakeGridParameters& makeGridParameters,
509 const GeometryList& geometryList,
510 const meshkernel::Projection& projection)
511 {
512 const meshkernel::CurvilinearGridRectangular grid(projection);
513
514 auto polygonNodes = ConvertGeometryListToPointVector(geometryList);
515
516 const auto polygon = std::make_shared<meshkernel::Polygons>(polygonNodes, projection);
517
518 return grid.Compute(makeGridParameters.angle,
519 makeGridParameters.block_size_x,
520 makeGridParameters.block_size_y,
521 polygon,
522 0);
523 }
524
529 static std::unique_ptr<meshkernel::CurvilinearGrid> CreateRectangularCurvilinearGridOnExtension(const meshkernel::MakeGridParameters& makeGridParameters,
530 const meshkernel::Projection& projection)
531 {
532 const meshkernel::CurvilinearGridRectangular grid(projection);
533
534 if (!meshkernel::IsEqual(makeGridParameters.angle, 0.0))
535 {
536 throw meshkernel::AlgorithmError("When generating an uniform grid on an defined extension, the grid angle must be equal to 0");
537 }
538
539 return grid.Compute(makeGridParameters.origin_x,
540 makeGridParameters.origin_y,
541 makeGridParameters.block_size_x,
542 makeGridParameters.block_size_y,
543 makeGridParameters.upper_right_x,
544 makeGridParameters.upper_right_y);
545 }
546
547 template <meshkernel::InterpolatableType T>
548 static std::unique_ptr<meshkernel::MeshInterpolation> CreateBilinearInterpolator(const meshkernel::Mesh2D& mesh2d,
549 const GriddedSamples& griddedSamples)
550 {
551 meshkernel::Point origin{griddedSamples.x_origin, griddedSamples.y_origin};
552 if (griddedSamples.x_coordinates == nullptr || griddedSamples.y_coordinates == nullptr)
553 {
554 return std::make_unique<meshkernel::BilinearInterpolationOnGriddedSamples<T>>(mesh2d,
555 griddedSamples.num_x,
556 griddedSamples.num_y,
557 origin,
558 griddedSamples.cell_size,
559 std::span<T const>{reinterpret_cast<T const* const>(griddedSamples.values),
560 static_cast<size_t>(griddedSamples.num_x * griddedSamples.num_y)});
561 }
562 return std::make_unique<meshkernel::BilinearInterpolationOnGriddedSamples<T>>(mesh2d,
563 std::span<double const>{griddedSamples.x_coordinates,
564 static_cast<size_t>(griddedSamples.num_x)},
565 std::span<double const>{griddedSamples.y_coordinates,
566 static_cast<size_t>(griddedSamples.num_y)},
567 std::span<T const>{reinterpret_cast<T const* const>(griddedSamples.values),
568 static_cast<size_t>(griddedSamples.num_x * griddedSamples.num_y)});
569 }
570
571 static std::unique_ptr<meshkernel::MeshInterpolation> CreateBilinearInterpolatorBasedOnType(const GriddedSamples& griddedSamples,
572 const meshkernel::Mesh2D& mesh2d)
573 {
574
575 switch (static_cast<meshkernel::InterpolationDataTypes>(griddedSamples.value_type))
576 {
578 return CreateBilinearInterpolator<short>(mesh2d, griddedSamples);
580 return CreateBilinearInterpolator<float>(mesh2d, griddedSamples);
582 return CreateBilinearInterpolator<int>(mesh2d, griddedSamples);
584 return CreateBilinearInterpolator<double>(mesh2d, griddedSamples);
585 default:
586 throw meshkernel::MeshKernelError("Invalid value_type for GriddedSamples");
587 }
588 }
589
590 static void FillFacePolygons(const meshkernel::Mesh2D& mesh2d,
591 const std::vector<bool>& facesInPolygon,
592 const GeometryList& facePolygons)
593 {
594 meshkernel::UInt count = 0;
595 for (meshkernel::UInt f = 0; f < mesh2d.GetNumFaces(); ++f)
596 {
597 if (!facesInPolygon[f])
598 {
599 continue;
600 }
601
602 const auto& faceNodes = mesh2d.m_facesNodes[f];
603 if (count != 0)
604 {
605 facePolygons.coordinates_x[count] = meshkernel::constants::missing::doubleValue;
606 facePolygons.coordinates_y[count] = meshkernel::constants::missing::doubleValue;
607 count++;
608 }
609
610 for (meshkernel::UInt n = 0u; n < faceNodes.size(); ++n)
611 {
612 const auto& currentNode = mesh2d.Node(faceNodes[n]);
613 facePolygons.coordinates_x[count] = currentNode.x;
614 facePolygons.coordinates_y[count] = currentNode.y;
615 count++;
616 }
617 const auto& currentNode = mesh2d.Node(faceNodes[0]);
618 facePolygons.coordinates_x[count] = currentNode.x;
619 facePolygons.coordinates_y[count] = currentNode.y;
620 count++;
621 }
622 }
623
624 static std::optional<double> MinValidElement(const std::vector<double>& values)
625 {
626 auto filtered = values | std::views::filter([](const double& v)
627 { return v != meshkernel::constants::missing::doubleValue; });
628 auto begin = std::ranges::begin(filtered);
629 auto end = std::ranges::end(filtered);
630
631 if (begin == end)
632 {
633 return std::nullopt; // No valid elements
634 }
635
636 return *std::ranges::min_element(filtered);
637 }
638
639} // namespace meshkernelapi
A class for throwing algorithm exceptions.
Definition Exceptions.hpp:248
An exception class thrown when an attempt is made that violates a range constraint.
Definition Exceptions.hpp:267
A class derived from Mesh, which describes 1d meshes.
Definition Mesh1D.hpp:43
A class derived from Mesh, which describes unstructures 2d meshes.
Definition Mesh2D.hpp:58
A class describing an unstructured mesh. This class contains the shared functionality between 1d or 2...
Definition Mesh.hpp:99
const Edge & GetEdge(const UInt index) const
Get constant reference to an edge.
Definition Mesh.hpp:542
std::vector< std::vector< UInt > > m_facesEdges
The edge indices composing the face (netcelllin)
Definition Mesh.hpp:473
const Point & Node(const UInt index) const
Get the node at the position.
Definition Mesh.hpp:523
std::vector< std::vector< UInt > > m_facesNodes
The nodes composing the faces, in ccw order (netcellNod)
Definition Mesh.hpp:471
auto GetNumFaces() const
Get the number of valid faces.
Definition Mesh.hpp:153
auto GetNumEdges() const
Get the number of valid edges.
Definition Mesh.hpp:149
std::vector< Point > m_facesMassCenters
The faces centers of mass (xzw, yzw)
Definition Mesh.hpp:474
UInt GetNumValidNodes() const
Get the number of valid nodes.
std::vector< std::array< UInt, 2 > > m_edgesFaces
For each edge, the shared face index (lne)
Definition Mesh.hpp:467
auto GetNumNodes() const
Get the number of valid nodes.
Definition Mesh.hpp:145
UInt GetNumValidEdges() const
Get the number of valid edges.
A class for throwing general MeshKernel exceptions.
Definition Exceptions.hpp:142
A struct describing a point in a two-dimensional space.
Definition Point.hpp:41
double x
X-coordinate.
Definition Point.hpp:43
double y
Y-coordinate.
Definition Point.hpp:44
A class describing splines.
Definition Splines.hpp:48
void AddSpline(const std::vector< Point > &splines, UInt start, UInt size)
Adds a new spline to m_splineCornerPoints.
Projection
Enumerator describing the supported projections.
Definition Definitions.hpp:43
bool IsEqual(const Point &p1, const Point &p2, const double epsilon)
Test points for equality upto a tolerance.
Definition Point.hpp:450
std::uint32_t UInt
Integer type used when indexing mesh graph entities.
Definition Definitions.hpp:39
InterpolationDataTypes
The possible types of the values to be interpolated in the gridded sample.
Definition Definitions.hpp:100
std::vector< std::pair< UInt, UInt > > FindIndices(const std::vector< Point > &vec, size_t start, size_t end, double separator)
Find all start-end positions in a vector separated by a separator.
Contains all structs and functions exposed at the API level.
Definition BoundingBox.hpp:33
This struct describes the necessary parameters to create a new curvilinear grid in a C-compatible man...
Definition Parameters.hpp:38
double origin_y
The y coordinate of the origin, located at the bottom left corner.
Definition Parameters.hpp:52
double upper_right_x
The x coordinate of the upper right corner.
Definition Parameters.hpp:61
double angle
The grid angle.
Definition Parameters.hpp:46
int num_rows
The number of rows in y direction.
Definition Parameters.hpp:43
double origin_x
The x coordinate of the origin, located at the bottom left corner.
Definition Parameters.hpp:49
int num_columns
The number of columns in x direction.
Definition Parameters.hpp:40
double block_size_x
The grid block size in x dimension, used only for squared grids.
Definition Parameters.hpp:55
double block_size_y
The grid block size in y dimension, used only for squared grids.
Definition Parameters.hpp:58
double upper_right_y
The y coordinate of the upper right corner.
Definition Parameters.hpp:64