Example #1
0
Sphere Sphere::OptimalEnclosingSphere(const vec &a, const vec &b, const vec &c, const vec &d, const vec &e,
                                      int &redundantPoint)
{
	Sphere s = OptimalEnclosingSphere(b,c,d,e);
	if (s.Contains(a, sEpsilon))
	{
		redundantPoint = 0;
		return s;
	}
	s = OptimalEnclosingSphere(a,c,d,e);
	if (s.Contains(b, sEpsilon))
	{
		redundantPoint = 1;
		return s;
	}
	s = OptimalEnclosingSphere(a,b,d,e);
	if (s.Contains(c, sEpsilon))
	{
		redundantPoint = 2;
		return s;
	}
	s = OptimalEnclosingSphere(a,b,c,e);
	if (s.Contains(d, sEpsilon))
	{
		redundantPoint = 3;
		return s;
	}
	s = OptimalEnclosingSphere(a,b,c,d);
	mathassert(s.Contains(e, sEpsilon));
	redundantPoint = 4;
	return s;
}
Example #2
0
Sphere Sphere::OptimalEnclosingSphere(const vec &a, const vec &b)
{
	Sphere s;
	s.pos = (a + b) * 0.5f;
	s.r = (b - s.pos).Length();
	assume(s.pos.IsFinite());
	assume(s.r >= 0.f);

	// Allow floating point inconsistency and expand the radius by a small epsilon so that the containment tests
	// really contain the points (note that the points must be sufficiently near enough to the origin)
	s.r += sEpsilon;

	mathassert(s.Contains(a));
	mathassert(s.Contains(b));
	return s;
}
Example #3
0
/** For reference, see http://realtimecollisiondetection.net/blog/?p=20 . */
Sphere Sphere::OptimalEnclosingSphere(const vec &a, const vec &b, const vec &c, const vec &d)
{
	Sphere sphere;

	float s,t,u;
	const vec ab = b-a;
	const vec ac = c-a;
	const vec ad = d-a;
	bool success = FitSphereThroughPoints(ab, ac, ad, s, t, u);
	if (!success || s < 0.f || t < 0.f || u < 0.f || s+t+u > 1.f)
	{
		sphere = OptimalEnclosingSphere(a,b,c);
		if (!sphere.Contains(d))
		{
			sphere = OptimalEnclosingSphere(a,b,d);
			if (!sphere.Contains(c))
			{
				sphere = OptimalEnclosingSphere(a,c,d);
				if (!sphere.Contains(b))
				{
					sphere = OptimalEnclosingSphere(b,c,d);
					sphere.r = Max(sphere.r, a.Distance(sphere.pos) + 1e-3f); // For numerical stability, expand the radius of the sphere so it certainly contains the fourth point.
					assume(sphere.Contains(a));
				}
			}
		}
	}
	/* // Note: Trying to approach the problem like this, like was in the triangle case, is flawed:
	if (s < 0.f)
		sphere = OptimalEnclosingSphere(a, c, d);
	else if (t < 0.f)
		sphere = OptimalEnclosingSphere(a, b, d);
	else if (u < 0.f)
		sphere = OptimalEnclosingSphere(a, b, c);
	else if (s + t + u > 1.f)
		sphere = OptimalEnclosingSphere(b, c, d); */
	else // The fitted sphere is inside the convex hull of the vertices (a,b,c,d), so it must be optimal.
	{
		const vec center = s*ab + t*ac + u*ad;

		sphere.pos = a + center;
		// Mathematically, the following would be correct, but it suffers from floating point inaccuracies,
		// since it only tests distance against one point.
		//sphere.r = center.Length();

		// For robustness, take the radius to be the distance to the farthest point (though the distance are all
		// equal).
		sphere.r = Sqrt(Max(sphere.pos.DistanceSq(a), sphere.pos.DistanceSq(b), sphere.pos.DistanceSq(c), sphere.pos.DistanceSq(d)));
	}

		// Allow floating point inconsistency and expand the radius by a small epsilon so that the containment tests
		// really contain the points (note that the points must be sufficiently near enough to the origin)
		sphere.r += 2.f*sEpsilon; // We test against one epsilon, so expand using 2 epsilons.

#ifdef MATH_ASSERT_CORRECTNESS
	if (!sphere.Contains(a, sEpsilon) || !sphere.Contains(b, sEpsilon) || !sphere.Contains(c, sEpsilon) || !sphere.Contains(d, sEpsilon))
	{
		LOGE("Pos: %s, r: %f", sphere.pos.ToString().c_str(), sphere.r);
		LOGE("A: %s, dist: %f", a.ToString().c_str(), a.Distance(sphere.pos));
		LOGE("B: %s, dist: %f", b.ToString().c_str(), b.Distance(sphere.pos));
		LOGE("C: %s, dist: %f", c.ToString().c_str(), c.Distance(sphere.pos));
		LOGE("D: %s, dist: %f", d.ToString().c_str(), d.Distance(sphere.pos));
		mathassert(false);
	}
#endif

	return sphere;
}
Example #4
0
/** For reference, see http://realtimecollisiondetection.net/blog/?p=20 . */
Sphere Sphere::OptimalEnclosingSphere(const vec &a, const vec &b, const vec &c)
{
	Sphere sphere;

	vec ab = b-a;
	vec ac = c-a;

	float s, t;
	bool areCollinear = ab.Cross(ac).LengthSq() < 1e-4f; // Manually test that we don't try to fit sphere to three collinear points.
	bool success = !areCollinear && FitSphereThroughPoints(ab, ac, s, t);
	if (!success || Abs(s) > 10000.f || Abs(t) > 10000.f) // If s and t are very far from the triangle, do a manual box fitting for numerical stability.
	{
		vec minPt = Min(a, b, c);
		vec maxPt = Max(a, b, c);
		sphere.pos = (minPt + maxPt) * 0.5f;
		sphere.r = sphere.pos.Distance(minPt);
	}
	else if (s < 0.f)
	{
		sphere.pos = (a + c) * 0.5f;
		sphere.r = a.Distance(c) * 0.5f;
		sphere.r = Max(sphere.r, b.Distance(sphere.pos)); // For numerical stability, expand the radius of the sphere so it certainly contains the third point.
	}
	else if (t < 0.f)
	{
		sphere.pos = (a + b) * 0.5f;
		sphere.r = a.Distance(b) * 0.5f;
		sphere.r = Max(sphere.r, c.Distance(sphere.pos)); // For numerical stability, expand the radius of the sphere so it certainly contains the third point.
	}
	else if (s+t > 1.f)
	{
		sphere.pos = (b + c) * 0.5f;
		sphere.r = b.Distance(c) * 0.5f;
		sphere.r = Max(sphere.r, a.Distance(sphere.pos)); // For numerical stability, expand the radius of the sphere so it certainly contains the third point.
	}
	else
	{
		const vec center = s*ab + t*ac;
		sphere.pos = a + center;
		// Mathematically, the following would be correct, but it suffers from floating point inaccuracies,
		// since it only tests distance against one point.
		//sphere.r = center.Length();

		// For robustness, take the radius to be the distance to the farthest point (though the distance are all
		// equal).
		sphere.r = Sqrt(Max(sphere.pos.DistanceSq(a), sphere.pos.DistanceSq(b), sphere.pos.DistanceSq(c)));
	}

	// Allow floating point inconsistency and expand the radius by a small epsilon so that the containment tests
	// really contain the points (note that the points must be sufficiently near enough to the origin)
	sphere.r += 2.f * sEpsilon; // We test against one epsilon, so expand by two epsilons.

#ifdef MATH_ASSERT_CORRECTNESS
	if (!sphere.Contains(a, sEpsilon) || !sphere.Contains(b, sEpsilon) || !sphere.Contains(c, sEpsilon))
	{
		LOGE("Pos: %s, r: %f", sphere.pos.ToString().c_str(), sphere.r);
		LOGE("A: %s, dist: %f", a.ToString().c_str(), a.Distance(sphere.pos));
		LOGE("B: %s, dist: %f", b.ToString().c_str(), b.Distance(sphere.pos));
		LOGE("C: %s, dist: %f", c.ToString().c_str(), c.Distance(sphere.pos));
		mathassert(false);
	}
#endif
	return sphere;
}