-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
math::Sphere::OptimalEnclosingSphere() breaks down for torus with sufficient detail #75
Comments
Oh, very interesting! Would you be able to dump the good and bad input vertices into a single .cpp test case file to showcase the error? |
First suspect might be to play around with the epsilon value at MathGeoLib/src/Geometry/Sphere.cpp Lines 325 to 326 in 55053da
which was needed to improve the numerical stability of the algorithm. |
Indeed, |
I can try to make a repro case some time later. |
Np.. another possibility to try if numerical stability is giving grief can be to duplicate the function into a version that uses |
Repro: #include <stdio.h>
#include <stdlib.h>
#include "../src/MathGeoLib.h"
#include "../src/Geometry/Sphere.h"
#include "../src/Math/myassert.h"
#include "TestRunner.h"
#include "TestData.h"
MATH_IGNORE_UNUSED_VARS_WARNING
MATH_BEGIN_NAMESPACE
std::vector<math::vec> GenerateTorus(
double major_radius,
double minor_radius,
int major_axis_steps,
int minor_axis_steps
)
{
std::vector<math::vec> points;
constexpr double pi = 3.14159265358979323846264338327950288;
const double R = major_radius;
const double r = minor_radius;
for (int major = 0; major < major_axis_steps; ++major)
{
const double rel_major = static_cast<double>(major) / static_cast<double>(major_axis_steps);
for (int minor = 0; minor < minor_axis_steps; ++minor)
{
const double rel_minor = static_cast<double>(minor) / static_cast<double>(minor_axis_steps);
const double theta = (pi * 2.0 * rel_major);
const double phi = (pi * 2.0 * rel_minor);
const double sin_theta = std::sin(theta);
const double cos_theta = std::cos(theta);
const double sin_phi = std::sin(phi);
const double cos_phi = std::cos(phi);
const double x = (R + r * cos_phi) * cos_theta;
const double z = (R + r * cos_phi) * sin_theta;
const double y = r * sin_phi;
const float fx = static_cast<float>(x);
const float fy = static_cast<float>(y);
const float fz = static_cast<float>(z);
points.push_back(math::vec{fx, fy, fz});
}
}
return points;
}
UNIQUE_TEST(BoundingSphere)
{
const auto points = GenerateTorus(0.5, 0.125, 40, 32);
const math::Sphere sphere = math::Sphere::OptimalEnclosingSphere(
points.data(),
static_cast<int>(points.size())
);
assert(sphere.r < (0.5 + 0.125 + 0.001));
}
MATH_END_NAMESPACE |
Torus that shows a problem:
This gives a bounding sphere that is too large to be optimal (center = (0.619, 0.0, 0.048), radius = 1.247):
Meanwhile, torus with less detail:
This gives the expected bounding sphere (center = (0,0,0), radius = 0.625)
The text was updated successfully, but these errors were encountered: