diff options
author | Marius Kintel <marius@kintel.net> | 2010-04-12 00:16:36 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2010-10-31 00:42:35 (GMT) |
commit | e8e213b3c9ce0580045ea6e7e86b00ab41d4c58b (patch) | |
tree | cb32e67b6334aa1f1dc62aa4a0686a22782e7f77 | |
parent | 53a9953b7dc4ab4a366046c91529b32fb6652551 (diff) |
Another refactoring session:
o mk_cache_id() obsoleted by removing the node index from the dump
o node index output removed from each node and make optional in NodeDumper
o The visitors are no longer global, but associated with a tree
o Added Tree class to manage node trees and the (now implicit) dump cache
o Moved PolySet cache into PolySetRenderer
35 files changed, 297 insertions, 275 deletions
diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc index 6a13994..67529b3 100644 --- a/src/CGALRenderer.cc +++ b/src/CGALRenderer.cc @@ -22,8 +22,6 @@ #include <assert.h> #include <QRegExp> -CGALRenderer *CGALRenderer::global_renderer = NULL; - CGAL_Nef_polyhedron CGALRenderer::renderCGALMesh(const AbstractNode &node) { if (!isCached(node)) { @@ -31,12 +29,12 @@ CGAL_Nef_polyhedron CGALRenderer::renderCGALMesh(const AbstractNode &node) render.execute(); assert(isCached(node)); } - return this->cache[mk_cache_id(node)]; + return this->cache[this->dumpcache[node]]; } bool CGALRenderer::isCached(const AbstractNode &node) const { - return this->cache.contains(mk_cache_id(node)); + return this->cache.contains(this->dumpcache[node]); } /*! @@ -111,8 +109,7 @@ void CGALRenderer::applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp chnode->progress_report(); } } - QString cacheid = mk_cache_id(node); - this->cache.insert(cacheid, N); + this->cache.insert(this->dumpcache[node], N); } /* @@ -175,8 +172,7 @@ Response CGALRenderer::visit(const State &state, const TransformNode &node) applyToChildren(node, UNION); // Then apply transform - QString cacheid = mk_cache_id(node); - CGAL_Nef_polyhedron N = this->cache[cacheid]; + CGAL_Nef_polyhedron N = this->cache[this->dumpcache[node]]; assert(N.dim >= 2 && N.dim <= 3); if (N.dim == 2) { // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2 @@ -241,8 +237,7 @@ Response CGALRenderer::visit(const State &state, const AbstractPolyNode &node) node.progress_report(); ps->unlink(); - QString cacheid = mk_cache_id(node); - this->cache.insert(cacheid, N); + this->cache.insert(this->dumpcache[node], N); } catch (...) { // Don't leak the PolySet on ProgressCancelException ps->unlink(); @@ -261,37 +256,12 @@ Response CGALRenderer::visit(const State &state, const AbstractPolyNode &node) void CGALRenderer::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)); + if (state.parent()) { + this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->dumpcache[node])); } } -/*! - 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; -} - #if 0 /*! Static function to render CGAL meshes. diff --git a/src/CGALRenderer.h b/src/CGALRenderer.h index fc7e0c4..0492c86 100644 --- a/src/CGALRenderer.h +++ b/src/CGALRenderer.h @@ -22,8 +22,8 @@ class CGALRenderer : public Visitor { public: enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI}; - // FIXME: If a cache is not give, we need to fix this ourselves - CGALRenderer(const NodeCache<string> &dumpcache) : root(NULL), dumpcache(dumpcache) {} + // FIXME: If a cache is not given, we need to fix this ourselves + CGALRenderer(QHash<QString, CGAL_Nef_polyhedron> &cache, const NodeCache<string> &dumpcache) : cache(cache), dumpcache(dumpcache) {} virtual ~CGALRenderer() {} virtual Response visit(const State &state, const AbstractNode &node); @@ -32,14 +32,9 @@ public: virtual Response visit(const State &state, const TransformNode &node); virtual Response visit(const State &state, const AbstractPolyNode &node); - QHash<QString, CGAL_Nef_polyhedron> &getCache() { return this->cache; } - CGAL_Nef_polyhedron renderCGALMesh(const AbstractNode &node); CGAL_Nef_polyhedron renderCGALMesh(const PolySet &polyset); - // FIXME: Questionable design... - static CGALRenderer *renderer() { return global_renderer; } - static void setRenderer(CGALRenderer *r) { global_renderer = r; } private: void addToParent(const State &state, const AbstractNode &node); bool isCached(const AbstractNode &node) const; @@ -48,15 +43,11 @@ private: void applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op); string currindent; - const AbstractNode *root; typedef list<pair<const AbstractNode *, QString> > ChildList; map<int, ChildList> visitedchildren; - // FIXME: enforce some maximum cache size (old version had 100K vertices as limit) - QHash<QString, CGAL_Nef_polyhedron> cache; + QHash<QString, CGAL_Nef_polyhedron> &cache; const NodeCache<string> &dumpcache; - - static CGALRenderer *global_renderer; }; #endif diff --git a/src/MainWindow.h b/src/MainWindow.h index c0a9844..3141386 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -32,6 +32,7 @@ public: ModuleInstantiation root_inst; // Top level instance AbstractNode *absolute_root_node; // Result of tree evaluation AbstractNode *root_node; // Root if the root modifier (!) is used + class NodeDumper *dumper; class CSGTerm *root_raw_term; // Result of CSG term rendering CSGTerm *root_norm_term; // Normalized CSG products @@ -76,6 +77,7 @@ private: void compileCSG(bool procevents); bool maybeSave(); bool checkModified(); + QString dumpCSGTree(AbstractNode *root); static void consoleOutput(const QString &msg, void *userdata) { static_cast<MainWindow*>(userdata)->console->append(msg); } diff --git a/src/PolySetCGALRenderer.cc b/src/PolySetCGALRenderer.cc index acd03eb..38cc1cc 100644 --- a/src/PolySetCGALRenderer.cc +++ b/src/PolySetCGALRenderer.cc @@ -14,6 +14,10 @@ PolySet *PolySetCGALRenderer::renderPolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e) { + // FIXME: create cacheid from node + QString cacheid; + if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link(); + CGAL_Nef_polyhedron N = this->cgalrenderer.renderCGALMesh(node); PolySet *ps = new PolySet(); @@ -155,6 +159,7 @@ PolySet *PolySetCGALRenderer::renderPolySet(const ProjectionNode &node, Abstract cant_project_non_simple_polyhedron: + this->cache.insert(cacheid, new cache_entry(ps->link())); return ps; } @@ -232,6 +237,10 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2, PolySet *PolySetCGALRenderer::renderPolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e) { + // FIXME: create cacheid from node + QString cacheid; + if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link(); + DxfData *dxf; if (node.filename.isEmpty()) @@ -305,11 +314,16 @@ PolySet *PolySetCGALRenderer::renderPolySet(const DxfLinearExtrudeNode &node, Ab delete dxf; + this->cache.insert(cacheid, new cache_entry(ps->link())); return ps; } PolySet *PolySetCGALRenderer::renderPolySet(const DxfRotateExtrudeNode &node, AbstractPolyNode::render_mode_e) { + // FIXME: create cacheid from node + QString cacheid; + if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link(); + DxfData *dxf; if (node.filename.isEmpty()) @@ -380,5 +394,6 @@ PolySet *PolySetCGALRenderer::renderPolySet(const DxfRotateExtrudeNode &node, Ab delete dxf; + this->cache.insert(cacheid, new cache_entry(ps->link())); return ps; } diff --git a/src/PolySetRenderer.cc b/src/PolySetRenderer.cc index 287cbb9..c2fddf0 100644 --- a/src/PolySetRenderer.cc +++ b/src/PolySetRenderer.cc @@ -1,5 +1,15 @@ #include "PolySetRenderer.h" +#include "printutils.h" +#include "polyset.h" PolySetRenderer *PolySetRenderer::global_renderer = NULL; +PolySetRenderer::cache_entry::cache_entry(PolySet *ps) : + ps(ps), msg(print_messages_stack.last()) +{ +} +PolySetRenderer::cache_entry::~cache_entry() +{ + ps->unlink(); +} diff --git a/src/PolySetRenderer.h b/src/PolySetRenderer.h index cff528f..ddd692f 100644 --- a/src/PolySetRenderer.h +++ b/src/PolySetRenderer.h @@ -2,20 +2,37 @@ #define POLYSETRENDERER_H_ #include "node.h" +#include <QCache> class PolySetRenderer { public: enum RenderMode { RENDER_CGAL, RENDER_OPENCSG }; - PolySetRenderer() {} + PolySetRenderer() : cache(100) {} + virtual ~PolySetRenderer() {} - virtual PolySet *renderPolySet(const class ProjectionNode &node, AbstractPolyNode::render_mode_e) = 0; - virtual PolySet *renderPolySet(const class DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e) = 0; - virtual PolySet *renderPolySet(const class DxfRotateExtrudeNode &node, AbstractPolyNode::render_mode_e) = 0; + virtual PolySet *renderPolySet(const class ProjectionNode &, AbstractPolyNode::render_mode_e) = 0; + virtual PolySet *renderPolySet(const class DxfLinearExtrudeNode &, AbstractPolyNode::render_mode_e) = 0; + virtual PolySet *renderPolySet(const class DxfRotateExtrudeNode &, AbstractPolyNode::render_mode_e) = 0; + + void clearCache() { + this->cache.clear(); + } static PolySetRenderer *renderer() { return global_renderer; } static void setRenderer(PolySetRenderer *r) { global_renderer = r; } +protected: + + struct cache_entry { + class PolySet *ps; + QString msg; + cache_entry(PolySet *ps); + ~cache_entry(); + }; + + QCache<QString, cache_entry> cache; + private: static PolySetRenderer *global_renderer; }; diff --git a/src/Tree.cc b/src/Tree.cc new file mode 100644 index 0000000..1561b4f --- /dev/null +++ b/src/Tree.cc @@ -0,0 +1,17 @@ +#include "Tree.h" +#include "nodedumper.h" + +#include <assert.h> + +const std::string &Tree::getString(const AbstractNode &node) const +{ + assert(this->root_node); + if (!this->nodecache.contains(node)) { + NodeDumper dumper(this->nodecache, false); + Traverser trav(dumper, *this->root_node, Traverser::PRE_AND_POSTFIX); + trav.execute(); + assert(this->nodecache.contains(*this->root_node) && + "NodeDumper failed to create a cache"); + } + return this->nodecache[node]; +} diff --git a/src/Tree.h b/src/Tree.h new file mode 100644 index 0000000..9cfef84 --- /dev/null +++ b/src/Tree.h @@ -0,0 +1,29 @@ +#ifndef TREE_H_ +#define TREE_H_ + +#include "nodecache.h" +//#include "cgal.h" + +using std::string; + +class Tree +{ +public: + Tree() { + this->root_node = NULL; + } + ~Tree() {} + + void setRoot(const AbstractNode *root) { this->root_node = root; } + const AbstractNode *root() const { return this->root_node; } + + // FIXME: Really return a reference? + const string &getString(const AbstractNode &node) const; +// CGAL_Nef_polyhedron getCGALMesh(const AbstractNode &node) const; + +private: + const AbstractNode *root_node; + mutable NodeCache nodecache; +}; + +#endif diff --git a/src/cgaladv.cc b/src/cgaladv.cc index 87975d2..114620f 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -160,7 +160,6 @@ CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlight std::string CgaladvNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; switch (type) { case MINKOWSKI: diff --git a/src/csgops.cc b/src/csgops.cc index dda523e..d814e87 100644 --- a/src/csgops.cc +++ b/src/csgops.cc @@ -80,7 +80,6 @@ CSGTerm *CsgNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, Q std::string CsgNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; switch (this->type) { case CSG_TYPE_UNION: diff --git a/src/dxflinextrude.cc b/src/dxflinextrude.cc index b704c35..3c8d7ac 100644 --- a/src/dxflinextrude.cc +++ b/src/dxflinextrude.cc @@ -136,16 +136,9 @@ PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e mode) const return ps; } - QString key = mk_cache_id(); - if (PolySet::ps_cache.contains(key)) { - PRINT(PolySet::ps_cache[key]->msg); - return PolySet::ps_cache[key]->ps->link(); - } - print_messages_push(); PolySet *ps = renderer->renderPolySet(*this, mode); - PolySet::ps_cache.insert(key, new PolySet::ps_cache_entry(ps->link())); print_messages_pop(); @@ -155,7 +148,6 @@ PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e mode) const std::string DxfLinearExtrudeNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; QString text; struct stat st; diff --git a/src/dxfrotextrude.cc b/src/dxfrotextrude.cc index a84097f..36e6cdf 100644 --- a/src/dxfrotextrude.cc +++ b/src/dxfrotextrude.cc @@ -112,18 +112,10 @@ PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e mode) const return ps; } - QString key = mk_cache_id(); - if (PolySet::ps_cache.contains(key)) { - PRINT(PolySet::ps_cache[key]->msg); - return PolySet::ps_cache[key]->ps->link(); - } - print_messages_push(); PolySet *ps = renderer->renderPolySet(*this, mode); - PolySet::ps_cache.insert(key, new PolySet::ps_cache_entry(ps->link())); - print_messages_pop(); return ps; @@ -132,7 +124,6 @@ PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e mode) const std::string DxfRotateExtrudeNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; struct stat st; memset(&st, 0, sizeof(struct stat)); diff --git a/src/import.cc b/src/import.cc index aeda529..619421a 100644 --- a/src/import.cc +++ b/src/import.cc @@ -192,7 +192,6 @@ PolySet *ImportNode::render_polyset(render_mode_e) const std::string ImportNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; QString text; struct stat st; diff --git a/src/mainwin.cc b/src/mainwin.cc index 5eb5498..9f14aed 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -151,6 +151,7 @@ MainWindow::MainWindow(const QString &filename) root_raw_term = NULL; root_norm_term = NULL; root_chain = NULL; + this->dumper = new NodeDumper; #ifdef ENABLE_CGAL this->root_N = NULL; this->recreate_cgal_ogl_p = false; @@ -538,6 +539,13 @@ AbstractNode *MainWindow::find_root_tag(AbstractNode *n) return NULL; } +QString MainWindow::dumpCSGTree(AbstractNode *root) +{ + Traverser trav(*this->dumper, *root, Traverser::PRE_AND_POSTFIX); + trav.execute(); + return QString::fromStdString(this->dumper->getDump() + "\n"); +} + /*! Parse and evaluate the design -> this->root_node */ @@ -653,11 +661,11 @@ void MainWindow::compile(bool procevents) if (!(this->root_node = find_root_tag(absolute_root_node))) { this->root_node = absolute_root_node; } - // Dump the tree (to initialize caches). I guess we wouldn't really need to do - // this explicitly.. - root_node->dump(); + // Dump the tree (to initialize caches). + // FIXME: We shouldn't really need to do this explicitly.. + dumpCSGTree(this->root_node); - if (1) { + if (1) { PRINT("Compilation finished."); if (procevents) QApplication::processEvents(); @@ -1131,7 +1139,11 @@ void MainWindow::actionRenderCGAL() progress_report_prep(root_node, report_func, pd); try { - this->root_N = new CGAL_Nef_polyhedron(CGALRenderer::renderer()->renderCGALMesh(*root_node)); +// this->root_N = new CGAL_Nef_polyhedron(CGALRenderer::renderer()->renderCGALMesh(*root_node)); + + Tree *tree = this->tree; + CGALRenderDriver renderer(tree); + this->root_N = new CGAL_Nef_polyhedron(renderer->renderCGALMesh()); } catch (ProgressCancelException e) { PRINT("Rendering cancelled."); @@ -1234,7 +1246,7 @@ void MainWindow::actionDisplayCSGTree() e->setWindowTitle("CSG Tree Dump"); e->setReadOnly(true); if (root_node) { - e->setPlainText(root_node->dump()); + e->setPlainText(QString::fromStdString(this->dumper->getDump())); } else { e->setPlainText("No CSG to dump. Please try compiling first..."); } @@ -1359,10 +1371,10 @@ void MainWindow::actionExportDXF() void MainWindow::actionFlushCaches() { // FIXME: Polycache -> PolySetRenderer - PolySet::ps_cache.clear(); + PolySetRenderer::renderer()->clearCache(); #ifdef ENABLE_CGAL CGALRenderer::renderer()->getCache().clear(); - NodeDumper::dumper()->clearCache(); + this->dumper->clearCache(); #endif dxf_dim_cache.clear(); dxf_cross_cache.clear(); diff --git a/src/node.cc b/src/node.cc index dc2fc0c..69c0692 100644 --- a/src/node.cc +++ b/src/node.cc @@ -64,26 +64,17 @@ Response AbstractPolyNode::accept(const class State &state, Visitor &visitor) co return visitor.visit(state, *this); } -// FIXME: Temporarily offer a top-level dump function to keep existing code running -QString AbstractNode::dump() const -{ - NodeDumper dumper; - Traverser trav(dumper, *this, Traverser::PRE_AND_POSTFIX); - trav.execute(); - return QString::fromStdString(dumper.getDump() + "\n"); -} - std::string AbstractNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": group()"; + stream << "group()"; return stream.str(); } std::string AbstractIntersectionNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": intersection()"; + stream << "intersection()"; return stream.str(); } @@ -161,13 +152,3 @@ std::ostream &operator<<(std::ostream &stream, const AbstractNode &node) stream << node.toString(); return stream; } - -QString AbstractNode::mk_cache_id() const -{ - QString cache_id = dump(); - 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; -} @@ -51,10 +51,6 @@ public: int idx; // Node index (unique per tree) - // FIXME: Remove these three with dump() method - virtual QString mk_cache_id() const; - QString dump() const; - // FIXME: Rewrite to visitor virtual class CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const; diff --git a/src/nodecache.h b/src/nodecache.h index efd5104..ca0bd6c 100644 --- a/src/nodecache.h +++ b/src/nodecache.h @@ -2,27 +2,36 @@ #define NODECACHE_H_ #include <vector> +#include <string> #include "node.h" -template <class T> +/*! + Caches values per node based on the node.index(). + The node index guaranteed to be unique per node tree since the index is reset + every time a new tree is generated. +*/ class NodeCache { public: NodeCache() { } virtual ~NodeCache() { } - const T & operator[](const AbstractNode &node) const { + bool contains(const AbstractNode &node) const { + return !(*this)[node].empty(); + } + + const std::string & operator[](const AbstractNode &node) const { if (this->cache.size() > node.index()) return this->cache[node.index()]; - else return nullvalue; + else return this->nullvalue; } - void insert(const class AbstractNode &node, const T & value) { + void insert(const class AbstractNode &node, const std::string & value) { if (this->cache.size() <= node.index()) this->cache.resize(node.index() + 1); this->cache[node.index()] = value; } void remove(const class AbstractNode &node) { - if (this->cache.size() > node.index()) this->cache[node.index()] = nullvalue; + if (this->cache.size() > node.index()) this->cache[node.index()] = std::string(); } void clear() { @@ -30,8 +39,8 @@ public: } private: - std::vector<T> cache; - T nullvalue; + std::vector<std::string> cache; + std::string nullvalue; }; #endif diff --git a/src/nodedumper.cc b/src/nodedumper.cc index a62ad98..7d0c850 100644 --- a/src/nodedumper.cc +++ b/src/nodedumper.cc @@ -10,21 +10,31 @@ #include <iostream> #include <assert.h> -// For compatibility with old dump() output -#define NODEDUMPER_COMPAT_MODE +// For compatibility with old dump() output. +// FIXME: Only needed for testing. +//#define NODEDUMPER_COMPAT_MODE #ifdef NODEDUMPER_COMPAT_MODE #include "dxflinextrudenode.h" #include "dxfrotextrudenode.h" #include "projectionnode.h" #endif -NodeDumper *NodeDumper::global_dumper = NULL; +/*! + \class NodeDumper + + A visitor responsible for creating a text dump of a node tree. Also + contains a cache for fast retrieval of the text representation of + any node or subtree. +*/ -bool NodeDumper::isCached(const AbstractNode &node) +bool NodeDumper::isCached(const AbstractNode &node) const { return !this->cache[node].empty(); } +/*! + Indent or deindent. Must be called before we output any children. +*/ void NodeDumper::handleIndent(const State &state) { if (state.isPrefix()) { @@ -36,6 +46,11 @@ void NodeDumper::handleIndent(const State &state) } } +/*! + Dumps the block of children contained in this->visitedchildren, + including braces and indentation. + All children are assumed to be cached already. + */ string NodeDumper::dumpChildren(const AbstractNode &node) { std::stringstream dump; @@ -45,7 +60,7 @@ string NodeDumper::dumpChildren(const AbstractNode &node) for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin(); iter != this->visitedchildren[node.index()].end(); iter++) { -// FIXME: assert that cache contains **iter + assert(isCached(**iter)); dump << this->cache[**iter] << "\n"; } @@ -65,14 +80,20 @@ string NodeDumper::dumpChildren(const AbstractNode &node) return dump.str(); } - +/*! + Called for each node in the tree. + Will abort traversal if we're cached +*/ Response NodeDumper::visit(const State &state, const AbstractNode &node) { if (isCached(node)) return PruneTraversal; - else handleIndent(state); + + handleIndent(state); if (state.isPostfix()) { std::stringstream dump; - dump << this->currindent << node; + dump << this->currindent; + if (this->idprefix) dump << "n" << node.index() << ":"; + dump << node; dump << dumpChildren(node); this->cache.insert(node, dump.str()); } @@ -81,13 +102,6 @@ Response NodeDumper::visit(const State &state, const AbstractNode &node) return ContinueTraversal; } -const string &NodeDumper::getDump() const -{ - assert(this->root); -// FIXME: assert that cache contains root - return this->cache[*this->root]; -} - /*! Adds this given node to its parent's child list. Should be called for all nodes, including leaf nodes. diff --git a/src/nodedumper.h b/src/nodedumper.h index ca76814..fceaacb 100644 --- a/src/nodedumper.h +++ b/src/nodedumper.h @@ -14,31 +14,27 @@ using std::list; class NodeDumper : public Visitor { public: - NodeDumper() : root(NULL) {} + /*! If idPrefix is true, we will output "n<id>:" in front of each node, + which is useful for debugging. */ + NodeDumper(NodeCache &cache, bool idPrefix = false) : + cache(cache), idprefix(idPrefix), root(NULL) { } virtual ~NodeDumper() {} virtual Response visit(const State &state, const AbstractNode &node); - const string &getDump() const; - const NodeCache<string> &getCache() const { return this->cache; } - void clearCache() { this->cache.clear(); } - - // FIXME: Questionable design... - static NodeDumper *dumper() { return global_dumper; } - static void setDumper(NodeDumper *d) { global_dumper = d; } private: void handleVisitedChildren(const State &state, const AbstractNode &node); - bool isCached(const AbstractNode &node); + bool isCached(const AbstractNode &node) const; void handleIndent(const State &state); string dumpChildren(const AbstractNode &node); + NodeCache &cache; + bool idprefix; + string currindent; const AbstractNode *root; typedef list<const AbstractNode *> ChildList; map<int, ChildList> visitedchildren; - NodeCache<string> cache; - - static NodeDumper *global_dumper; }; #endif diff --git a/src/openscad.cc b/src/openscad.cc index 1e78316..35da4d7 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -241,7 +241,6 @@ int main(int argc, char **argv) NodeDumper dumper; CGALRenderer cgalrenderer(dumper.getCache()); PolySetCGALRenderer psrenderer(cgalrenderer); - NodeDumper::setDumper(&dumper); CGALRenderer::setRenderer(&cgalrenderer); PolySetRenderer::setRenderer(&psrenderer); @@ -297,9 +296,11 @@ int main(int argc, char **argv) // FIXME: It shouldn't be necessary to dump manually, only when // the dumper and the renderer wants to share a cache - Traverser trav(*NodeDumper::dumper(), *root_node, Traverser::PRE_AND_POSTFIX); - trav.execute(); - CGAL_Nef_polyhedron root_N = CGALRenderer::renderer()->renderCGALMesh(*root_node); + // FIXME: Rewrite to non-global dumper +// Traverser trav(*NodeDumper::dumper(), *root_node, Traverser::PRE_AND_POSTFIX); +// trav.execute(); +// CGAL_Nef_polyhedron root_N = CGALRenderer::renderer()->renderCGALMesh(*root_node); + CGAL_Nef_polyhedron root_N; QDir::setCurrent(original_path.absolutePath()); diff --git a/src/polyset.cc b/src/polyset.cc index 9f32f6e..396f759 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -33,15 +33,6 @@ #include <Eigen/Core> #include <Eigen/LU> -QCache<QString,PolySet::ps_cache_entry> PolySet::ps_cache(100); - -PolySet::ps_cache_entry::ps_cache_entry(PolySet *ps) : - ps(ps), msg(print_messages_stack.last()) { } - -PolySet::ps_cache_entry::~ps_cache_entry() { - ps->unlink(); -} - PolySet::PolySet() : grid(GRID_FINE) { is2d = false; diff --git a/src/polyset.h b/src/polyset.h index 3f0e725..0183fd8 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -62,15 +62,6 @@ public: CSGMODE_HIGHLIGHT_DIFFERENCE = 22 }; - struct ps_cache_entry { - PolySet *ps; - QString msg; - ps_cache_entry(PolySet *ps); - ~ps_cache_entry(); - }; - - static QCache<QString,ps_cache_entry> ps_cache; - void render_surface(colormode_e colormode, csgmode_e csgmode, double *m, GLint *shaderinfo = NULL) const; void render_edges(colormode_e colormode, csgmode_e csgmode) const; diff --git a/src/primitives.cc b/src/primitives.cc index 16c6ab7..de9689d 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -529,7 +529,6 @@ sphere_next_r2: std::string PrimitiveNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; switch (this->type) { case CUBE: diff --git a/src/projection.cc b/src/projection.cc index 83f0205..073a5b1 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -85,11 +85,6 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant return node; } -void register_builtin_projection() -{ - builtin_modules["projection"] = new ProjectionModule(); -} - PolySet *ProjectionNode::render_polyset(render_mode_e mode) const { PolySetRenderer *renderer = PolySetRenderer::renderer(); @@ -100,16 +95,9 @@ PolySet *ProjectionNode::render_polyset(render_mode_e mode) const return ps; } - QString key = mk_cache_id(); - if (PolySet::ps_cache.contains(key)) { - PRINT(PolySet::ps_cache[key]->msg); - return PolySet::ps_cache[key]->ps->link(); - } - print_messages_push(); PolySet *ps = renderer->renderPolySet(*this, mode); - PolySet::ps_cache.insert(key, new PolySet::ps_cache_entry(ps->link())); print_messages_pop(); @@ -119,10 +107,14 @@ PolySet *ProjectionNode::render_polyset(render_mode_e mode) const std::string ProjectionNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; stream << "projection(cut = " << (this->cut_mode ? "true" : "false") << ", convexity = " << this->convexity << ")"; return stream.str(); } + +void register_builtin_projection() +{ + builtin_modules["projection"] = new ProjectionModule(); +} diff --git a/src/render.cc b/src/render.cc index 0218e7f..92ec88c 100644 --- a/src/render.cc +++ b/src/render.cc @@ -206,7 +206,6 @@ CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights std::string RenderNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; stream << "render(convexity = " << convexity << ")"; diff --git a/src/surface.cc b/src/surface.cc index a7b58a1..afaaeb0 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -206,7 +206,6 @@ PolySet *SurfaceNode::render_polyset(render_mode_e) const std::string SurfaceNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; stream << "surface(file = \"" << this->filename << "\", center = " << (this->center ? "true" : "false") << ")"; diff --git a/src/transform.cc b/src/transform.cc index 0bbf9bd..82e5659 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -266,7 +266,6 @@ CSGTerm *TransformNode::render_csg_term(double c[20], QVector<CSGTerm*> *highlig std::string TransformNode::toString() const { std::stringstream stream; - stream << "n" << this->index() << ": "; if (m[16] >= 0 || m[17] >= 0 || m[18] >= 0 || m[19] >= 0) { stream << "color([" << m[16] << ", " << m[17] << ", " << m[18] << ", " << m[19] << "])"; diff --git a/test-code/CSGTextRenderer.cc b/test-code/CSGTextRenderer.cc index d9e3667..ab498f6 100644 --- a/test-code/CSGTextRenderer.cc +++ b/test-code/CSGTextRenderer.cc @@ -1,10 +1,10 @@ #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" @@ -15,23 +15,9 @@ #include <assert.h> #include <QRegExp> -string CSGTextRenderer::getCSGString() 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)); + return this->cache.contains(this->tree.getString(node)); } /*! @@ -118,7 +104,7 @@ void CSGTextRenderer::applyToChildren(const AbstractNode &node, CSGTextRenderer: iter != this->visitedchildren[node.index()].end(); iter++) { const AbstractNode *chnode = iter->first; - const QString &chcacheid = iter->second; + const string &chcacheid = iter->second; // FIXME: Don't use deep access to modinst members if (chnode->modinst->tag_background) continue; if (first) { @@ -132,8 +118,7 @@ void CSGTextRenderer::applyToChildren(const AbstractNode &node, CSGTextRenderer: } N += ")"; } - QString cacheid = mk_cache_id(node); - this->cache.insert(cacheid, N); + this->cache.insert(this->tree.getString(node), N); } /* @@ -235,8 +220,7 @@ Response CSGTextRenderer::visit(const State &state, const AbstractPolyNode &node // } string N = typeid(node).name(); - QString cacheid = mk_cache_id(node); - this->cache.insert(cacheid, N); + this->cache.insert(this->tree.getString(node), N); // std::cout << "Insert: " << N << "\n"; // std::cout << "Node: " << cacheid.toStdString() << "\n\n"; @@ -254,33 +238,28 @@ Response CSGTextRenderer::visit(const State &state, const AbstractPolyNode &node 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)); + if (state.parent()) { + this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getString(node))); } } -/*! - 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 + + +static uint hash(const uchar *p, int n) { - // FIXME: should we keep a cache of cache_id's to avoid recalculating this? - // -> check how often we recalculate it. + uint h = 0; + uint g; + + while (n--) { + h = (h << 4) + *p++; + if ((g = (h & 0xf0000000)) != 0) + h ^= g >> 23; + h &= ~g; + } + return h; +} - // 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; +uint qHash(const string &str) { + return hash(reinterpret_cast<const uchar *>(str.c_str()), str.length()); } diff --git a/test-code/CSGTextRenderer.h b/test-code/CSGTextRenderer.h index 22d722f..236f900 100644 --- a/test-code/CSGTextRenderer.h +++ b/test-code/CSGTextRenderer.h @@ -1,11 +1,15 @@ #ifndef CSGTEXTRENDERER_H_ #define CSGTEXTRENDERER_H_ +#include <qglobal.h> #include <string> +extern uint qHash(const std::string &); + #include <map> #include <list> +#include <QHash> #include "visitor.h" -#include "nodecache.h" +#include "Tree.h" using std::string; using std::map; @@ -15,8 +19,8 @@ using std::pair; class CSGTextRenderer : public Visitor { public: - enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI}; - CSGTextRenderer(const NodeCache<string> &dumpcache) : root(NULL), dumpcache(dumpcache) {} + CSGTextRenderer(QHash<string, string> &cache, const Tree &tree) : + cache(cache), tree(tree) {} virtual ~CSGTextRenderer() {} virtual Response visit(const State &state, const AbstractNode &node); @@ -25,21 +29,19 @@ public: virtual Response visit(const State &state, const TransformNode &node); virtual Response visit(const State &state, const AbstractPolyNode &node); - string getCSGString() const; private: + enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI}; 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; + typedef list<pair<const AbstractNode *, string> > ChildList; map<int, ChildList> visitedchildren; - QHash<QString, string> cache; - const NodeCache<string> &dumpcache; + QHash<string, string> &cache; + const Tree &tree; }; #endif diff --git a/test-code/cgaltest.cc b/test-code/cgaltest.cc index 8529da8..147e390 100644 --- a/test-code/cgaltest.cc +++ b/test-code/cgaltest.cc @@ -33,6 +33,7 @@ #include "nodedumper.h" #include "CGALRenderer.h" #include "PolySetCGALRenderer.h" +#include "Tree.h" #include <QApplication> #include <QFile> @@ -61,6 +62,24 @@ void handle_dep(QString filename) } } +// FIXME: enforce some maximum cache size (old version had 100K vertices as limit) +QHash<string, CGAL_Nef_polyhedron> cache; + +void cgalTree(Tree &tree) +{ + const AbstractNode *root = tree.root(); + assert(root); + NodeCache<string> &cache = tree.cache(); + NodeDumper dumper(cache, false); + Traverser trav(dumper, *root, Traverser::PRE_AND_POSTFIX); + trav.execute(); + assert(!cache[*root].empty()); + + CSGTextRenderer renderer(csgcache, cache); + Traverser render(renderer, *root, Traverser::PRE_AND_POSTFIX); + render.execute(); +} + int main(int argc, char **argv) { if (argc != 2) { @@ -146,11 +165,12 @@ int main(int argc, char **argv) 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"; + Tree tree; + tree.setRoot(root_node); + + cgalTree(tree); + + std::cout << cache[tree.cache()[*root_node]] << "\n"; CGALRenderer cgalrenderer(dumper.getCache()); PolySetCGALRenderer psrenderer(cgalrenderer); diff --git a/test-code/cgaltest.pro b/test-code/cgaltest.pro index c181046..a91cb5b 100644 --- a/test-code/cgaltest.pro +++ b/test-code/cgaltest.pro @@ -1,10 +1,10 @@ DEFINES += OPENSCAD_VERSION=test TEMPLATE = app -OBJECTS_DIR = objects -MOC_DIR = objects -UI_DIR = objects -RCC_DIR = objects +OBJECTS_DIR = cgal-objects +MOC_DIR = cgal-objects +UI_DIR = cgal-objects +RCC_DIR = cgal-objects INCLUDEPATH += ../src macx { @@ -61,7 +61,8 @@ HEADERS += ../src/builtin.h \ ../src/importnode.h \ ../src/state.h \ ../src/PolySetRenderer.h \ - ../src/PolySetCGALRenderer.h + ../src/PolySetCGALRenderer.h \ + ../src/Tree.h SOURCES += cgaltest.cc \ ../src/export.cc \ @@ -98,4 +99,5 @@ SOURCES += cgaltest.cc \ ../src/CGALRenderer.cc \ ../src/traverser.cc \ ../src/PolySetRenderer.cc \ - ../src/PolySetCGALRenderer.cc + ../src/PolySetCGALRenderer.cc \ + ../src/Tree.cc diff --git a/test-code/csgtexttest.cc b/test-code/csgtexttest.cc index b07bc92..f464900 100644 --- a/test-code/csgtexttest.cc +++ b/test-code/csgtexttest.cc @@ -23,6 +23,7 @@ * */ +#include "CSGTextRenderer.h" #include "openscad.h" #include "node.h" #include "module.h" @@ -30,14 +31,14 @@ #include "value.h" #include "export.h" #include "builtin.h" -#include "nodedumper.h" -#include "CSGTextRenderer.h" +#include "Tree.h" #include <QApplication> #include <QFile> #include <QDir> #include <QSet> #include <getopt.h> +#include <assert.h> #include <iostream> QString commandline_commands; @@ -60,6 +61,17 @@ void handle_dep(QString filename) } } + +QHash<string, string> csgcache; +void csgTree(Tree &tree) +{ + assert(tree.root()); + + CSGTextRenderer renderer(csgcache, tree); + Traverser render(renderer, *tree.root(), Traverser::PRE_AND_POSTFIX); + render.execute(); +} + int main(int argc, char **argv) { if (argc != 2) { @@ -145,17 +157,13 @@ int main(int argc, char **argv) AbstractNode::resetIndexCounter(); root_node = root_module->evaluate(&root_ctx, &root_inst); + Tree tree; + tree.setRoot(root_node); - NodeDumper dumper; - Traverser trav(dumper, *root_node, Traverser::PRE_AND_POSTFIX); - trav.execute(); - std::string dumpstdstr = dumper.getDump() + "\n"; - std::cout << dumpstdstr << "\n"; + csgTree(tree); + std::cout << tree.getString(*root_node) << "\n"; - CSGTextRenderer renderer(dumper.getCache()); - Traverser render(renderer, *root_node, Traverser::PRE_AND_POSTFIX); - render.execute(); - std::cout << renderer.getCSGString() << "\n"; + std::cout << csgcache[tree.getString(*root_node)] << "\n"; destroy_builtin_functions(); destroy_builtin_modules(); diff --git a/test-code/csgtexttest.pro b/test-code/csgtexttest.pro index 60dd731..a1c3148 100644 --- a/test-code/csgtexttest.pro +++ b/test-code/csgtexttest.pro @@ -61,11 +61,12 @@ HEADERS += ../src/builtin.h \ ../src/csgnode.h \ ../src/visitor.h \ ../src/nodedumper.h \ - ../src/CSGTextRenderer.h \ ../src/nodecache.h \ ../src/importnode.h \ ../src/state.h \ - ../src/PolySetRenderer.h + ../src/PolySetRenderer.h \ + ../src/Tree.h \ + CSGTextRenderer.h SOURCES += csgtexttest.cc \ ../src/export.cc \ @@ -96,6 +97,7 @@ SOURCES += csgtexttest.cc \ ../src/printutils.cc \ ../src/progress.cc \ ../src/nodedumper.cc \ - ../src/CSGTextRenderer.cc \ ../src/traverser.cc \ - ../src/PolySetRenderer.cc + ../src/PolySetRenderer.cc \ + ../src/Tree.cc \ + CSGTextRenderer.cc diff --git a/test-code/dumptest.cc b/test-code/dumptest.cc index 36261b6..e26259c 100644 --- a/test-code/dumptest.cc +++ b/test-code/dumptest.cc @@ -31,12 +31,17 @@ #include "export.h" #include "builtin.h" #include "nodedumper.h" +#include "Tree.h" #include <QApplication> #include <QFile> #include <QDir> #include <QSet> #include <getopt.h> +#include <assert.h> +#include <iostream> + +using std::string; QString commandline_commands; const char *make_command = NULL; @@ -144,23 +149,15 @@ int main(int argc, char **argv) root_node = root_module->evaluate(&root_ctx, &root_inst); // Cache test - QString dumpstr = root_node->dump(); - QString dumpstr_cached = root_node->dump(); - if (dumpstr != dumpstr_cached) rc = 1; - - NodeDumper dumper; - Traverser trav(dumper, *root_node, Traverser::PRE_AND_POSTFIX); - trav.execute(); - std::string dumpstdstr = dumper.getDump() + "\n"; - trav.execute(); - std::string dumpstdstr_cached = dumper.getDump() + "\n"; + QString teststr("test"); + Tree tree; + tree.setRoot(root_node); + + string dumpstdstr = tree.getString(*root_node); + string dumpstdstr_cached = tree.getString(*root_node); if (dumpstdstr != dumpstdstr_cached) rc = 1; - if (QString::fromStdString(dumpstdstr) != dumpstr) { - printf(dumpstr.toUtf8()); - printf(dumpstdstr.c_str()); - rc = 1; - } + std::cout << dumpstdstr << "\n"; destroy_builtin_functions(); destroy_builtin_modules(); diff --git a/test-code/dumptest.pro b/test-code/dumptest.pro index f861f9a..80d51be 100644 --- a/test-code/dumptest.pro +++ b/test-code/dumptest.pro @@ -67,7 +67,8 @@ HEADERS += ../src/builtin.h \ ../src/nodecache.h \ ../src/importnode.h \ ../src/state.h \ - ../src/PolySetRenderer.h + ../src/PolySetRenderer.h \ + ../src/Tree.h SOURCES += dumptest.cc \ ../src/export.cc \ @@ -99,4 +100,5 @@ SOURCES += dumptest.cc \ ../src/progress.cc \ ../src/nodedumper.cc \ ../src/traverser.cc \ - ../src/PolySetRenderer.cc + ../src/PolySetRenderer.cc \ + ../src/Tree.cc |