12 inline bool overlap(
const Eigen::Vector3d &displacement,
const Eigen::Matrix3d &
first,
13 const Eigen::Matrix3d &second)
15 if(!displacement.allFinite() || !
first.allFinite() || !second.allFinite() ||
16 first.llt().info() != Eigen::Success || second.llt().info() != Eigen::Success)
18 throw std::invalid_argument(
"Ellipsoid overlap requires finite positive shape tensors");
22 const double scale = std::max(
first.norm(), second.norm());
23 const Eigen::Matrix3d
a =
first / scale,
b = second / scale;
24 const Eigen::Vector3d d = displacement / std::sqrt(scale);
25 const auto contact = [&](
double t)
27 const Eigen::Matrix3d shape = (1 -
t) *
a +
t *
b;
28 return t * (1 -
t) * d.dot(shape.ldlt().solve(d));
30 double lo = 0, hi = 1;
31 constexpr double ratio = 0.6180339887498948482;
32 double left = hi - ratio * (hi - lo),
right = lo + ratio * (hi - lo);
33 double fl = contact(
left), fr = contact(
right);
34 for(
int k = 0;
k < 100; ++
k)
36 if(std::max(fl, fr) > 1.0 + 1.e-12)
45 right = lo + ratio * (hi - lo);
53 left = hi - ratio * (hi - lo);
57 return std::max(fl, fr) <= 1.0 + 1.e-12;
63 const auto edgeDistance = [](
const Eigen::Vector3d &
p,
const Eigen::Vector3d &
q)
65 const Eigen::Vector3d edge =
q -
p;
66 const double t = edge.squaredNorm() > 0 ? std::clamp(-
p.dot(edge) / edge.squaredNorm(), 0.0, 1.0) : 0.0;
67 return (
p +
t * edge).squaredNorm();
69 double distance = std::min({edgeDistance(
a,
b), edgeDistance(
b,
c), edgeDistance(
c,
a)});
70 const Eigen::Vector3d
u =
b -
a,
v =
c -
a, n =
u.cross(
v);
71 if(n.squaredNorm() > 0)
73 const double s = (-
a).cross(
v).dot(n) / n.squaredNorm();
74 const double t =
u.cross(-
a).dot(n) / n.squaredNorm();
75 if(s >= 0 &&
t >= 0 && s +
t <= 1)
77 distance = std::min(distance, (
a + s *
u +
t *
v).squaredNorm());