summaryrefslogtreecommitdiff
path: root/test-code
diff options
context:
space:
mode:
Diffstat (limited to 'test-code')
-rw-r--r--test-code/CSGTextRenderer.cc286
-rw-r--r--test-code/CSGTextRenderer.h48
2 files changed, 334 insertions, 0 deletions
diff --git a/test-code/CSGTextRenderer.cc b/test-code/CSGTextRenderer.cc
new file mode 100644
index 0000000..a366fb7
--- /dev/null
+++ b/test-code/CSGTextRenderer.cc
@@ -0,0 +1,286 @@
+#include "CSGTextRenderer.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 "transformnode.h"
+
+#include <sstream>
+#include <iostream>
+#include <assert.h>
+#include <QRegExp>
+
+string CSGTextRenderer::getCGALMesh() const
+{
+ assert(this->root);
+ // FIXME: assert that cache contains root
+ return this->cache[mk_cache_id(*this->root)];
+}
+
+// CGAL_Nef_polyhedron CSGTextRenderer::getCGALMesh() const
+// {
+// assert(this->root);
+// // FIXME: assert that cache contains root
+// return this->cache[*this->root];
+// }
+
+bool CSGTextRenderer::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
+CSGTextRenderer::process(string &target, const string &src, CSGTextRenderer::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 CSGTextRenderer::applyToChildren(const AbstractNode &node, CSGTextRenderer::CsgOp op)
+{
+ std::stringstream stream;
+ stream << typeid(node).name();
+ stream << "<" << node.index() << ">";
+ string N = stream.str();
+ if (this->visitedchildren[node.index()].size() > 0) {
+ // FIXME: assert that cache contains nodes in code below
+ bool first = true;
+// CGAL_Nef_polyhedron 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);
+}
+
+/*
+ Typical visitor behavior:
+ o In prefix: Check if we're cached -> prune
+ o In postfix: Check if we're cached -> don't apply operator to children
+ o In postfix: addToParent()
+ */
+
+Response CSGTextRenderer::visit(const State &state, const AbstractNode &node)
+{
+ if (state.isPrefix() && isCached(node)) return PruneTraversal;
+ if (state.isPostfix()) {
+ if (!isCached(node)) applyToChildren(node, UNION);
+ addToParent(state, node);
+ }
+ return ContinueTraversal;
+}
+
+Response CSGTextRenderer::visit(const State &state, const AbstractIntersectionNode &node)
+{
+ if (state.isPrefix() && isCached(node)) return PruneTraversal;
+ if (state.isPostfix()) {
+ if (!isCached(node)) applyToChildren(node, INTERSECTION);
+ addToParent(state, node);
+ }
+ return ContinueTraversal;
+}
+
+Response CSGTextRenderer::visit(const State &state, const CsgNode &node)
+{
+ if (state.isPrefix() && isCached(node)) return PruneTraversal;
+ if (state.isPostfix()) {
+ if (!isCached(node)) {
+ 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;
+ }
+ applyToChildren(node, op);
+ }
+ addToParent(state, node);
+ }
+ return ContinueTraversal;
+}
+
+Response CSGTextRenderer::visit(const State &state, const TransformNode &node)
+{
+ if (state.isPrefix() && isCached(node)) return PruneTraversal;
+ if (state.isPostfix()) {
+ if (!isCached(node)) {
+ // First union all children
+ applyToChildren(node, UNION);
+ // FIXME: Then apply transform
+ }
+ addToParent(state, node);
+ }
+ 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 CSGTextRenderer::visit(const State &state, const AbstractPolyNode &node)
+{
+ if (state.isPrefix() && isCached(node)) return PruneTraversal;
+ if (state.isPostfix()) {
+ if (!isCached(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;
+// }
+
+ string N = typeid(node).name();
+ QString cacheid = mk_cache_id(node);
+ this->cache.insert(cacheid, N);
+
+// std::cout << "Insert: " << N << "\n";
+// std::cout << "Node: " << cacheid.toStdString() << "\n\n";
+ }
+ addToParent(state, node);
+ }
+
+ return ContinueTraversal;
+}
+
+/*!
+ Adds ourself to out parent's list of traversed children.
+ Call this for _every_ node which affects output during the postfix traversal.
+*/
+void CSGTextRenderer::addToParent(const State &state, const AbstractNode &node)
+{
+ assert(state.isPostfix());
+ QString cacheid = mk_cache_id(node);
+ 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 CSGTextRenderer::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/test-code/CSGTextRenderer.h b/test-code/CSGTextRenderer.h
new file mode 100644
index 0000000..84f3d30
--- /dev/null
+++ b/test-code/CSGTextRenderer.h
@@ -0,0 +1,48 @@
+#ifndef CSGTEXTRENDERER_H_
+#define CSGTEXTRENDERER_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 CSGTextRenderer : public Visitor
+{
+public:
+ enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI};
+ CSGTextRenderer(const NodeCache<string> &dumpcache) : root(NULL), dumpcache(dumpcache) {}
+ virtual ~CSGTextRenderer() {}
+
+ 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 addToParent(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, CSGTextRenderer::CsgOp op);
+ void applyToChildren(const AbstractNode &node, CSGTextRenderer::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
contact: Jan Huwald // Impressum