summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2010-03-19 03:07:01 (GMT)
committerMarius Kintel <marius@kintel.net>2010-10-31 00:42:34 (GMT)
commit311d1befb425a684349fcd7255bb76217ac9f4b6 (patch)
treea2aef95af99c6dc999d1658296dd5110e6742df0
parent0b06db6bc925a5cf5f3bb9f80dd07efd9402bc16 (diff)
Added CGALRenderer + some minor fixes
-rw-r--r--src/CGALRenderer.cc264
-rw-r--r--src/CGALRenderer.h48
-rw-r--r--test-code/cgaltest.cc164
-rw-r--r--test-code/cgaltest.pro99
4 files changed, 575 insertions, 0 deletions
diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc
new file mode 100644
index 0000000..5e8accb
--- /dev/null
+++ b/src/CGALRenderer.cc
@@ -0,0 +1,264 @@
+#include "CGALRenderer.h"
+#include <string>
+#include <map>
+#include <list>
+#include "visitor.h"
+#include "state.h"
+#include "nodecache.h"
+#include "module.h" // FIXME: Temporarily for ModuleInstantiation
+
+#include "csgnode.h"
+
+
+#include <sstream>
+#include <iostream>
+#include <QRegExp>
+
+string CGALRenderer::getCGALMesh() const
+{
+ assert(this->root);
+ // FIXME: assert that cache contains root
+ return this->cache[mk_cache_id(*this->root)];
+}
+
+// CGAL_Nef_polyhedron CGALRenderer::getCGALMesh() const
+// {
+// assert(this->root);
+// // FIXME: assert that cache contains root
+// return this->cache[*this->root];
+// }
+
+bool CGALRenderer::isCached(const AbstractNode &node)
+{
+ return this->cache.contains(mk_cache_id(node));
+}
+
+/*!
+ Modifies target by applying op to target and src:
+ target = target [op] src
+ */
+void
+CGALRenderer::process(string &target, const string &src, CGALRenderer::CsgOp op)
+{
+// if (target.dim != 2 && target.dim != 3) {
+// assert(false && "Dimension of Nef polyhedron must be 2 or 3");
+// }
+
+ switch (op) {
+ case UNION:
+ target += "+" + src;
+ break;
+ case INTERSECTION:
+ target += "*" + src;
+ break;
+ case DIFFERENCE:
+ target += "-" + src;
+ break;
+ case MINKOWSKI:
+ target += "M" + src;
+ break;
+ }
+}
+
+// /*!
+// Modifies target by applying op to target and src:
+// target = target [op] src
+// */
+// void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CsgOp op)
+// {
+// if (target.dim == 2) {
+// switch (op) {
+// case UNION:
+// target.p2 += src.p2;
+// break;
+// case INTERSECTION:
+// target.p2 *= src.p2;
+// break;
+// case DIFFERENCE:
+// target.p2 -= src.p2;
+// break;
+// case MINKOWSKI:
+// target.p2 = minkowski2(target.p2, src.p2);
+// break;
+// }
+// }
+// else if (target.dim == 3) {
+// switch (op) {
+// case UNION:
+// target.p3 += src.p3;
+// break;
+// case INTERSECTION:
+// target.p3 *= src.p3;
+// break;
+// case DIFFERENCE:
+// target.p3 -= src.p3;
+// break;
+// case MINKOWSKI:
+// target.p3 = minkowski3(target.p3, src.p3);
+// break;
+// }
+// }
+// else {
+// assert(false && "Dimention of Nef polyhedron must be 2 or 3");
+// }
+// }
+
+void CGALRenderer::applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op)
+{
+ // FIXME: assert that cache contains nodes in code below
+ bool first = true;
+// CGAL_Nef_polyhedron N;
+ string N;
+ for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
+ iter != this->visitedchildren[node.index()].end();
+ iter++) {
+ const AbstractNode *chnode = iter->first;
+ const QString &chcacheid = iter->second;
+ // FIXME: Don't use deep access to modinst members
+ if (chnode->modinst->tag_background) continue;
+ if (first) {
+ N = "(" + this->cache[chcacheid];
+// if (N.dim != 0) first = false; // FIXME: when can this happen?
+ first = false;
+ } else {
+ process(N, this->cache[chcacheid], op);
+ }
+ chnode->progress_report();
+ }
+ N += ")";
+ QString cacheid = mk_cache_id(node);
+ this->cache.insert(cacheid, N);
+}
+
+Response CGALRenderer::visit(const State &state, const AbstractNode &node)
+{
+ if (isCached(node)) return PruneTraversal;
+
+ if (state.isPostfix()) {
+ applyToChildren(node, UNION);
+ }
+
+ handleVisitedChildren(state, node);
+ return ContinueTraversal;
+}
+
+Response CGALRenderer::visit(const State &state, const AbstractIntersectionNode &node)
+{
+ if (isCached(node)) return PruneTraversal;
+
+ if (state.isPostfix()) {
+ applyToChildren(node, INTERSECTION);
+ }
+
+ handleVisitedChildren(state, node);
+ return ContinueTraversal;
+}
+
+Response CGALRenderer::visit(const State &state, const CsgNode &node)
+{
+ if (isCached(node)) return PruneTraversal;
+
+ CsgOp op;
+ switch (node.type) {
+ case CSG_TYPE_UNION:
+ op = UNION;
+ break;
+ case CSG_TYPE_DIFFERENCE:
+ op = DIFFERENCE;
+ break;
+ case CSG_TYPE_INTERSECTION:
+ op = INTERSECTION;
+ break;
+ }
+
+ if (state.isPostfix()) {
+ applyToChildren(node, op);
+ }
+
+ handleVisitedChildren(state, node);
+ return ContinueTraversal;
+}
+
+Response CGALRenderer::visit(const State &state, const TransformNode &node)
+{
+ // FIXME: First union, then 2D/3D transform
+ return ContinueTraversal;
+}
+
+// FIXME: RenderNode: Union over children + some magic
+// FIXME: CgaladvNode: Iterate over children. Special operation
+
+// FIXME: Subtypes of AbstractPolyNode:
+// ProjectionNode
+// DxfLinearExtrudeNode
+// DxfRotateExtrudeNode
+// (SurfaceNode)
+// (PrimitiveNode)
+Response CGALRenderer::visit(const State &state, const AbstractPolyNode &node)
+{
+ // FIXME: Manage caching
+ // FIXME: Will generate one single Nef polyhedron (no csg ops necessary)
+
+// PolySet *ps = render_polyset(RENDER_CGAL);
+// try {
+// CGAL_Nef_polyhedron N = ps->renderCSGMesh();
+// cgal_nef_cache.insert(cache_id, new cgal_nef_cache_entry(N), N.weight());
+// print_messages_pop();
+// progress_report();
+
+// ps->unlink();
+// return N;
+// }
+// catch (...) { // Don't leak the PolySet on ProgressCancelException
+// ps->unlink();
+// throw;
+// }
+
+ if (state.isPostfix()) {
+ string N = "X";
+ QString cacheid = mk_cache_id(node);
+ this->cache.insert(cacheid, N);
+
+ std::cout << "Insert: " << N << "\n";
+ std::cout << "Node: " << cacheid.toStdString() << "\n\n";
+ }
+
+ handleVisitedChildren(state, node);
+
+ return ContinueTraversal;
+}
+
+void CGALRenderer::handleVisitedChildren(const State &state, const AbstractNode &node)
+{
+ QString cacheid = mk_cache_id(node);
+ if (state.isPostfix()) {
+ this->visitedchildren.erase(node.index());
+ if (!state.parent()) {
+ this->root = &node;
+ }
+ else {
+ this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, cacheid));
+ }
+ }
+}
+
+/*!
+ Create a cache id of the entire tree under this node. This cache id
+ is a non-whitespace plaintext of the evaluated scad tree and is used
+ for lookup in cgal_nef_cache.
+*/
+QString CGALRenderer::mk_cache_id(const AbstractNode &node) const
+{
+ // FIXME: should we keep a cache of cache_id's to avoid recalculating this?
+ // -> check how often we recalculate it.
+
+ // FIXME: Get dump from dump cache
+ // FIXME: assert that cache contains node
+ QString cache_id = QString::fromStdString(this->dumpcache[node]);
+ // Remove all node indices and whitespace
+ cache_id.remove(QRegExp("[a-zA-Z_][a-zA-Z_0-9]*:"));
+ cache_id.remove(' ');
+ cache_id.remove('\t');
+ cache_id.remove('\n');
+ return cache_id;
+}
diff --git a/src/CGALRenderer.h b/src/CGALRenderer.h
new file mode 100644
index 0000000..b30a24b
--- /dev/null
+++ b/src/CGALRenderer.h
@@ -0,0 +1,48 @@
+#ifndef CGALRENDERER_H_
+#define CGALRENDERER_H_
+
+#include <string>
+#include <map>
+#include <list>
+#include "visitor.h"
+#include "nodecache.h"
+
+using std::string;
+using std::map;
+using std::list;
+using std::pair;
+
+class CGALRenderer : public Visitor
+{
+public:
+ enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI};
+ CGALRenderer(const NodeCache<string> &dumpcache) : root(NULL), dumpcache(dumpcache) {}
+ virtual ~CGALRenderer() {}
+
+ virtual Response visit(const State &state, const AbstractNode &node);
+ virtual Response visit(const State &state, const AbstractIntersectionNode &node);
+ virtual Response visit(const State &state, const CsgNode &node);
+ virtual Response visit(const State &state, const TransformNode &node);
+ virtual Response visit(const State &state, const AbstractPolyNode &node);
+
+ string getCGALMesh() const;
+// CGAL_Nef_polyhedron getCGALMesh() const;
+private:
+ void handleVisitedChildren(const State &state, const AbstractNode &node);
+ bool isCached(const AbstractNode &node);
+ QString mk_cache_id(const AbstractNode &node) const;
+ void process(string &target, const string &src, CGALRenderer::CsgOp op);
+ void applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op);
+
+ string currindent;
+ const AbstractNode *root;
+ typedef list<pair<const AbstractNode *, QString> > ChildList;
+ map<int, ChildList> visitedchildren;
+// hashmap<string, CGAL_Nef_polyhedron> cache;
+
+ // For now use strings instead of Nef polyhedrons for testing caching
+ QHash<QString, string> cache;
+ const NodeCache<string> &dumpcache;
+};
+
+#endif
diff --git a/test-code/cgaltest.cc b/test-code/cgaltest.cc
new file mode 100644
index 0000000..837f442
--- /dev/null
+++ b/test-code/cgaltest.cc
@@ -0,0 +1,164 @@
+/*
+ * OpenSCAD (www.openscad.at)
+ * Copyright (C) 2009 Clifford Wolf <clifford@clifford.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * As a special exception, you have permission to link this program
+ * with the CGAL library and distribute executables, as long as you
+ * follow the requirements of the GNU GPL in regard to all of the
+ * software in the executable aside from CGAL.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "openscad.h"
+#include "node.h"
+#include "module.h"
+#include "context.h"
+#include "value.h"
+#include "export.h"
+#include "builtin.h"
+#include "nodedumper.h"
+#include "CGALRenderer.h"
+
+#include <QApplication>
+#include <QFile>
+#include <QDir>
+#include <QSet>
+#include <getopt.h>
+#include <iostream>
+
+QString commandline_commands;
+const char *make_command = NULL;
+QSet<QString> dependencies;
+QString currentdir;
+QString examplesdir;
+QString librarydir;
+
+void handle_dep(QString filename)
+{
+ if (filename.startsWith("/"))
+ dependencies.insert(filename);
+ else
+ dependencies.insert(QDir::currentPath() + QString("/") + filename);
+ if (!QFile(filename).exists() && make_command) {
+ char buffer[4096];
+ snprintf(buffer, 4096, "%s '%s'", make_command, filename.replace("'", "'\\''").toUtf8().data());
+ system(buffer); // FIXME: Handle error
+ }
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
+ exit(1);
+ }
+
+ const char *filename = argv[1];
+
+ int rc = 0;
+
+ initialize_builtin_functions();
+ initialize_builtin_modules();
+
+ QApplication app(argc, argv, false);
+ QDir original_path = QDir::current();
+
+ currentdir = QDir::currentPath();
+
+ QDir libdir(QApplication::instance()->applicationDirPath());
+#ifdef Q_WS_MAC
+ libdir.cd("../Resources"); // Libraries can be bundled
+ if (!libdir.exists("libraries")) libdir.cd("../../..");
+#elif defined(Q_OS_UNIX)
+ if (libdir.cd("../share/openscad/libraries")) {
+ librarydir = libdir.path();
+ } else
+ if (libdir.cd("../../share/openscad/libraries")) {
+ librarydir = libdir.path();
+ } else
+ if (libdir.cd("../../libraries")) {
+ librarydir = libdir.path();
+ } else
+#endif
+ if (libdir.cd("libraries")) {
+ librarydir = libdir.path();
+ }
+
+ Context root_ctx;
+ root_ctx.functions_p = &builtin_functions;
+ root_ctx.modules_p = &builtin_modules;
+ root_ctx.set_variable("$fn", Value(0.0));
+ root_ctx.set_variable("$fs", Value(1.0));
+ root_ctx.set_variable("$fa", Value(12.0));
+ root_ctx.set_variable("$t", Value(0.0));
+
+ Value zero3;
+ zero3.type = Value::VECTOR;
+ zero3.vec.append(new Value(0.0));
+ zero3.vec.append(new Value(0.0));
+ zero3.vec.append(new Value(0.0));
+ root_ctx.set_variable("$vpt", zero3);
+ root_ctx.set_variable("$vpr", zero3);
+
+
+ AbstractModule *root_module;
+ ModuleInstantiation root_inst;
+ AbstractNode *root_node;
+
+ QFileInfo fileInfo(filename);
+ handle_dep(filename);
+ FILE *fp = fopen(filename, "rt");
+ if (!fp) {
+ fprintf(stderr, "Can't open input file `%s'!\n", filename);
+ exit(1);
+ } else {
+ QString text;
+ char buffer[513];
+ int ret;
+ while ((ret = fread(buffer, 1, 512, fp)) > 0) {
+ buffer[ret] = 0;
+ text += buffer;
+ }
+ fclose(fp);
+ root_module = parse((text+commandline_commands).toAscii().data(), fileInfo.absolutePath().toLocal8Bit(), false);
+ if (!root_module) {
+ exit(1);
+ }
+ }
+
+ QDir::setCurrent(fileInfo.absolutePath());
+
+ AbstractNode::resetIndexCounter();
+ root_node = root_module->evaluate(&root_ctx, &root_inst);
+
+
+ NodeDumper dumper;
+ Traverser trav(dumper, *root_node, Traverser::PRE_AND_POSTFIX);
+ trav.execute();
+ std::string dumpstdstr = dumper.getDump() + "\n";
+ std::cout << dumpstdstr << "\n";
+
+ CGALRenderer renderer(dumper.getCache());
+ Traverser render(renderer, *root_node, Traverser::PRE_AND_POSTFIX);
+ render.execute();
+ std::cout << renderer.getCGALMesh() << "\n";
+
+ destroy_builtin_functions();
+ destroy_builtin_modules();
+
+ return rc;
+}
diff --git a/test-code/cgaltest.pro b/test-code/cgaltest.pro
new file mode 100644
index 0000000..8b68937
--- /dev/null
+++ b/test-code/cgaltest.pro
@@ -0,0 +1,99 @@
+DEFINES += OPENSCAD_VERSION=test
+TEMPLATE = app
+
+OBJECTS_DIR = objects
+MOC_DIR = objects
+UI_DIR = objects
+RCC_DIR = objects
+INCLUDEPATH += ../src
+
+DEFINES += REMOVE_DUMP
+macx {
+ CONFIG -= app_bundle
+ LIBS += -framework Carbon
+}
+
+CONFIG += qt
+QT += opengl
+
+# Optionally specify location of Eigen2 using the
+# EIGEN2DIR env. variable
+EIGEN2_DIR = $$(EIGEN2DIR)
+!isEmpty(EIGEN2_DIR) {
+ INCLUDEPATH += $$EIGEN2_DIR
+}
+else {
+ macx {
+ INCLUDEPATH += /opt/local/include/eigen2
+ }
+ else {
+ INCLUDEPATH += /usr/include/eigen2
+ }
+}
+
+LEXSOURCES += ../src/lexer.l
+YACCSOURCES += ../src/parser.y
+
+HEADERS += ../src/builtin.h \
+ ../src/cgal.h \
+ ../src/context.h \
+ ../src/csgterm.h \
+ ../src/dxfdata.h \
+ ../src/dxfdim.h \
+ ../src/dxftess.h \
+ ../src/export.h \
+ ../src/expression.h \
+ ../src/function.h \
+ ../src/grid.h \
+ ../src/module.h \
+ ../src/node.h \
+ ../src/dxflinextrudenode.h \
+ ../src/dxfrotextrudenode.h \
+ ../src/projectionnode.h \
+ ../src/importnode.h \
+ ../src/csgnode.h \
+ ../src/openscad.h \
+ ../src/polyset.h \
+ ../src/printutils.h \
+ ../src/value.h \
+ ../src/progress.h \
+ ../src/traverser.h \
+ ../src/csgnode.h \
+ ../src/visitor.h \
+ ../src/nodedumper.h \
+ ../src/CGALRenderer.h \
+ ../src/nodecache.h \
+ ../src/importnode.h \
+ ../src/state.h
+
+SOURCES += cgaltest.cc \
+ ../src/export.cc \
+ ../src/value.cc \
+ ../src/expr.cc \
+ ../src/func.cc \
+ ../src/module.cc \
+ ../src/node.cc \
+ ../src/context.cc \
+ ../src/csgterm.cc \
+ ../src/polyset.cc \
+ ../src/csgops.cc \
+ ../src/transform.cc \
+ ../src/primitives.cc \
+ ../src/projection.cc \
+ ../src/cgaladv.cc \
+ ../src/surface.cc \
+ ../src/control.cc \
+ ../src/render.cc \
+ ../src/import.cc \
+ ../src/dxfdata.cc \
+ ../src/dxftess.cc \
+ ../src/dxftess-glu.cc \
+ ../src/dxftess-cgal.cc \
+ ../src/dxfdim.cc \
+ ../src/dxflinextrude.cc \
+ ../src/dxfrotextrude.cc \
+ ../src/printutils.cc \
+ ../src/progress.cc \
+ ../src/nodedumper.cc \
+ ../src/CGALRenderer.cc \
+ ../src/traverser.cc
contact: Jan Huwald // Impressum