From f2b80bfe64d8334ccc6bde178811daa28c3bd6f1 Mon Sep 17 00:00:00 2001 From: Gawaboumga Date: Fri, 21 Aug 2015 11:57:56 +0200 Subject: [PATCH] Planes are ax+by+cz=d Planes are changed to ax+by+cz=d, so the plane with normal (0, 1, 0) and distance 1 is y=1. Operators == and !=. Former-commit-id: 5267a183a9e6fb490de099d536ea2f64558f674d --- tests/Nazara/Math/Plane.cpp | 75 ++++++++++++++ tests/Nazara/Math/Plane.hpp | 60 +++++++++++ tests/Nazara/Math/Plane.inl | 193 ++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 tests/Nazara/Math/Plane.cpp create mode 100644 tests/Nazara/Math/Plane.hpp create mode 100644 tests/Nazara/Math/Plane.inl diff --git a/tests/Nazara/Math/Plane.cpp b/tests/Nazara/Math/Plane.cpp new file mode 100644 index 000000000..59db2ef29 --- /dev/null +++ b/tests/Nazara/Math/Plane.cpp @@ -0,0 +1,75 @@ +#include +#include + +SCENARIO("Plane", "[MATH][PLANE]") +{ + GIVEN("Two planes normal(1, 1, 1), distance 1") + { + NzPlanef firstPlane(NzVector3f::Unit().Normalize(), 1.f); + NzPlanef secondPlane(NzPlaned(NzVector3d::Unit().Normalize(), 1.0)); + + WHEN("We compare them") + { + THEN("They are equal") + { + REQUIRE(firstPlane == secondPlane); + } + + AND_THEN("We compare with normal(-1, -1, -1), distance -1") + { + REQUIRE(firstPlane == NzPlanef(-NzVector3f::Unit().Normalize(), -1.f)); + } + + AND_THEN("They have the same distance from the same point") + { + NzVector3f point(-2.f, 3.f, 1.f); + REQUIRE(firstPlane.Distance(point) == Approx(secondPlane.Distance(point))); + REQUIRE(firstPlane.Distance(-2.f, 3.f, 1.f) == Approx(0.1547f)); + } + + AND_THEN("Distance between Plane (0, 1, 0), distance 1 and point (0, 2, 0) should be 1") + { + REQUIRE(NzPlanef(NzVector3f::UnitY(), 1.f).Distance(NzVector3f::UnitY() * 2.f) == Approx(1.f)); + } + + AND_THEN("Distance between Plane (0, 1, 0), distance 5 and point (0, 2, 0) should be -3") + { + REQUIRE(NzPlanef(NzVector3f::UnitY(), 5.f).Distance(NzVector3f::UnitY() * 2.f) == Approx(-3.f)); + } + + AND_THEN("Distance between Plane (0, 1, 0), distance 1000 and point (0, 500, 0) and (0, 1500, 0)") + { + REQUIRE(NzPlanef(NzVector3f::UnitY(), 1000.f).Distance(NzVector3f::UnitY() * 500.f) == Approx(-500.f)); + REQUIRE(NzPlanef(NzVector3f::UnitY(), 1000.f).Distance(NzVector3f::UnitY() * 1500.f) == Approx(500.f)); + } + + AND_THEN("Distance between Plane (0, -1, 0), distance -1000 and point (0, 500, 0) and (0, 1500, 0)") + { + REQUIRE(NzPlanef(-NzVector3f::UnitY(), -1000.f).Distance(NzVector3f::UnitY() * 500.f) == Approx(500.f)); + REQUIRE(NzPlanef(-NzVector3f::UnitY(), -1000.f).Distance(NzVector3f::UnitY() * 1500.f) == Approx(-500.f)); + } + } + } + + GIVEN("The plane XZ, distance 1 with 3 points (0, 1, 0), (1, 1, 1), (-1, 1, 0)") + { + WHEN("We do a positive plane") + { + NzPlanef xy(NzVector3f(2.f, 1.f, 0.f), NzVector3f(-1.f, 1.f, -1.f), NzVector3f(-1.f, 1.f, 0.f)); + + THEN("It must be equal to XZ distance 1") + { + REQUIRE(xy == NzPlanef(NzVector3f::UnitY(), 1.f)); + } + } + + WHEN("We do a negative plane") + { + NzPlanef xy(NzVector3f(0.f, 1.f, 0.f), NzVector3f(1.f, 1.f, 1.f), NzVector3f(-1.f, 1.f, 0.f)); + THEN("It must be equal to XZ distance 1") + { + REQUIRE(xy == NzPlanef(-NzVector3f::UnitY(), -1.f)); + } + } + } +} diff --git a/tests/Nazara/Math/Plane.hpp b/tests/Nazara/Math/Plane.hpp new file mode 100644 index 000000000..f3971acb1 --- /dev/null +++ b/tests/Nazara/Math/Plane.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Mathematics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PLANE_HPP +#define NAZARA_PLANE_HPP + +#include +#include + +template +class NzPlane +{ + public: + NzPlane() = default; + NzPlane(T normalX, T normalY, T normalZ, T Distance); + NzPlane(const T plane[4]); + NzPlane(const NzVector3& Normal, T Distance); + NzPlane(const NzVector3& Normal, const NzVector3& point); + NzPlane(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3); + template explicit NzPlane(const NzPlane& plane); + NzPlane(const NzPlane& plane) = default; + ~NzPlane() = default; + + T Distance(const NzVector3& point) const; + T Distance(T x, T y, T z) const; + + NzPlane& Set(T normalX, T normalY, T normalZ, T Distance); + NzPlane& Set(const T plane[4]); + NzPlane& Set(const NzPlane& plane); + NzPlane& Set(const NzVector3& Normal, T Distance); + NzPlane& Set(const NzVector3& Normal, const NzVector3& point); + NzPlane& Set(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3); + template NzPlane& Set(const NzPlane& plane); + + NzString ToString() const; + + bool operator==(const NzPlane& plane) const; + bool operator!=(const NzPlane& plane) const; + + static NzPlane Lerp(const NzPlane& from, const NzPlane& to, T interpolation); + static NzPlane XY(); + static NzPlane XZ(); + static NzPlane YZ(); + + NzVector3 normal; + T distance; +}; + +template +std::ostream& operator<<(std::ostream& out, const NzPlane& plane); + +typedef NzPlane NzPlaned; +typedef NzPlane NzPlanef; + +#include + +#endif // NAZARA_PLANE_HPP diff --git a/tests/Nazara/Math/Plane.inl b/tests/Nazara/Math/Plane.inl new file mode 100644 index 000000000..834435085 --- /dev/null +++ b/tests/Nazara/Math/Plane.inl @@ -0,0 +1,193 @@ +// Copyright (C) 2015 Jérôme Leclercq +// This file is part of the "Nazara Engine - Mathematics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +#define F(a) static_cast(a) + +template +NzPlane::NzPlane(T normalX, T normalY, T normalZ, T D) +{ + Set(normalX, normalY, normalZ, D); +} + +template +NzPlane::NzPlane(const T plane[4]) +{ + Set(plane); +} + +template +NzPlane::NzPlane(const NzVector3& Normal, T D) +{ + Set(Normal, D); +} + +template +NzPlane::NzPlane(const NzVector3& Normal, const NzVector3& point) +{ + Set(Normal, point); +} + +template +NzPlane::NzPlane(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3) +{ + Set(point1, point2, point3); +} + +template +template +NzPlane::NzPlane(const NzPlane& plane) +{ + Set(plane); +} + +template +T NzPlane::Distance(const NzVector3& point) const +{ + return normal.DotProduct(point) - distance; // ax + by + cd - d = 0. +} + +template +T NzPlane::Distance(T x, T y, T z) const +{ + return Distance(NzVector3(x, y, z)); +} + +template +NzPlane& NzPlane::Set(T normalX, T normalY, T normalZ, T D) +{ + distance = D; + normal.Set(normalX, normalY, normalZ); + + return *this; +} + +template +NzPlane& NzPlane::Set(const T plane[4]) +{ + normal.Set(plane[0], plane[1], plane[2]); + distance = plane[3]; + + return *this; +} + +template +NzPlane& NzPlane::Set(const NzPlane& plane) +{ + std::memcpy(this, &plane, sizeof(NzPlane)); + + return *this; +} + +template +NzPlane& NzPlane::Set(const NzVector3& Normal, T D) +{ + distance = D; + normal = Normal; + + return *this; +} + +template +NzPlane& NzPlane::Set(const NzVector3& Normal, const NzVector3& point) +{ + normal = Normal; + distance = -normal.DotProduct(point); + + return *this; +} + +template +NzPlane& NzPlane::Set(const NzVector3& point1, const NzVector3& point2, const NzVector3& point3) +{ + NzVector3 edge1 = point2 - point1; + NzVector3 edge2 = point3 - point1; + normal = edge1.CrossProduct(edge2); + normal.Normalize(); + + distance = normal.DotProduct(point3); + + return *this; +} + +template +template +NzPlane& NzPlane::Set(const NzPlane& plane) +{ + normal.Set(plane.normal); + distance = F(plane.distance); + + return *this; +} + +template +NzString NzPlane::ToString() const +{ + NzStringStream ss; + + return ss << "Plane(Normal: " << normal.ToString() << "; Distance: " << distance << ')'; +} + +template +bool NzPlane::operator==(const NzPlane& plane) const +{ + return (normal == plane.normal && NzNumberEquals(distance, plane.distance)) || (normal == -plane.normal && NzNumberEquals(distance, -plane.distance)); +} + +template +bool NzPlane::operator!=(const NzPlane& plane) const +{ + return !operator==(plane); +} + +template +NzPlane NzPlane::Lerp(const NzPlane& from, const NzPlane& to, T interpolation) +{ + #ifdef NAZARA_DEBUG + if (interpolation < F(0.0) || interpolation > F(1.0)) + { + NazaraError("Interpolation must be in range [0..1] (Got " + NzString::Number(interpolation) + ')'); + return NzPlane(); + } + #endif + + NzPlane plane; + plane.distance = NzLerp(from.distance, to.distance, interpolation); + plane.normal = NzVector3::Lerp(from.normal, to.normal, interpolation); + plane.normal.Normalize(); + + return plane; +} + +template +NzPlane NzPlane::XY() +{ + return NzPlane(F(0.0), F(0.0), F(1.0), F(0.0)); +} + +template +NzPlane NzPlane::XZ() +{ + return NzPlane(F(0.0), F(1.0), F(0.0), F(0.0)); +} + +template +NzPlane NzPlane::YZ() +{ + return NzPlane(F(1.0), F(0.0), F(0.0), F(0.0)); +} + +template +std::ostream& operator<<(std::ostream& out, const NzPlane& plane) +{ + return out << plane.ToString(); +} + +#undef F + +#include