co-maps/libs/geometry/geometry_tests/spline_test.cpp
2025-11-22 13:58:55 +01:00

248 lines
6.3 KiB
C++

#include "testing/testing.hpp"
#include "geometry/geometry_tests/equality.hpp"
#include "geometry/spline.hpp"
#include <vector>
namespace spline_test
{
using namespace std;
using m2::PointD;
using m2::Spline;
namespace
{
double constexpr kAlmostZero = 1.0E-16;
void TestEqual(double x, double y)
{
if (fabs(x) < kAlmostZero || fabs(y) < kAlmostZero)
TEST_ALMOST_EQUAL_ABS(x, y, kAlmostZero, ());
else
TEST_ALMOST_EQUAL_ULPS(x, y, ());
}
void TestPointDDir(PointD const & dst, PointD const & src)
{
double const len1 = dst.Length();
double const len2 = src.Length();
if (len1 < kAlmostZero || len2 < kAlmostZero)
{
TestEqual(dst.x, src.x);
TestEqual(dst.y, src.y);
}
else
{
TestEqual(dst.x / len1, src.x / len2);
TestEqual(dst.y / len1, src.y / len2);
}
}
} // namespace
UNIT_TEST(Spline_SmoothedDirections)
{
vector<PointD> path;
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 0));
Spline spl(path);
double const sqrt2 = sqrt(2.0);
Spline::iterator itr;
PointD dir1(sqrt2 / 2.0, sqrt2 / 2.0);
PointD dir2(sqrt2 / 2.0, -sqrt2 / 2.0);
itr.Attach(spl);
TestPointDDir(itr.m_avrDir, dir1);
itr.Advance(sqrt2 * 30.0);
TestPointDDir(itr.m_avrDir, dir1);
itr.Advance(sqrt2 * 40.0);
TestPointDDir(itr.m_avrDir, dir1 * 0.25 + dir2 * 0.75);
itr.Advance(sqrt2 * 10.0);
TestPointDDir(itr.m_avrDir, dir2);
path.clear();
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 40));
path.push_back(PointD(120, 0));
PointD dir12(1.0, 0.0);
Spline spl2(path);
itr.Attach(spl2);
TestPointDDir(itr.m_avrDir, dir1);
itr.Advance(sqrt2 * 80.0 + 40.0);
#if defined(DEBUG) || __apple_build_version__ < 15000000
// TODO(AB): Fails on Mac's clang with any optimization enabled and -ffp-contract=fast
TestPointDDir(itr.m_avrDir, dir12);
#endif
itr.Attach(spl2);
itr.Advance(sqrt2 * 40.0);
TestPointDDir(itr.m_avrDir, dir1);
itr.Advance(80.0);
TestPointDDir(itr.m_avrDir, dir12 * 0.5 + dir2 * 0.5);
}
UNIT_TEST(UsualDirections)
{
vector<PointD> path;
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 0));
Spline spl(path);
double const sqrt2 = sqrtf(2.0);
Spline::iterator itr;
PointD dir1(sqrt2 / 2.0, sqrt2 / 2.0);
PointD dir2(sqrt2 / 2.0, -sqrt2 / 2.0);
itr.Attach(spl);
TestPointDDir(itr.m_dir, dir1);
itr.Advance(sqrt2 * 30.0);
TestPointDDir(itr.m_dir, dir1);
itr.Advance(sqrt2 * 40.0);
TestPointDDir(itr.m_dir, dir2);
path.clear();
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 40));
path.push_back(PointD(120, 0));
PointD dir12(1.0, 0.0);
Spline spl2(path);
itr.Attach(spl2);
TestPointDDir(itr.m_dir, dir1);
itr.Advance(sqrt2 * 80.0 + 35.0);
TestPointDDir(itr.m_dir, dir2);
itr.Attach(spl2);
itr.Advance(sqrt2 * 45.0);
TestPointDDir(itr.m_dir, dir12);
itr.Advance(80.0);
TestPointDDir(itr.m_dir, dir2);
}
UNIT_TEST(Positions)
{
vector<PointD> path;
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 0));
Spline spl0(path);
Spline spl4;
spl4 = spl0;
double const sqrt2 = sqrt(2.0);
Spline::iterator itr;
itr.Attach(spl0);
TestPointDDir(itr.m_pos, PointD(0, 0));
itr.Advance(sqrt2 * 40.0);
TestPointDDir(itr.m_pos, PointD(40, 40));
itr.Advance(sqrt2 * 40.0);
#if defined(DEBUG) || __apple_build_version__ < 15000000
// TODO(AB): Fails on Mac's clang with any optimization enabled and -ffp-contract=fast
TestPointDDir(itr.m_pos, PointD(80, 0));
#endif
itr.Attach(spl4);
TestPointDDir(itr.m_pos, PointD(0, 0));
itr.Advance(sqrt2 * 40.0);
TestPointDDir(itr.m_pos, PointD(40, 40));
itr.Advance(sqrt2 * 40.0);
#if defined(DEBUG) || __apple_build_version__ < 15000000
// TODO(AB): Fails on Mac's clang with any optimization enabled and -ffp-contract=fast
TestPointDDir(itr.m_pos, PointD(80, 0));
#endif
path.clear();
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 40));
path.push_back(PointD(120, 0));
Spline spl2(path);
Spline spl3 = spl2;
itr.Attach(spl3);
TestPointDDir(itr.m_pos, PointD(0, 0));
itr.Advance(sqrt2 * 80.0 + 40.0);
#if defined(DEBUG) || __apple_build_version__ < 15000000
// TODO(AB): Fails on Mac's clang with any optimization enabled and -ffp-contract=fast
TestPointDDir(itr.m_pos, PointD(120, 0));
#endif
itr.Attach(spl2);
itr.Advance(sqrt2 * 40.0);
TestPointDDir(itr.m_pos, PointD(40, 40));
itr.Advance(2.0);
TestPointDDir(itr.m_pos, PointD(42, 40));
itr.Advance(20.0);
TestPointDDir(itr.m_pos, PointD(62, 40));
itr.Advance(18.0);
TestPointDDir(itr.m_pos, PointD(80, 40));
}
UNIT_TEST(BeginAgain)
{
vector<PointD> path;
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 0));
Spline spl(path);
double const sqrt2 = sqrtf(2.0);
Spline::iterator itr;
PointD dir1(sqrt2 / 2.0, sqrt2 / 2.0);
PointD dir2(sqrt2 / 2.0, -sqrt2 / 2.0);
itr.Attach(spl);
TEST_EQUAL(itr.BeginAgain(), false, ());
itr.Advance(90.0);
TEST_EQUAL(itr.BeginAgain(), false, ());
itr.Advance(90.0);
TEST_EQUAL(itr.BeginAgain(), true, ());
itr.Advance(190.0);
TEST_EQUAL(itr.BeginAgain(), true, ());
path.clear();
path.push_back(PointD(0, 0));
path.push_back(PointD(40, 40));
path.push_back(PointD(80, 40));
path.push_back(PointD(120, 0));
Spline spl2(path);
itr.Attach(spl2);
TEST_EQUAL(itr.BeginAgain(), false, ());
itr.Advance(90.0);
TEST_EQUAL(itr.BeginAgain(), false, ());
itr.Advance(90.0);
TEST_EQUAL(itr.BeginAgain(), true, ());
itr.Advance(190.0);
TEST_EQUAL(itr.BeginAgain(), true, ());
}
UNIT_TEST(Length)
{
vector<PointD> path;
PointD const p1(27.5536633, 64.2492523);
PointD const p2(27.5547638, 64.2474289);
PointD const p3(27.5549412, 64.2471237);
PointD const p4(27.5559044, 64.2456436);
PointD const p5(27.556284, 64.2451782);
path.push_back(p1);
path.push_back(p2);
path.push_back(p3);
path.push_back(p4);
path.push_back(p5);
Spline spl(path);
double len1 = spl.GetLength();
double l1 = p1.Length(p2);
double l2 = p2.Length(p3);
double l3 = p3.Length(p4);
double l4 = p4.Length(p5);
double len2 = l1 + l2 + l3 + l4;
TEST_ALMOST_EQUAL_ULPS(len1, len2, ());
}
} // namespace spline_test