From 7efac3940e64364e84d1bf08ee5146d50e62108c Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 22 Dec 2013 01:43:08 -0500 Subject: [PATCH] Use GeometryEvaluator instead of CGALEvaluator. A bunch of refactoring and fixes as a result of that. Renamed GUI menu items to reflect preview vs. render --- openscad.pro | 2 - src/AppleEvents.cc | 2 +- src/CGALRenderer.cc | 20 ++-- src/CGALRenderer.h | 4 +- src/CGAL_Nef_polyhedron.h | 3 +- src/CGAL_Nef_polyhedron_DxfData.cc | 1 - src/CSGTermEvaluator.cc | 22 ++-- src/GeometryEvaluator.cc | 124 ++++++++++--------- src/GeometryEvaluator.h | 2 - src/MainWindow.h | 16 +-- src/MainWindow.ui | 40 +++---- src/OpenCSGRenderer.cc | 20 ++-- src/cgaladv.cc | 6 - src/cgaladvnode.h | 1 - src/cgalutils.cc | 2 +- src/cgalworker.cc | 7 +- src/cgalworker.h | 2 +- src/csgterm.cc | 14 ++- src/export.cc | 59 +++++++++ src/export.h | 12 +- src/export_png.cc | 17 ++- src/linearextrude.cc | 18 +-- src/linearextrudenode.h | 1 - src/mainwin.cc | 184 ++++++++++++++++------------- src/openscad.cc | 38 +++--- src/polyset.h | 1 + src/primitives.cc | 7 +- src/projection.cc | 17 --- src/projectionnode.h | 1 - src/render.cc | 6 - src/rendernode.h | 1 - src/rotateextrude.cc | 17 --- src/rotateextrudenode.h | 1 - src/surface.cc | 1 - tests/CMakeLists.txt | 1 - tests/CSGTextRenderer.cc | 2 + tests/cgalcachetest.cc | 5 +- 37 files changed, 356 insertions(+), 321 deletions(-) diff --git a/openscad.pro b/openscad.pro index 7c01b798..bae41a9e 100644 --- a/openscad.pro +++ b/openscad.pro @@ -379,7 +379,6 @@ cgal { HEADERS += src/cgal.h \ src/cgalfwd.h \ src/cgalutils.h \ - src/CGALEvaluator.h \ src/CGALCache.h \ src/CGALRenderer.h \ src/CGAL_Nef_polyhedron.h \ @@ -388,7 +387,6 @@ HEADERS += src/cgal.h \ src/Polygon2d-CGAL.h SOURCES += src/cgalutils.cc \ - src/CGALEvaluator.cc \ src/CGALCache.cc \ src/CGALRenderer.cc \ src/CGAL_Nef_polyhedron.cc \ diff --git a/src/AppleEvents.cc b/src/AppleEvents.cc index 3102792c..a1eb6e1a 100644 --- a/src/AppleEvents.cc +++ b/src/AppleEvents.cc @@ -15,7 +15,7 @@ OSErr eventHandler(const AppleEvent *, AppleEvent *, SRefCon ) if (mainwin) break; } if (mainwin) { - mainwin->actionReloadRenderCSG(); + mainwin->actionReloadRenderPreview(); } return noErr; } diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc index a85ed496..1af4ad43 100644 --- a/src/CGALRenderer.cc +++ b/src/CGALRenderer.cc @@ -41,21 +41,21 @@ //#include "Preferences.h" -CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root) +CGALRenderer::CGALRenderer(shared_ptr root) : root(root) { - if (this->root.isNull()) { + if (this->root->isNull()) { this->polyhedron = NULL; this->polyset = NULL; } - else if (root.getDimension() == 2) { - DxfData *dd = root.convertToDxfData(); + else if (root->getDimension() == 2) { + DxfData *dd = root->convertToDxfData(); this->polyhedron = NULL; this->polyset = new PolySet(); this->polyset->is2d = true; dxf_tesselate(this->polyset, *dd, 0, Vector2d(1,1), true, false, 0); delete dd; } - else if (root.getDimension() == 3) { + else if (root->getDimension() == 3) { this->polyset = NULL; this->polyhedron = new Polyhedron(); // FIXME: Make independent of Preferences @@ -68,7 +68,7 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root) // Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).green(), // Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).blue()); - CGAL::OGL::Nef3_Converter::convert_to_OGLPolyhedron(*this->root.p3, this->polyhedron); + CGAL::OGL::Nef3_Converter::convert_to_OGLPolyhedron(*this->root->p3, this->polyhedron); this->polyhedron->init(); } } @@ -81,8 +81,8 @@ CGALRenderer::~CGALRenderer() void CGALRenderer::draw(bool showfaces, bool showedges) const { - if (this->root.isNull()) return; - if (this->root.getDimension() == 2) { + if (this->root->isNull()) return; + if (this->root->getDimension() == 2) { // Draw 2D polygons glDisable(GL_LIGHTING); // FIXME: const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR); @@ -101,7 +101,7 @@ void CGALRenderer::draw(bool showfaces, bool showedges) const typedef Explorer::Face_const_iterator fci_t; typedef Explorer::Halfedge_around_face_const_circulator heafcc_t; typedef Explorer::Point Point; - Explorer E = this->root.p2->explorer(); + Explorer E = this->root->p2->explorer(); // Draw 2D edges glDisable(GL_DEPTH_TEST); @@ -135,7 +135,7 @@ void CGALRenderer::draw(bool showfaces, bool showedges) const glEnable(GL_DEPTH_TEST); } - else if (this->root.getDimension() == 3) { + else if (this->root->getDimension() == 3) { if (showfaces) this->polyhedron->set_style(SNC_BOUNDARY); else this->polyhedron->set_style(SNC_SKELETON); diff --git a/src/CGALRenderer.h b/src/CGALRenderer.h index 9c19e5ae..65615b4f 100644 --- a/src/CGALRenderer.h +++ b/src/CGALRenderer.h @@ -6,12 +6,12 @@ class CGALRenderer : public Renderer { public: - CGALRenderer(const class CGAL_Nef_polyhedron &root); + CGALRenderer(shared_ptr root); ~CGALRenderer(); void draw(bool showfaces, bool showedges) const; public: - const CGAL_Nef_polyhedron &root; + const shared_ptr root; class Polyhedron *polyhedron; class PolySet *polyset; }; diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h index 4339e795..6a8920ee 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -16,7 +16,8 @@ public: ~CGAL_Nef_polyhedron() {} virtual size_t memsize() const; - virtual BoundingBox getBoundingBox() const {}; // FIXME: Implement + // FIXME: Implement, but we probably want a high-resolution BBox.. + virtual BoundingBox getBoundingBox() const { assert(false && "not implemented"); } virtual std::string dump() const; virtual unsigned int getDimension() const { return this->dim; } diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc index 3b700d95..17e8a0c0 100644 --- a/src/CGAL_Nef_polyhedron_DxfData.cc +++ b/src/CGAL_Nef_polyhedron_DxfData.cc @@ -33,7 +33,6 @@ #include #include "polyset.h" #include "dxftess.h" -#include "CGALEvaluator.h" #include "Tree.h" #ifdef ENABLE_CGAL diff --git a/src/CSGTermEvaluator.cc b/src/CSGTermEvaluator.cc index f6490649..854d91de 100644 --- a/src/CSGTermEvaluator.cc +++ b/src/CSGTermEvaluator.cc @@ -113,11 +113,9 @@ Response CSGTermEvaluator::visit(State &state, const AbstractPolyNode &node) shared_ptr t1; if (this->geomevaluator) { shared_ptr geom = this->geomevaluator->evaluateGeometry(node, false); - if (geom) { - t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background, - geom, node.modinst, node); - node.progress_report(); - } + t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background, + geom, node.modinst, node); + node.progress_report(); } this->stored_term[node.index()] = t1; addToParent(state, node); @@ -182,10 +180,8 @@ Response CSGTermEvaluator::visit(State &state, const RenderNode &node) geom = this->geomevaluator->evaluateGeometry(node, false); node.progress_report(); } - if (geom) { - t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background, - geom, node.modinst, node); - } + t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background, + geom, node.modinst, node); this->stored_term[node.index()] = t1; addToParent(state, node); } @@ -201,11 +197,9 @@ Response CSGTermEvaluator::visit(State &state, const CgaladvNode &node) if (this->geomevaluator) { geom = this->geomevaluator->evaluateGeometry(node, false); } - if (geom) { - t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background, - geom, node.modinst, node); - node.progress_report(); - } + t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background, + geom, node.modinst, node); + node.progress_report(); this->stored_term[node.index()] = t1; addToParent(state, node); } diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index 2ec1b8b6..66899c65 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -17,7 +17,6 @@ #include "rendernode.h" #include "clipper-utils.h" #include "polyset-utils.h" -#include "CGALEvaluator.h" #include "PolySet.h" #include "openscad.h" // get_fragments_from_r() #include "printutils.h" @@ -32,7 +31,6 @@ GeometryEvaluator::GeometryEvaluator(const class Tree &tree): tree(tree) { - this->cgalevaluator = new CGALEvaluator(tree, *this); } /*! @@ -80,6 +78,7 @@ shared_ptr GeometryEvaluator::evaluateGeometry(const AbstractNod if (!allownef) { shared_ptr N = dynamic_pointer_cast(this->root); if (N) { + assert(N->getDimension() != 2); // FIXME: Remove 2D code if (N->getDimension() == 2) this->root.reset(N->convertToPolygon2d()); else if (N->getDimension() == 3) this->root.reset(N->convertToPolyset()); else this->root.reset(); @@ -99,7 +98,8 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren(const Abstrac if (item.second) { if (!dim) dim = item.second->getDimension(); else if (dim != item.second->getDimension()) { - return ResultObject(); + PRINT("WARNING: Mixing 2D and 3D objects is not supported."); + break; } } } @@ -128,17 +128,22 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; 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)); + shared_ptr chN; + if (!chgeom) { + chN.reset(new CGAL_Nef_polyhedron(3)); // Create null polyhedron + } + else { + 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); - } + // 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(); } @@ -225,6 +230,7 @@ void GeometryEvaluator::applyResize3D(CGAL_Nef_polyhedron &N, const Vector3d &newsize, const Eigen::Matrix &autosize) { + assert(N.getDimension() != 2); // FIXME: Remove 2D code // Based on resize() in Giles Bathgate's RapCAD (but not exactly) if (N.isNull() || N.isEmpty()) return; @@ -312,15 +318,13 @@ std::vector GeometryEvaluator::collectChildren2D(const GeometryCache::instance()->insert(this->tree.getIdString(*chnode), chgeom); } - if (chgeom) { - if (chgeom->getDimension() == 2) { + if (chgeom && chgeom->getDimension() == 2) { const Polygon2d *polygons = dynamic_cast(chgeom.get()); assert(polygons); children.push_back(polygons); - } - else { - PRINT("ERROR: Only 2D children are supported by this operation!"); - } + } + else { + PRINT("ERROR: Only 2D children are supported by this operation!"); } } return children; @@ -361,13 +365,13 @@ Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &nod // sibling object. smartCache(*chnode, chgeom); - if (chgeom) { - if (chgeom->getDimension() == 3) { + if (chgeom && chgeom->getDimension() == 3) { children.push_back(item); - } - else { - PRINT("ERROR: Only 3D children are supported by this operation!"); - } + } + else { + PRINT("ERROR: Only 3D children are supported by this operation!"); + shared_ptr nullptr; + children.push_back(Geometry::ChildItem(item.first, nullptr)); } } return children; @@ -594,43 +598,44 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node) else { // First union all children ResultObject res = applyToChildren(node, OPENSCAD_UNION); - geom = res.constptr(); - if (geom->getDimension() == 2) { - shared_ptr polygons = dynamic_pointer_cast(geom); - assert(polygons); - - // If we got a const object, make a copy - shared_ptr newpoly; - if (res.isConst()) newpoly.reset(new Polygon2d(*polygons)); - else newpoly = dynamic_pointer_cast(res.ptr()); - - Transform2d mat2; - mat2.matrix() << - node.matrix(0,0), node.matrix(0,1), node.matrix(0,3), - node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), - node.matrix(3,0), node.matrix(3,1), node.matrix(3,3); - newpoly->transform(mat2); - geom = newpoly; - } - else if (geom->getDimension() == 3) { - shared_ptr ps = dynamic_pointer_cast(geom); - if (ps) { + if ((geom = res.constptr())) { + if (geom->getDimension() == 2) { + shared_ptr polygons = dynamic_pointer_cast(geom); + assert(polygons); + // If we got a const object, make a copy - shared_ptr newps; - if (res.isConst()) newps.reset(new PolySet(*ps)); - else newps = dynamic_pointer_cast(res.ptr()); - newps->transform(node.matrix); - geom = newps; + shared_ptr newpoly; + if (res.isConst()) newpoly.reset(new Polygon2d(*polygons)); + else newpoly = dynamic_pointer_cast(res.ptr()); + + Transform2d mat2; + mat2.matrix() << + node.matrix(0,0), node.matrix(0,1), node.matrix(0,3), + node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), + node.matrix(3,0), node.matrix(3,1), node.matrix(3,3); + newpoly->transform(mat2); + geom = newpoly; } - else { - shared_ptr N = dynamic_pointer_cast(geom); - assert(N); - // If we got a const object, make a copy - shared_ptr newN; - if (res.isConst()) newN.reset(new CGAL_Nef_polyhedron(*N)); - else newN = dynamic_pointer_cast(res.ptr()); - newN->transform(node.matrix); - geom = newN; + else if (geom->getDimension() == 3) { + shared_ptr ps = dynamic_pointer_cast(geom); + if (ps) { + // If we got a const object, make a copy + shared_ptr newps; + if (res.isConst()) newps.reset(new PolySet(*ps)); + else newps = dynamic_pointer_cast(res.ptr()); + newps->transform(node.matrix); + geom = newps; + } + else { + shared_ptr N = dynamic_pointer_cast(geom); + assert(N); + // If we got a const object, make a copy + shared_ptr newN; + if (res.isConst()) newN.reset(new CGAL_Nef_polyhedron(*N)); + else newN = dynamic_pointer_cast(res.ptr()); + newN->transform(node.matrix); + geom = newN; + } } } } @@ -1096,6 +1101,7 @@ Response GeometryEvaluator::visit(State &state, const RenderNode &node) geom = applyToChildren(node, OPENSCAD_UNION).constptr(); shared_ptr N = dynamic_pointer_cast(geom); if (N) { + assert(N->getDimension() != 2); // FIXME: Remove 2D code PolySet *ps = NULL; if (!N->isNull()) { if (N->getDimension() == 3 && !N->p3->is_simple()) { diff --git a/src/GeometryEvaluator.h b/src/GeometryEvaluator.h index 24aa0e6a..df920073 100644 --- a/src/GeometryEvaluator.h +++ b/src/GeometryEvaluator.h @@ -70,8 +70,6 @@ private: shared_ptr root; public: -// FIXME: Deal with visibility - class CGALEvaluator *cgalevaluator; }; diff --git a/src/MainWindow.h b/src/MainWindow.h index a132d2bf..c493d51c 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -41,7 +41,7 @@ public: shared_ptr root_norm_term; // Normalized CSG products class CSGChain *root_chain; #ifdef ENABLE_CGAL - shared_ptr root_N; + shared_ptr root_geom; class CGALRenderer *cgalRenderer; #endif #ifdef ENABLE_OPENCSG @@ -116,12 +116,12 @@ private slots: void preferences(); private slots: - void actionRenderCSG(); + void actionRenderPreview(); void csgRender(); void csgReloadRender(); #ifdef ENABLE_CGAL - void actionRenderCGAL(); - void actionRenderCGALDone(shared_ptr); + void actionRender(); + void actionRenderDone(shared_ptr); void cgalRender(); #endif void actionDisplayAST(); @@ -142,13 +142,13 @@ public: void clearCurrentOutput(); public slots: - void actionReloadRenderCSG(); + void actionReloadRenderPreview(); #ifdef ENABLE_OPENCSG - void viewModeOpenCSG(); + void viewModePreview(); #endif #ifdef ENABLE_CGAL - void viewModeCGALSurface(); - void viewModeCGALGrid(); + void viewModeSurface(); + void viewModeWireframe(); #endif void viewModeThrownTogether(); void viewModeShowEdges(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 4cb043f9..147a41f2 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -174,9 +174,9 @@ &Design - - - + + + @@ -194,9 +194,9 @@ &View - - - + + + @@ -233,8 +233,8 @@ - + @@ -395,25 +395,25 @@ Hide editor - + - &Reload and Compile + &Reload and Preview F4 - + - &Compile + &Preview F5 - + - Compile and &Render (CGAL) + &Render F6 @@ -444,34 +444,34 @@ Export as &OFF... - + true - OpenCSG + Preview F9 - + true - CGAL Surfaces + Surfaces F10 - + true - CGAL Grid Only + Wireframe F11 @@ -668,7 +668,7 @@ true - Automatic Reload and Compile + Automatic Reload and Preview diff --git a/src/OpenCSGRenderer.cc b/src/OpenCSGRenderer.cc index df802427..c56dad13 100644 --- a/src/OpenCSGRenderer.cc +++ b/src/OpenCSGRenderer.cc @@ -133,15 +133,17 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo, if (last) break; - OpenCSGPrim *prim = new OpenCSGPrim(i_obj.type == CSGTerm::TYPE_DIFFERENCE ? - OpenCSG::Subtraction : OpenCSG::Intersection, i_obj.geom->getConvexity()); - - prim->geom = i_obj.geom; - prim->m = i_obj.matrix; - prim->csgmode = i_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : CSGMODE_NORMAL; - if (highlight) prim->csgmode = csgmode_e(prim->csgmode + 20); - else if (background) prim->csgmode = csgmode_e(prim->csgmode + 10); - primitives.push_back(prim); + if (i_obj.geom) { + OpenCSGPrim *prim = new OpenCSGPrim(i_obj.type == CSGTerm::TYPE_DIFFERENCE ? + OpenCSG::Subtraction : OpenCSG::Intersection, i_obj.geom->getConvexity()); + + prim->geom = i_obj.geom; + prim->m = i_obj.matrix; + prim->csgmode = i_obj.type == CSGTerm::TYPE_DIFFERENCE ? CSGMODE_DIFFERENCE : CSGMODE_NORMAL; + if (highlight) prim->csgmode = csgmode_e(prim->csgmode + 20); + else if (background) prim->csgmode = csgmode_e(prim->csgmode + 10); + primitives.push_back(prim); + } } std::for_each(primitives.begin(), primitives.end(), del_fun()); } diff --git a/src/cgaladv.cc b/src/cgaladv.cc index 43e60f82..82100023 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -28,7 +28,6 @@ #include "module.h" #include "evalcontext.h" #include "builtin.h" -#include "PolySetEvaluator.h" #include "polyset.h" #include #include @@ -117,11 +116,6 @@ AbstractNode *CgaladvModule::instantiate(const Context *ctx, const ModuleInstant return node; } -Geometry *CgaladvNode::evaluate_geometry(PolySetEvaluator *ps) const -{ - return ps->evaluateGeometry(*this); -} - std::string CgaladvNode::name() const { switch (this->type) { diff --git a/src/cgaladvnode.h b/src/cgaladvnode.h index f3b4db97..71cf6838 100644 --- a/src/cgaladvnode.h +++ b/src/cgaladvnode.h @@ -26,7 +26,6 @@ public: } virtual std::string toString() const; virtual std::string name() const; - Geometry *evaluate_geometry(class PolySetEvaluator *ps) const; Value path; std::string subdiv_type; diff --git a/src/cgalutils.cc b/src/cgalutils.cc index d1fa323f..2a5d8e15 100644 --- a/src/cgalutils.cc +++ b/src/cgalutils.cc @@ -692,7 +692,7 @@ CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const Geometry &geom) const Polygon2d *poly2d = dynamic_cast(&geom); if (poly2d) return createNefPolyhedronFromPolygon2d(*poly2d); } - assert(false && "CGALEvaluator::evaluateCGALMesh(): Unsupported geometry type"); + assert(false && "createNefPolyhedronFromGeometry(): Unsupported geometry type"); return NULL; } diff --git a/src/cgalworker.cc b/src/cgalworker.cc index 3c1dd777..d0709e36 100644 --- a/src/cgalworker.cc +++ b/src/cgalworker.cc @@ -3,7 +3,6 @@ #include "Tree.h" #include "GeometryEvaluator.h" -#include "CGALEvaluator.h" #include "progress.h" #include "printutils.h" @@ -28,15 +27,15 @@ void CGALWorker::start(const Tree &tree) void CGALWorker::work() { - shared_ptr root_N; + shared_ptr root_geom; try { GeometryEvaluator evaluator(*this->tree); - root_N = evaluator.cgalevaluator->evaluateCGALMesh(*this->tree->root()); + root_geom = evaluator.evaluateGeometry(*this->tree->root(), true); } catch (const ProgressCancelException &e) { PRINT("Rendering cancelled."); } - emit done(root_N); + emit done(root_geom); thread->quit(); } diff --git a/src/cgalworker.h b/src/cgalworker.h index 0a7f09d8..bf17e201 100644 --- a/src/cgalworker.h +++ b/src/cgalworker.h @@ -18,7 +18,7 @@ protected slots: void work(); signals: - void done(shared_ptr); + void done(shared_ptr); protected: diff --git a/src/csgterm.cc b/src/csgterm.cc index 54d24ec3..e50018a7 100644 --- a/src/csgterm.cc +++ b/src/csgterm.cc @@ -38,6 +38,11 @@ may or may not have a subtree which is already evaluated (e.g. using the render() module). + Note: To distinguish between geometry evaluated to an empty volume + and non-geometric nodes (e.g. echo), a NULL CSGTerm is considered a + non-geometric node, while a CSGTerm with a NULL geometry is + considered empty geometry. This is important when e.g. establishing + positive vs. negative volumes using the difference operator. */ /*! @@ -128,6 +133,7 @@ CSGTerm::~CSGTerm() void CSGTerm::initBoundingBox() { if (this->type == TYPE_PRIMITIVE) { + if (!this->geom) return; this->bbox = this->m * this->geom->getBoundingBox(); } else { @@ -223,9 +229,11 @@ BoundingBox CSGChain::getBoundingBox() const BoundingBox bbox; BOOST_FOREACH(const CSGChainObject &obj, this->objects) { if (obj.type != CSGTerm::TYPE_DIFFERENCE) { - BoundingBox psbox = obj.geom->getBoundingBox(); - if (!psbox.isNull()) { - bbox.extend(obj.matrix * psbox); + if (obj.geom) { + BoundingBox psbox = obj.geom->getBoundingBox(); + if (!psbox.isNull()) { + bbox.extend(obj.matrix * psbox); + } } } } diff --git a/src/export.cc b/src/export.cc index f59ef647..8abfc917 100644 --- a/src/export.cc +++ b/src/export.cc @@ -29,16 +29,72 @@ #include "polyset.h" #include "dxfdata.h" +#include + #ifdef ENABLE_CGAL #include "CGAL_Nef_polyhedron.h" #include "cgal.h" +void exportFile(const class Geometry *root_geom, std::ostream &output, FileFormat format) +{ + if (const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom)) { + + switch (format) { + case OPENSCAD_STL: + export_stl(N, output); + break; + case OPENSCAD_OFF: + export_off(N, output); + break; + case OPENSCAD_DXF: + export_dxf(N, output); + break; + default: + assert(false && "Unknown file format"); + } + } + else { + if (const PolySet *ps = dynamic_cast(root_geom)) { + switch (format) { + case OPENSCAD_STL: + export_stl(ps, output); + break; + default: + assert(false && "Unsupported file format"); + } + } + else { + assert(false && "Not implemented"); + } + } +} + +void export_stl(const PolySet *ps, std::ostream &output) +{ + setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output + output << "solid OpenSCAD_Model\n"; + BOOST_FOREACH(const PolySet::Polygon &p, ps->polygons) { + output << " facet normal 0 0 0\n"; + output << " outer loop\n"; + BOOST_FOREACH(const Vector3d &v, p) { + output << "vertex" << v[0] << " " << v[1] << " " << v[2] << "\n"; + } + output << " endloop\n"; + output << " endfacet\n"; + } + output << "endsolid OpenSCAD_Model\n"; + setlocale(LC_NUMERIC, ""); // Set default locale +} + /*! Saves the current 3D CGAL Nef polyhedron as STL to the given file. The file must be open. */ void export_stl(const CGAL_Nef_polyhedron *root_N, std::ostream &output) { + if (!root_N->p3->is_simple()) { + PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); + } CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { CGAL_Polyhedron P; @@ -127,6 +183,9 @@ void export_stl(const CGAL_Nef_polyhedron *root_N, std::ostream &output) void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output) { + if (!root_N->p3->is_simple()) { + PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); + } CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { CGAL_Polyhedron P; diff --git a/src/export.h b/src/export.h index 6344b057..7df58263 100644 --- a/src/export.h +++ b/src/export.h @@ -7,10 +7,20 @@ #ifdef ENABLE_CGAL +enum FileFormat { + OPENSCAD_STL, + OPENSCAD_OFF, + OPENSCAD_DXF +}; + +void exportFile(const class Geometry *root_geom, std::ostream &output, FileFormat format); +void export_png(const class Geometry *root_geom, Camera &c, std::ostream &output); + void export_stl(const class CGAL_Nef_polyhedron *root_N, std::ostream &output); +void export_stl(const class PolySet *ps, 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(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 258dc309..0f8fc526 100644 --- a/src/export_png.cc +++ b/src/export_png.cc @@ -10,8 +10,20 @@ #include "CGALRenderer.h" #include "CGAL_renderer.h" #include "cgal.h" +#include "cgalutils.h" +#include "CGAL_Nef_polyhedron.h" -void export_png_with_cgal(const CGAL_Nef_polyhedron *root_N, Camera &cam, std::ostream &output) +void export_png(const Geometry *root_geom, Camera &cam, std::ostream &output) +{ + const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom); + if (!N) { + // FIXME: Support rendering non-Nef directly + N = createNefPolyhedronFromGeometry(*root_geom); + } + export_png(N, cam, output); +} + +void export_png(const CGAL_Nef_polyhedron *root_N, Camera &cam, std::ostream &output) { OffscreenView *glview; try { @@ -20,7 +32,8 @@ void export_png_with_cgal(const CGAL_Nef_polyhedron *root_N, Camera &cam, std::o fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i.\n", error); return; } - CGALRenderer cgalRenderer(*root_N); + shared_ptr ptr(root_N); + CGALRenderer cgalRenderer(ptr); BoundingBox bbox; if (cgalRenderer.polyhedron) { diff --git a/src/linearextrude.cc b/src/linearextrude.cc index e1f9ec78..0c1cc119 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -31,8 +31,8 @@ #include "printutils.h" #include "fileutils.h" #include "builtin.h" -#include "PolySetEvaluator.h" #include "calc.h" +#include "polyset.h" #include "mathc99.h" #include @@ -127,22 +127,6 @@ AbstractNode *LinearExtrudeModule::instantiate(const Context *ctx, const ModuleI return node; } -class Geometry *LinearExtrudeNode::evaluate_geometry(PolySetEvaluator *evaluator) const -{ - if (!evaluator) { - PRINTB("WARNING: No suitable PolySetEvaluator found for %s module!", this->name()); - return NULL; - } - - print_messages_push(); - - Geometry *ps = evaluator->evaluateGeometry(*this); - - print_messages_pop(); - - return ps; -} - std::string LinearExtrudeNode::toString() const { std::stringstream stream; diff --git a/src/linearextrudenode.h b/src/linearextrudenode.h index 5f5f5c03..ca5e32d1 100644 --- a/src/linearextrudenode.h +++ b/src/linearextrudenode.h @@ -27,7 +27,6 @@ public: bool center, has_twist; Filename filename; std::string layername; - virtual Geometry *evaluate_geometry(class PolySetEvaluator *) const; }; #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index 0020b038..9916f3f2 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -86,12 +86,12 @@ #ifdef ENABLE_CGAL #include "CGALCache.h" -#include "CGALEvaluator.h" #include "GeometryEvaluator.h" #include "CGALRenderer.h" #include "CGAL_Nef_polyhedron.h" #include "cgal.h" #include "cgalworker.h" +#include "cgalutils.h" #else @@ -160,8 +160,8 @@ MainWindow::MainWindow(const QString &filename) #ifdef ENABLE_CGAL this->cgalworker = new CGALWorker(); - connect(this->cgalworker, SIGNAL(done(shared_ptr)), - this, SLOT(actionRenderCGALDone(shared_ptr))); + connect(this->cgalworker, SIGNAL(done(shared_ptr)), + this, SLOT(actionRenderDone(shared_ptr))); #endif top_ctx.registerBuiltin(); @@ -206,7 +206,7 @@ MainWindow::MainWindow(const QString &filename) waitAfterReloadTimer->setInterval(200); connect(waitAfterReloadTimer, SIGNAL(timeout()), this, SLOT(waitAfterReload())); - connect(this->e_tval, SIGNAL(textChanged(QString)), this, SLOT(actionRenderCSG())); + connect(this->e_tval, SIGNAL(textChanged(QString)), this, SLOT(actionRenderPreview())); connect(this->e_fps, SIGNAL(textChanged(QString)), this, SLOT(updatedFps())); animate_panel->hide(); @@ -285,12 +285,12 @@ MainWindow::MainWindow(const QString &filename) // Design menu connect(this->designActionAutoReload, SIGNAL(toggled(bool)), this, SLOT(autoReloadSet(bool))); - connect(this->designActionReloadAndCompile, SIGNAL(triggered()), this, SLOT(actionReloadRenderCSG())); - connect(this->designActionCompile, SIGNAL(triggered()), this, SLOT(actionRenderCSG())); + connect(this->designActionReloadAndPreview, SIGNAL(triggered()), this, SLOT(actionReloadRenderPreview())); + connect(this->designActionPreview, SIGNAL(triggered()), this, SLOT(actionRenderPreview())); #ifdef ENABLE_CGAL - connect(this->designActionCompileAndRender, SIGNAL(triggered()), this, SLOT(actionRenderCGAL())); + connect(this->designActionRender, SIGNAL(triggered()), this, SLOT(actionRender())); #else - this->designActionCompileAndRender->setVisible(false); + this->designActionRender->setVisible(false); #endif connect(this->designActionDisplayAST, SIGNAL(triggered()), this, SLOT(actionDisplayAST())); connect(this->designActionDisplayCSGTree, SIGNAL(triggered()), this, SLOT(actionDisplayCSGTree())); @@ -304,20 +304,20 @@ MainWindow::MainWindow(const QString &filename) // View menu #ifndef ENABLE_OPENCSG - this->viewActionOpenCSG->setVisible(false); + this->viewActionPreview->setVisible(false); #else - connect(this->viewActionOpenCSG, SIGNAL(triggered()), this, SLOT(viewModeOpenCSG())); + connect(this->viewActionPreview, SIGNAL(triggered()), this, SLOT(viewModePreview())); if (!this->qglview->hasOpenCSGSupport()) { - this->viewActionOpenCSG->setEnabled(false); + this->viewActionPreview->setEnabled(false); } #endif #ifdef ENABLE_CGAL - connect(this->viewActionCGALSurfaces, SIGNAL(triggered()), this, SLOT(viewModeCGALSurface())); - connect(this->viewActionCGALGrid, SIGNAL(triggered()), this, SLOT(viewModeCGALGrid())); + connect(this->viewActionSurfaces, SIGNAL(triggered()), this, SLOT(viewModeSurface())); + connect(this->viewActionWireframe, SIGNAL(triggered()), this, SLOT(viewModeWireframe())); #else - this->viewActionCGALSurfaces->setVisible(false); - this->viewActionCGALGrid->setVisible(false); + this->viewActionSurfaces->setVisible(false); + this->viewActionWireframe->setVisible(false); #endif connect(this->viewActionThrownTogether, SIGNAL(triggered()), this, SLOT(viewModeThrownTogether())); connect(this->viewActionShowEdges, SIGNAL(triggered()), this, SLOT(viewModeShowEdges())); @@ -385,7 +385,7 @@ MainWindow::MainWindow(const QString &filename) show(); #ifdef ENABLE_OPENCSG - viewModeOpenCSG(); + viewModePreview(); #else viewModeThrownTogether(); #endif @@ -446,7 +446,7 @@ MainWindow::~MainWindow() if (root_module) delete root_module; if (root_node) delete root_node; #ifdef ENABLE_CGAL - this->root_N.reset(); + this->root_geom.reset(); delete this->cgalRenderer; #endif #ifdef ENABLE_OPENCSG @@ -581,7 +581,7 @@ void MainWindow::updateTVal() double fps = this->e_fps->text().toDouble(&fps_ok); if (fps_ok) { if (fps <= 0) { - actionRenderCSG(); + actionRenderPreview(); } else { double s = this->e_fsteps->text().toDouble(); double t = this->e_tval->text().toDouble() + 1/s; @@ -1159,7 +1159,7 @@ void MainWindow::compileTopLevelDocument() void MainWindow::checkAutoReload() { if (!this->fileName.isEmpty()) { - actionReloadRenderCSG(); + actionReloadRenderPreview(); } } @@ -1190,7 +1190,7 @@ bool MainWindow::checkEditorModified() return true; } -void MainWindow::actionReloadRenderCSG() +void MainWindow::actionReloadRenderPreview() { if (GuiLocker::isLocked()) return; GuiLocker::lock(); @@ -1214,7 +1214,7 @@ void MainWindow::csgReloadRender() } else { #ifdef ENABLE_OPENCSG - viewModeOpenCSG(); + viewModePreview(); #else viewModeThrownTogether(); #endif @@ -1222,7 +1222,7 @@ void MainWindow::csgReloadRender() compileEnded(); } -void MainWindow::actionRenderCSG() +void MainWindow::actionRenderPreview() { if (GuiLocker::isLocked()) return; GuiLocker::lock(); @@ -1246,7 +1246,7 @@ void MainWindow::csgRender() } else { #ifdef ENABLE_OPENCSG - viewModeOpenCSG(); + viewModePreview(); #else viewModeThrownTogether(); #endif @@ -1266,7 +1266,7 @@ void MainWindow::csgRender() #ifdef ENABLE_CGAL -void MainWindow::actionRenderCGAL() +void MainWindow::actionRender() { if (GuiLocker::isLocked()) return; GuiLocker::lock(); @@ -1289,7 +1289,7 @@ void MainWindow::cgalRender() this->qglview->setRenderer(NULL); delete this->cgalRenderer; this->cgalRenderer = NULL; - this->root_N.reset(); + this->root_geom.reset(); PRINT("Rendering Polygon Mesh using CGAL..."); @@ -1301,60 +1301,75 @@ void MainWindow::cgalRender() this->cgalworker->start(this->tree); } -void MainWindow::actionRenderCGALDone(shared_ptr root_N) +void MainWindow::actionRenderDone(shared_ptr root_geom) { progress_report_fin(); - if (root_N) { + if (root_geom) { GeometryCache::instance()->print(); #ifdef ENABLE_CGAL CGALCache::instance()->print(); #endif - if (!root_N->isNull()) { - if (root_N->getDimension() == 2) { - PRINT(" Top level object is a 2D object:"); - PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no")); - PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no")); - PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices()); - PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges()); - PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges()); - PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces()); - PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles()); - PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components()); - } - - if (root_N->getDimension() == 3) { - PRINT(" Top level object is a 3D object:"); - PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no")); - PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no")); - PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices()); - PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges()); - PRINTB(" Edges: %6d", root_N->p3->number_of_edges()); - PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets()); - PRINTB(" Facets: %6d", root_N->p3->number_of_facets()); - PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes()); - } - } int s = this->progresswidget->elapsedTime() / 1000; PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60)); - - this->root_N = root_N; - if (!this->root_N->isNull()) { - this->cgalRenderer = new CGALRenderer(*this->root_N); - // Go to CGAL view mode - if (viewActionCGALGrid->isChecked()) { - viewModeCGALGrid(); - } - else { - viewModeCGALSurface(); - } - PRINT("Rendering finished."); + if (const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom.get())) { + if (!N->isNull()) { + if (N->getDimension() == 2) { + PRINT(" Top level object is a 2D object:"); + PRINTB(" Empty: %6s", (N->p2->is_empty() ? "yes" : "no")); + PRINTB(" Plane: %6s", (N->p2->is_plane() ? "yes" : "no")); + PRINTB(" Vertices: %6d", N->p2->explorer().number_of_vertices()); + PRINTB(" Halfedges: %6d", N->p2->explorer().number_of_halfedges()); + PRINTB(" Edges: %6d", N->p2->explorer().number_of_edges()); + PRINTB(" Faces: %6d", N->p2->explorer().number_of_faces()); + PRINTB(" FaceCycles: %6d", N->p2->explorer().number_of_face_cycles()); + PRINTB(" ConnComp: %6d", N->p2->explorer().number_of_connected_components()); + } + + if (N->getDimension() == 3) { + PRINT(" Top level object is a 3D object:"); + PRINTB(" Simple: %6s", (N->p3->is_simple() ? "yes" : "no")); + PRINTB(" Valid: %6s", (N->p3->is_valid() ? "yes" : "no")); + PRINTB(" Vertices: %6d", N->p3->number_of_vertices()); + PRINTB(" Halfedges: %6d", N->p3->number_of_halfedges()); + PRINTB(" Edges: %6d", N->p3->number_of_edges()); + PRINTB(" Halffacets: %6d", N->p3->number_of_halffacets()); + PRINTB(" Facets: %6d", N->p3->number_of_facets()); + PRINTB(" Volumes: %6d", N->p3->number_of_volumes()); + } + } } - else { - PRINT("WARNING: No top level geometry to render"); + else if (const PolySet *ps = dynamic_cast(root_geom.get())) { + assert(ps->getDimension() == 3); + PRINT(" Top level object is a 3D object:"); + PRINTB(" Facets: %6d", ps->numPolygons()); + } else if (const Polygon2d *poly = dynamic_cast(root_geom.get())) { + PRINT(" Top level object is a 2D object:"); + PRINTB(" Contours: %6d", poly->outlines().size()); + } else { + assert(false && "Unknown geometry type"); } + PRINT("Rendering finished."); + + this->root_geom = root_geom; + if (this->root_geom) { + // FIXME: Support rendering PolySets and Polygon2d roots + + shared_ptr new_N = dynamic_pointer_cast(this->root_geom); + if (!new_N) { + new_N.reset(createNefPolyhedronFromGeometry(*this->root_geom)); + } + + this->cgalRenderer = new CGALRenderer(new_N); + // Go to CGAL view mode + if (viewActionWireframe->isChecked()) viewModeWireframe(); + else viewModeSurface(); + } + } + else { + PRINT("WARNING: No top level geometry to render"); } this->statusBar()->removeWidget(this->progresswidget); @@ -1431,19 +1446,20 @@ void MainWindow::actionExportSTLorOFF(bool) #ifdef ENABLE_CGAL setCurrentOutput(); - if (!this->root_N) { + if (!this->root_geom) { PRINT("Nothing to export! Try building first (press F6)."); clearCurrentOutput(); return; } - if (this->root_N->getDimension() != 3) { + if (this->root_geom->getDimension() != 3) { PRINT("Current top level object is not a 3D object."); clearCurrentOutput(); return; } - if (!this->root_N->p3->is_simple()) { + const CGAL_Nef_polyhedron *N = dynamic_cast(this->root_geom.get()); + if (N && N->p3->is_simple()) { PRINT("Object isn't a valid 2-manifold! Modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export"); clearCurrentOutput(); return; @@ -1465,8 +1481,8 @@ void MainWindow::actionExportSTLorOFF(bool) PRINTB("Can't open file \"%s\" for export", stl_filename.toLocal8Bit().constData()); } else { - if (stl_mode) export_stl(this->root_N.get(), fstream); - else export_off(this->root_N.get(), fstream); + if (stl_mode) exportFile(this->root_geom.get(), fstream, OPENSCAD_STL); + else exportFile(this->root_geom.get(), fstream, OPENSCAD_OFF); fstream.close(); PRINTB("%s export finished.", (stl_mode ? "STL" : "OFF")); @@ -1491,13 +1507,13 @@ void MainWindow::actionExportDXF() #ifdef ENABLE_CGAL setCurrentOutput(); - if (!this->root_N) { + if (!this->root_geom) { PRINT("Nothing to export! Try building first (press F6)."); clearCurrentOutput(); return; } - if (this->root_N->getDimension() != 2) { + if (this->root_geom->getDimension() != 2) { PRINT("Current top level object is not a 2D object."); clearCurrentOutput(); return; @@ -1518,7 +1534,7 @@ void MainWindow::actionExportDXF() PRINTB("Can't open file \"%s\" for export", dxf_filename.toLocal8Bit().constData()); } else { - export_dxf(this->root_N.get(), fstream); + exportFile(this->root_geom.get(), fstream, OPENSCAD_DXF); fstream.close(); PRINT("DXF export finished."); } @@ -1587,10 +1603,10 @@ void MainWindow::actionFlushCaches() void MainWindow::viewModeActionsUncheck() { - viewActionOpenCSG->setChecked(false); + viewActionPreview->setChecked(false); #ifdef ENABLE_CGAL - viewActionCGALSurfaces->setChecked(false); - viewActionCGALGrid->setChecked(false); + viewActionSurfaces->setChecked(false); + viewActionWireframe->setChecked(false); #endif viewActionThrownTogether->setChecked(false); } @@ -1601,11 +1617,11 @@ void MainWindow::viewModeActionsUncheck() Go to the OpenCSG view mode. Falls back to thrown together mode if OpenCSG is not available */ -void MainWindow::viewModeOpenCSG() +void MainWindow::viewModePreview() { if (this->qglview->hasOpenCSGSupport()) { viewModeActionsUncheck(); - viewActionOpenCSG->setChecked(true); + viewActionPreview->setChecked(true); this->qglview->setRenderer(this->opencsgRenderer ? (Renderer *)this->opencsgRenderer : (Renderer *)this->thrownTogetherRenderer); this->qglview->updateGL(); } else { @@ -1617,19 +1633,19 @@ void MainWindow::viewModeOpenCSG() #ifdef ENABLE_CGAL -void MainWindow::viewModeCGALSurface() +void MainWindow::viewModeSurface() { viewModeActionsUncheck(); - viewActionCGALSurfaces->setChecked(true); + viewActionSurfaces->setChecked(true); this->qglview->setShowFaces(true); this->qglview->setRenderer(this->cgalRenderer); this->qglview->updateGL(); } -void MainWindow::viewModeCGALGrid() +void MainWindow::viewModeWireframe() { viewModeActionsUncheck(); - viewActionCGALGrid->setChecked(true); + viewActionWireframe->setChecked(true); this->qglview->setShowFaces(false); this->qglview->setRenderer(this->cgalRenderer); this->qglview->updateGL(); @@ -1673,7 +1689,7 @@ void MainWindow::viewModeAnimate() { if (viewActionAnimate->isChecked()) { animate_panel->show(); - actionRenderCSG(); + actionRenderPreview(); updatedFps(); } else { animate_panel->hide(); diff --git a/src/openscad.cc b/src/openscad.cc index 704c70f0..0861e696 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -46,7 +46,6 @@ #ifdef ENABLE_CGAL #include "CGAL_Nef_polyhedron.h" -#include "CGALEvaluator.h" #endif #include "csgterm.h" @@ -249,7 +248,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; - shared_ptr root_N; + shared_ptr root_geom; handle_dep(filename.c_str()); @@ -333,7 +332,13 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c if ((echo_output_file || png_output_file) && !(renderer==Render::CGAL)) { // echo or OpenCSG png -> don't necessarily need CGALMesh evaluation } else { - root_N = geomevaluator.cgalevaluator->evaluateCGALMesh(*tree.root()); + root_geom = geomevaluator.evaluateGeometry(*tree.root(), true); + const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom.get()); + if (!root_geom || (N && N->isNull())) { + PRINT("Empty top-level object"); + return 1; + } + } fs::current_path(original_path); @@ -358,45 +363,37 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c } if (stl_output_file) { - if (root_N->getDimension() != 3) { + if (root_geom->getDimension() != 3) { PRINT("Current top level object is not a 3D object.\n"); return 1; } - if (!root_N->p3->is_simple()) { - PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); - return 1; - } std::ofstream fstream(stl_output_file); if (!fstream.is_open()) { PRINTB("Can't open file \"%s\" for export", stl_output_file); } else { - export_stl(root_N.get(), fstream); + exportFile(root_geom.get(), fstream, OPENSCAD_STL); fstream.close(); } } if (off_output_file) { - if (root_N->getDimension() != 3) { + if (root_geom->getDimension() != 3) { PRINT("Current top level object is not a 3D object.\n"); return 1; } - if (!root_N->p3->is_simple()) { - PRINT("Object isn't a valid 2-manifold! Modify your design.\n"); - return 1; - } std::ofstream fstream(off_output_file); if (!fstream.is_open()) { PRINTB("Can't open file \"%s\" for export", off_output_file); } else { - export_off(root_N.get(), fstream); + exportFile(root_geom.get(), fstream, OPENSCAD_OFF); fstream.close(); } } if (dxf_output_file) { - if (root_N->getDimension() != 2) { + if (root_geom->getDimension() != 2) { PRINT("Current top level object is not a 2D object.\n"); return 1; } @@ -405,7 +402,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.get(), fstream); + exportFile(root_geom.get(), fstream, OPENSCAD_DXF); fstream.close(); } } @@ -417,12 +414,13 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c } else { if (renderer==Render::CGAL) { - export_png_with_cgal(root_N.get(), camera, fstream); + export_png(root_geom.get(), camera, fstream); } else if (renderer==Render::THROWNTOGETHER) { export_png_with_throwntogether(tree, camera, fstream); } else { export_png_with_opencsg(tree, camera, fstream); } + PRINTB("Camera eye: %f %f %f\n", camera.eye[0] % camera.eye[1] % camera.eye[2]); fstream.close(); } } @@ -452,7 +450,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c #include #include -Q_DECLARE_METATYPE(shared_ptr); +Q_DECLARE_METATYPE(shared_ptr); // Only if "fileName" is not absolute, prepend the "absoluteBase". static QString assemblePath(const fs::path& absoluteBase, @@ -496,7 +494,7 @@ int gui(vector &inputFiles, const fs::path &original_path, int argc, cha QCoreApplication::setApplicationVersion(TOSTRING(OPENSCAD_VERSION)); // Other global settings - qRegisterMetaType >(); + qRegisterMetaType >(); const QString &app_path = app.applicationDirPath(); diff --git a/src/polyset.h b/src/polyset.h index 1bd8bc86..3c84dfdc 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -27,6 +27,7 @@ public: virtual unsigned int getDimension() const { return this->is2d ? 2 : 3; } bool empty() const { return polygons.size() == 0; } + size_t numPolygons() const { return polygons.size(); } void append_poly(); void append_vertex(double x, double y, double z = 0.0); void append_vertex(Vector3d v); diff --git a/src/primitives.cc b/src/primitives.cc index e10ff018..14225de8 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -107,7 +107,6 @@ public: primitive_type_e type; int convexity; Value points, paths, faces; - virtual Geometry *evaluate_geometry(class PolySetEvaluator *) const { return createGeometry(); } virtual Geometry *createGeometry() const; }; @@ -293,6 +292,10 @@ static void generate_circle(point2d *circle, double r, int fragments) } } +/*! + Creates geometry for this node. + May return NULL if geometry creation failed. + */ Geometry *PrimitiveNode::createGeometry() const { Geometry *g = NULL; @@ -575,8 +578,6 @@ sphere_next_r2: p->setConvexity(convexity); } - // FIXME: IF the above failed, create an empty polyset as that's required later on - if (!g) g = new PolySet(); return g; } diff --git a/src/projection.cc b/src/projection.cc index ca93bbb4..6d2b76c4 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -30,7 +30,6 @@ #include "printutils.h" #include "builtin.h" #include "visitor.h" -#include "PolySetEvaluator.h" #include "polyset.h" #include @@ -69,22 +68,6 @@ AbstractNode *ProjectionModule::instantiate(const Context *ctx, const ModuleInst return node; } -Geometry *ProjectionNode::evaluate_geometry(PolySetEvaluator *evaluator) const -{ - if (!evaluator) { - PRINTB("WARNING: No suitable PolySetEvaluator found for %s module!", this->name()); - return NULL; - } - - print_messages_push(); - - Geometry *ps = evaluator->evaluateGeometry(*this); - - print_messages_pop(); - - return ps; -} - std::string ProjectionNode::toString() const { std::stringstream stream; diff --git a/src/projectionnode.h b/src/projectionnode.h index 39ad85e9..cbed0209 100644 --- a/src/projectionnode.h +++ b/src/projectionnode.h @@ -19,7 +19,6 @@ public: int convexity; bool cut_mode; - virtual class Geometry *evaluate_geometry(class PolySetEvaluator *evaluator) const; }; #endif diff --git a/src/render.cc b/src/render.cc index 2b9b1bbc..95ff6d54 100644 --- a/src/render.cc +++ b/src/render.cc @@ -28,7 +28,6 @@ #include "module.h" #include "evalcontext.h" #include "builtin.h" -#include "PolySetEvaluator.h" #include "polyset.h" #include @@ -62,11 +61,6 @@ AbstractNode *RenderModule::instantiate(const Context *ctx, const ModuleInstanti return node; } -class Geometry *RenderNode::evaluate_geometry(PolySetEvaluator *ps) const -{ - return ps->evaluateGeometry(*this); -} - std::string RenderNode::toString() const { std::stringstream stream; diff --git a/src/rendernode.h b/src/rendernode.h index f6ee3963..9138c291 100644 --- a/src/rendernode.h +++ b/src/rendernode.h @@ -14,7 +14,6 @@ public: } virtual std::string toString() const; virtual std::string name() const { return "render"; } - Geometry *evaluate_geometry(class PolySetEvaluator *ps) const; int convexity; }; diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index b86498b1..eefaed25 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -32,7 +32,6 @@ #include "builtin.h" #include "polyset.h" #include "visitor.h" -#include "PolySetEvaluator.h" #include #include @@ -92,22 +91,6 @@ AbstractNode *RotateExtrudeModule::instantiate(const Context *ctx, const ModuleI return node; } -Geometry *RotateExtrudeNode::evaluate_geometry(PolySetEvaluator *evaluator) const -{ - if (!evaluator) { - PRINTB("WARNING: No suitable PolySetEvaluator found for %s module!", this->name()); - return NULL; - } - - print_messages_push(); - - Geometry *ps = evaluator->evaluateGeometry(*this); - - print_messages_pop(); - - return ps; -} - std::string RotateExtrudeNode::toString() const { std::stringstream stream; diff --git a/src/rotateextrudenode.h b/src/rotateextrudenode.h index 4eedd4a7..f2078615 100644 --- a/src/rotateextrudenode.h +++ b/src/rotateextrudenode.h @@ -24,7 +24,6 @@ public: double origin_x, origin_y, scale; Filename filename; std::string layername; - virtual Geometry *evaluate_geometry(class PolySetEvaluator *) const; }; #endif diff --git a/src/surface.cc b/src/surface.cc index 4fe5f16f..5ab1d02e 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -67,7 +67,6 @@ public: Filename filename; bool center; int convexity; - virtual Geometry *evaluate_geometry(class PolySetEvaluator *) const { return createGeometry(); } virtual Geometry *createGeometry() const; }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 90df4d72..53899014 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -555,7 +555,6 @@ set(CGAL_SOURCES ../src/CSGTermEvaluator.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc - ../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/CGAL_Nef_polyhedron_DxfData.cc ../src/cgaladv_minkowski2.cc diff --git a/tests/CSGTextRenderer.cc b/tests/CSGTextRenderer.cc index 9bd066e3..300e6b06 100644 --- a/tests/CSGTextRenderer.cc +++ b/tests/CSGTextRenderer.cc @@ -43,6 +43,8 @@ CSGTextRenderer::process(string &target, const string &src, OpenSCADOperator op) case OPENSCAD_MINKOWSKI: target += "M" + src; break; + default: + assert(false); } } diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index 8b89f818..3c517f00 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -38,7 +38,6 @@ #include "CGAL_Nef_polyhedron.h" #include "GeometryEvaluator.h" #include "CGALEvaluator.h" -#include "PolySetCGALEvaluator.h" #include "CGALCache.h" #ifndef _MSC_VER @@ -149,9 +148,9 @@ int main(int argc, char **argv) print_messages_push(); std::cout << "First evaluation:\n"; - shared_ptr N = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node); + shared_ptr geom = geomevaluator.evaluateGeometry(*root_node, true); std::cout << "Second evaluation:\n"; - shared_ptr N2 = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node); + shared_ptr geom2 = geomevaluator.evaluateGeometry(*root_node, true); // FIXME: // Evaluate again to make cache kick in // Record printed output and compare it