219 lines
6.4 KiB
C++
219 lines
6.4 KiB
C++
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
|
|
|
#include "BoundingSphere.h"
|
|
#include "BoundingBox.h"
|
|
#include "Matrix.h"
|
|
#include "Ray.h"
|
|
#include "../Types/String.h"
|
|
|
|
const BoundingSphere BoundingSphere::Empty(Vector3(0, 0, 0), 0);
|
|
|
|
String BoundingSphere::ToString() const
|
|
{
|
|
return String::Format(TEXT("{}"), *this);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const Ray& ray) const
|
|
{
|
|
Real distance;
|
|
return CollisionsHelper::RayIntersectsSphere(ray, *this, distance);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const Ray& ray, Real& distance) const
|
|
{
|
|
return CollisionsHelper::RayIntersectsSphere(ray, *this, distance);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const Ray& ray, Real& distance, Vector3& normal) const
|
|
{
|
|
return CollisionsHelper::RayIntersectsSphere(ray, *this, distance, normal);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const Ray& ray, Vector3& point) const
|
|
{
|
|
return CollisionsHelper::RayIntersectsSphere(ray, *this, point);
|
|
}
|
|
|
|
PlaneIntersectionType BoundingSphere::Intersects(const Plane& plane) const
|
|
{
|
|
return CollisionsHelper::PlaneIntersectsSphere(plane, *this);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3) const
|
|
{
|
|
return CollisionsHelper::SphereIntersectsTriangle(*this, vertex1, vertex2, vertex3);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const BoundingBox& box) const
|
|
{
|
|
return CollisionsHelper::BoxIntersectsSphere(box, *this);
|
|
}
|
|
|
|
bool BoundingSphere::Intersects(const BoundingSphere& sphere) const
|
|
{
|
|
const Real radiisum = Radius + sphere.Radius;
|
|
const Real x = Center.X - sphere.Center.X;
|
|
const Real y = Center.Y - sphere.Center.Y;
|
|
const Real z = Center.Z - sphere.Center.Z;
|
|
return x * x + y * y + z * z <= radiisum * radiisum;
|
|
}
|
|
|
|
ContainmentType BoundingSphere::Contains(const Vector3& point) const
|
|
{
|
|
return CollisionsHelper::SphereContainsPoint(*this, point);
|
|
}
|
|
|
|
ContainmentType BoundingSphere::Contains(const Vector3& vertex1, const Vector3& vertex2, const Vector3& vertex3) const
|
|
{
|
|
return CollisionsHelper::SphereContainsTriangle(*this, vertex1, vertex2, vertex3);
|
|
}
|
|
|
|
ContainmentType BoundingSphere::Contains(const BoundingBox& box) const
|
|
{
|
|
return CollisionsHelper::SphereContainsBox(*this, box);
|
|
}
|
|
|
|
ContainmentType BoundingSphere::Contains(const BoundingSphere& sphere) const
|
|
{
|
|
return CollisionsHelper::SphereContainsSphere(*this, sphere);
|
|
}
|
|
|
|
BoundingBox BoundingSphere::GetBoundingBox() const
|
|
{
|
|
BoundingBox result;
|
|
BoundingBox::FromSphere(*this, result);
|
|
return result;
|
|
}
|
|
|
|
void BoundingSphere::GetBoundingBox(BoundingBox& result) const
|
|
{
|
|
BoundingBox::FromSphere(*this, result);
|
|
}
|
|
|
|
void BoundingSphere::FromPoints(const Float3* points, int32 pointsCount, BoundingSphere& result)
|
|
{
|
|
ASSERT(points && pointsCount > 0);
|
|
|
|
// Find the center of all points
|
|
Float3 center = Float3::Zero;
|
|
for (int32 i = 0; i < pointsCount; i++)
|
|
Float3::Add(points[i], center, center);
|
|
center /= (float)pointsCount;
|
|
|
|
// Find the radius of the sphere
|
|
float radius = 0.0f;
|
|
for (int32 i = 0; i < pointsCount; i++)
|
|
{
|
|
const float distance = Float3::DistanceSquared(center, points[i]);
|
|
if (distance > radius)
|
|
radius = distance;
|
|
}
|
|
|
|
// Construct the sphere
|
|
result.Center = center;
|
|
result.Radius = Math::Sqrt(radius);
|
|
}
|
|
|
|
void BoundingSphere::FromPoints(const Double3* points, int32 pointsCount, BoundingSphere& result)
|
|
{
|
|
ASSERT(points && pointsCount > 0);
|
|
|
|
// Find the center of all points
|
|
Double3 center = Double3::Zero;
|
|
for (int32 i = 0; i < pointsCount; i++)
|
|
Double3::Add(points[i], center, center);
|
|
center /= (double)pointsCount;
|
|
|
|
// Find the radius of the sphere
|
|
double radius = 0.0;
|
|
for (int32 i = 0; i < pointsCount; i++)
|
|
{
|
|
const double distance = Double3::DistanceSquared(center, points[i]);
|
|
if (distance > radius)
|
|
radius = distance;
|
|
}
|
|
|
|
// Construct the sphere
|
|
result.Center = center;
|
|
result.Radius = (Real)Math::Sqrt(radius);
|
|
}
|
|
|
|
void BoundingSphere::FromBox(const BoundingBox& box, BoundingSphere& result)
|
|
{
|
|
ASSERT(!box.Minimum.IsNanOrInfinity() && !box.Maximum.IsNanOrInfinity());
|
|
const Real x = box.Maximum.X - box.Minimum.X;
|
|
const Real y = box.Maximum.Y - box.Minimum.Y;
|
|
const Real z = box.Maximum.Z - box.Minimum.Z;
|
|
result.Center.X = box.Minimum.X + x * 0.5f;
|
|
result.Center.Y = box.Minimum.Y + y * 0.5f;
|
|
result.Center.Z = box.Minimum.Z + z * 0.5f;
|
|
result.Radius = Math::Sqrt(x * x + y * y + z * z) * 0.5f;
|
|
}
|
|
|
|
void BoundingSphere::Merge(const BoundingSphere& value1, const BoundingSphere& value2, BoundingSphere& result)
|
|
{
|
|
// Pre-exit if one of the bounding sphere by assuming that a merge with an empty sphere is equivalent at taking the non-empty sphere
|
|
if (value1 == Empty)
|
|
{
|
|
result = value2;
|
|
return;
|
|
}
|
|
if (value2 == Empty)
|
|
{
|
|
result = value1;
|
|
return;
|
|
}
|
|
|
|
const Vector3 difference = value2.Center - value1.Center;
|
|
const Real length = difference.Length();
|
|
const Real radius = value1.Radius;
|
|
const Real radius2 = value2.Radius;
|
|
|
|
if (radius + radius2 >= length)
|
|
{
|
|
if (radius - radius2 >= length)
|
|
{
|
|
result = value1;
|
|
return;
|
|
}
|
|
|
|
if (radius2 - radius >= length)
|
|
{
|
|
result = value2;
|
|
return;
|
|
}
|
|
}
|
|
|
|
const Vector3 vector = difference * (1.0f / length);
|
|
const Real min = Math::Min(-radius, length - radius2);
|
|
const Real max = (Math::Max(radius, length + radius2) - min) * 0.5f;
|
|
|
|
result.Center = value1.Center + vector * (max + min);
|
|
result.Radius = max;
|
|
}
|
|
|
|
void BoundingSphere::Merge(const BoundingSphere& value1, const Vector3& value2, BoundingSphere& result)
|
|
{
|
|
const Vector3 difference = value2 - value1.Center;
|
|
const Real length = difference.Length();
|
|
const Real radius = value1.Radius;
|
|
if (radius >= length)
|
|
{
|
|
result = value1;
|
|
return;
|
|
}
|
|
|
|
const Vector3 vector = difference * (1.0f / length);
|
|
const Real min = Math::Min(-radius, length);
|
|
const Real max = (Math::Max(radius, length) - min) * 0.5f;
|
|
|
|
result.Center = value1.Center + vector * (max + min);
|
|
result.Radius = max;
|
|
}
|
|
|
|
void BoundingSphere::Transform(const BoundingSphere& sphere, const Matrix& matrix, BoundingSphere& result)
|
|
{
|
|
Vector3::Transform(sphere.Center, matrix, result.Center);
|
|
result.Radius = sphere.Radius * matrix.GetScaleVector().GetAbsolute().MaxValue();
|
|
}
|