Skip to content

Commit 786729f

Browse files
GRIDEDIT-2189: Normalize spline direction
1 parent 0430103 commit 786729f

File tree

3 files changed

+102
-4
lines changed

3 files changed

+102
-4
lines changed

libs/MeshKernel/include/MeshKernel/Splines.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,14 @@ namespace meshkernel
191191
/// @param[in] splineIndex The index of the spline to delete
192192
void DeleteSpline(UInt splineIndex);
193193

194-
/// @brief Allocate spline properties vectors
195-
void AllocateSplinesProperties();
196-
197194
/// @brief Compute the second order derivative of the spline.
198195
static std::vector<Point> ComputeSplineDerivative(const std::vector<Point>& splinesNodes);
196+
197+
/// @brief Normalizes spline direction to ensure consistent orientation
198+
/// @param[in,out] splinePoints The spline points to normalize
199+
/// @details Ensures left-to-right for horizontal splines, bottom-to-top for vertical splines.
200+
/// This provides a consistent reference direction regardless of input point order.
201+
static void NormalizeSplineDirection(std::vector<Point>& splinePoints);
199202
};
200203

201204
/// @brief This structure is used to create a function for converting an adimensional distance on a spline to a dimensional one

libs/MeshKernel/src/Splines.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include <MeshKernel/CurvilinearGrid/CurvilinearGrid.hpp>
3232
#include <MeshKernel/Entities.hpp>
3333
#include <MeshKernel/Exceptions.hpp>
34-
#include <MeshKernel/LandBoundaries.hpp>
3534
#include <MeshKernel/Operations.hpp>
3635
#include <MeshKernel/SplineAlgorithms.hpp>
3736
#include <MeshKernel/Splines.hpp>
@@ -75,13 +74,42 @@ void Splines::AddSpline(const std::vector<Point>& splines, UInt start, UInt size
7574
count++;
7675
}
7776

77+
NormalizeSplineDirection(splinesNodes);
78+
7879
m_splineNodes.emplace_back(splinesNodes);
7980

8081
// compute second order derivatives
8182
m_splineDerivatives.emplace_back(ComputeSplineDerivative(splinesNodes));
8283
m_splinesLength.emplace_back(ComputeSplineLength(GetNumSplines() - 1, 0.0, static_cast<double>(size - 1)));
8384
}
8485

86+
void Splines::NormalizeSplineDirection(std::vector<Point>& splinePoints)
87+
{
88+
if (splinePoints.size() < 2)
89+
{
90+
return;
91+
}
92+
93+
const auto& first = splinePoints.front();
94+
const auto& last = splinePoints.back();
95+
96+
bool shouldReverse;
97+
98+
if (!IsEqual(first.x, last.x))
99+
{
100+
shouldReverse = first.x > last.x;
101+
}
102+
else
103+
{
104+
shouldReverse = first.y > last.y;
105+
}
106+
107+
if (shouldReverse)
108+
{
109+
std::ranges::reverse(splinePoints);
110+
}
111+
}
112+
85113
std::vector<meshkernel::Point> Splines::ComputeSplineDerivative(const std::vector<Point>& splinesNodes)
86114
{
87115
std::vector<Point> splineDerivatives(splinesNodes.size());
@@ -108,6 +136,10 @@ void Splines::AddSpline(const std::vector<Point>& splines)
108136

109137
void Splines::Replace(const UInt splineIndex, const std::vector<Point>& splinePoints)
110138
{
139+
std::vector<Point> normalizedPoints = splinePoints;
140+
141+
NormalizeSplineDirection(normalizedPoints);
142+
111143
m_splineNodes[splineIndex] = splinePoints;
112144
m_splineDerivatives[splineIndex] = ComputeSplineDerivative(splinePoints);
113145
m_splinesLength[splineIndex] = ComputeSplineLength(splineIndex, 0.0, static_cast<double>(splinePoints.size() - 1));

libs/MeshKernel/tests/src/SplineTests.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,69 @@ TEST(Splines, SetSpline)
4848

4949
ASSERT_EQ(1, splines.GetNumSplines());
5050
ASSERT_EQ(4, splines.m_splineNodes[0].size());
51+
52+
constexpr double tolerance = 1e-6;
53+
ASSERT_NEAR(212.001953125000, splines.m_splineNodes[0][0].x, tolerance);
54+
ASSERT_NEAR(529.253906250000, splines.m_splineNodes[0][1].x, tolerance);
55+
ASSERT_NEAR(930.506469726562, splines.m_splineNodes[0][2].x, tolerance);
56+
ASSERT_NEAR(1030.506469726562, splines.m_splineNodes[0][3].x, tolerance);
57+
58+
ASSERT_NEAR(155.627197265625, splines.m_splineNodes[0][0].y, tolerance);
59+
ASSERT_NEAR(432.379974365234, splines.m_splineNodes[0][1].y, tolerance);
60+
ASSERT_NEAR(453.380187988281, splines.m_splineNodes[0][2].y, tolerance);
61+
ASSERT_NEAR(653.380187988281, splines.m_splineNodes[0][3].y, tolerance);
62+
}
63+
64+
TEST(Splines, NormalizeHorizontalSplineDirection)
65+
{
66+
std::vector<meshkernel::Point> splineNodes({{1000.0, 400.0},
67+
{800.0, 300.0},
68+
{500.0, 250.0},
69+
{200.0, 100.0}});
70+
71+
meshkernel::Splines splines(meshkernel::Projection::cartesian);
72+
splines.AddSpline(splineNodes, 0, static_cast<meshkernel::UInt>(splineNodes.size()));
73+
74+
ASSERT_EQ(1, splines.GetNumSplines());
75+
ASSERT_EQ(4, splines.m_splineNodes[0].size());
76+
77+
constexpr double tolerance = 1e-6;
78+
79+
ASSERT_NEAR(200.0, splines.m_splineNodes[0][0].x, tolerance);
80+
ASSERT_NEAR(500.0, splines.m_splineNodes[0][1].x, tolerance);
81+
ASSERT_NEAR(800.0, splines.m_splineNodes[0][2].x, tolerance);
82+
ASSERT_NEAR(1000.0, splines.m_splineNodes[0][3].x, tolerance);
83+
84+
ASSERT_NEAR(100.0, splines.m_splineNodes[0][0].y, tolerance);
85+
ASSERT_NEAR(250.0, splines.m_splineNodes[0][1].y, tolerance);
86+
ASSERT_NEAR(300.0, splines.m_splineNodes[0][2].y, tolerance);
87+
ASSERT_NEAR(400.0, splines.m_splineNodes[0][3].y, tolerance);
88+
}
89+
90+
TEST(Splines, NormalizeVerticalSplineDirection)
91+
{
92+
std::vector<meshkernel::Point> splineNodes({{500.0, 800.0},
93+
{500.0, 600.0},
94+
{500.0, 400.0},
95+
{500.0, 200.0}});
96+
97+
meshkernel::Splines splines(meshkernel::Projection::cartesian);
98+
splines.AddSpline(splineNodes, 0, static_cast<meshkernel::UInt>(splineNodes.size()));
99+
100+
ASSERT_EQ(1, splines.GetNumSplines());
101+
ASSERT_EQ(4, splines.m_splineNodes[0].size());
102+
103+
constexpr double tolerance = 1e-6;
104+
105+
ASSERT_NEAR(500.0, splines.m_splineNodes[0][0].x, tolerance);
106+
ASSERT_NEAR(500.0, splines.m_splineNodes[0][1].x, tolerance);
107+
ASSERT_NEAR(500.0, splines.m_splineNodes[0][2].x, tolerance);
108+
ASSERT_NEAR(500.0, splines.m_splineNodes[0][3].x, tolerance);
109+
110+
ASSERT_NEAR(200.0, splines.m_splineNodes[0][0].y, tolerance);
111+
ASSERT_NEAR(400.0, splines.m_splineNodes[0][1].y, tolerance);
112+
ASSERT_NEAR(600.0, splines.m_splineNodes[0][2].y, tolerance);
113+
ASSERT_NEAR(800.0, splines.m_splineNodes[0][3].y, tolerance);
51114
}
52115

53116
TEST(Splines, CubicSplineInterpolation)

0 commit comments

Comments
 (0)