From 1f488f851da6afd87342417414cd900c4a6c2a93 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Mon, 2 Dec 2013 01:48:22 -0500 Subject: [PATCH] Refactoring to facilitate more sharing of code between CGALEvaluator, GeometryEvaluator and CGALUtils --- openscad.pro | 4 - src/CGALCache.cc | 20 ++- src/CGALCache.h | 14 +- src/CGALEvaluator.cc | 188 ++++++++++++------------- src/CGALEvaluator.h | 14 +- src/Geometry.h | 6 + src/GeometryEvaluator.cc | 89 ++++++------ src/GeometryEvaluator.h | 17 ++- src/cgalutils.cc | 295 ++++++++++++++++++++++----------------- src/cgalutils.h | 9 +- src/cgalworker.cc | 4 +- src/cgalworker.h | 3 +- src/export.cc | 6 +- src/export.h | 8 +- src/export_png.cc | 2 +- src/openscad.cc | 21 ++- tests/CMakeLists.txt | 2 - tests/cgalcachetest.cc | 4 +- 18 files changed, 378 insertions(+), 328 deletions(-) diff --git a/openscad.pro b/openscad.pro index 9c8c5fb6..3b5ac51f 100644 --- a/openscad.pro +++ b/openscad.pro @@ -251,7 +251,6 @@ HEADERS += src/typedefs.h \ src/nodedumper.h \ src/ModuleCache.h \ src/GeometryCache.h \ - src/PolySetEvaluator.h \ src/GeometryEvaluator.h \ src/CSGTermEvaluator.h \ src/Tree.h \ @@ -320,7 +319,6 @@ SOURCES += src/version_check.cc \ \ src/nodedumper.cc \ src/traverser.cc \ - src/PolySetEvaluator.cc \ src/GeometryEvaluator.cc \ src/ModuleCache.cc \ src/GeometryCache.cc \ @@ -384,7 +382,6 @@ HEADERS += src/cgal.h \ src/cgalutils.h \ src/CGALEvaluator.h \ src/CGALCache.h \ - src/PolySetCGALEvaluator.h \ src/CGALRenderer.h \ src/CGAL_Nef_polyhedron.h \ src/CGAL_Nef3_workaround.h \ @@ -393,7 +390,6 @@ HEADERS += src/cgal.h \ SOURCES += src/cgalutils.cc \ src/CGALEvaluator.cc \ - src/PolySetCGALEvaluator.cc \ src/CGALCache.cc \ src/CGALRenderer.cc \ src/CGAL_Nef_polyhedron.cc \ diff --git a/src/CGALCache.cc b/src/CGALCache.cc index 75d83c09..42a265d8 100644 --- a/src/CGALCache.cc +++ b/src/CGALCache.cc @@ -8,21 +8,21 @@ CGALCache::CGALCache(size_t limit) : cache(limit) { } -const CGAL_Nef_polyhedron &CGALCache::get(const std::string &id) const +shared_ptr CGALCache::get(const std::string &id) const { - const CGAL_Nef_polyhedron &N = *this->cache[id]; + const shared_ptr &N = this->cache[id]->N; #ifdef DEBUG - PRINTB("CGAL Cache hit: %s (%d bytes)", id.substr(0, 40) % N.memsize()); + PRINTB("CGAL Cache hit: %s (%d bytes)", id.substr(0, 40) % (N ? N->memsize() : 0)); #endif return N; } -bool CGALCache::insert(const std::string &id, const CGAL_Nef_polyhedron &N) +bool CGALCache::insert(const std::string &id, const shared_ptr &N) { - bool inserted = this->cache.insert(id, new CGAL_Nef_polyhedron(N), N.memsize()); + bool inserted = this->cache.insert(id, new cache_entry(N), N ? N->memsize() : 0); #ifdef DEBUG - if (inserted) PRINTB("CGAL Cache insert: %s (%d bytes)", id.substr(0, 40) % N.memsize()); - else PRINTB("CGAL Cache insert failed: %s (%d bytes)", id.substr(0, 40) % N.memsize()); + if (inserted) PRINTB("CGAL Cache insert: %s (%d bytes)", id.substr(0, 40) % (N ? N->memsize() : 0)); + else PRINTB("CGAL Cache insert failed: %s (%d bytes)", id.substr(0, 40) % (N ? N->memsize() : 0)); #endif return inserted; } @@ -47,3 +47,9 @@ void CGALCache::print() PRINTB("CGAL Polyhedrons in cache: %d", this->cache.size()); PRINTB("CGAL cache size in bytes: %d", this->cache.totalCost()); } + +CGALCache::cache_entry::cache_entry(const shared_ptr &N) + : N(N) +{ + if (print_messages_stack.size() > 0) this->msg = print_messages_stack.back(); +} diff --git a/src/CGALCache.h b/src/CGALCache.h index 831ef27c..b82d8cc3 100644 --- a/src/CGALCache.h +++ b/src/CGALCache.h @@ -2,6 +2,7 @@ #define CGALCACHE_H_ #include "cache.h" +#include "memory.h" /*! */ @@ -13,8 +14,8 @@ public: static CGALCache *instance() { if (!inst) inst = new CGALCache; return inst; } bool contains(const std::string &id) const { return this->cache.contains(id); } - const class CGAL_Nef_polyhedron &get(const std::string &id) const; - bool insert(const std::string &id, const CGAL_Nef_polyhedron &N); + shared_ptr get(const std::string &id) const; + bool insert(const std::string &id, const shared_ptr &N); size_t maxSize() const; void setMaxSize(size_t limit); void clear(); @@ -23,7 +24,14 @@ public: private: static CGALCache *inst; - Cache cache; + struct cache_entry { + shared_ptr N; + std::string msg; + cache_entry(const shared_ptr &N); + ~cache_entry() { } + }; + + Cache cache; }; #endif diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 08a2e578..003d9558 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -16,15 +16,15 @@ #include "dxftess.h" #include "Tree.h" -#include "CGALCache.h" #include "cgal.h" #include "cgalutils.h" +#include + #ifdef NDEBUG #define PREV_NDEBUG NDEBUG #undef NDEBUG #endif -#include #ifdef PREV_NDEBUG #define NDEBUG PREV_NDEBUG #endif @@ -40,7 +40,7 @@ #include #include -CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node) +shared_ptr CGALEvaluator::evaluateCGALMesh(const AbstractNode &node) { if (!isCached(node)) { Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX); @@ -57,12 +57,12 @@ bool CGALEvaluator::isCached(const AbstractNode &node) const /*! */ -CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op) +CGAL_Nef_polyhedron *CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op) { - CGAL_Nef_polyhedron N; + CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { const AbstractNode *chnode = item.first; - const CGAL_Nef_polyhedron &chN = item.second; + const shared_ptr chN = item.second; // FIXME: Don't use deep access to modinst members if (chnode->modinst->isBackground()) continue; @@ -74,94 +74,93 @@ CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, Ope CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN); } // Initialize N on first iteration with first expected geometric object - if (N.isNull() && !N.isEmpty()) N = chN.copy(); - else CGAL_binary_operator(N, chN, op); - + if (chN) { + if (N->isNull() && !N->isEmpty()) *N = chN->copy(); + else CGALUtils::applyBinaryOperator(*N, *chN, op); + } + chnode->progress_report(); } return N; } -CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node) +const CGAL_Nef_polyhedron *CGALEvaluator::applyHull(const CgaladvNode &node) { - CGAL_Nef_polyhedron N; - std::list polys; - std::list points2d; - std::list points3d; - int dim = 0; + unsigned int dim = 0; BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { - const AbstractNode *chnode = item.first; - const CGAL_Nef_polyhedron &chN = item.second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->isBackground()) continue; - if (chN.getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo) - if (dim == 0) { - dim = chN.getDimension(); + if (!dim) { + dim = item.second->getDimension(); + if (dim) break; } - else if (dim != chN.getDimension()) { - PRINT("WARNING: hull() does not support mixing 2D and 3D objects."); - continue; - } - if (chN.isNull()) { // If one of the children evaluated to a null object - continue; - } - if (dim == 2) { - CGAL_Nef_polyhedron2::Explorer explorer = chN.p2->explorer(); + } + + CGAL_Nef_polyhedron *N = NULL; + if (dim == 2) { + std::list polys; + std::list points2d; + std::list points3d; + BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + const AbstractNode *chnode = item.first; + const shared_ptr chN = item.second; + // FIXME: Don't use deep access to modinst members + if (chnode->modinst->isBackground()) continue; + if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo) + if (dim != chN->getDimension()) { + PRINT("WARNING: hull() does not support mixing 2D and 3D objects."); + continue; + } + if (chN->isNull()) { // If one of the children evaluated to a null object + continue; + } + CGAL_Nef_polyhedron2::Explorer explorer = chN->p2->explorer(); BOOST_FOREACH(const CGAL_Nef_polyhedron2::Explorer::Vertex &vh, std::make_pair(explorer.vertices_begin(), explorer.vertices_end())) { if (explorer.is_standard(&vh)) { points2d.push_back(explorer.point(&vh)); } } + chnode->progress_report(); } - else if (dim == 3) { - CGAL_Polyhedron P; - if (!chN.p3->is_simple()) { - PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export"); - } - else { - bool err = false; - std::string errmsg(""); - try { - err = nefworkaround::convert_to_Polyhedron( *(chN.p3), P ); - //chN.p3->convert_to_Polyhedron(P); - } catch (const CGAL::Failure_exception &e) { - err = true; - errmsg = std::string(e.what()); - } - if (err) { - PRINTB("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. %s", errmsg); - } else { - std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d), - boost::bind(static_cast(&CGAL_Polyhedron::Vertex::point), _1)); - } - } - } - chnode->progress_report(); - } - if (dim == 2) { std::list result; CGAL::convex_hull_2(points2d.begin(), points2d.end(),std:: back_inserter(result)); - N = CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron2(result.begin(), result.end(), - CGAL_Nef_polyhedron2::INCLUDED)); + N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron2(result.begin(), result.end(), + CGAL_Nef_polyhedron2::INCLUDED)); } else if (dim == 3) { + Geometry::ChildList children; + BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + const AbstractNode *chnode = item.first; + const shared_ptr chN = item.second; + // FIXME: Don't use deep access to modinst members + if (chnode->modinst->isBackground()) continue; + if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo) + if (dim == 0) { + dim = chN->getDimension(); + } + else if (dim != chN->getDimension()) { + PRINT("WARNING: hull() does not support mixing 2D and 3D objects."); + continue; + } + if (chN->isNull()) { // If one of the children evaluated to a null object + continue; + } + children.push_back(std::make_pair(chnode, chN)); + } CGAL_Polyhedron P; - if (points3d.size()>3) - CGAL::convex_hull_3(points3d.begin(), points3d.end(), P); - N = CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P)); + if (CGALUtils::applyHull(children, P)) { + N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P)); + } } return N; } -CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node) +const CGAL_Nef_polyhedron *CGALEvaluator::applyResize(const CgaladvNode &node) { // Based on resize() in Giles Bathgate's RapCAD (but not exactly) - CGAL_Nef_polyhedron N; - N = applyToChildren(node, OPENSCAD_UNION); + CGAL_Nef_polyhedron *N = applyToChildren(node, OPENSCAD_UNION); - if ( N.isNull() || N.isEmpty() ) return N; + if (N->isNull() || N->isEmpty()) return N; for (int i=0;i<3;i++) { if (node.newsize[i]<0) { @@ -172,15 +171,15 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node) CGAL_Iso_cuboid_3 bb; - if ( N.getDimension() == 2 ) { - CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 ); + if (N->getDimension() == 2) { + CGAL_Iso_rectangle_2e bbox = bounding_box(*N->p2); CGAL_Point_2e min2(bbox.min()), max2(bbox.max()); CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0), max3(CGAL::to_double(max2.x()), CGAL::to_double(max2.y()), 0); bb = CGAL_Iso_cuboid_3( min3, max3 ); } else { - bb = bounding_box( *N.p3 ); + bb = bounding_box(*N->p3); } std::vector scale, bbox_size; @@ -189,7 +188,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node) bbox_size.push_back( bb.ymax()-bb.ymin() ); bbox_size.push_back( bb.zmax()-bb.zmin() ); int newsizemax_index = 0; - for (int i=0;igetDimension();i++) { if (node.newsize[i]) { if (bbox_size[i]==NT3(0)) { PRINT("WARNING: Resize in direction normal to flat object is not implemented"); @@ -206,7 +205,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node) NT3 autoscale = NT3( 1 ); if ( node.newsize[ newsizemax_index ] != 0 ) autoscale = NT3( node.newsize[ newsizemax_index ] ) / bbox_size[ newsizemax_index ]; - for (int i=0;igetDimension();i++) { if (node.autosize[i] && node.newsize[i]==0) scale[i] = autoscale; } @@ -217,7 +216,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node) 0, 0, CGAL::to_double(scale[2]), 0, 0, 0, 0, 1; - N.transform( Transform3d( t ) ); + N->transform( Transform3d( t ) ); return N; } @@ -234,8 +233,8 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - CGAL_Nef_polyhedron N; - if (!isCached(node)) N = applyToChildren(node, OPENSCAD_UNION); + shared_ptr N; + if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_UNION)); else N = CGALCache::instance()->get(this->tree.getIdString(node)); addToParent(state, node, N); } @@ -246,8 +245,8 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - CGAL_Nef_polyhedron N; - if (!isCached(node)) N = applyToChildren(node, OPENSCAD_INTERSECTION); + shared_ptr N; + if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_INTERSECTION)); else N = CGALCache::instance()->get(this->tree.getIdString(node)); addToParent(state, node, N); } @@ -258,13 +257,9 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - CGAL_Nef_polyhedron N; - if (!isCached(node)) { - N = applyToChildren(node, node.type); - } - else { - N = CGALCache::instance()->get(this->tree.getIdString(node)); - } + shared_ptr N; + if (!isCached(node)) N.reset(applyToChildren(node, node.type)); + else N = CGALCache::instance()->get(this->tree.getIdString(node)); addToParent(state, node, N); } return ContinueTraversal; @@ -274,16 +269,19 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - CGAL_Nef_polyhedron N; + shared_ptr N; if (!isCached(node)) { // First union all children - N = applyToChildren(node, OPENSCAD_UNION); - if ( matrix_contains_infinity( node.matrix ) || matrix_contains_nan( node.matrix ) ) { + CGAL_Nef_polyhedron *tmpN = applyToChildren(node, OPENSCAD_UNION); + if (matrix_contains_infinity(node.matrix) || matrix_contains_nan(node.matrix)) { // due to the way parse/eval works we can't currently distinguish between NaN and Inf PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object."); N.reset(); } - N.transform( node.matrix ); + else { + tmpN->transform(node.matrix); + N.reset(tmpN); + } } else { N = CGALCache::instance()->get(this->tree.getIdString(node)); @@ -300,7 +298,7 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - CGAL_Nef_polyhedron N; + shared_ptr N; if (!isCached(node)) { // Apply polyset operation shared_ptr geom = this->geomevaluator.evaluateGeometry(node, true); @@ -309,7 +307,7 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node) if (!Nptr) { Nptr.reset(createNefPolyhedronFromGeometry(*geom)); } - N = *Nptr; + N = Nptr; } node.progress_report(); } @@ -325,13 +323,13 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - CGAL_Nef_polyhedron N; + shared_ptr N; if (!isCached(node)) { OpenSCADOperator op; switch (node.type) { case MINKOWSKI: op = OPENSCAD_MINKOWSKI; - N = applyToChildren(node, op); + N.reset(applyToChildren(node, op)); break; case GLIDE: PRINT("WARNING: glide() is not implemented yet!"); @@ -342,10 +340,10 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node) return PruneTraversal; break; case HULL: - N = applyHull(node); + N.reset(applyHull(node)); break; case RESIZE: - N = applyResize(node); + N.reset(applyResize(node)); break; } } @@ -361,7 +359,9 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node) Adds ourself to out parent's list of traversed children. Call this for _every_ node which affects output during the postfix traversal. */ -void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N) +void CGALEvaluator::addToParent(const State &state, + const AbstractNode &node, + const shared_ptr &N) { assert(state.isPostfix()); this->visitedchildren.erase(node.index()); diff --git a/src/CGALEvaluator.h b/src/CGALEvaluator.h index d8ca50b7..51b31d43 100644 --- a/src/CGALEvaluator.h +++ b/src/CGALEvaluator.h @@ -24,24 +24,24 @@ public: virtual Response visit(State &state, const AbstractPolyNode &node); virtual Response visit(State &state, const CgaladvNode &node); - CGAL_Nef_polyhedron evaluateCGALMesh(const AbstractNode &node); + shared_ptr evaluateCGALMesh(const AbstractNode &node); const Tree &getTree() const { return this->tree; } private: - void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N); + void addToParent(const State &state, const AbstractNode &node, const shared_ptr &N); bool isCached(const AbstractNode &node) const; void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); - CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, OpenSCADOperator op); - CGAL_Nef_polyhedron applyHull(const CgaladvNode &node); - CGAL_Nef_polyhedron applyResize(const CgaladvNode &node); + CGAL_Nef_polyhedron *applyToChildren(const AbstractNode &node, OpenSCADOperator op); + const CGAL_Nef_polyhedron *applyHull(const CgaladvNode &node); + const CGAL_Nef_polyhedron *applyResize(const CgaladvNode &node); - typedef std::pair ChildItem; + typedef std::pair > ChildItem; typedef std::list ChildList; std::map visitedchildren; const Tree &tree; - CGAL_Nef_polyhedron root; + shared_ptr root; public: // FIXME: Do we need to make this visible? Used for cache management // Note: psevaluator constructor needs this->tree to be initialized first diff --git a/src/Geometry.h b/src/Geometry.h index 5ac1790f..2183023a 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -3,11 +3,17 @@ #include #include +#include + #include "linalg.h" +#include "memory.h" class Geometry { public: + typedef std::pair > ChildItem; + typedef std::list ChildList; + Geometry() : convexity(1) {} virtual ~Geometry() {} diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 5ce3d4df..9fffd364 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -28,7 +28,6 @@ #include #include -#include GeometryEvaluator::GeometryEvaluator(const class Tree &tree): tree(tree) @@ -96,7 +95,7 @@ shared_ptr GeometryEvaluator::evaluateGeometry(const AbstractNod Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op) { unsigned int dim = 0; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { if (item.second) { if (!dim) dim = item.second->getDimension(); else if (dim != item.second->getDimension()) { @@ -115,8 +114,28 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA return applyHull3D(node); } + Geometry::ChildList children = collectChildren3D(node); + CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + BOOST_FOREACH(const Geometry::ChildItem &item, children) { + const shared_ptr &chgeom = item.second; + shared_ptr chN = dynamic_pointer_cast(chgeom); + if (!chN) { + const PolySet *chps = dynamic_cast(chgeom.get()); + if (chps) chN.reset(createNefPolyhedronFromGeometry(*chps)); + } + + if (chN) { + // Initialize N on first iteration with first expected geometric object + if (N->isNull() && !N->isEmpty()) *N = chN->copy(); + else CGALUtils::applyBinaryOperator(*N, *chN, op); + } + item.first->progress_report(); + } + +/* + CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; + BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { const AbstractNode *chnode = item.first; const shared_ptr &chgeom = item.second; // FIXME: Don't use deep access to modinst members @@ -138,7 +157,7 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA if (chgeom->getDimension() == 3) { // Initialize N on first iteration with first expected geometric object if (N->isNull() && !N->isEmpty()) *N = chN->copy(); - else CGAL_binary_operator(*N, *chN, op); + else CGALUtils::applyBinaryOperator(*N, *chN, op); } else { // FIXME: Fix error message @@ -147,11 +166,12 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA } chnode->progress_report(); } +*/ return N; } -Geometry *GeometryEvaluator::applyHull2D(const AbstractNode &node) +Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node) { std::vector children = collectChildren2D(node); Polygon2d *geometry = NULL; @@ -183,45 +203,16 @@ Geometry *GeometryEvaluator::applyHull2D(const AbstractNode &node) Geometry *GeometryEvaluator::applyHull3D(const AbstractNode &node) { - std::vector children = collectChildren3D(node); + Geometry::ChildList children = collectChildren3D(node); - // Collect point cloud - std::list points; CGAL_Polyhedron P; - BOOST_FOREACH(const Geometry *geometry, children) { - const CGAL_Nef_polyhedron *N = dynamic_cast(geometry); - if (N) { - if (!N->p3->is_simple()) { - PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export"); - } - else { - N->p3->convert_to_Polyhedron(P); - std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points), - boost::bind(static_cast(&CGAL_Polyhedron::Vertex::point), _1)); - } - } - else { - const PolySet *ps = dynamic_cast(geometry); - BOOST_FOREACH(const PolySet::Polygon &p, ps->polygons) { - BOOST_FOREACH(const Vector3d &v, p) { - points.push_back(CGAL_Polyhedron::Vertex::Point_3(v[0], v[1], v[2])); - } - } - } - } - if (points.size() > 0) { - // Apply hull - CGAL_Polyhedron P; - if (points.size() > 3) { - CGAL::convex_hull_3(points.begin(), points.end(), P); - } - + if (CGALUtils::applyHull(children, P)) { return new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P)); } return NULL; } -Geometry *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node) +Polygon2d *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node) { std::vector children = collectChildren2D(node); if (children.size() > 0) { @@ -249,10 +240,10 @@ Geometry *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node) return NULL; } -std::vector GeometryEvaluator::collectChildren2D(const AbstractNode &node) +std::vector GeometryEvaluator::collectChildren2D(const AbstractNode &node) { std::vector children; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { const AbstractNode *chnode = item.first; const shared_ptr &chgeom = item.second; // FIXME: Don't use deep access to modinst members @@ -285,10 +276,10 @@ void GeometryEvaluator::smartCache(const AbstractNode &node, { // Since we can generate both Nef and non-Nef geometry, we need to insert it into // the appropriate cache - const CGAL_Nef_polyhedron *N = dynamic_cast(geom.get()); + shared_ptr N = dynamic_pointer_cast(geom); if (N) { if (!CGALCache::instance()->contains(this->tree.getIdString(node))) { - CGALCache::instance()->insert(this->tree.getIdString(node), *N); + CGALCache::instance()->insert(this->tree.getIdString(node), N); } } else { @@ -300,10 +291,10 @@ void GeometryEvaluator::smartCache(const AbstractNode &node, } } -std::vector GeometryEvaluator::collectChildren3D(const AbstractNode &node) +Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &node) { - std::vector children; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + Geometry::ChildList children; + BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { const AbstractNode *chnode = item.first; const shared_ptr &chgeom = item.second; // FIXME: Don't use deep access to modinst members @@ -317,7 +308,7 @@ std::vector GeometryEvaluator::collectChildren3D(const Abstrac if (chgeom) { if (chgeom->getDimension() == 3) { - children.push_back(chgeom.get()); + children.push_back(item); } else { PRINT("ERROR: Only 3D children are supported by this operation!"); @@ -330,7 +321,7 @@ std::vector GeometryEvaluator::collectChildren3D(const Abstrac /*! */ -Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCADOperator op) +Polygon2d *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCADOperator op) { if (op == OPENSCAD_MINKOWSKI) { return applyMinkowski2D(node); @@ -341,7 +332,7 @@ Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCA ClipperLib::Clipper sumclipper; bool first = true; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { const AbstractNode *chnode = item.first; const shared_ptr &chgeom = item.second; // FIXME: Don't use deep access to modinst members @@ -837,7 +828,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node) if (!node.cut_mode) { ClipperLib::Clipper sumclipper; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { + BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { const AbstractNode *chnode = item.first; const shared_ptr &chgeom = item.second; // FIXME: Don't use deep access to modinst members @@ -907,7 +898,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node) Nptr = createNefPolyhedronFromGeometry(*geometry); } if (!Nptr->isNull()) { - CGAL_Nef_polyhedron nef_poly = CGAL_project(*Nptr, node.cut_mode); + CGAL_Nef_polyhedron nef_poly = CGALUtils::project(*Nptr, node.cut_mode); Polygon2d *poly = nef_poly.convertToPolygon2d(); assert(poly); poly->setConvexity(node.convexity); diff --git a/src/GeometryEvaluator.h b/src/GeometryEvaluator.h index 1b128296..18ee4781 100644 --- a/src/GeometryEvaluator.h +++ b/src/GeometryEvaluator.h @@ -4,6 +4,7 @@ #include "visitor.h" #include "enums.h" #include "memory.h" +#include "Geometry.h" #include #include @@ -16,8 +17,8 @@ public: GeometryEvaluator(const class Tree &tree); virtual ~GeometryEvaluator() {} - shared_ptr getGeometry(const AbstractNode &node, bool cache); - shared_ptr evaluateGeometry(const AbstractNode &node, bool allownef); + shared_ptr getGeometry(const AbstractNode &node, bool cache); + shared_ptr evaluateGeometry(const AbstractNode &node, bool allownef); virtual Response visit(State &state, const AbstractNode &node); virtual Response visit(State &state, const AbstractPolyNode &node); @@ -36,18 +37,16 @@ private: bool isCached(const AbstractNode &node) const; void smartCache(const AbstractNode &node, const shared_ptr &geom); std::vector collectChildren2D(const AbstractNode &node); - std::vector collectChildren3D(const AbstractNode &node); - Geometry *applyMinkowski2D(const AbstractNode &node); - Geometry *applyHull2D(const AbstractNode &node); + Geometry::ChildList collectChildren3D(const AbstractNode &node); + Polygon2d *applyMinkowski2D(const AbstractNode &node); + Polygon2d *applyHull2D(const AbstractNode &node); Geometry *applyHull3D(const AbstractNode &node); - Geometry *applyToChildren2D(const AbstractNode &node, OpenSCADOperator op); + Polygon2d *applyToChildren2D(const AbstractNode &node, OpenSCADOperator op); Geometry *applyToChildren3D(const AbstractNode &node, OpenSCADOperator op); Geometry *applyToChildren(const AbstractNode &node, OpenSCADOperator op); void addToParent(const State &state, const AbstractNode &node, const shared_ptr &geom); - typedef std::pair > ChildItem; - typedef std::list ChildList; - std::map visitedchildren; + std::map visitedchildren; const Tree &tree; shared_ptr root; diff --git a/src/cgalutils.cc b/src/cgalutils.cc index 306d04cf..a47cdb68 100644 --- a/src/cgalutils.cc +++ b/src/cgalutils.cc @@ -12,6 +12,175 @@ #include #include +namespace CGALUtils { + + bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &result) + { + // Collect point cloud + std::list points; + CGAL_Polyhedron P; + BOOST_FOREACH(const Geometry::ChildItem &item, children) { + const shared_ptr &chgeom = item.second; + const CGAL_Nef_polyhedron *N = dynamic_cast(chgeom.get()); + if (N) { + if (!N->p3->is_simple()) { + PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export"); + } + else { + N->p3->convert_to_Polyhedron(P); + std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points), + boost::bind(static_cast(&CGAL_Polyhedron::Vertex::point), _1)); + } + } + else { + const PolySet *ps = dynamic_cast(chgeom.get()); + BOOST_FOREACH(const PolySet::Polygon &p, ps->polygons) { + BOOST_FOREACH(const Vector3d &v, p) { + points.push_back(CGAL_Polyhedron::Vertex::Point_3(v[0], v[1], v[2])); + } + } + } + } + if (points.size() > 0) { + // Apply hull + if (points.size() > 3) { + CGAL::convex_hull_3(points.begin(), points.end(), result); + return true; + } + } + return false; + } + +/*! + Modifies target by applying op to target and src: + target = target [op] src +*/ + void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op) + { + if (target.getDimension() != 2 && target.getDimension() != 3) { + assert(false && "Dimension of Nef polyhedron must be 2 or 3"); + } + if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0]) + if (target.isEmpty() && op != OPENSCAD_UNION) return; // empty op => empty + if (target.getDimension() != src.getDimension()) return; // If someone tries to e.g. union 2d and 3d objects + + CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + try { + switch (op) { + case OPENSCAD_UNION: + if (target.isEmpty()) target = src.copy(); + else target += src; + break; + case OPENSCAD_INTERSECTION: + target *= src; + break; + case OPENSCAD_DIFFERENCE: + target -= src; + break; + case OPENSCAD_MINKOWSKI: + target.minkowski(src); + break; + default: + PRINTB("ERROR: Unsupported CGAL operator: %d", op); + } + } + catch (const CGAL::Failure_exception &e) { + // union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad + std::string opstr = op == OPENSCAD_UNION ? "union" : op == OPENSCAD_INTERSECTION ? "intersection" : op == OPENSCAD_DIFFERENCE ? "difference" : op == OPENSCAD_MINKOWSKI ? "minkowski" : "UNKNOWN"; + PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what()); + + // Errors can result in corrupt polyhedrons, so put back the old one + target = src; + } + CGAL::set_error_behaviour(old_behaviour); + } + + CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut) + { + logstream log(5); + CGAL_Nef_polyhedron nef_poly(2); + if (N.getDimension() != 3) return nef_poly; + + CGAL_Nef_polyhedron newN; + if (cut) { + CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + try { + CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3(0,0,1,0); + newN.p3.reset(new CGAL_Nef_polyhedron3(N.p3->intersection(xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY))); + } + catch (const CGAL::Failure_exception &e) { + PRINTB("CGAL error in projection node during plane intersection: %s", e.what()); + try { + PRINT("Trying alternative intersection using very large thin box: "); + std::vector pts; + // dont use z of 0. there are bugs in CGAL. + double inf = 1e8; + double eps = 0.001; + CGAL_Point_3 minpt( -inf, -inf, -eps ); + CGAL_Point_3 maxpt( inf, inf, eps ); + CGAL_Iso_cuboid_3 bigcuboid( minpt, maxpt ); + for ( int i=0;i<8;i++ ) pts.push_back( bigcuboid.vertex(i) ); + CGAL_Polyhedron bigbox; + CGAL::convex_hull_3(pts.begin(), pts.end(), bigbox); + CGAL_Nef_polyhedron3 nef_bigbox( bigbox ); + newN.p3.reset(new CGAL_Nef_polyhedron3(nef_bigbox.intersection(*N.p3))); + } + catch (const CGAL::Failure_exception &e) { + PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what()); + } + } + + if (!newN.p3 || newN.p3->is_empty()) { + CGAL::set_error_behaviour(old_behaviour); + PRINT("WARNING: projection() failed."); + return nef_poly; + } + + log << OpenSCAD::svg_header( 480, 100000 ) << "\n"; + try { + ZRemover zremover; + CGAL_Nef_polyhedron3::Volume_const_iterator i; + CGAL_Nef_polyhedron3::Shell_entry_const_iterator j; + CGAL_Nef_polyhedron3::SFace_const_handle sface_handle; + for ( i = newN.p3->volumes_begin(); i != newN.p3->volumes_end(); ++i ) { + log << "\n"; + for ( j = i->shells_begin(); j != i->shells_end(); ++j ) { + log << "\n"; + sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j ); + newN.p3->visit_shell_objects( sface_handle , zremover ); + log << "\n"; + } + log << "\n"; + } + nef_poly.p2 = zremover.output_nefpoly2d; + } catch (const CGAL::Failure_exception &e) { + PRINTB("CGAL error in projection node while flattening: %s", e.what()); + } + log << "\n"; + + CGAL::set_error_behaviour(old_behaviour); + } + // In projection mode all the triangles are projected manually into the XY plane + else { + PolySet *ps3 = N.convertToPolyset(); + if (!ps3) return nef_poly; + const Polygon2d *poly = PolysetUtils::project(*ps3); + + // FIXME: Convert back to Nef2 and delete poly? +/* if (nef_poly.isEmpty()) { + nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); + } + else { + (*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); + } +*/ + delete ps3; + } + return nef_poly; + } + +}; + bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps) { bool err = false; @@ -517,131 +686,5 @@ CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const Geometry &geom) return NULL; } -/*! - Modifies target by applying op to target and src: - target = target [op] src - */ -void CGAL_binary_operator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op) -{ - if (target.getDimension() != 2 && target.getDimension() != 3) { - assert(false && "Dimension of Nef polyhedron must be 2 or 3"); - } - if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0]) - if (target.isEmpty() && op != OPENSCAD_UNION) return; // empty op => empty - if (target.getDimension() != src.getDimension()) return; // If someone tries to e.g. union 2d and 3d objects - - CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); - try { - switch (op) { - case OPENSCAD_UNION: - if (target.isEmpty()) target = src.copy(); - else target += src; - break; - case OPENSCAD_INTERSECTION: - target *= src; - break; - case OPENSCAD_DIFFERENCE: - target -= src; - break; - case OPENSCAD_MINKOWSKI: - target.minkowski(src); - break; - } - } - catch (const CGAL::Failure_exception &e) { - // union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad - std::string opstr = op == OPENSCAD_UNION ? "union" : op == OPENSCAD_INTERSECTION ? "intersection" : op == OPENSCAD_DIFFERENCE ? "difference" : op == OPENSCAD_MINKOWSKI ? "minkowski" : "UNKNOWN"; - PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what()); - - // Errors can result in corrupt polyhedrons, so put back the old one - target = src; - } - CGAL::set_error_behaviour(old_behaviour); -} - -CGAL_Nef_polyhedron CGAL_project(const CGAL_Nef_polyhedron &N, bool cut) -{ - logstream log(5); - CGAL_Nef_polyhedron nef_poly(2); - if (N.getDimension() != 3) return nef_poly; - - CGAL_Nef_polyhedron newN; - if (cut) { - CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); - try { - CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3(0,0,1,0); - newN.p3.reset(new CGAL_Nef_polyhedron3(N.p3->intersection(xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY))); - } - catch (const CGAL::Failure_exception &e) { - PRINTB("CGAL error in projection node during plane intersection: %s", e.what()); - try { - PRINT("Trying alternative intersection using very large thin box: "); - std::vector pts; - // dont use z of 0. there are bugs in CGAL. - double inf = 1e8; - double eps = 0.001; - CGAL_Point_3 minpt( -inf, -inf, -eps ); - CGAL_Point_3 maxpt( inf, inf, eps ); - CGAL_Iso_cuboid_3 bigcuboid( minpt, maxpt ); - for ( int i=0;i<8;i++ ) pts.push_back( bigcuboid.vertex(i) ); - CGAL_Polyhedron bigbox; - CGAL::convex_hull_3(pts.begin(), pts.end(), bigbox); - CGAL_Nef_polyhedron3 nef_bigbox( bigbox ); - newN.p3.reset(new CGAL_Nef_polyhedron3(nef_bigbox.intersection(*N.p3))); - } - catch (const CGAL::Failure_exception &e) { - PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what()); - } - } - - if (!newN.p3 || newN.p3->is_empty()) { - CGAL::set_error_behaviour(old_behaviour); - PRINT("WARNING: projection() failed."); - return nef_poly; - } - - log << OpenSCAD::svg_header( 480, 100000 ) << "\n"; - try { - ZRemover zremover; - CGAL_Nef_polyhedron3::Volume_const_iterator i; - CGAL_Nef_polyhedron3::Shell_entry_const_iterator j; - CGAL_Nef_polyhedron3::SFace_const_handle sface_handle; - for ( i = newN.p3->volumes_begin(); i != newN.p3->volumes_end(); ++i ) { - log << "\n"; - for ( j = i->shells_begin(); j != i->shells_end(); ++j ) { - log << "\n"; - sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j ); - newN.p3->visit_shell_objects( sface_handle , zremover ); - log << "\n"; - } - log << "\n"; - } - nef_poly.p2 = zremover.output_nefpoly2d; - } catch (const CGAL::Failure_exception &e) { - PRINTB("CGAL error in projection node while flattening: %s", e.what()); - } - log << "\n"; - - CGAL::set_error_behaviour(old_behaviour); - } - // In projection mode all the triangles are projected manually into the XY plane - else { - PolySet *ps3 = N.convertToPolyset(); - if (!ps3) return nef_poly; - const Polygon2d *poly = PolysetUtils::project(*ps3); - - // FIXME: Convert back to Nef2 and delete poly? -/* if (nef_poly.isEmpty()) { - nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); - } - else { - (*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); - } -*/ - delete ps3; - } - return nef_poly; -} - #endif /* ENABLE_CGAL */ diff --git a/src/cgalutils.h b/src/cgalutils.h index 8fa8d909..071bdaa2 100644 --- a/src/cgalutils.h +++ b/src/cgalutils.h @@ -6,15 +6,18 @@ #include "CGAL_Nef_polyhedron.h" #include "enums.h" +namespace CGALUtils { + bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &P); + void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); + CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut); +}; + CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom); bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps); bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p); CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ); CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N ); -void CGAL_binary_operator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); -CGAL_Nef_polyhedron CGAL_project(const CGAL_Nef_polyhedron &N, bool cut); - #include "svg.h" #include "printutils.h" diff --git a/src/cgalworker.cc b/src/cgalworker.cc index 4acd2b39..3c1dd777 100644 --- a/src/cgalworker.cc +++ b/src/cgalworker.cc @@ -28,10 +28,10 @@ void CGALWorker::start(const Tree &tree) void CGALWorker::work() { - CGAL_Nef_polyhedron *root_N = NULL; + shared_ptr root_N; try { GeometryEvaluator evaluator(*this->tree); - root_N = new CGAL_Nef_polyhedron(evaluator.cgalevaluator->evaluateCGALMesh(*this->tree->root())); + root_N = evaluator.cgalevaluator->evaluateCGALMesh(*this->tree->root()); } catch (const ProgressCancelException &e) { PRINT("Rendering cancelled."); diff --git a/src/cgalworker.h b/src/cgalworker.h index cf60c24f..0a7f09d8 100644 --- a/src/cgalworker.h +++ b/src/cgalworker.h @@ -2,6 +2,7 @@ #define CGALWORKER_H_ #include +#include "memory.h" class CGALWorker : public QObject { @@ -17,7 +18,7 @@ protected slots: void work(); signals: - void done(class CGAL_Nef_polyhedron *); + void done(shared_ptr); protected: diff --git a/src/export.cc b/src/export.cc index cef323e8..f59ef647 100644 --- a/src/export.cc +++ b/src/export.cc @@ -37,7 +37,7 @@ Saves the current 3D CGAL Nef polyhedron as STL to the given file. The file must be open. */ -void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output) +void export_stl(const CGAL_Nef_polyhedron *root_N, std::ostream &output) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { @@ -125,7 +125,7 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output) CGAL::set_error_behaviour(old_behaviour); } -void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output) +void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { @@ -142,7 +142,7 @@ void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output) /*! Saves the current 2D CGAL Nef polyhedron as DXF to the given absolute filename. */ -void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output) +void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output) { setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output // Some importers (e.g. Inkscape) needs a BLOCKS section to be present diff --git a/src/export.h b/src/export.h index 5dae7e06..6344b057 100644 --- a/src/export.h +++ b/src/export.h @@ -7,10 +7,10 @@ #ifdef ENABLE_CGAL -void export_stl(class CGAL_Nef_polyhedron *root_N, std::ostream &output); -void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output); -void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output); -void export_png_with_cgal(CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output); +void export_stl(const class CGAL_Nef_polyhedron *root_N, std::ostream &output); +void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output); +void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output); +void export_png_with_cgal(const CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output); void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output); void export_png_with_throwntogether(Tree &tree, Camera &c, std::ostream &output); diff --git a/src/export_png.cc b/src/export_png.cc index 6d64d650..258dc309 100644 --- a/src/export_png.cc +++ b/src/export_png.cc @@ -11,7 +11,7 @@ #include "CGAL_renderer.h" #include "cgal.h" -void export_png_with_cgal(CGAL_Nef_polyhedron *root_N, Camera &cam, std::ostream &output) +void export_png_with_cgal(const CGAL_Nef_polyhedron *root_N, Camera &cam, std::ostream &output) { OffscreenView *glview; try { diff --git a/src/openscad.cc b/src/openscad.cc index 51fa5969..c61d427c 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -47,7 +47,6 @@ #ifdef ENABLE_CGAL #include "CGAL_Nef_polyhedron.h" #include "CGALEvaluator.h" -#include "PolySetCGALEvaluator.h" #endif #include "csgterm.h" @@ -250,7 +249,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c ModuleInstantiation root_inst("group"); AbstractNode *root_node; AbstractNode *absolute_root_node; - CGAL_Nef_polyhedron root_N; + shared_ptr root_N; handle_dep(filename.c_str()); @@ -359,11 +358,11 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c } if (stl_output_file) { - if (root_N.getDimension() != 3) { + if (root_N->getDimension() != 3) { PRINT("Current top level object is not a 3D object.\n"); return 1; } - if (!root_N.p3->is_simple()) { + if (!root_N->p3->is_simple()) { PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); return 1; } @@ -372,17 +371,17 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c PRINTB("Can't open file \"%s\" for export", stl_output_file); } else { - export_stl(&root_N, fstream); + export_stl(root_N.get(), fstream); fstream.close(); } } if (off_output_file) { - if (root_N.getDimension() != 3) { + if (root_N->getDimension() != 3) { PRINT("Current top level object is not a 3D object.\n"); return 1; } - if (!root_N.p3->is_simple()) { + if (!root_N->p3->is_simple()) { PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); return 1; } @@ -391,13 +390,13 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c PRINTB("Can't open file \"%s\" for export", off_output_file); } else { - export_off(&root_N, fstream); + export_off(root_N.get(), fstream); fstream.close(); } } if (dxf_output_file) { - if (root_N.getDimension() != 2) { + if (root_N->getDimension() != 2) { PRINT("Current top level object is not a 2D object.\n"); return 1; } @@ -406,7 +405,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c PRINTB("Can't open file \"%s\" for export", dxf_output_file); } else { - export_dxf(&root_N, fstream); + export_dxf(root_N.get(), fstream); fstream.close(); } } @@ -418,7 +417,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c } else { if (renderer==Render::CGAL) { - export_png_with_cgal(&root_N, camera, fstream); + export_png_with_cgal(root_N.get(), camera, fstream); } else if (renderer==Render::THROWNTOGETHER) { export_png_with_throwntogether(tree, camera, fstream); } else { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3127ab1c..79acee09 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -581,7 +581,6 @@ set(CGAL_SOURCES ../src/cgalutils.cc ../src/CGALEvaluator.cc ../src/CGALCache.cc - ../src/PolySetCGALEvaluator.cc ../src/CGAL_Nef_polyhedron_DxfData.cc ../src/cgaladv_minkowski2.cc ../src/Polygon2d-CGAL.cc @@ -591,7 +590,6 @@ set(CGAL_SOURCES set(COMMON_SOURCES ../src/nodedumper.cc ../src/traverser.cc - ../src/PolySetEvaluator.cc ../src/GeometryCache.cc ../src/clipper-utils.cc ../src/polyclipping/clipper.cpp diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index 1c74ba5f..cd425f79 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -149,9 +149,9 @@ int main(int argc, char **argv) print_messages_push(); std::cout << "First evaluation:\n"; - CGAL_Nef_polyhedron N = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node); + shared_ptr N = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node); std::cout << "Second evaluation:\n"; - CGAL_Nef_polyhedron N2 = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node); + shared_ptr N2 = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node); // FIXME: // Evaluate again to make cache kick in // Record printed output and compare it