summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrad Pitcher <bradpitcher@gmail.com>2011-11-01 17:15:35 (GMT)
committerBrad Pitcher <bradpitcher@gmail.com>2011-11-01 17:15:35 (GMT)
commite2caf3726d68ff1fef63113519049abffc0563af (patch)
tree6558c6f03ccc21e7138d23861f80e8d97b09e60e /src
parent7541854212d6c1223e015faf55a6ca0657a1c184 (diff)
parentcb56f700b1b0f4ae589da62a5fd1d4e368deb604 (diff)
merge master
Diffstat (limited to 'src')
-rw-r--r--src/CGALEvaluator.cc142
-rw-r--r--src/CGALEvaluator.h5
-rw-r--r--src/CGALRenderer.cc6
-rw-r--r--src/CSGTermEvaluator.cc1
-rw-r--r--src/CSGTermEvaluator.h1
-rw-r--r--src/MainWindow.h5
-rw-r--r--src/MainWindow.ui6
-rw-r--r--src/PolySetCGALEvaluator.cc6
-rw-r--r--src/PolySetCache.cc2
-rw-r--r--src/PolySetCache.h2
-rw-r--r--src/Tree.h6
-rw-r--r--src/color.cc6
-rw-r--r--src/dxfdata.h8
-rw-r--r--src/expr.cc4
-rw-r--r--src/lexer.l9
-rw-r--r--src/linalg.h2
-rw-r--r--src/linearextrude.cc1
-rw-r--r--src/mainwin.cc42
-rw-r--r--src/nodedumper.h12
-rw-r--r--src/openscad.cc157
-rw-r--r--src/openscad.h6
-rw-r--r--src/parser.y2
-rw-r--r--src/printutils.cc35
-rw-r--r--src/printutils.h20
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() { }
};
diff --git a/src/Tree.h b/src/Tree.h
index aaa61d7..41ae613 100644
--- a/src/Tree.h
+++ b/src/Tree.h
@@ -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);
contact: Jan Huwald // Impressum