mirror of
https://github.com/orange-cpp/omath.git
synced 2026-04-20 07:23:27 +00:00
Merge pull request #183 from orange-cpp/featue/aabb-improvement
Featue/aabb improvement
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
|
||||
namespace omath::primitives
|
||||
{
|
||||
enum class UpAxis { X, Y, Z };
|
||||
|
||||
template<class Type>
|
||||
struct Aabb final
|
||||
{
|
||||
@@ -24,5 +26,42 @@ namespace omath::primitives
|
||||
{
|
||||
return (max - min) / static_cast<Type>(2);
|
||||
}
|
||||
|
||||
template<UpAxis Up = UpAxis::Y>
|
||||
[[nodiscard]]
|
||||
constexpr Vector3<Type> top() const noexcept
|
||||
{
|
||||
const auto aabb_center = center();
|
||||
if constexpr (Up == UpAxis::Z)
|
||||
return {aabb_center.x, aabb_center.y, max.z};
|
||||
else if constexpr (Up == UpAxis::X)
|
||||
return {max.x, aabb_center.y, aabb_center.z};
|
||||
else if constexpr (Up == UpAxis::Y)
|
||||
return {aabb_center.x, max.y, aabb_center.z};
|
||||
else
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
template<UpAxis Up = UpAxis::Y>
|
||||
[[nodiscard]]
|
||||
constexpr Vector3<Type> bottom() const noexcept
|
||||
{
|
||||
const auto aabb_center = center();
|
||||
if constexpr (Up == UpAxis::Z)
|
||||
return {aabb_center.x, aabb_center.y, min.z};
|
||||
else if constexpr (Up == UpAxis::X)
|
||||
return {min.x, aabb_center.y, aabb_center.z};
|
||||
else if constexpr (Up == UpAxis::Y)
|
||||
return {aabb_center.x, min.y, aabb_center.z};
|
||||
else
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool is_collide(const Aabb& other) const noexcept
|
||||
{
|
||||
return min.x <= other.max.x && max.x >= other.min.x &&
|
||||
min.y <= other.max.y && max.y >= other.min.y &&min.z <= other.max.z && max.z >= other.min.z;
|
||||
}
|
||||
};
|
||||
} // namespace omath::primitives
|
||||
|
||||
@@ -20,19 +20,19 @@
|
||||
#include <vector>
|
||||
|
||||
#if defined(__linux__)
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
# if defined(__ANDROID__)
|
||||
# if __ANDROID_API__ >= 30
|
||||
# include <sys/mman.h>
|
||||
# define OMATH_TEST_USE_MEMFD 1
|
||||
# endif
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__ANDROID__)
|
||||
#if __ANDROID_API__ >= 30
|
||||
#include <sys/mman.h>
|
||||
#define OMATH_TEST_USE_MEMFD 1
|
||||
#endif
|
||||
// Android < 30: fall through to tmpfile() path below
|
||||
# else
|
||||
#else
|
||||
// Desktop Linux: memfd_create available since glibc 2.27 / kernel 3.17
|
||||
# include <sys/mman.h>
|
||||
# define OMATH_TEST_USE_MEMFD 1
|
||||
# endif
|
||||
#include <sys/mman.h>
|
||||
#define OMATH_TEST_USE_MEMFD 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class MemFdFile
|
||||
@@ -57,9 +57,11 @@ public:
|
||||
MemFdFile(MemFdFile&& o) noexcept
|
||||
: m_path(std::move(o.m_path))
|
||||
#if defined(OMATH_TEST_USE_MEMFD)
|
||||
, m_fd(o.m_fd)
|
||||
,
|
||||
m_fd(o.m_fd)
|
||||
#else
|
||||
, m_temp_path(std::move(o.m_temp_path))
|
||||
,
|
||||
m_temp_path(std::move(o.m_temp_path))
|
||||
#endif
|
||||
{
|
||||
#if defined(OMATH_TEST_USE_MEMFD)
|
||||
@@ -69,9 +71,15 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const { return !m_path.empty(); }
|
||||
[[nodiscard]] bool valid() const
|
||||
{
|
||||
return !m_path.empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::filesystem::path& path() const { return m_path; }
|
||||
[[nodiscard]] const std::filesystem::path& path() const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
static MemFdFile create(const std::vector<std::uint8_t>& data)
|
||||
{
|
||||
@@ -101,7 +109,7 @@ public:
|
||||
std::mt19937_64 rng(std::random_device{}());
|
||||
const auto unique_name = "omath_test_" + std::to_string(rng()) + ".bin";
|
||||
f.m_temp_path = (tmp_dir / unique_name).string();
|
||||
f.m_path = f.m_temp_path;
|
||||
f.m_path = f.m_temp_path;
|
||||
|
||||
std::ofstream out(f.m_temp_path, std::ios::binary | std::ios::trunc);
|
||||
if (!out.is_open())
|
||||
@@ -153,38 +161,40 @@ private:
|
||||
// ---------------------------------------------------------------------------
|
||||
inline std::vector<std::uint8_t> build_minimal_pe(const std::vector<std::uint8_t>& section_bytes)
|
||||
{
|
||||
constexpr std::uint32_t e_lfanew = 0x80u;
|
||||
constexpr std::uint16_t size_opt = 0xF0u;
|
||||
constexpr std::size_t nt_off = e_lfanew;
|
||||
constexpr std::size_t fh_off = nt_off + 4;
|
||||
constexpr std::size_t oh_off = fh_off + 20;
|
||||
constexpr std::size_t sh_off = oh_off + size_opt;
|
||||
constexpr std::size_t data_off = sh_off + 44;
|
||||
constexpr std::uint32_t e_lfanew = 0x80u;
|
||||
constexpr std::uint16_t size_opt = 0xF0u;
|
||||
constexpr std::size_t nt_off = e_lfanew;
|
||||
constexpr std::size_t fh_off = nt_off + 4;
|
||||
constexpr std::size_t oh_off = fh_off + 20;
|
||||
constexpr std::size_t sh_off = oh_off + size_opt;
|
||||
constexpr std::size_t data_off = sh_off + 44;
|
||||
|
||||
std::vector<std::uint8_t> buf(data_off + section_bytes.size(), 0u);
|
||||
|
||||
buf[0] = 'M'; buf[1] = 'Z';
|
||||
buf[0] = 'M';
|
||||
buf[1] = 'Z';
|
||||
std::memcpy(buf.data() + 0x3Cu, &e_lfanew, 4);
|
||||
|
||||
buf[nt_off] = 'P'; buf[nt_off + 1] = 'E';
|
||||
buf[nt_off] = 'P';
|
||||
buf[nt_off + 1] = 'E';
|
||||
|
||||
const std::uint16_t machine = 0x8664u, num_sections = 1u;
|
||||
std::memcpy(buf.data() + fh_off, &machine, 2);
|
||||
std::memcpy(buf.data() + fh_off + 2, &num_sections, 2);
|
||||
std::memcpy(buf.data() + fh_off + 16, &size_opt, 2);
|
||||
constexpr std::uint16_t machine = 0x8664u, num_sections = 1u;
|
||||
std::memcpy(buf.data() + fh_off, &machine, 2);
|
||||
std::memcpy(buf.data() + fh_off + 2, &num_sections, 2);
|
||||
std::memcpy(buf.data() + fh_off + 16, &size_opt, 2);
|
||||
|
||||
const std::uint16_t magic = 0x20Bu;
|
||||
constexpr std::uint16_t magic = 0x20Bu;
|
||||
std::memcpy(buf.data() + oh_off, &magic, 2);
|
||||
|
||||
const char name[8] = {'.','t','e','x','t',0,0,0};
|
||||
constexpr char name[8] = {'.', 't', 'e', 'x', 't', 0, 0, 0};
|
||||
std::memcpy(buf.data() + sh_off, name, 8);
|
||||
|
||||
const auto vsize = static_cast<std::uint32_t>(section_bytes.size());
|
||||
const std::uint32_t vaddr = 0x1000u;
|
||||
const auto ptr_raw = static_cast<std::uint32_t>(data_off);
|
||||
std::memcpy(buf.data() + sh_off + 8, &vsize, 4);
|
||||
std::memcpy(buf.data() + sh_off + 12, &vaddr, 4);
|
||||
std::memcpy(buf.data() + sh_off + 16, &vsize, 4);
|
||||
const auto vsize = static_cast<std::uint32_t>(section_bytes.size());
|
||||
constexpr std::uint32_t vaddr = 0x1000u;
|
||||
constexpr auto ptr_raw = static_cast<std::uint32_t>(data_off);
|
||||
std::memcpy(buf.data() + sh_off + 8, &vsize, 4);
|
||||
std::memcpy(buf.data() + sh_off + 12, &vaddr, 4);
|
||||
std::memcpy(buf.data() + sh_off + 16, &vsize, 4);
|
||||
std::memcpy(buf.data() + sh_off + 20, &ptr_raw, 4);
|
||||
|
||||
std::memcpy(buf.data() + data_off, section_bytes.data(), section_bytes.size());
|
||||
|
||||
240
tests/general/unit_test_aabb.cpp
Normal file
240
tests/general/unit_test_aabb.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// Created by Vladislav on 19.04.2026.
|
||||
//
|
||||
#include <gtest/gtest.h>
|
||||
#include "omath/3d_primitives/aabb.hpp"
|
||||
|
||||
using AABB = omath::primitives::Aabb<float>;
|
||||
using Vec3 = omath::Vector3<float>;
|
||||
|
||||
// --- center() ---
|
||||
|
||||
TEST(AabbTests, CenterOfSymmetricBox)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr auto c = box.center();
|
||||
EXPECT_FLOAT_EQ(c.x, 0.f);
|
||||
EXPECT_FLOAT_EQ(c.y, 0.f);
|
||||
EXPECT_FLOAT_EQ(c.z, 0.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, CenterOfOffsetBox)
|
||||
{
|
||||
constexpr AABB box{{1.f, 2.f, 3.f}, {3.f, 6.f, 7.f}};
|
||||
constexpr auto c = box.center();
|
||||
EXPECT_FLOAT_EQ(c.x, 2.f);
|
||||
EXPECT_FLOAT_EQ(c.y, 4.f);
|
||||
EXPECT_FLOAT_EQ(c.z, 5.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, CenterOfDegenerateBox)
|
||||
{
|
||||
constexpr AABB box{{5.f, 5.f, 5.f}, {5.f, 5.f, 5.f}};
|
||||
constexpr auto c = box.center();
|
||||
EXPECT_FLOAT_EQ(c.x, 5.f);
|
||||
EXPECT_FLOAT_EQ(c.y, 5.f);
|
||||
EXPECT_FLOAT_EQ(c.z, 5.f);
|
||||
}
|
||||
|
||||
// --- extents() ---
|
||||
|
||||
TEST(AabbTests, ExtentsOfSymmetricBox)
|
||||
{
|
||||
constexpr AABB box{{-2.f, -3.f, -4.f}, {2.f, 3.f, 4.f}};
|
||||
constexpr auto e = box.extents();
|
||||
EXPECT_FLOAT_EQ(e.x, 2.f);
|
||||
EXPECT_FLOAT_EQ(e.y, 3.f);
|
||||
EXPECT_FLOAT_EQ(e.z, 4.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, ExtentsOfUnitBox)
|
||||
{
|
||||
constexpr AABB box{{0.f, 0.f, 0.f}, {2.f, 2.f, 2.f}};
|
||||
constexpr auto e = box.extents();
|
||||
EXPECT_FLOAT_EQ(e.x, 1.f);
|
||||
EXPECT_FLOAT_EQ(e.y, 1.f);
|
||||
EXPECT_FLOAT_EQ(e.z, 1.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, ExtentsOfDegenerateBox)
|
||||
{
|
||||
constexpr AABB box{{3.f, 3.f, 3.f}, {3.f, 3.f, 3.f}};
|
||||
constexpr auto e = box.extents();
|
||||
EXPECT_FLOAT_EQ(e.x, 0.f);
|
||||
EXPECT_FLOAT_EQ(e.y, 0.f);
|
||||
EXPECT_FLOAT_EQ(e.z, 0.f);
|
||||
}
|
||||
|
||||
using UpAxis = omath::primitives::UpAxis;
|
||||
|
||||
// --- top() ---
|
||||
|
||||
TEST(AabbTests, TopYUpSymmetricBox)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -2.f, -3.f}, {1.f, 2.f, 3.f}};
|
||||
constexpr auto t = box.top<UpAxis::Y>();
|
||||
EXPECT_FLOAT_EQ(t.x, 0.f);
|
||||
EXPECT_FLOAT_EQ(t.y, 2.f);
|
||||
EXPECT_FLOAT_EQ(t.z, 0.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, TopYUpOffsetBox)
|
||||
{
|
||||
constexpr AABB box{{1.f, 4.f, 2.f}, {3.f, 10.f, 6.f}};
|
||||
constexpr auto t = box.top<UpAxis::Y>();
|
||||
EXPECT_FLOAT_EQ(t.x, 2.f);
|
||||
EXPECT_FLOAT_EQ(t.y, 10.f);
|
||||
EXPECT_FLOAT_EQ(t.z, 4.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, TopZUpSymmetricBox)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -2.f, -3.f}, {1.f, 2.f, 3.f}};
|
||||
constexpr auto t = box.top<UpAxis::Z>();
|
||||
EXPECT_FLOAT_EQ(t.x, 0.f);
|
||||
EXPECT_FLOAT_EQ(t.y, 0.f);
|
||||
EXPECT_FLOAT_EQ(t.z, 3.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, TopZUpOffsetBox)
|
||||
{
|
||||
constexpr AABB box{{1.f, 4.f, 2.f}, {3.f, 10.f, 6.f}};
|
||||
constexpr auto t = box.top<UpAxis::Z>();
|
||||
EXPECT_FLOAT_EQ(t.x, 2.f);
|
||||
EXPECT_FLOAT_EQ(t.y, 7.f);
|
||||
EXPECT_FLOAT_EQ(t.z, 6.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, TopDefaultIsYUp)
|
||||
{
|
||||
constexpr AABB box{{0.f, 0.f, 0.f}, {2.f, 4.f, 6.f}};
|
||||
EXPECT_EQ(box.top(), box.top<UpAxis::Y>());
|
||||
}
|
||||
|
||||
// --- bottom() ---
|
||||
|
||||
TEST(AabbTests, BottomYUpSymmetricBox)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -2.f, -3.f}, {1.f, 2.f, 3.f}};
|
||||
constexpr auto b = box.bottom<UpAxis::Y>();
|
||||
EXPECT_FLOAT_EQ(b.x, 0.f);
|
||||
EXPECT_FLOAT_EQ(b.y, -2.f);
|
||||
EXPECT_FLOAT_EQ(b.z, 0.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, BottomYUpOffsetBox)
|
||||
{
|
||||
constexpr AABB box{{1.f, 4.f, 2.f}, {3.f, 10.f, 6.f}};
|
||||
constexpr auto b = box.bottom<UpAxis::Y>();
|
||||
EXPECT_FLOAT_EQ(b.x, 2.f);
|
||||
EXPECT_FLOAT_EQ(b.y, 4.f);
|
||||
EXPECT_FLOAT_EQ(b.z, 4.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, BottomZUpSymmetricBox)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -2.f, -3.f}, {1.f, 2.f, 3.f}};
|
||||
constexpr auto b = box.bottom<UpAxis::Z>();
|
||||
EXPECT_FLOAT_EQ(b.x, 0.f);
|
||||
EXPECT_FLOAT_EQ(b.y, 0.f);
|
||||
EXPECT_FLOAT_EQ(b.z, -3.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, BottomZUpOffsetBox)
|
||||
{
|
||||
constexpr AABB box{{1.f, 4.f, 2.f}, {3.f, 10.f, 6.f}};
|
||||
constexpr auto b = box.bottom<UpAxis::Z>();
|
||||
EXPECT_FLOAT_EQ(b.x, 2.f);
|
||||
EXPECT_FLOAT_EQ(b.y, 7.f);
|
||||
EXPECT_FLOAT_EQ(b.z, 2.f);
|
||||
}
|
||||
|
||||
TEST(AabbTests, BottomDefaultIsYUp)
|
||||
{
|
||||
constexpr AABB box{{0.f, 0.f, 0.f}, {2.f, 4.f, 6.f}};
|
||||
EXPECT_EQ(box.bottom(), box.bottom<UpAxis::Y>());
|
||||
}
|
||||
|
||||
TEST(AabbTests, TopAndBottomAreSymmetric)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -2.f, -3.f}, {1.f, 2.f, 3.f}};
|
||||
EXPECT_FLOAT_EQ(box.top<UpAxis::Y>().y, -box.bottom<UpAxis::Y>().y);
|
||||
EXPECT_FLOAT_EQ(box.top<UpAxis::Z>().z, -box.bottom<UpAxis::Z>().z);
|
||||
}
|
||||
|
||||
// --- is_collide() ---
|
||||
|
||||
TEST(AabbTests, OverlappingBoxesCollide)
|
||||
{
|
||||
constexpr AABB a{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB b{{0.f, 0.f, 0.f}, {2.f, 2.f, 2.f}};
|
||||
EXPECT_TRUE(a.is_collide(b));
|
||||
EXPECT_TRUE(b.is_collide(a));
|
||||
}
|
||||
|
||||
TEST(AabbTests, SeparatedBoxesDoNotCollide)
|
||||
{
|
||||
constexpr AABB a{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB b{{2.f, 2.f, 2.f}, {4.f, 4.f, 4.f}};
|
||||
EXPECT_FALSE(a.is_collide(b));
|
||||
EXPECT_FALSE(b.is_collide(a));
|
||||
}
|
||||
|
||||
TEST(AabbTests, TouchingFacesCollide)
|
||||
{
|
||||
constexpr AABB a{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB b{{1.f, -1.f, -1.f}, {3.f, 1.f, 1.f}};
|
||||
EXPECT_TRUE(a.is_collide(b));
|
||||
EXPECT_TRUE(b.is_collide(a));
|
||||
}
|
||||
|
||||
TEST(AabbTests, ContainedBoxCollides)
|
||||
{
|
||||
constexpr AABB outer{{-3.f, -3.f, -3.f}, {3.f, 3.f, 3.f}};
|
||||
constexpr AABB inner{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
EXPECT_TRUE(outer.is_collide(inner));
|
||||
EXPECT_TRUE(inner.is_collide(outer));
|
||||
}
|
||||
|
||||
TEST(AabbTests, SeparatedOnXAxisDoNotCollide)
|
||||
{
|
||||
constexpr AABB a{{0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB b{{2.f, 0.f, 0.f}, {3.f, 1.f, 1.f}};
|
||||
EXPECT_FALSE(a.is_collide(b));
|
||||
}
|
||||
|
||||
TEST(AabbTests, SeparatedOnYAxisDoNotCollide)
|
||||
{
|
||||
constexpr AABB a{{0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB b{{0.f, 2.f, 0.f}, {1.f, 3.f, 1.f}};
|
||||
EXPECT_FALSE(a.is_collide(b));
|
||||
}
|
||||
|
||||
TEST(AabbTests, SeparatedOnZAxisDoNotCollide)
|
||||
{
|
||||
constexpr AABB a{{0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB b{{0.f, 0.f, 2.f}, {1.f, 1.f, 3.f}};
|
||||
EXPECT_FALSE(a.is_collide(b));
|
||||
}
|
||||
|
||||
TEST(AabbTests, IdenticalBoxesCollide)
|
||||
{
|
||||
constexpr AABB a{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
EXPECT_TRUE(a.is_collide(a));
|
||||
}
|
||||
|
||||
TEST(AabbTests, DegeneratePointBoxCollidesWhenInsideOther)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB point{{0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}};
|
||||
EXPECT_TRUE(box.is_collide(point));
|
||||
EXPECT_TRUE(point.is_collide(box));
|
||||
}
|
||||
|
||||
TEST(AabbTests, DegeneratePointBoxDoesNotCollideWhenOutside)
|
||||
{
|
||||
constexpr AABB box{{-1.f, -1.f, -1.f}, {1.f, 1.f, 1.f}};
|
||||
constexpr AABB point{{5.f, 0.f, 0.f}, {5.f, 0.f, 0.f}};
|
||||
EXPECT_FALSE(box.is_collide(point));
|
||||
EXPECT_FALSE(point.is_collide(box));
|
||||
}
|
||||
Reference in New Issue
Block a user