Reinstate Grid to fix problems introduced due to floating point inaccuracy. Grid does a certain job at vertex melding across objects and also help keeping plans planar

customizer
Marius Kintel 2014-01-23 21:22:05 -05:00
parent 3288447e70
commit 548b9c7c93
2 changed files with 120 additions and 17 deletions

View File

@ -772,6 +772,96 @@ public:
const PolySet &ps;
CGAL_Build_PolySet(const PolySet &ps) : ps(ps) { }
/*
Using Grid here is important for performance reasons. See following model.
If we don't grid the geometry before converting to a Nef Polyhedron, the quads
in the cylinders to tessellated into triangles since floating point
incertainty causes the faces to not be 100% planar. The incertainty is exaggerated
by the transform. This wasn't a problem earlier since we used Nef for everything,
but optimizations since then has made us keep it in floating point space longer.
minkowski() {
cube([200, 50, 7], center = true);
rotate([90,0,0]) cylinder($fn = 8, h = 1, r = 8.36, center = true);
rotate([0,90,0]) cylinder($fn = 8, h = 1, r = 8.36, center = true);
}
*/
#if 1 // Use Grid
void operator()(CGAL_HDS& hds) {
CGAL_Polybuilder B(hds, true);
std::vector<CGALPoint> vertices;
Grid3d<int> grid(GRID_FINE);
std::vector<size_t> indices(3);
BOOST_FOREACH(const PolySet::Polygon &p, ps.polygons) {
BOOST_REVERSE_FOREACH(Vector3d v, p) {
if (!grid.has(v[0], v[1], v[2])) {
// align v to the grid; the CGALPoint will receive the aligned vertex
grid.align(v[0], v[1], v[2]) = vertices.size();
vertices.push_back(CGALPoint(v[0], v[1], v[2]));
}
}
}
#ifdef DEBUG
printf("polyhedron(faces=[");
int pidx = 0;
#endif
B.begin_surface(vertices.size(), ps.polygons.size());
BOOST_FOREACH(const CGALPoint &p, vertices) {
B.add_vertex(p);
}
BOOST_FOREACH(const PolySet::Polygon &p, ps.polygons) {
#ifdef DEBUG
if (pidx++ > 0) printf(",");
#endif
indices.clear();
BOOST_FOREACH(const Vector3d &v, p) {
indices.push_back(grid.data(v[0], v[1], v[2]));
}
// We perform this test since there is a bug in CGAL's
// Polyhedron_incremental_builder_3::test_facet() which
// fails to detect duplicate indices
bool err = false;
for (std::size_t i = 0; i < indices.size(); ++i) {
// check if vertex indices[i] is already in the sequence [0..i-1]
for (std::size_t k = 0; k < i && !err; ++k) {
if (indices[k] == indices[i]) {
err = true;
break;
}
}
}
if (!err && B.test_facet(indices.begin(), indices.end())) {
B.add_facet(indices.begin(), indices.end());
}
#ifdef DEBUG
printf("[");
int fidx = 0;
BOOST_FOREACH(size_t i, indices) {
if (fidx++ > 0) printf(",");
printf("%ld", i);
}
printf("]");
#endif
}
B.end_surface();
#ifdef DEBUG
printf("],\n");
#endif
#ifdef DEBUG
printf("points=[");
for (int i=0;i<vertices.size();i++) {
if (i > 0) printf(",");
const CGALPoint &p = vertices[i];
printf("[%g,%g,%g]", CGAL::to_double(p.x()), CGAL::to_double(p.y()), CGAL::to_double(p.z()));
}
printf("]);\n");
#endif
}
#else // Don't use Grid
void operator()(CGAL_HDS& hds)
{
CGAL_Polybuilder B(hds, true);
@ -790,36 +880,37 @@ public:
if (pidx++ > 0) printf(",");
#endif
indices.clear();
BOOST_FOREACH(const Vector3d &v, p) {
BOOST_REVERSE_FOREACH(const Vector3d &v, p) {
size_t s = vertices.size();
size_t idx = vertices.lookup(v);
// If we added a vertex, also add it to the CGAL builder
if (idx == s) B.add_vertex(CGALPoint(v[0], v[1], v[2]));
indices.push_back(idx);
}
std::map<size_t,int> fc;
bool facet_is_degenerate = false;
BOOST_REVERSE_FOREACH(size_t i, indices) {
if (fc[i]++ > 0) facet_is_degenerate = true;
// We perform this test since there is a bug in CGAL's
// Polyhedron_incremental_builder_3::test_facet() which
// fails to detect duplicate indices
bool err = false;
for (std::size_t i = 0; i < indices.size(); ++i) {
// check if vertex indices[i] is already in the sequence [0..i-1]
for (std::size_t k = 0; k < i && !err; ++k) {
if (indices[k] == indices[i]) {
err = true;
break;
}
}
}
if (!facet_is_degenerate) {
B.begin_facet();
if (!err && B.test_facet(indices.begin(), indices.end())) {
B.add_facet(indices.begin(), indices.end());
#ifdef DEBUG
printf("[");
#endif
int fidx = 0;
std::map<int,int> fc;
BOOST_REVERSE_FOREACH(size_t i, indices) {
B.add_vertex_to_facet(i);
#ifdef DEBUG
BOOST_FOREACH(size_t i, indices) {
if (fidx++ > 0) printf(",");
printf("%ld", i);
#endif
}
#ifdef DEBUG
printf("]");
#endif
B.end_facet();
}
}
B.end_surface();
@ -835,6 +926,7 @@ public:
printf("]);\n");
#endif
}
#endif
};
bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p)
@ -916,6 +1008,11 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
try {
CGAL_Polyhedron P;
bool err = createPolyhedronFromPolySet(ps, P);
// if (!err) {
// PRINTB("Polyhedron is closed: %d", P.is_closed());
// PRINTB("Polyhedron is valid: %d", P.is_valid(true, 0));
// }
if (!err) N = new CGAL_Nef_polyhedron3(P);
}
catch (const CGAL::Assertion_exception &e) {

View File

@ -50,6 +50,7 @@ public:
x = ix * res, y = iy * res;
return db[std::make_pair(ix, iy)];
}
bool has(double x, double y) const {
int64_t ix = (int64_t)round(x / res);
int64_t iy = (int64_t)round(y / res);
@ -62,6 +63,7 @@ public:
}
return false;
}
bool eq(double x1, double y1, double x2, double y2) {
align(x1, y1);
align(x2, y2);
@ -87,6 +89,7 @@ public:
Grid3d(double resolution) {
res = resolution;
}
T &align(double &x, double &y, double &z) {
int64_t ix = (int64_t)round(x / res);
int64_t iy = (int64_t)round(y / res);
@ -110,8 +113,9 @@ public:
}
}
x = ix * res, y = iy * res, z = iz * res;
return db[std::make_pair(std::make_pair(ix, iy), iz)];
return db[std::make_pair(std::make_pair(ix, iy), iz)];
}
bool has(double x, double y, double z) {
int64_t ix = (int64_t)round(x / res);
int64_t iy = (int64_t)round(y / res);
@ -125,8 +129,8 @@ public:
return true;
}
return false;
}
bool eq(double x1, double y1, double z1, double x2, double y2, double z2) {
align(x1, y1, z1);
align(x2, y2, z2);
@ -134,9 +138,11 @@ public:
return true;
return false;
}
T &data(double x, double y, double z) {
return align(x, y, z);
}
T &operator()(double x, double y, double z) {
return align(x, y, z);
}