Program Listing for File BoundingSphere.h
↰ Return to documentation for file (Simulation/BoundingSphere.h)
#ifndef __BOUNDINGSPHERE_H__
#define __BOUNDINGSPHERE_H__
#include "Common/Common.h"
#include <vector>
namespace PBD
{
class BoundingSphere
{
public:
BoundingSphere() : m_x(Vector3r::Zero()), m_r(0.0) {}
BoundingSphere(Vector3r const& x, const Real r) : m_x(x), m_r(r) {}
BoundingSphere(const Vector3r& a)
{
m_x = a;
m_r = 0.0;
}
BoundingSphere(const Vector3r& a, const Vector3r& b)
{
const Vector3r ba = b - a;
m_x = (a + b) * static_cast<Real>(0.5);
m_r = static_cast<Real>(0.5) * ba.norm();
}
BoundingSphere(const Vector3r& a, const Vector3r& b, const Vector3r& c)
{
const Vector3r ba = b - a;
const Vector3r ca = c - a;
const Vector3r baxca = ba.cross(ca);
Vector3r r;
Matrix3r T;
T << ba[0], ba[1], ba[2],
ca[0], ca[1], ca[2],
baxca[0], baxca[1], baxca[2];
r[0] = static_cast<Real>(0.5) * ba.squaredNorm();
r[1] = static_cast<Real>(0.5) * ca.squaredNorm();
r[2] = static_cast<Real>(0.0);
m_x = T.inverse() * r;
m_r = m_x.norm();
m_x += a;
}
BoundingSphere(const Vector3r& a, const Vector3r& b, const Vector3r& c, const Vector3r& d)
{
const Vector3r ba = b - a;
const Vector3r ca = c - a;
const Vector3r da = d - a;
Vector3r r;
Matrix3r T;
T << ba[0], ba[1], ba[2],
ca[0], ca[1], ca[2],
da[0], da[1], da[2];
r[0] = static_cast<Real>(0.5) * ba.squaredNorm();
r[1] = static_cast<Real>(0.5) * ca.squaredNorm();
r[2] = static_cast<Real>(0.5) * da.squaredNorm();
m_x = T.inverse() * r;
m_r = m_x.norm();
m_x += a;
}
BoundingSphere(const std::vector<Vector3r>& p)
{
m_r = 0;
m_x.setZero();
setPoints(p);
}
Vector3r const& x() const { return m_x; }
Vector3r& x() { return m_x; }
Real r() const { return m_r; }
Real& r() { return m_r; }
void setPoints(const std::vector<Vector3r>& p)
{
//remove duplicates
std::vector<Vector3r> v(p);
std::sort(v.begin(), v.end(), [](const Vector3r& a, const Vector3r& b)
{
if (a[0] < b[0]) return true;
if (a[0] > b[0]) return false;
if (a[1] < b[1]) return true;
if (a[1] > b[1]) return false;
return (a[2] < b[2]);
});
v.erase(std::unique(v.begin(), v.end(), [](Vector3r& a, Vector3r& b) { return a.isApprox(b); }), v.end());
Vector3r d;
const int n = int(v.size());
//generate random permutation of the points and permute the points by epsilon to avoid corner cases
const double epsilon = 1.0e-6;
for (int i = n - 1; i > 0; i--)
{
const Vector3r epsilon_vec = epsilon * Vector3r::Random();
const int j = static_cast<int>(floor(i * double(rand()) / RAND_MAX));
d = v[i] + epsilon_vec;
v[i] = v[j] - epsilon_vec;
v[j] = d;
}
BoundingSphere S = BoundingSphere(v[0], v[1]);
for (int i = 2; i < n; i++)
{
//SES0
d = v[i] - S.x();
if (d.squaredNorm() > S.r()* S.r())
S = ses1(i, v, v[i]);
}
m_x = S.m_x;
m_r = S.m_r + static_cast<Real>(epsilon); //add epsilon to make sure that all non-pertubated points are inside the sphere
}
bool overlaps(BoundingSphere const& other) const
{
double rr = m_r + other.m_r;
return (m_x - other.m_x).squaredNorm() < rr * rr;
}
bool contains(BoundingSphere const& other) const
{
double rr = r() - other.r();
return (x() - other.x()).squaredNorm() < rr * rr;
}
bool contains(Vector3r const& other) const
{
return (x() - other).squaredNorm() < m_r * m_r;
}
private:
BoundingSphere ses3(int n, std::vector<Vector3r>& p, Vector3r& q1, Vector3r& q2, Vector3r& q3)
{
BoundingSphere S(q1, q2, q3);
for (int i = 0; i < n; i++)
{
Vector3r d = p[i] - S.x();
if (d.squaredNorm() > S.r()* S.r())
S = BoundingSphere(q1, q2, q3, p[i]);
}
return S;
}
BoundingSphere ses2(int n, std::vector<Vector3r>& p, Vector3r& q1, Vector3r& q2)
{
BoundingSphere S(q1, q2);
for (int i = 0; i < n; i++)
{
Vector3r d = p[i] - S.x();
if (d.squaredNorm() > S.r()* S.r())
S = ses3(i, p, q1, q2, p[i]);
}
return S;
}
BoundingSphere ses1(int n, std::vector<Vector3r>& p, Vector3r& q1)
{
BoundingSphere S(p[0], q1);
for (int i = 1; i < n; i++)
{
Vector3r d = p[i] - S.x();
if (d.squaredNorm() > S.r()* S.r())
S = ses2(i, p, q1, p[i]);
}
return S;
}
Vector3r m_x;
Real m_r;
};
}
#endif