diff options
author | Brad Pitcher <bradpitcher@gmail.com> | 2011-11-01 17:15:35 (GMT) |
---|---|---|
committer | Brad Pitcher <bradpitcher@gmail.com> | 2011-11-01 17:15:35 (GMT) |
commit | e2caf3726d68ff1fef63113519049abffc0563af (patch) | |
tree | 6558c6f03ccc21e7138d23861f80e8d97b09e60e /src | |
parent | 7541854212d6c1223e015faf55a6ca0657a1c184 (diff) | |
parent | cb56f700b1b0f4ae589da62a5fd1d4e368deb604 (diff) |
merge master
Diffstat (limited to 'src')
-rw-r--r-- | src/CGALEvaluator.cc | 142 | ||||
-rw-r--r-- | src/CGALEvaluator.h | 5 | ||||
-rw-r--r-- | src/CGALRenderer.cc | 6 | ||||
-rw-r--r-- | src/CSGTermEvaluator.cc | 1 | ||||
-rw-r--r-- | src/CSGTermEvaluator.h | 1 | ||||
-rw-r--r-- | src/MainWindow.h | 5 | ||||
-rw-r--r-- | src/MainWindow.ui | 6 | ||||
-rw-r--r-- | src/PolySetCGALEvaluator.cc | 6 | ||||
-rw-r--r-- | src/PolySetCache.cc | 2 | ||||
-rw-r--r-- | src/PolySetCache.h | 2 | ||||
-rw-r--r-- | src/Tree.h | 6 | ||||
-rw-r--r-- | src/color.cc | 6 | ||||
-rw-r--r-- | src/dxfdata.h | 8 | ||||
-rw-r--r-- | src/expr.cc | 4 | ||||
-rw-r--r-- | src/lexer.l | 9 | ||||
-rw-r--r-- | src/linalg.h | 2 | ||||
-rw-r--r-- | src/linearextrude.cc | 1 | ||||
-rw-r--r-- | src/mainwin.cc | 42 | ||||
-rw-r--r-- | src/nodedumper.h | 12 | ||||
-rw-r--r-- | src/openscad.cc | 157 | ||||
-rw-r--r-- | src/openscad.h | 6 | ||||
-rw-r--r-- | src/parser.y | 2 | ||||
-rw-r--r-- | src/printutils.cc | 35 | ||||
-rw-r--r-- | src/printutils.h | 20 |
24 files changed, 276 insertions, 210 deletions
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 10160ae..550f300 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -27,6 +27,8 @@ #include <assert.h> #include <QRegExp> +#include <boost/foreach.hpp> + CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node) { if (!isCached(node)) { @@ -75,22 +77,23 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op) { CGAL_Nef_polyhedron N; - if (this->visitedchildren[node.index()].size() > 0) { - for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin(); - iter != this->visitedchildren[node.index()].end(); - iter++) { - const AbstractNode *chnode = iter->first; - const string &chcacheid = iter->second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->tag_background) continue; - assert(isCached(*chnode)); - if (N.empty()) { - N = CGALCache::instance()->get(chcacheid).copy(); - } else { - process(N, CGALCache::instance()->get(chcacheid), op); - } - chnode->progress_report(); + 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->tag_background) continue; + + // NB! We insert into the cache here to ensure that all children of + // a node is a valid object. If we inserted as we created them, the + // cache could have been modified before we reach this point due to a large + // sibling object. + if (!isCached(*chnode)) { + CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN); } + if (N.empty()) N = chN.copy(); + else process(N, chN, op); + + chnode->progress_report(); } return N; } @@ -100,31 +103,25 @@ extern CGAL_Nef_polyhedron2 *convexhull2(std::list<CGAL_Nef_polyhedron2*> a); CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node) { CGAL_Nef_polyhedron N; - if (this->visitedchildren[node.index()].size() > 0) { - std::list<CGAL_Nef_polyhedron2*> polys; - bool all2d = true; - for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin(); - iter != this->visitedchildren[node.index()].end(); - iter++) { - const AbstractNode *chnode = iter->first; - const string &chcacheid = iter->second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->tag_background) continue; - assert(isCached(*chnode)); - const CGAL_Nef_polyhedron &ch = CGALCache::instance()->get(chcacheid); - if (ch.dim == 2) { - polys.push_back(ch.p2.get()); - } - else if (ch.dim == 3) { - PRINT("WARNING: hull() is not implemented yet for 3D objects!"); - all2d = false; - } - chnode->progress_report(); + std::list<CGAL_Nef_polyhedron2*> polys; + bool all2d = true; + 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->tag_background) continue; + if (chN.dim == 2) { + polys.push_back(chN.p2.get()); } - - if (all2d) { - N = CGAL_Nef_polyhedron(convexhull2(polys)); + else if (chN.dim == 3) { + PRINT("WARNING: hull() is not implemented yet for 3D objects!"); + all2d = false; } + chnode->progress_report(); + } + + if (all2d) { + N = CGAL_Nef_polyhedron(convexhull2(polys)); } return N; } @@ -140,11 +137,10 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - if (!isCached(node)) { - CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION); - CGALCache::instance()->insert(this->tree.getIdString(node), N); - } - addToParent(state, node); + CGAL_Nef_polyhedron N; + if (!isCached(node)) N = applyToChildren(node, CGE_UNION); + else N = CGALCache::instance()->get(this->tree.getIdString(node)); + addToParent(state, node, N); } return ContinueTraversal; } @@ -153,11 +149,10 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { - if (!isCached(node)) { - CGAL_Nef_polyhedron N = applyToChildren(node, CGE_INTERSECTION); - CGALCache::instance()->insert(this->tree.getIdString(node), N); - } - addToParent(state, node); + CGAL_Nef_polyhedron N; + if (!isCached(node)) N = applyToChildren(node, CGE_INTERSECTION); + else N = CGALCache::instance()->get(this->tree.getIdString(node)); + addToParent(state, node, N); } return ContinueTraversal; } @@ -166,6 +161,7 @@ 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)) { CGALEvaluator::CsgOp op; switch (node.type) { @@ -181,10 +177,12 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node) default: assert(false); } - CGAL_Nef_polyhedron N = applyToChildren(node, op); - CGALCache::instance()->insert(this->tree.getIdString(node), N); + N = applyToChildren(node, op); + } + else { + N = CGALCache::instance()->get(this->tree.getIdString(node)); } - addToParent(state, node); + addToParent(state, node, N); } return ContinueTraversal; } @@ -193,9 +191,10 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { + CGAL_Nef_polyhedron N; if (!isCached(node)) { // First union all children - CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION); + N = applyToChildren(node, CGE_UNION); // Then apply transform // If there is no geometry under the transform, N will be empty and of dim 0, @@ -231,9 +230,11 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node) node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3)); N.p3->transform(t); } - CGALCache::instance()->insert(this->tree.getIdString(node), N); } - addToParent(state, node); + else { + N = CGALCache::instance()->get(this->tree.getIdString(node)); + } + addToParent(state, node, N); } return ContinueTraversal; } @@ -242,18 +243,20 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { + CGAL_Nef_polyhedron N; if (!isCached(node)) { // Apply polyset operation shared_ptr<PolySet> ps = this->psevaluator.getPolySet(node, false); - CGAL_Nef_polyhedron N; if (ps) { N = evaluateCGALMesh(*ps); // print_messages_pop(); node.progress_report(); } - CGALCache::instance()->insert(this->tree.getIdString(node), N); } - addToParent(state, node); + else { + N = CGALCache::instance()->get(this->tree.getIdString(node)); + } + addToParent(state, node, N); } return ContinueTraversal; } @@ -262,8 +265,8 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { + CGAL_Nef_polyhedron N; if (!isCached(node)) { - CGAL_Nef_polyhedron N; CGALEvaluator::CsgOp op; switch (node.type) { case MINKOWSKI: @@ -282,9 +285,11 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node) N = applyHull(node); break; } - CGALCache::instance()->insert(this->tree.getIdString(node), N); } - addToParent(state, node); + else { + N = CGALCache::instance()->get(this->tree.getIdString(node)); + } + addToParent(state, node, N); } return ContinueTraversal; } @@ -293,12 +298,18 @@ 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) +void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N) { assert(state.isPostfix()); this->visitedchildren.erase(node.index()); if (state.parent()) { - this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getIdString(node))); + this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, N)); + } + else { + // Root node, insert into cache + if (!isCached(node)) { + CGALCache::instance()->insert(this->tree.getIdString(node), N); + } } } @@ -520,9 +531,12 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) }; PolyReducer pr(ps); - PRINTF("Number of polygons before reduction: %d\n", pr.polygons.size()); + int numpolygons_before = pr.polygons.size(); pr.reduce(); - PRINTF("Number of polygons after reduction: %d\n", pr.polygons.size()); + int numpolygons_after = pr.polygons.size(); + if (numpolygons_after < numpolygons_before) { + PRINTF("reduce polygons: %d -> %d", numpolygons_before, numpolygons_after); + } return CGAL_Nef_polyhedron(pr.toNef()); #endif #if 0 diff --git a/src/CGALEvaluator.h b/src/CGALEvaluator.h index 0ac716c..1dce4d9 100644 --- a/src/CGALEvaluator.h +++ b/src/CGALEvaluator.h @@ -30,14 +30,15 @@ public: const Tree &getTree() const { return this->tree; } private: - void addToParent(const State &state, const AbstractNode &node); + void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N); bool isCached(const AbstractNode &node) const; void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op); CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op); CGAL_Nef_polyhedron applyHull(const CgaladvNode &node); std::string currindent; - typedef std::list<std::pair<const AbstractNode *, std::string> > ChildList; + typedef std::pair<const AbstractNode *, CGAL_Nef_polyhedron> ChildItem; + typedef std::list<ChildItem> ChildList; std::map<int, ChildList> visitedchildren; const Tree &tree; diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc index 4d165ce..95bcba1 100644 --- a/src/CGALRenderer.cc +++ b/src/CGALRenderer.cc @@ -24,10 +24,12 @@ * */ -#include "CGALRenderer.h" +// dxfdata.h must come first for Eigen SIMD alignment issues +#include "dxfdata.h" #include "polyset.h" + +#include "CGALRenderer.h" #include "CGAL_renderer.h" -#include "dxfdata.h" #include "dxftess.h" #include "CGAL_Nef_polyhedron.h" #include "cgal.h" diff --git a/src/CSGTermEvaluator.cc b/src/CSGTermEvaluator.cc index d1af987..0c7bca7 100644 --- a/src/CSGTermEvaluator.cc +++ b/src/CSGTermEvaluator.cc @@ -17,6 +17,7 @@ #include <sstream> #include <iostream> #include <assert.h> +#include <cstddef> /*! \class CSGTermEvaluator diff --git a/src/CSGTermEvaluator.h b/src/CSGTermEvaluator.h index cca6c91..3a8122b 100644 --- a/src/CSGTermEvaluator.h +++ b/src/CSGTermEvaluator.h @@ -4,6 +4,7 @@ #include <map> #include <list> #include <vector> +#include <cstddef> #include "visitor.h" class CSGTermEvaluator : public Visitor diff --git a/src/MainWindow.h b/src/MainWindow.h index 37a6a4c..06332b0 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -79,8 +79,8 @@ private: bool maybeSave(); bool checkModified(); QString dumpCSGTree(AbstractNode *root); - static void consoleOutput(const QString &msg, void *userdata) { - static_cast<MainWindow*>(userdata)->console->append(msg); + static void consoleOutput(const std::string &msg, void *userdata) { + static_cast<MainWindow*>(userdata)->console->append(QString::fromStdString(msg)); } void loadViewSettings(); void loadDesignSettings(); @@ -115,6 +115,7 @@ private slots: void actionExportSTL(); void actionExportOFF(); void actionExportDXF(); + void actionExportCSG(); void actionExportImage(); void actionFlushCaches(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 1741557..4d5ff22 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -178,6 +178,7 @@ <addaction name="designActionExportSTL"/> <addaction name="designActionExportOFF"/> <addaction name="designActionExportDXF"/> + <addaction name="designActionExportCSG"/> <addaction name="designActionExportImage"/> <addaction name="designActionFlushCaches"/> </widget> @@ -657,6 +658,11 @@ <string>Export as Image...</string> </property> </action> + <action name="designActionExportCSG"> + <property name="text"> + <string>Export as CSG...</string> + </property> + </action> </widget> <customwidgets> <customwidget> diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index 7f62d0a..190d75a 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -181,6 +181,7 @@ cant_project_non_simple_polyhedron: static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, double rot1, double rot2, double h1, double h2) { + bool splitfirst = sin(rot2 - rot1) >= 0.0; for (size_t j = 1; j < path.indices.size(); j++) { int k = j - 1; @@ -197,10 +198,7 @@ static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, doub double kx2 = dxf.points[path.indices[k]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot2*M_PI/180); double ky2 = dxf.points[path.indices[k]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot2*M_PI/180); - double dia1_len_sq = (jy1-ky2)*(jy1-ky2) + (jx1-kx2)*(jx1-kx2); - double dia2_len_sq = (jy2-ky1)*(jy2-ky1) + (jx2-kx1)*(jx2-kx1); - - if (dia1_len_sq > dia2_len_sq) + if (splitfirst) { ps->append_poly(); if (path.is_inner) { diff --git a/src/PolySetCache.cc b/src/PolySetCache.cc index 0a93642..2a2da9c 100644 --- a/src/PolySetCache.cc +++ b/src/PolySetCache.cc @@ -17,5 +17,5 @@ void PolySetCache::print() PolySetCache::cache_entry::cache_entry(const shared_ptr<PolySet> &ps) : ps(ps) { - if (print_messages_stack.size() > 0) this->msg = print_messages_stack.last(); + if (print_messages_stack.size() > 0) this->msg = print_messages_stack.back(); } diff --git a/src/PolySetCache.h b/src/PolySetCache.h index da51c5e..d1efeb7 100644 --- a/src/PolySetCache.h +++ b/src/PolySetCache.h @@ -23,7 +23,7 @@ private: struct cache_entry { shared_ptr<class PolySet> ps; - QString msg; + std::string msg; cache_entry(const shared_ptr<PolySet> &ps); ~cache_entry() { } }; @@ -3,8 +3,6 @@ #include "nodecache.h" -using std::string; - /*! For now, just an abstraction of the node tree which keeps a dump cache based on node indices around. @@ -20,8 +18,8 @@ public: void setRoot(const AbstractNode *root); const AbstractNode *root() const { return this->root_node; } - const string &getString(const AbstractNode &node) const; - const string &getIdString(const AbstractNode &node) const; + const std::string &getString(const AbstractNode &node) const; + const std::string &getIdString(const AbstractNode &node) const; private: const AbstractNode *root_node; diff --git a/src/color.cc b/src/color.cc index ee8f872..3c6942c 100644 --- a/src/color.cc +++ b/src/color.cc @@ -42,8 +42,6 @@ public: virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; }; -using std::string; - AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const { ColorNode *node = new ColorNode(inst); @@ -87,7 +85,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio return node; } -string ColorNode::toString() const +std::string ColorNode::toString() const { std::stringstream stream; @@ -96,7 +94,7 @@ string ColorNode::toString() const return stream.str(); } -string ColorNode::name() const +std::string ColorNode::name() const { return "color"; } diff --git a/src/dxfdata.h b/src/dxfdata.h index e2f229e..17da1b9 100644 --- a/src/dxfdata.h +++ b/src/dxfdata.h @@ -4,10 +4,8 @@ #define EIGEN_DONT_ALIGN #endif +#include "linalg.h" #include <vector> -#include <Eigen/Dense> - -using Eigen::Vector2d; class DxfData { @@ -33,7 +31,11 @@ public: } }; +#ifdef __APPLE__ + std::vector<Vector2d, Eigen::aligned_allocator<Vector2d> > points; +#else std::vector<Vector2d> points; +#endif std::vector<Path> paths; std::vector<Dim> dims; diff --git a/src/expr.cc b/src/expr.cc index c9eda4e..fc1fbf0 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -75,9 +75,7 @@ Value Expression::evaluate(const Context *context) const return this->children[0]->evaluate(context) > this->children[1]->evaluate(context); if (this->type == "?:") { Value v = this->children[0]->evaluate(context); - if (v.type == Value::BOOL) - return this->children[v.b ? 1 : 2]->evaluate(context); - return Value(); + return this->children[v.toBool() ? 1 : 2]->evaluate(context); } if (this->type == "[]") { Value v1 = this->children[0]->evaluate(context); diff --git a/src/lexer.l b/src/lexer.l index 3cd4a19..d9ccd76 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -35,8 +35,11 @@ #include <QDir> #include <assert.h> -//isatty for visual c++ -#ifdef _MSC_VER +//isatty for visual c++ and mingw-cross-env +#if defined __WIN32__ && ! defined _MSC_VER +#include "unistd.h" +#endif +#if defined __WIN32__ || defined _MSC_VER extern "C" int __cdecl _isatty(int _FileHandle); #define isatty _isatty #endif @@ -97,7 +100,7 @@ include[ \t\r\n>]*"<" { BEGIN(include); } } -use[ \t\r\n>]*"<"[^ \t\r\n>]+">" { +use[ \t\r\n>]*"<"[^\t\r\n>]+">" { QString filename(yytext); filename.remove(QRegExp("^use[ \t\r\n>]*<")); filename.remove(QRegExp(">$")); diff --git a/src/linalg.h b/src/linalg.h index eb1ed3c..744e810 100644 --- a/src/linalg.h +++ b/src/linalg.h @@ -5,7 +5,9 @@ #endif #include <Eigen/Core> #include <Eigen/Geometry> +#include <Eigen/Dense> +using Eigen::Vector2d; using Eigen::Vector3d; typedef Eigen::AlignedBox<double, 3> BoundingBox; using Eigen::Matrix3f; diff --git a/src/linearextrude.cc b/src/linearextrude.cc index 5c3b684..9c3557b 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -32,6 +32,7 @@ #include "builtin.h" #include "PolySetEvaluator.h" #include "openscad.h" // get_fragments_from_r() +#include "mathc99.h" #include <sstream> #include <boost/assign/std/vector.hpp> diff --git a/src/mainwin.cc b/src/mainwin.cc index 238bd10..9944f67 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -218,8 +218,12 @@ MainWindow::MainWindow(const QString &filename) connect(this->fileActionReload, SIGNAL(triggered()), this, SLOT(actionReload())); connect(this->fileActionQuit, SIGNAL(triggered()), this, SLOT(quit())); #ifndef __APPLE__ - this->fileActionSave->setShortcut(QKeySequence(Qt::Key_F2)); - this->fileActionReload->setShortcut(QKeySequence(Qt::Key_F3)); + QList<QKeySequence> shortcuts = this->fileActionSave->shortcuts(); + shortcuts.push_back(QKeySequence(Qt::Key_F2)); + this->fileActionSave->setShortcuts(shortcuts); + shortcuts = this->fileActionReload->shortcuts(); + shortcuts.push_back(QKeySequence(Qt::Key_F3)); + this->fileActionReload->setShortcuts(shortcuts); #endif // Open Recent for (int i = 0;i<maxRecentFiles; i++) { @@ -283,6 +287,7 @@ MainWindow::MainWindow(const QString &filename) connect(this->designActionExportSTL, SIGNAL(triggered()), this, SLOT(actionExportSTL())); connect(this->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF())); connect(this->designActionExportDXF, SIGNAL(triggered()), this, SLOT(actionExportDXF())); + connect(this->designActionExportCSG, SIGNAL(triggered()), this, SLOT(actionExportCSG())); connect(this->designActionExportImage, SIGNAL(triggered()), this, SLOT(actionExportImage())); connect(this->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches())); @@ -871,7 +876,6 @@ void MainWindow::compileCSG(bool procevents) this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain, this->highlights_chain, this->background_chain); - PRINT("CSG generation finished."); int s = t.elapsed() / 1000; PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); @@ -1474,6 +1478,38 @@ void MainWindow::actionExportDXF() #endif /* ENABLE_CGAL */ } +void MainWindow::actionExportCSG() +{ + setCurrentOutput(); + + if (!this->root_node) { + PRINT("Nothing to export. Please try compiling first..."); + clearCurrentOutput(); + return; + } + + QString csg_filename = QFileDialog::getSaveFileName(this, "Export CSG File", + this->fileName.isEmpty() ? "Untitled.csg" : QFileInfo(this->fileName).baseName()+".csg", + "CSG Files (*.csg)"); + if (csg_filename.isEmpty()) { + PRINTF("No filename specified. CSG export aborted."); + clearCurrentOutput(); + return; + } + + std::ofstream fstream(csg_filename.toUtf8()); + if (!fstream.is_open()) { + PRINTA("Can't open file \"%s\" for export", csg_filename); + } + else { + fstream << this->tree.getString(*this->root_node) << "\n"; + fstream.close(); + PRINTF("CSG export finished."); + } + + clearCurrentOutput(); +} + void MainWindow::actionExportImage() { QImage img = this->glview->grabFrameBuffer(); diff --git a/src/nodedumper.h b/src/nodedumper.h index efaf4fa..aca17ed 100644 --- a/src/nodedumper.h +++ b/src/nodedumper.h @@ -7,10 +7,6 @@ #include "visitor.h" #include "nodecache.h" -using std::string; -using std::map; -using std::list; - class NodeDumper : public Visitor { public: @@ -26,15 +22,15 @@ private: void handleVisitedChildren(const State &state, const AbstractNode &node); bool isCached(const AbstractNode &node) const; void handleIndent(const State &state); - string dumpChildren(const AbstractNode &node); + std::string dumpChildren(const AbstractNode &node); NodeCache &cache; bool idprefix; - string currindent; + std::string currindent; const AbstractNode *root; - typedef list<const AbstractNode *> ChildList; - map<int, ChildList> visitedchildren; + typedef std::list<const AbstractNode *> ChildList; + std::map<int, ChildList> visitedchildren; }; #endif diff --git a/src/openscad.cc b/src/openscad.cc index 878cb22..4ff250d 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -70,7 +70,7 @@ namespace po = boost::program_options; static void help(const char *progname) { - fprintf(stderr, "Usage: %s [ { -s stl_file | -o off_file | -x dxf_file } [ -d deps_file ] ]\\\n" + fprintf(stderr, "Usage: %s [ { -o output_file } [ -d deps_file ] ]\\\n" "%*s[ -m make_command ] [ -D var=val [..] ] filename\n", progname, int(strlen(progname))+8, ""); exit(1); @@ -126,18 +126,14 @@ int main(int argc, char **argv) QCoreApplication::setApplicationName("OpenSCAD"); const char *filename = NULL; - const char *stl_output_file = NULL; - const char *off_output_file = NULL; - const char *dxf_output_file = NULL; + const char *output_file = NULL; const char *deps_output_file = NULL; po::options_description desc("Allowed options"); desc.add_options() ("help,h", "help message") ("version,v", "print the version") - ("s,s", po::value<string>(), "stl-file") - ("o,o", po::value<string>(), "off-file") - ("x,x", po::value<string>(), "dxf-file") + ("o,o", po::value<string>(), "out-file") ("d,d", po::value<string>(), "deps-file") ("m,m", po::value<string>(), "makefile") ("D,D", po::value<vector<string> >(), "var=val"); @@ -159,20 +155,10 @@ int main(int argc, char **argv) if (vm.count("help")) help(argv[0]); if (vm.count("version")) version(); - if (vm.count("s")) { - if (stl_output_file || off_output_file || dxf_output_file) - help(argv[0]); - stl_output_file = vm["s"].as<string>().c_str(); - } if (vm.count("o")) { - if (stl_output_file || off_output_file || dxf_output_file) - help(argv[0]); - off_output_file = vm["o"].as<string>().c_str(); - } - if (vm.count("x")) { - if (stl_output_file || off_output_file || dxf_output_file) - help(argv[0]); - dxf_output_file = vm["x"].as<string>().c_str(); + // FIXME: Allow for multiple output files? + if (output_file) help(argv[0]); + output_file = vm["o"].as<string>().c_str(); } if (vm.count("d")) { if (deps_output_file) @@ -253,10 +239,24 @@ int main(int argc, char **argv) PolySetCGALEvaluator psevaluator(cgalevaluator); #endif - if (stl_output_file || off_output_file || dxf_output_file) + if (output_file) { - if (!filename) - help(argv[0]); + const char *stl_output_file = NULL; + const char *off_output_file = NULL; + const char *dxf_output_file = NULL; + const char *csg_output_file = NULL; + + QString suffix = QFileInfo(output_file).suffix().toLower(); + if (suffix == "stl") stl_output_file = output_file; + else if (suffix == "off") off_output_file = output_file; + else if (suffix == "dxf") dxf_output_file = output_file; + else if (suffix == "csg") csg_output_file = output_file; + else { + fprintf(stderr, "Unknown suffix for output file %s\n", output_file); + exit(1); + } + + if (!filename) help(argv[0]); #ifdef ENABLE_CGAL Context root_ctx; @@ -304,68 +304,80 @@ int main(int argc, char **argv) AbstractNode::resetIndexCounter(); root_node = root_module->evaluate(&root_ctx, &root_inst); - tree.setRoot(root_node); - CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root()); - - QDir::setCurrent(original_path.absolutePath()); - if (deps_output_file) { - if (!write_deps(deps_output_file, - stl_output_file ? stl_output_file : off_output_file)) { - exit(1); - } - } - - if (stl_output_file) { - if (root_N.dim != 3) { - fprintf(stderr, "Current top level object is not a 3D object.\n"); - exit(1); - } - if (!root_N.p3->is_simple()) { - fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n"); - exit(1); - } - std::ofstream fstream(stl_output_file); + if (csg_output_file) { + QDir::setCurrent(original_path.absolutePath()); + std::ofstream fstream(csg_output_file); if (!fstream.is_open()) { - PRINTF("Can't open file \"%s\" for export", stl_output_file); + PRINTF("Can't open file \"%s\" for export", csg_output_file); } else { - export_stl(&root_N, fstream, NULL); + fstream << tree.getString(*root_node) << "\n"; fstream.close(); } } - - if (off_output_file) { - if (root_N.dim != 3) { - fprintf(stderr, "Current top level object is not a 3D object.\n"); - exit(1); - } - if (!root_N.p3->is_simple()) { - fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n"); - exit(1); - } - std::ofstream fstream(off_output_file); - if (!fstream.is_open()) { - PRINTF("Can't open file \"%s\" for export", off_output_file); - } - else { - export_off(&root_N, fstream, NULL); - fstream.close(); + else { + CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root()); + + QDir::setCurrent(original_path.absolutePath()); + + if (deps_output_file) { + if (!write_deps(deps_output_file, + stl_output_file ? stl_output_file : off_output_file)) { + exit(1); + } } - } - if (dxf_output_file) { - std::ofstream fstream(dxf_output_file); - if (!fstream.is_open()) { - PRINTF("Can't open file \"%s\" for export", dxf_output_file); + if (stl_output_file) { + if (root_N.dim != 3) { + fprintf(stderr, "Current top level object is not a 3D object.\n"); + exit(1); + } + if (!root_N.p3->is_simple()) { + fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n"); + exit(1); + } + std::ofstream fstream(stl_output_file); + if (!fstream.is_open()) { + PRINTF("Can't open file \"%s\" for export", stl_output_file); + } + else { + export_stl(&root_N, fstream, NULL); + fstream.close(); + } } - else { - export_dxf(&root_N, fstream, NULL); - fstream.close(); + + if (off_output_file) { + if (root_N.dim != 3) { + fprintf(stderr, "Current top level object is not a 3D object.\n"); + exit(1); + } + if (!root_N.p3->is_simple()) { + fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n"); + exit(1); + } + std::ofstream fstream(off_output_file); + if (!fstream.is_open()) { + PRINTF("Can't open file \"%s\" for export", off_output_file); + } + else { + export_off(&root_N, fstream, NULL); + fstream.close(); + } + } + + if (dxf_output_file) { + std::ofstream fstream(dxf_output_file); + if (!fstream.is_open()) { + PRINTF("Can't open file \"%s\" for export", dxf_output_file); + } + else { + export_dxf(&root_N, fstream, NULL); + fstream.close(); + } } } - delete root_node; #else fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n"); @@ -415,3 +427,4 @@ int main(int argc, char **argv) return rc; } + diff --git a/src/openscad.h b/src/openscad.h index e6b9b9f..61aec0e 100644 --- a/src/openscad.h +++ b/src/openscad.h @@ -27,12 +27,6 @@ #ifndef OPENSCAD_H #define OPENSCAD_H -// for win32 and maybe others.. -#ifndef M_PI -# define M_PI 3.14159265358979323846 -#endif - - extern class AbstractModule *parse(const char *text, const char *path, int debug); extern int get_fragments_from_r(double r, double fn, double fs, double fa); diff --git a/src/parser.y b/src/parser.y index 33fbc3f..d703a81 100644 --- a/src/parser.y +++ b/src/parser.y @@ -649,7 +649,7 @@ Module *Module::compile_library(std::string filename) if (lib_mod) { libs_cache[filename].mod = lib_mod; - libs_cache[filename].msg = print_messages_stack.last().toStdString(); + libs_cache[filename].msg = print_messages_stack.back(); } else { libs_cache.erase(filename); } diff --git a/src/printutils.cc b/src/printutils.cc index a315ab3..ec41765 100644 --- a/src/printutils.cc +++ b/src/printutils.cc @@ -2,7 +2,7 @@ #include <stdio.h> #include <QDate> -QList<QString> print_messages_stack; +std::list<std::string> print_messages_stack; OutputHandlerFunc *outputhandler = NULL; void *outputhandler_data = NULL; @@ -14,37 +14,38 @@ void set_output_handler(OutputHandlerFunc *newhandler, void *userdata) void print_messages_push() { - print_messages_stack.append(QString()); + print_messages_stack.push_back(std::string()); } void print_messages_pop() { - QString msg = print_messages_stack.takeLast(); - if (print_messages_stack.size() > 0 && !msg.isNull()) { - if (!print_messages_stack.last().isEmpty()) - print_messages_stack.last() += "\n"; - print_messages_stack.last() += msg; + std::string msg = print_messages_stack.back(); + print_messages_stack.pop_back(); + if (print_messages_stack.size() > 0 && !msg.empty()) { + if (!print_messages_stack.back().empty()) { + print_messages_stack.back() += "\n"; + } + print_messages_stack.back() += msg; } } -void PRINT(const QString &msg) +void PRINT(const std::string &msg) { - if (msg.isNull()) - return; + if (msg.empty()) return; if (print_messages_stack.size() > 0) { - if (!print_messages_stack.last().isEmpty()) - print_messages_stack.last() += "\n"; - print_messages_stack.last() += msg; + if (!print_messages_stack.back().empty()) { + print_messages_stack.back() += "\n"; + } + print_messages_stack.back() += msg; } PRINT_NOCACHE(msg); } -void PRINT_NOCACHE(const QString &msg) +void PRINT_NOCACHE(const std::string &msg) { - if (msg.isNull()) - return; + if (msg.empty()) return; if (!outputhandler) { - fprintf(stderr, "%s\n", msg.toUtf8().data()); + fprintf(stderr, "%s\n", msg.c_str()); } else { outputhandler(msg, outputhandler_data); } diff --git a/src/printutils.h b/src/printutils.h index 60cd12a..761e6c8 100644 --- a/src/printutils.h +++ b/src/printutils.h @@ -1,28 +1,28 @@ #ifndef PRINTUTILS_H_ #define PRINTUTILS_H_ -#include <QString> -#include <QList> +#include <string> +#include <list> #include <iostream> #include <QFileInfo> -typedef void (OutputHandlerFunc)(const QString &msg, void *userdata); +typedef void (OutputHandlerFunc)(const std::string &msg, void *userdata); extern OutputHandlerFunc *outputhandler; extern void *outputhandler_data; void set_output_handler(OutputHandlerFunc *newhandler, void *userdata); -extern QList<QString> print_messages_stack; +extern std::list<std::string> print_messages_stack; void print_messages_push(); void print_messages_pop(); -void PRINT(const QString &msg); -#define PRINTF(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT(_m); } while (0) -#define PRINTA(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT(_m); } while (0) +void PRINT(const std::string &msg); +#define PRINTF(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT(_m.toStdString()); } while (0) +#define PRINTA(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT(_m.toStdString()); } while (0) -void PRINT_NOCACHE(const QString &msg); -#define PRINTF_NOCACHE(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT_NOCACHE(_m); } while (0) -#define PRINTA_NOCACHE(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT_NOCACHE(_m); } while (0) +void PRINT_NOCACHE(const std::string &msg); +#define PRINTF_NOCACHE(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT_NOCACHE(_m.toStdString()); } while (0) +#define PRINTA_NOCACHE(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT_NOCACHE(_m.toStdString()); } while (0) std::ostream &operator<<(std::ostream &os, const QFileInfo &fi); |