// 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 #include #include #define F(a) static_cast(a) template NzSphere::NzSphere(T X, T Y, T Z, T Radius) { Set(X, Y, Z, Radius); } /* template NzSphere::NzSphere(const NzCircle& circle) { Set(rect); } */ template NzSphere::NzSphere(const NzVector3& center, T Radius) { Set(center, Radius); } template NzSphere::NzSphere(const T sphere[4]) { Set(sphere); } template template NzSphere::NzSphere(const NzSphere& sphere) { Set(sphere); } template bool NzSphere::Contains(T X, T Y, T Z) const { return SquaredDistance(X, Y, Z) <= radius*radius; } template bool NzSphere::Contains(const NzBox& box) const { if (box.GetMinimum().SquaredDistance(GetPosition()) <= radius * radius) { if (box.GetMaximum().SquaredDistance(GetPosition()) <= radius * radius) return true; } return false; } template bool NzSphere::Contains(const NzVector3& point) const { return Contains(point.x, point.y, point.z); } template T NzSphere::Distance(T X, T Y, T Z) const { return Distance({X, Y, Z}); } template T NzSphere::Distance(const NzVector3& point) const { return NzVector3f::Distance(point, GetPosition()) - radius; } template NzSphere& NzSphere::ExtendTo(T X, T Y, T Z) { T distance = SquaredDistance(X, Y, Z); if (distance > radius*radius) radius = std::sqrt(distance); return *this; } template NzSphere& NzSphere::ExtendTo(const NzVector3& point) { return ExtendTo(point.x, point.y, point.z); } template NzVector3 NzSphere::GetNegativeVertex(const NzVector3& normal) const { NzVector3 neg(GetPosition()); neg -= normal * radius; return neg; } template NzVector3 NzSphere::GetPosition() const { return NzVector3(x, y, z); } template NzVector3 NzSphere::GetPositiveVertex(const NzVector3& normal) const { NzVector3 pos(GetPosition()); pos += normal * radius; return pos; } template bool NzSphere::Intersect(const NzBox& box) const { // Arvo's algorithm. T squaredDistance = T(0.0); if (x < box.x) { T diff = x - box.x; squaredDistance += diff*diff; } else if (x > box.x + box.width) { T diff = x - (box.x + box.width); squaredDistance += diff*diff; } if (y < box.y) { T diff = y - box.y; squaredDistance += diff*diff; } else if (y > box.y + box.height) { T diff = y - (box.y + box.height); squaredDistance += diff*diff; } if (z < box.z) { T diff = z - box.z; squaredDistance += diff*diff; } else if (z > box.z + box.depth) { T diff = z - (box.z + box.depth); squaredDistance += diff*diff; } return squaredDistance <= radius * radius; } template bool NzSphere::Intersect(const NzSphere& sphere) const { return SquaredDistance(sphere.x, sphere.y, sphere.z) - radius*radius <= sphere.radius*sphere.radius; } template bool NzSphere::IsValid() const { return radius > F(0.0); } template NzSphere& NzSphere::MakeZero() { x = F(0.0); y = F(0.0); z = F(0.0); radius = F(0.0); return *this; } template NzSphere& NzSphere::Set(T X, T Y, T Z, T Radius) { x = X; y = Y; z = Z; radius = Radius; return *this; } template NzSphere& NzSphere::Set(const NzVector3& center, T Radius) { x = center.x; y = center.y; z = center.z; radius = Radius; return *this; } /* template NzSphere& NzSphere::Set(const NzCircle& circle) { x = circle.x; y = circle.y; z = F(0.0); radius = circle.radius; return *this; } */ template NzSphere& NzSphere::Set(const NzSphere& sphere) { std::memcpy(this, &sphere, sizeof(NzSphere)); return *this; } template NzSphere& NzSphere::Set(const T sphere[4]) { x = sphere[0]; y = sphere[1]; z = sphere[2]; radius = sphere[3]; return *this; } template template NzSphere& NzSphere::Set(const NzSphere& sphere) { x = F(sphere.x); y = F(sphere.y); z = F(sphere.z); radius = F(sphere.radius); return *this; } template T NzSphere::SquaredDistance(T X, T Y, T Z) const { return SquaredDistance({X, Y, Z}); } template T NzSphere::SquaredDistance(const NzVector3& point) const { return NzVector3f::Distance(point, GetPosition()) - radius * radius; } template NzString NzSphere::ToString() const { NzStringStream ss; return ss << "Sphere(" << x << ", " << y << ", " << z << "; " << radius << ')'; } template T& NzSphere::operator[](unsigned int i) { #if NAZARA_MATH_SAFE if (i >= 4) { NzStringStream ss; ss << "Index out of range: (" << i << " >= 4)"; NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif return *(&x+i); } template T NzSphere::operator[](unsigned int i) const { #if NAZARA_MATH_SAFE if (i >= 4) { NzStringStream ss; ss << "Index out of range: (" << i << " >= 4)"; NazaraError(ss); throw std::domain_error(ss.ToString()); } #endif return *(&x+i); } template NzSphere NzSphere::operator*(T scalar) const { return NzSphere(x, y, z, radius*scalar); } template NzSphere& NzSphere::operator*=(T scalar) { radius *= scalar; } template bool NzSphere::operator==(const NzSphere& sphere) const { return NzNumberEquals(x, sphere.x) && NzNumberEquals(y, sphere.y) && NzNumberEquals(z, sphere.z) && NzNumberEquals(radius, sphere.radius); } template bool NzSphere::operator!=(const NzSphere& sphere) const { return !operator==(sphere); } template NzSphere NzSphere::Lerp(const NzSphere& from, const NzSphere& 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 Zero(); } #endif NzSphere sphere; sphere.x = NzLerp(from.x, to.x, interpolation); sphere.y = NzLerp(from.y, to.y, interpolation); sphere.z = NzLerp(from.z, to.z, interpolation); sphere.radius = NzLerp(from.radius, to.radius, interpolation); return sphere; } template NzSphere NzSphere::Zero() { NzSphere sphere; sphere.MakeZero(); return sphere; } template std::ostream& operator<<(std::ostream& out, const NzSphere& sphere) { return out << sphere.ToString(); } #undef F #include