mirror of https://github.com/vitalif/openscad
This should fix Clipper-based non-cut projection
parent
b2945cc714
commit
2ca39595cd
|
@ -112,7 +112,7 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA
|
|||
// cache could have been modified before we reach this point due to a large
|
||||
// sibling object.
|
||||
if (!CGALCache::instance()->contains(this->tree.getIdString(*chnode))) {
|
||||
CGALCache::instance()->insert(this->tree.getIdString(*chnode), *chN);
|
||||
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN ? *chN : CGAL_Nef_polyhedron());
|
||||
}
|
||||
|
||||
if (chgeom) {
|
||||
|
@ -644,7 +644,33 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
|||
// FIXME: Don't use deep access to modinst members
|
||||
if (chnode->modinst->isBackground()) continue;
|
||||
|
||||
|
||||
const Polygon2d *poly = NULL;
|
||||
|
||||
// CGAL version of Geometry projection
|
||||
// Causes crashes in createNefPolyhedronFromGeometry() for this model:
|
||||
// projection(cut=false) {
|
||||
// cube(10);
|
||||
// difference() {
|
||||
// sphere(10);
|
||||
// cylinder(h=30, r=5, center=true);
|
||||
// }
|
||||
// }
|
||||
#if 0
|
||||
shared_ptr<const PolySet> chPS = dynamic_pointer_cast<const PolySet>(chgeom);
|
||||
const PolySet *ps2d = NULL;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> chN = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(chgeom);
|
||||
if (chN) chPS.reset(chN->convertToPolyset());
|
||||
if (chPS) ps2d = PolysetUtils::flatten(*chPS);
|
||||
if (ps2d) {
|
||||
CGAL_Nef_polyhedron *N2d = createNefPolyhedronFromGeometry(*ps2d);
|
||||
poly = N2d->convertToPolygon2d();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Clipper version of Geometry projection
|
||||
// Clipper doesn't handle meshes very well.
|
||||
// It's better in V6 but not quite there. FIXME: stand-alone example.
|
||||
#if 1
|
||||
// project chgeom -> polygon2d
|
||||
shared_ptr<const PolySet> chPS = dynamic_pointer_cast<const PolySet>(chgeom);
|
||||
if (!chPS) {
|
||||
|
@ -653,9 +679,10 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
|||
chPS.reset(chN->convertToPolyset());
|
||||
}
|
||||
}
|
||||
if (chPS) {
|
||||
const Polygon2d *poly = PolysetUtils::project(*chPS);
|
||||
if (chPS) poly = PolysetUtils::project(*chPS);
|
||||
#endif
|
||||
|
||||
if (poly) {
|
||||
ClipperLib::Polygons result = ClipperUtils::fromPolygon2d(*poly);
|
||||
// Using NonZero ensures that we don't create holes from polygons sharing
|
||||
// edges since we're unioning a mesh
|
||||
|
@ -667,6 +694,8 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
|||
}
|
||||
}
|
||||
ClipperLib::Polygons sumresult;
|
||||
// This is key - without StrictlySimple, we tend to get self-intersecting results
|
||||
sumclipper.StrictlySimple(true);
|
||||
sumclipper.Execute(ClipperLib::ctUnion, sumresult, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
geom.reset(ClipperUtils::toPolygon2d(sumresult));
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ namespace ClipperUtils {
|
|||
BOOST_FOREACH(const Vector2d &v, outline) {
|
||||
p.push_back(ClipperLib::IntPoint(v[0]*CLIPPER_SCALE, v[1]*CLIPPER_SCALE));
|
||||
}
|
||||
// Make sure all polygons point up, since we project also
|
||||
// back-facing polygon in PolysetUtils::project()
|
||||
if (!ClipperLib::Orientation(p)) std::reverse(p.begin(), p.end());
|
||||
|
||||
result.push_back(p);
|
||||
}
|
||||
return result;
|
||||
|
@ -19,9 +23,13 @@ namespace ClipperUtils {
|
|||
Polygon2d *result = new Polygon2d;
|
||||
BOOST_FOREACH(const ClipperLib::Polygon &p, poly) {
|
||||
Outline2d outline;
|
||||
const Vector2d *lastv = NULL;
|
||||
BOOST_FOREACH(const ClipperLib::IntPoint &ip, p) {
|
||||
outline.push_back(Vector2d(1.0*ip.X/CLIPPER_SCALE,
|
||||
1.0*ip.Y/CLIPPER_SCALE));
|
||||
Vector2d v(1.0*ip.X/CLIPPER_SCALE, 1.0*ip.Y/CLIPPER_SCALE);
|
||||
// Ignore too close vertices. This is to be nice to subsequent processes.
|
||||
if (lastv && (v-*lastv).squaredNorm() < 0.001) continue;
|
||||
outline.push_back(v);
|
||||
lastv = &outline.back();
|
||||
}
|
||||
result->addOutline(outline);
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
namespace PolysetUtils {
|
||||
|
||||
// Project all polygons (also back-facing) into a Polygon2d instance.
|
||||
// It's important to select all faces, since filtering by normal vector here
|
||||
// will trigger floating point incertainties and cause problems later.
|
||||
const Polygon2d *project(const PolySet &ps) {
|
||||
Polygon2d *poly = new Polygon2d;
|
||||
|
||||
BOOST_FOREACH(const PolySet::Polygon &p, ps.polygons) {
|
||||
// Filter away down-facing normal vectors
|
||||
if ((p[1]-p[0]).cross(p[2]-p[0])[2] <=0) continue;
|
||||
|
||||
Outline2d outline;
|
||||
BOOST_FOREACH(const Vector3d &v, p) {
|
||||
outline.push_back(Vector2d(v[0], v[1]));
|
||||
|
|
Loading…
Reference in New Issue