harfang3d/harfang/tests/foundation/minmax.cpp
2023-06-08 22:17:16 +02:00

272 lines
12 KiB
C++

// HARFANG(R) Copyright (C) 2022 NWNC. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
#include <math.h>
#include <float.h>
#define TEST_NO_MAIN
#include "acutest.h"
#include "foundation/math.h"
#include "foundation/minmax.h"
#include "foundation/axis.h"
#include "foundation/math.h"
#include "foundation/matrix4.h"
#include "foundation/vector3.h"
#include "foundation/vector4.h"
using namespace hg;
void test_minmax() {
{
MinMax box;
TEST_CHECK(box.mn == Vec3::Max);
TEST_CHECK(box.mx == Vec3::Min);
}
{
MinMax box(Vec3(-1.f, -1.f, -1.f), Vec3(1.f, 1.f, 1.f));
TEST_CHECK(box.mn == Vec3(-1.f, -1.f, -1.f));
TEST_CHECK(box.mx == Vec3(1.f, 1.f, 1.f));
}
TEST_CHECK(Equal(GetArea(MinMax(Vec3(-1.f, 1.f, 0.f), Vec3(0.f, 2.f, 1.f))), 1.f));
TEST_CHECK(AlmostEqual(GetCenter(MinMax(Vec3(-1.f, 1.f, 0.f), Vec3(0.f, 2.f, 1.f))), Vec3(-0.5f, 1.5f, 0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(GetSize(MinMax(Vec3(-1.f, 1.f, 0.f), Vec3(0.f, 2.f, 1.f))), Vec3::One, 0.000001f));
{
Vec3 v[8];
MinMax box(Vec3(-1.f, 1.f, 0.f), Vec3(0.f, 2.f, 1.f));
GetMinMaxVertices(box, v);
TEST_CHECK(AlmostEqual(v[0], Vec3(-1.f, 1.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[1], Vec3(0.f, 1.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[2], Vec3(0.f, 2.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[3], Vec3(-1.f, 2.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[4], Vec3(-1.f, 1.f, 1.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[5], Vec3(0.f, 1.f, 1.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[6], Vec3(0.f, 2.f, 1.f), 0.000001f));
TEST_CHECK(AlmostEqual(v[7], Vec3(-1.f, 2.f, 1.f), 0.000001f));
}
{
MinMax box(Vec3(-1.f, 1.f, 0.f), Vec3(0.f, 2.f, 1.f));
Vec3 origin;
float radius;
ComputeMinMaxBoundingSphere(box, origin, radius);
TEST_CHECK(AlmostEqual(origin, Vec3(-0.5f, 1.5f, 0.5f), 0.000001f));
TEST_CHECK(Equal(radius, Dist(Vec3(-1.f, 1.f, 0.f), Vec3(0.f, 2.f, 1.f)) / 2.f));
}
{
TEST_CHECK(Overlap(MinMax(Vec3(-2.f, -1.f, -1.f), Vec3(-1.0f, 0.f, 0.f)), MinMax(Vec3(-1.5f, -0.5f, -0.5f), Vec3(-0.5f, 0.5f, 0.5f)), A_X));
TEST_CHECK(Overlap(MinMax(Vec3(-2.f, -1.f, -1.f), Vec3(-1.f, 0.f, 0.f)), MinMax(Vec3(-0.5f, -0.5f, -0.5f), Vec3(0.5f, 0.5f, 0.5f)), A_X) == false);
TEST_CHECK(Overlap(MinMax(Vec3(-2.f, -1.f, -1.f), Vec3(-1.f, 0.f, 0.f)), MinMax(Vec3(-0.5f, -0.5f, -0.5f), Vec3(0.5f, 0.5f, 0.5f)), A_Y));
TEST_CHECK(Overlap(MinMax(Vec3(-2.f, -1.f, -1.f), Vec3(-1.f, 0.f, 0.f)), MinMax(Vec3(-0.2f, -3.5f, -0.5f), Vec3(0.8f, -2.5f, 0.5f)), A_Y) == false);
TEST_CHECK(Overlap(MinMax(Vec3(-2.f, -1.f, -1.f), Vec3(-1.f, 0.f, 0.f)), MinMax(Vec3(-0.2f, -0.5f, -0.5f), Vec3(0.8f, 0.5f, 0.5f)), A_Z));
TEST_CHECK(Overlap(MinMax(Vec3(-2.f, -1.f, -1.f), Vec3(-1.f, 0.f, 0.f)), MinMax(Vec3(-0.2f, -0.5f, 3.f), Vec3(0.8f, 0.5f, 4.f)), A_Z) == false);
}
{
TEST_CHECK(Overlap(MinMax(Vec3(-1.f, -1.f, -1.f), Vec3(1.0f, 1.f, 1.f)), MinMax(Vec3(0.2f, -0.5f, -0.2f), Vec3(0.7f, 0.5f, 0.8f))));
TEST_CHECK(Overlap(MinMax(Vec3(0.2f, -0.5f, -0.2f), Vec3(0.7f, 0.5f, 0.8f)), MinMax(Vec3(-1.f, -1.f, -1.f), Vec3(1.0f, 1.f, 1.f))));
TEST_CHECK(Overlap(MinMax(Vec3(-1.f, -1.f, -1.f), Vec3(1.0f, 1.f, 1.f)), MinMax(Vec3(1.2f, -0.5f, -0.2f), Vec3(1.7f, 0.5f, 0.8f))) == false);
TEST_CHECK(Overlap(MinMax(Vec3(-1.f, -1.f, -1.f), Vec3(1.0f, 1.f, 1.f)), MinMax(Vec3(0.2f, -3.f, -2.2f), Vec3(0.7f, -2.f, -1.2f))) == false);
}
{
MinMax m0(Vec3(-1.f, -1.f, -1.f), Vec3(1.f, 1.f, 1.f));
MinMax m1(Vec3(-1.f, -1.f, -1.f), Vec3(1.f, 1.f, 1.f));
MinMax m2(Vec3(0.2f, -0.5f, -0.2f), Vec3(0.7f, 0.5f, 0.8f));
TEST_CHECK(m0 == m1);
TEST_CHECK((m0 == m2) == false);
TEST_CHECK((m1 == m2) == false);
}
{
MinMax m0(Vec3(-1.f, -1.f, -1.f), Vec3(1.f, 1.f, 1.f));
MinMax m1(Vec3(-1.f, -1.f, -1.f), Vec3(1.f, 1.f, 1.f));
MinMax m2(Vec3(0.2f, -0.5f, -0.2f), Vec3(0.7f, 0.5f, 0.8f));
TEST_CHECK(m0 != m2);
TEST_CHECK(m1 != m2);
TEST_CHECK((m0 != m1) == false);
}
{
MinMax box(Vec3(-1.f, -1.f, -1.f), Vec3(1.f, 1.f, 1.f));
TEST_CHECK(Contains(box, Vec3(-0.5f, 0.75f, -0.1f)));
TEST_CHECK(Contains(box, Vec3(0.4f, -1.75f, 0.3f)) == false);
TEST_CHECK(Contains(box, Vec3(1.4f, 0.5f, 0.3f)) == false);
TEST_CHECK(Contains(box, Vec3(-0.2f, 0.5f, 6.3f)) == false);
TEST_CHECK(Contains(box, Vec3(0.8f, 0.5f, -2.3f)) == false);
}
{
MinMax m0(Vec3(-1.f, -1.f, -1.f), Vec3(1.0f, 1.f, 1.f));
MinMax m1(Vec3(0.2f, -0.5f, -0.2f), Vec3(0.7f, 0.5f, 0.8f));
MinMax m2(Vec3(0.5f, 0.5f, 0.5f), Vec3(1.5f, 1.5f, 1.5f));
MinMax m3(Vec3(-3.5f, -2.0f, 0.5f), Vec3(-3.f, -1.f, 1.5f));
TEST_CHECK(Union(m0, m1) == m0);
TEST_CHECK(Union(m1, m0) == m0);
TEST_CHECK(Union(m0, m2) == MinMax(Vec3(-1.f, -1.f, -1.f), Vec3(1.5f, 1.5f, 1.5f)));
TEST_CHECK(Union(m0, m3) == MinMax(Vec3(-3.5f, -2.f, -1.f), Vec3(1.f, 1.f, 1.5f)));
}
{
MinMax m0(Vec3(-1.f, -1.f, -1.f), Vec3(1.0f, 1.f, 1.f));
TEST_CHECK(Union(m0, Vec3(0.7f, -0.2f, 0.1f)) == m0);
{
MinMax m1 = Union(m0, Vec3(1.7f, -0.2f, 0.1f));
TEST_CHECK(AlmostEqual(m1.mn, m0.mn, 0.000001f));
TEST_CHECK(AlmostEqual(m1.mx, Vec3(1.7f, 1.f, 1.f), 0.000001f));
}
{
MinMax m1 = Union(m0, Vec3(0.1f, -2.6f, 1.2f));
TEST_CHECK(AlmostEqual(m1.mn, Vec3(-1.f,-2.6f,-1.f), 0.000001f));
TEST_CHECK(AlmostEqual(m1.mx, Vec3(1.f, 1.f, 1.2f), 0.000001f));
}
{
MinMax m1 = Union(m0, Vec3(-3.1f, -2.6f,-1.2f));
TEST_CHECK(AlmostEqual(m1.mn, Vec3(-3.1f, -2.6f, -1.2f), 0.000001f));
TEST_CHECK(AlmostEqual(m1.mx, Vec3(1.f, 1.f, 1.f), 0.000001f));
}
{
MinMax m1 = Union(m0, Vec3(4.1f, 1.5f, 2.5f));
TEST_CHECK(AlmostEqual(m1.mn, Vec3(-1.f, -1.f, -1.f), 0.000001f));
TEST_CHECK(AlmostEqual(m1.mx, Vec3(4.1f, 1.5f, 2.5f), 0.000001f));
}
}
{
MinMax m0(-Vec3::One, Vec3::One);
Mat4 trs = TransformationMat4(Vec3(-0.5f, 0.5f, 0.8f), Deg3(45.f, -30.f, 60.f), Vec3(2.f, 0.8f, 1.f));
MinMax m1 = trs * m0;
// Brute force computation of the new minmax
Vec3 p[8] = {
trs * m0.mn,
trs * Vec3(m0.mn.x, m0.mn.y, m0.mx.z),
trs * Vec3(m0.mn.x, m0.mx.y, m0.mn.z),
trs * Vec3(m0.mn.x, m0.mx.y, m0.mx.z),
trs * Vec3(m0.mx.x, m0.mn.y, m0.mn.z),
trs * Vec3(m0.mx.x, m0.mn.y, m0.mx.z),
trs * Vec3(m0.mx.x, m0.mx.y, m0.mn.z),
trs * m0.mx
};
Vec3 p0 = p[0], p1 = p[0];
for (int i = 1; i < 8; i++) {
p0 = Min(p0, p[i]);
p1 = Max(p1, p[i]);
}
TEST_CHECK(AlmostEqual(m1.mn, p0, 0.000001f));
TEST_CHECK(AlmostEqual(m1.mx, p1, 0.000001f));
}
{
MinMax m0(-Vec3::One, Vec3::One);
bool ret = false;
float t0 = 0.f, t1 = 0.f;
TEST_CHECK(IntersectRay(m0, Vec3(0.5f, -0.5f, 0.5f), Vec3(0.f, 0.f, 1.f), t0, t1));
TEST_CHECK(Equal(t0, 0.0f));
TEST_CHECK(Equal(t1, 0.5f));
TEST_CHECK(IntersectRay(m0, Vec3(2.0f, 1.0f, -1.0f), Vec3(0.f, 0.f, 1.f), t0, t1) == false);
TEST_CHECK(Equal(t0, 0.0f));
TEST_CHECK(Equal(t1, FLT_MAX));
TEST_CHECK(IntersectRay(m0, Vec3(2.0f, 0.1f, 0.1f), Vec3(0.f, 0.f,-1.f), t0, t1) == false);
TEST_CHECK(Equal(t0, 0.0f));
TEST_CHECK(Equal(t1, FLT_MAX));
TEST_CHECK(IntersectRay(m0, Vec3(2.0f, 2.0f, 2.0f), Vec3(0.f, 1.f, 0.f)) == false);
TEST_CHECK(IntersectRay(m0, Vec3(1.0f, 2.0f, -2.0f), Normalize(Vec3(-1.f,-1.f, 1.f))));
}
{
MinMax m0(-Vec3::One, Vec3::One);
bool ret = false;
Vec3 i, n;
TEST_CHECK(ClassifyLine(m0, Vec3(0.5f, -0.5f, 0.5f), Vec3(0.f, 0.f, 1.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(0.5f, -0.5f, 0.5), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3::Zero, 0.000001f));
TEST_CHECK(ClassifyLine(m0, Vec3(-2.f, 1.0f, 0.f), Normalize(Vec3(1.f, -1.f, 0.f)), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-1.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(-1.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(ClassifyLine(m0, Vec3(-4.f, 1.0f, 0.f), Normalize(Vec3(1.f, -1.f, 0.f)), i, &n) == false);
TEST_CHECK(ClassifyLine(m0, Vec3(0.5f, 2.0f, 0.5f), Vec3(0.f, -1.f, 0.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(0.5f, 1.f, 0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, 1.f, 0.f), 0.000001f));
TEST_CHECK(ClassifyLine(m0, Vec3(1.5f, 2.0f, 0.5f), Vec3(0.f, -1.f, 0.f), i, &n) == false);
TEST_CHECK(ClassifyLine(m0, Vec3(-0.5f, -2.0f, -0.5f), Vec3(0.f, 1.f, 0.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-0.5f, -1.f, -0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, -1.f, 0.f), 0.000001f));
TEST_CHECK(ClassifyLine(m0, Vec3(1.5f, -2.0f, -0.5f), Vec3(0.f, 1.f, 0.f), i, &n) == false);
TEST_CHECK(ClassifyLine(m0, Vec3(-0.5f, -0.5f, 2.0f), Vec3(0.f, 0.f, -1.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-0.5f, -0.5f, 1.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, 0.f, 1.f), 0.000001f));
TEST_CHECK(ClassifyLine(m0, Vec3(-0.5f,-2.0f, 2.0f), Vec3(0.f, 0.f, 1.f), i, &n) == false);
TEST_CHECK(ClassifyLine(m0, Vec3(-0.5f, 0.5f, -2.0f), Vec3(0.f, 0.f, 1.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-0.5f, 0.5f, -1.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, 0.f, -1.f), 0.000001f));
TEST_CHECK(ClassifyLine(m0, Vec3(0.5f, -2.0f, -2.0f), Vec3(0.f, 0.f, 1.f), i, &n) == false);
}
{
MinMax m0(-Vec3::One, Vec3::One);
bool ret = false;
Vec3 i, n;
TEST_CHECK(ClassifySegment(m0, Vec3(0.5f, -0.5f, 0.5f), Vec3(0.5f, -0.5f, 1.5f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(0.5f, -0.5f, 0.5), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3::Zero, 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(0.5f, -0.5f, 0.5f), Vec3(0.5f, -0.5f, 0.75f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(0.5f, -0.5f, 0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3::Zero, 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(2.f, 2.0f, 2.f), Vec3(0.f, 0.f, 0.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(0.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3::Zero, 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(-2.f, 1.0f, 0.f), Vec3(1.f, -2.f, 0.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-1.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(-1.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(2.f, 1.0f, 0.f), Vec3(-1.f, -2.f, 0.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(1.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(1.f, 0.f, 0.f), 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(-2.f, 1.0f, 0.f), Vec3(-1.5f, 0.5f, 0.f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(-4.f, 1.0f, 0.f), Vec3(-1.f, -2.f, 0.f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(0.5f, 2.0f, 0.5f), Vec3(0.5f, -1.2f, 0.5f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(0.5f, 1.f, 0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, 1.f, 0.f), 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(0.5f, 2.0f, 0.5f), Vec3(0.5f, 1.1f, 0.5f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(1.5f, 2.0f, 0.5f), Vec3(1.5f, -1.f, 0.5f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, -2.0f, -0.5f), Vec3(-0.5f, 2.f, -0.5f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-0.5f, -1.f, -0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, -1.f, 0.f), 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, -2.0f, -0.5f), Vec3(0.5f, -1.5f, -0.5f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(1.5f, -2.0f, -0.5f), Vec3(1.5f, 2.f, -0.5f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, -0.5f, 2.0f), Vec3(-0.5f,-0.5f,-5.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-0.5f, -0.5f, 1.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, 0.f, 1.f), 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, -2.0f, 2.0f), Vec3(-0.5f, -2.f, -4.f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, -0.5f, 2.0f), Vec3(-0.5f, -0.5f, 1.5f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, 0.5f, -2.0f), Vec3(-0.5f, 0.5f, 3.f), i, &n));
TEST_CHECK(AlmostEqual(i, Vec3(-0.5f, 0.5f, -1.f), 0.000001f));
TEST_CHECK(AlmostEqual(n, Vec3(0.f, 0.f, -1.f), 0.000001f));
TEST_CHECK(ClassifySegment(m0, Vec3(-0.5f, 0.5f, -2.0f), Vec3(-0.5f, 0.5f, -1.3f), i, &n) == false);
TEST_CHECK(ClassifySegment(m0, Vec3(0.5f, -2.0f, -2.0f), Vec3(0.5f, -4.f, 4.f), i, &n) == false);
}
{
MinMax m0 = MinMaxFromPositionSize(Vec3::Zero, Vec3::One);
TEST_CHECK(AlmostEqual(m0.mn, Vec3(-0.5f), 0.000001f));
TEST_CHECK(AlmostEqual(m0.mx, Vec3( 0.5f), 0.000001f));
}
}