Added CSGTextCache for experimenting with cache-tree organization

stl_dim
Marius Kintel 2010-04-12 06:57:02 +02:00
parent e8e213b3c9
commit 1caf80e561
15 changed files with 139 additions and 149 deletions

View File

@ -1,7 +1,6 @@
#include "CGALRenderer.h" #include "CGALRenderer.h"
#include "visitor.h" #include "visitor.h"
#include "state.h" #include "state.h"
#include "nodecache.h"
#include "module.h" // FIXME: Temporarily for ModuleInstantiation #include "module.h" // FIXME: Temporarily for ModuleInstantiation
#include "printutils.h" #include "printutils.h"
@ -29,12 +28,12 @@ CGAL_Nef_polyhedron CGALRenderer::renderCGALMesh(const AbstractNode &node)
render.execute(); render.execute();
assert(isCached(node)); assert(isCached(node));
} }
return this->cache[this->dumpcache[node]]; return this->cache[this->tree.getString(node)];
} }
bool CGALRenderer::isCached(const AbstractNode &node) const bool CGALRenderer::isCached(const AbstractNode &node) const
{ {
return this->cache.contains(this->dumpcache[node]); return this->cache.contains(this->tree.getString(node));
} }
/*! /*!
@ -94,7 +93,7 @@ void CGALRenderer::applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp
iter != this->visitedchildren[node.index()].end(); iter != this->visitedchildren[node.index()].end();
iter++) { iter++) {
const AbstractNode *chnode = iter->first; const AbstractNode *chnode = iter->first;
const QString &chcacheid = iter->second; const string &chcacheid = iter->second;
// FIXME: Don't use deep access to modinst members // FIXME: Don't use deep access to modinst members
if (chnode->modinst->tag_background) continue; if (chnode->modinst->tag_background) continue;
assert(isCached(*chnode)); assert(isCached(*chnode));
@ -109,7 +108,7 @@ void CGALRenderer::applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp
chnode->progress_report(); chnode->progress_report();
} }
} }
this->cache.insert(this->dumpcache[node], N); this->cache.insert(this->tree.getString(node), N);
} }
/* /*
@ -172,7 +171,7 @@ Response CGALRenderer::visit(const State &state, const TransformNode &node)
applyToChildren(node, UNION); applyToChildren(node, UNION);
// Then apply transform // Then apply transform
CGAL_Nef_polyhedron N = this->cache[this->dumpcache[node]]; CGAL_Nef_polyhedron N = this->cache[this->tree.getString(node)];
assert(N.dim >= 2 && N.dim <= 3); assert(N.dim >= 2 && N.dim <= 3);
if (N.dim == 2) { if (N.dim == 2) {
// Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2 // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
@ -205,7 +204,7 @@ Response CGALRenderer::visit(const State &state, const TransformNode &node)
node.m[2], node.m[6], node.m[10], node.m[14], node.m[15]); node.m[2], node.m[6], node.m[10], node.m[14], node.m[15]);
N.p3.transform(t); N.p3.transform(t);
} }
this->cache.insert(cacheid, N); this->cache.insert(this->tree.getString(node), N);
} }
addToParent(state, node); addToParent(state, node);
} }
@ -237,7 +236,7 @@ Response CGALRenderer::visit(const State &state, const AbstractPolyNode &node)
node.progress_report(); node.progress_report();
ps->unlink(); ps->unlink();
this->cache.insert(this->dumpcache[node], N); this->cache.insert(this->tree.getString(node), N);
} }
catch (...) { // Don't leak the PolySet on ProgressCancelException catch (...) { // Don't leak the PolySet on ProgressCancelException
ps->unlink(); ps->unlink();
@ -258,7 +257,7 @@ void CGALRenderer::addToParent(const State &state, const AbstractNode &node)
assert(state.isPostfix()); assert(state.isPostfix());
this->visitedchildren.erase(node.index()); this->visitedchildren.erase(node.index());
if (state.parent()) { if (state.parent()) {
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->dumpcache[node])); this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getString(node)));
} }
} }

View File

@ -1,11 +1,13 @@
#ifndef CGALRENDERER_H_ #ifndef CGALRENDERER_H_
#define CGALRENDERER_H_ #define CGALRENDERER_H_
#include "myqhash.h"
#include <string> #include <string>
#include <map> #include <map>
#include <list> #include <list>
#include "visitor.h" #include "visitor.h"
#include "nodecache.h" #include "Tree.h"
#include "cgal.h" #include "cgal.h"
#ifdef ENABLE_CGAL #ifdef ENABLE_CGAL
@ -23,7 +25,7 @@ class CGALRenderer : public Visitor
public: public:
enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI}; enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI};
// FIXME: If a cache is not given, we need to fix this ourselves // 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) {} CGALRenderer(QHash<string, CGAL_Nef_polyhedron> &cache, const Tree &tree) : cache(cache), tree(tree) {}
virtual ~CGALRenderer() {} virtual ~CGALRenderer() {}
virtual Response visit(const State &state, const AbstractNode &node); virtual Response visit(const State &state, const AbstractNode &node);
@ -38,16 +40,15 @@ public:
private: private:
void addToParent(const State &state, const AbstractNode &node); void addToParent(const State &state, const AbstractNode &node);
bool isCached(const AbstractNode &node) const; bool isCached(const AbstractNode &node) const;
QString mk_cache_id(const AbstractNode &node) const;
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALRenderer::CsgOp op); void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALRenderer::CsgOp op);
void applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op); void applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op);
string currindent; string currindent;
typedef list<pair<const AbstractNode *, QString> > ChildList; typedef list<pair<const AbstractNode *, string> > ChildList;
map<int, ChildList> visitedchildren; map<int, ChildList> visitedchildren;
QHash<QString, CGAL_Nef_polyhedron> &cache; QHash<string, CGAL_Nef_polyhedron> &cache;
const NodeCache<string> &dumpcache; const Tree &tree;
}; };
#endif #endif

View File

@ -2,7 +2,6 @@
#define POLYSETCGALRENDERER_H_ #define POLYSETCGALRENDERER_H_
#include "PolySetRenderer.h" #include "PolySetRenderer.h"
#include <QHash>
#include "CGALRenderer.h" #include "CGALRenderer.h"
/*! /*!

View File

@ -2,7 +2,6 @@
#define TREE_H_ #define TREE_H_
#include "nodecache.h" #include "nodecache.h"
//#include "cgal.h"
using std::string; using std::string;
@ -19,7 +18,6 @@ public:
// FIXME: Really return a reference? // FIXME: Really return a reference?
const string &getString(const AbstractNode &node) const; const string &getString(const AbstractNode &node) const;
// CGAL_Nef_polyhedron getCGALMesh(const AbstractNode &node) const;
private: private:
const AbstractNode *root_node; const AbstractNode *root_node;

View File

@ -1,10 +1,10 @@
#ifndef GRID_H_ #ifndef GRID_H_
#define GRID_H_ #define GRID_H_
#include <QHash>
#include <math.h> #include <math.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <QHash>
const double GRID_COARSE = 0.001; const double GRID_COARSE = 0.001;
const double GRID_FINE = 0.000001; const double GRID_FINE = 0.000001;

9
src/myqhash.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef OPENSCAD_QHASH_H_
#define OPENSCAD_QHASH_H_
#include <qglobal.h>
#include <string>
extern uint qHash(const std::string &);
#include <QHash>
#endif

19
src/qhash.cc Normal file
View File

@ -0,0 +1,19 @@
#include "myqhash.h"
static uint hash(const uchar *p, int n)
{
uint h = 0;
uint g;
while (n--) {
h = (h << 4) + *p++;
if ((g = (h & 0xf0000000)) != 0)
h ^= g >> 23;
h &= ~g;
}
return h;
}
uint qHash(const std::string &str) {
return hash(reinterpret_cast<const uchar *>(str.c_str()), str.length());
}

27
test-code/CSGTextCache.cc Normal file
View File

@ -0,0 +1,27 @@
#include "CSGTextCache.h"
bool CSGTextCache::contains(const AbstractNode &node) const
{
return this->cache.contains(this->tree.getString(node));
}
// We cannot return a reference since the [] operator returns a temporary value
string CSGTextCache::operator[](const AbstractNode &node) const
{
return this->cache[this->tree.getString(node)];
}
void CSGTextCache::insert(const class AbstractNode &node, const string & value)
{
this->cache.insert(this->tree.getString(node), value);
}
void CSGTextCache::remove(const class AbstractNode &node)
{
this->cache.remove(this->tree.getString(node));
}
void CSGTextCache::clear()
{
this->cache.clear();
}

27
test-code/CSGTextCache.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef CSGTEXTCACHE_H_
#define CSGTEXTCACHE_H_
#include "myqhash.h"
#include "Tree.h"
#include <string>
using std::string;
class CSGTextCache
{
public:
CSGTextCache(const Tree &tree) : tree(tree) {}
~CSGTextCache() {}
bool contains(const AbstractNode &node) const;
string operator[](const AbstractNode &node) const;
void insert(const class AbstractNode &node, const string & value);
void remove(const class AbstractNode &node);
void clear();
private:
QHash<string, string> cache;
const Tree &tree;
};
#endif

View File

@ -17,7 +17,7 @@
bool CSGTextRenderer::isCached(const AbstractNode &node) bool CSGTextRenderer::isCached(const AbstractNode &node)
{ {
return this->cache.contains(this->tree.getString(node)); return this->cache.contains(node);
} }
/*! /*!
@ -47,49 +47,6 @@ CSGTextRenderer::process(string &target, const string &src, CSGTextRenderer::Csg
} }
} }
// /*!
// 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) void CSGTextRenderer::applyToChildren(const AbstractNode &node, CSGTextRenderer::CsgOp op)
{ {
std::stringstream stream; std::stringstream stream;
@ -99,26 +56,25 @@ void CSGTextRenderer::applyToChildren(const AbstractNode &node, CSGTextRenderer:
if (this->visitedchildren[node.index()].size() > 0) { if (this->visitedchildren[node.index()].size() > 0) {
// FIXME: assert that cache contains nodes in code below // FIXME: assert that cache contains nodes in code below
bool first = true; bool first = true;
// CGAL_Nef_polyhedron N;
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin(); for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
iter != this->visitedchildren[node.index()].end(); iter != this->visitedchildren[node.index()].end();
iter++) { iter++) {
const AbstractNode *chnode = iter->first; const AbstractNode *chnode = *iter;
const string &chcacheid = iter->second; assert(this->cache.contains(*chnode));
// FIXME: Don't use deep access to modinst members // FIXME: Don't use deep access to modinst members
if (chnode->modinst->tag_background) continue; if (chnode->modinst->tag_background) continue;
if (first) { if (first) {
N += "(" + this->cache[chcacheid]; N += "(" + this->cache[*chnode];
// if (N.dim != 0) first = false; // FIXME: when can this happen? // if (N.dim != 0) first = false; // FIXME: when can this happen?
first = false; first = false;
} else { } else {
process(N, this->cache[chcacheid], op); process(N, this->cache[*chnode], op);
} }
chnode->progress_report(); chnode->progress_report();
} }
N += ")"; N += ")";
} }
this->cache.insert(this->tree.getString(node), N); this->cache.insert(node, N);
} }
/* /*
@ -204,23 +160,8 @@ Response CSGTextRenderer::visit(const State &state, const AbstractPolyNode &node
// FIXME: Manage caching // FIXME: Manage caching
// FIXME: Will generate one single Nef polyhedron (no csg ops necessary) // 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(); string N = typeid(node).name();
this->cache.insert(this->tree.getString(node), N); this->cache.insert(node, N);
// std::cout << "Insert: " << N << "\n"; // std::cout << "Insert: " << N << "\n";
// std::cout << "Node: " << cacheid.toStdString() << "\n\n"; // std::cout << "Node: " << cacheid.toStdString() << "\n\n";
@ -240,26 +181,6 @@ void CSGTextRenderer::addToParent(const State &state, const AbstractNode &node)
assert(state.isPostfix()); assert(state.isPostfix());
this->visitedchildren.erase(node.index()); this->visitedchildren.erase(node.index());
if (state.parent()) { if (state.parent()) {
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getString(node))); this->visitedchildren[state.parent()->index()].push_back(&node);
} }
} }
static uint hash(const uchar *p, int n)
{
uint h = 0;
uint g;
while (n--) {
h = (h << 4) + *p++;
if ((g = (h & 0xf0000000)) != 0)
h ^= g >> 23;
h &= ~g;
}
return h;
}
uint qHash(const string &str) {
return hash(reinterpret_cast<const uchar *>(str.c_str()), str.length());
}

View File

@ -1,26 +1,20 @@
#ifndef CSGTEXTRENDERER_H_ #ifndef CSGTEXTRENDERER_H_
#define CSGTEXTRENDERER_H_ #define CSGTEXTRENDERER_H_
#include <qglobal.h> #include "visitor.h"
#include <string> #include "CSGTextCache.h"
extern uint qHash(const std::string &);
#include <map> #include <map>
#include <list> #include <list>
#include <QHash>
#include "visitor.h"
#include "Tree.h"
using std::string; using std::string;
using std::map; using std::map;
using std::list; using std::list;
using std::pair;
class CSGTextRenderer : public Visitor class CSGTextRenderer : public Visitor
{ {
public: public:
CSGTextRenderer(QHash<string, string> &cache, const Tree &tree) : CSGTextRenderer(CSGTextCache &cache) : cache(cache) {}
cache(cache), tree(tree) {}
virtual ~CSGTextRenderer() {} virtual ~CSGTextRenderer() {}
virtual Response visit(const State &state, const AbstractNode &node); virtual Response visit(const State &state, const AbstractNode &node);
@ -37,11 +31,10 @@ private:
void applyToChildren(const AbstractNode &node, CSGTextRenderer::CsgOp op); void applyToChildren(const AbstractNode &node, CSGTextRenderer::CsgOp op);
string currindent; string currindent;
typedef list<pair<const AbstractNode *, string> > ChildList; typedef list<const AbstractNode *> ChildList;
map<int, ChildList> visitedchildren; map<int, ChildList> visitedchildren;
QHash<string, string> &cache; CSGTextCache &cache;
const Tree &tree;
}; };
#endif #endif

View File

@ -23,6 +23,7 @@
* *
*/ */
#include "myqhash.h"
#include "openscad.h" #include "openscad.h"
#include "node.h" #include "node.h"
#include "module.h" #include "module.h"
@ -30,10 +31,9 @@
#include "value.h" #include "value.h"
#include "export.h" #include "export.h"
#include "builtin.h" #include "builtin.h"
#include "nodedumper.h" #include "Tree.h"
#include "CGALRenderer.h" #include "CGALRenderer.h"
#include "PolySetCGALRenderer.h" #include "PolySetCGALRenderer.h"
#include "Tree.h"
#include <QApplication> #include <QApplication>
#include <QFile> #include <QFile>
@ -49,6 +49,8 @@ QString currentdir;
QString examplesdir; QString examplesdir;
QString librarydir; QString librarydir;
using std::string;
void handle_dep(QString filename) void handle_dep(QString filename)
{ {
if (filename.startsWith("/")) if (filename.startsWith("/"))
@ -63,20 +65,14 @@ void handle_dep(QString filename)
} }
// FIXME: enforce some maximum cache size (old version had 100K vertices as limit) // FIXME: enforce some maximum cache size (old version had 100K vertices as limit)
QHash<string, CGAL_Nef_polyhedron> cache; QHash<std::string, CGAL_Nef_polyhedron> cache;
void cgalTree(Tree &tree) void cgalTree(Tree &tree)
{ {
const AbstractNode *root = tree.root(); assert(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); CGALRenderer renderer(cache, tree);
Traverser render(renderer, *root, Traverser::PRE_AND_POSTFIX); Traverser render(renderer, *tree.root(), Traverser::PRE_AND_POSTFIX);
render.execute(); render.execute();
} }
@ -170,16 +166,13 @@ int main(int argc, char **argv)
cgalTree(tree); cgalTree(tree);
std::cout << cache[tree.cache()[*root_node]] << "\n"; std::cout << tree.getString(*root_node) << "\n";
CGALRenderer cgalrenderer(dumper.getCache()); // CGALRenderer cgalrenderer(dumper.getCache());
PolySetCGALRenderer psrenderer(cgalrenderer); // PolySetCGALRenderer psrenderer(cgalrenderer);
PolySetRenderer::setRenderer(&psrenderer); // PolySetRenderer::setRenderer(&psrenderer);
// This is done in renderCGALMesh() for convenience, but can be overridden here CGAL_Nef_polyhedron N = cache[tree.getString(*root_node)];
// Traverser render(cgalrenderer, *root_node, Traverser::PRE_AND_POSTFIX);
// render.execute();
CGAL_Nef_polyhedron N = cgalrenderer.renderCGALMesh(*root_node);
QDir::setCurrent(original_path.absolutePath()); QDir::setCurrent(original_path.absolutePath());
export_stl(&N, fileInfo.baseName() + ".stl", NULL); export_stl(&N, fileInfo.baseName() + ".stl", NULL);

View File

@ -62,6 +62,7 @@ HEADERS += ../src/builtin.h \
../src/state.h \ ../src/state.h \
../src/PolySetRenderer.h \ ../src/PolySetRenderer.h \
../src/PolySetCGALRenderer.h \ ../src/PolySetCGALRenderer.h \
../src/myqhash.h \
../src/Tree.h ../src/Tree.h
SOURCES += cgaltest.cc \ SOURCES += cgaltest.cc \
@ -100,4 +101,5 @@ SOURCES += cgaltest.cc \
../src/traverser.cc \ ../src/traverser.cc \
../src/PolySetRenderer.cc \ ../src/PolySetRenderer.cc \
../src/PolySetCGALRenderer.cc \ ../src/PolySetCGALRenderer.cc \
../src/qhash.cc \
../src/Tree.cc ../src/Tree.cc

View File

@ -24,6 +24,7 @@
*/ */
#include "CSGTextRenderer.h" #include "CSGTextRenderer.h"
#include "CSGTextCache.h"
#include "openscad.h" #include "openscad.h"
#include "node.h" #include "node.h"
#include "module.h" #include "module.h"
@ -61,14 +62,10 @@ void handle_dep(QString filename)
} }
} }
void csgTree(CSGTextCache &cache, const AbstractNode &root)
QHash<string, string> csgcache;
void csgTree(Tree &tree)
{ {
assert(tree.root()); CSGTextRenderer renderer(cache);
Traverser render(renderer, root, Traverser::PRE_AND_POSTFIX);
CSGTextRenderer renderer(csgcache, tree);
Traverser render(renderer, *tree.root(), Traverser::PRE_AND_POSTFIX);
render.execute(); render.execute();
} }
@ -159,11 +156,12 @@ int main(int argc, char **argv)
Tree tree; Tree tree;
tree.setRoot(root_node); tree.setRoot(root_node);
CSGTextCache csgcache(tree);
csgTree(tree); csgTree(csgcache, *root_node);
std::cout << tree.getString(*root_node) << "\n"; std::cout << tree.getString(*root_node) << "\n";
std::cout << csgcache[tree.getString(*root_node)] << "\n"; std::cout << csgcache[*root_node] << "\n";
destroy_builtin_functions(); destroy_builtin_functions();
destroy_builtin_modules(); destroy_builtin_modules();

View File

@ -66,7 +66,9 @@ HEADERS += ../src/builtin.h \
../src/state.h \ ../src/state.h \
../src/PolySetRenderer.h \ ../src/PolySetRenderer.h \
../src/Tree.h \ ../src/Tree.h \
CSGTextRenderer.h ../src/myqhash.h \
CSGTextRenderer.h \
CSGTextCache.h
SOURCES += csgtexttest.cc \ SOURCES += csgtexttest.cc \
../src/export.cc \ ../src/export.cc \
@ -100,4 +102,6 @@ SOURCES += csgtexttest.cc \
../src/traverser.cc \ ../src/traverser.cc \
../src/PolySetRenderer.cc \ ../src/PolySetRenderer.cc \
../src/Tree.cc \ ../src/Tree.cc \
CSGTextRenderer.cc ../src/qhash.cc \
CSGTextRenderer.cc \
CSGTextCache.cc