Started refactoring of render_csg_term() into a visitor

stl_dim
Marius Kintel 2010-07-15 02:48:00 +02:00
parent f2323c78b3
commit f0b49ee9e9
13 changed files with 650 additions and 276 deletions

335
src/CSGTermRenderer.cc Normal file
View File

@ -0,0 +1,335 @@
#include "CSGTermRenderer.h"
#include "visitor.h"
#include "state.h"
#include "csgterm.h"
#include "module.h"
#include "csgnode.h"
#include "transformnode.h"
#include "rendernode.h"
#include "printutils.h"
#include <string>
#include <map>
#include <list>
#include <sstream>
#include <iostream>
#include <assert.h>
/*!
\class CSGTermRenderer
A visitor responsible for creating a tree of CSGTerm nodes used for rendering
with OpenCSG.
*/
void CSGTermRenderer::applyToChildren(const AbstractNode &node, CSGTermRenderer::CsgOp op)
{
if (this->visitedchildren[node.index()].size() == 0) return;
CSGTerm *t1 = NULL;
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
iter != this->visitedchildren[node.index()].end();
iter++) {
const AbstractNode *chnode = *iter;
CSGTerm *t2 = this->stored_term[chnode->index()];
this->stored_term.erase(chnode->index());
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
if (op == UNION) {
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
} else if (op == DIFFERENCE) {
t1 = new CSGTerm(CSGTerm::TYPE_DIFFERENCE, t1, t2);
} else if (op == INTERSECTION) {
t1 = new CSGTerm(CSGTerm::TYPE_INTERSECTION, t1, t2);
}
}
}
if (t1 && node.modinst->tag_highlight && this->highlights) {
this->highlights->push_back(t1->link());
}
if (t1 && node.modinst->tag_background && this->background) {
this->background->push_back(t1);
// FIXME: don't store in stored_term? return NULL;
}
this->stored_term[node.index()] = t1;
}
Response CSGTermRenderer::visit(const State &state, const AbstractNode &node)
{
if (state.isPostfix()) {
applyToChildren(node, UNION);
addToParent(state, node);
}
return ContinueTraversal;
}
Response CSGTermRenderer::visit(const State &state, const AbstractIntersectionNode &node)
{
if (state.isPostfix()) {
applyToChildren(node, INTERSECTION);
addToParent(state, node);
}
return ContinueTraversal;
}
static CSGTerm *render_csg_term_from_ps(double m[20],
QVector<CSGTerm*> *highlights,
QVector<CSGTerm*> *background,
PolySet *ps,
const ModuleInstantiation *modinst,
int idx)
{
CSGTerm *t = new CSGTerm(ps, m, QString("n%1").arg(idx));
if (modinst->tag_highlight && highlights)
highlights->push_back(t->link());
if (modinst->tag_background && background) {
background->push_back(t);
return NULL;
}
return t;
}
Response CSGTermRenderer::visit(const State &state, const AbstractPolyNode &node)
{
if (state.isPostfix()) {
PolySet *ps = node.render_polyset(AbstractPolyNode::RENDER_OPENCSG);
CSGTerm *t1 = render_csg_term_from_ps(m, this->highlights, this->background, ps, node.modinst, node.index());
this->stored_term[node.index()] = t1;
addToParent(state, node);
}
return ContinueTraversal;
}
Response CSGTermRenderer::visit(const State &state, const CsgNode &node)
{
if (state.isPostfix()) {
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 CSGTermRenderer::visit(const State &state, const TransformNode &node)
{
if (state.isPostfix()) {
double x[20];
for (int i = 0; i < 16; i++)
{
int c_row = i%4;
int m_col = i/4;
x[i] = 0;
for (int j = 0; j < 4; j++)
x[i] += c[c_row + j*4] * m[m_col*4 + j];
}
for (int i = 16; i < 20; i++)
x[i] = m[i] < 0 ? c[i] : m[i];
// FIXME: Apply the x matrix.
// FIXME: Look into how bottom-up vs. top down affects matrix handling
applyToChildren(node, UNION);
addToParent(state, node);
}
return ContinueTraversal;
}
// FIXME: Find out how to best call into CGAL from this visitor
Response CSGTermRenderer::visit(const State &state, const RenderNode &node)
{
PRINT("WARNING: Found render() statement but compiled without CGAL support!");
if (state.isPostfix()) {
applyToChildren(node, UNION);
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 CSGTermRenderer::addToParent(const State &state, const AbstractNode &node)
{
assert(state.isPostfix());
this->visitedchildren.erase(node.index());
if (state.parent()) {
this->visitedchildren[state.parent()->index()].push_back(&node);
}
}
#if 0
// FIXME: #ifdef ENABLE_CGAL
#if 0
CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
if (type == MINKOWSKI)
return render_csg_term_from_nef(m, highlights, background, "minkowski", this->convexity);
if (type == GLIDE)
return render_csg_term_from_nef(m, highlights, background, "glide", this->convexity);
if (type == SUBDIV)
return render_csg_term_from_nef(m, highlights, background, "subdiv", this->convexity);
return NULL;
}
#else // ENABLE_CGAL
CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
PRINT("WARNING: Found minkowski(), glide() or subdiv() statement but compiled without CGAL support!");
return NULL;
}
#endif // ENABLE_CGAL
// FIXME: #ifdef ENABLE_CGAL
#if 0
CSGTerm *AbstractNode::render_csg_term_from_nef(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, const char *statement, int convexity) const
{
QString key = mk_cache_id();
if (PolySet::ps_cache.contains(key)) {
PRINT(PolySet::ps_cache[key]->msg);
return AbstractPolyNode::render_csg_term_from_ps(m, highlights, background,
PolySet::ps_cache[key]->ps->link(), modinst, idx);
}
print_messages_push();
CGAL_Nef_polyhedron N;
QString cache_id = mk_cache_id();
if (cgal_nef_cache.contains(cache_id))
{
PRINT(cgal_nef_cache[cache_id]->msg);
N = cgal_nef_cache[cache_id]->N;
}
else
{
PRINTF_NOCACHE("Processing uncached %s statement...", statement);
// PRINTA("Cache ID: %1", cache_id);
QApplication::processEvents();
QTime t;
t.start();
N = this->renderCSGMesh();
int s = t.elapsed() / 1000;
PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60);
}
PolySet *ps = NULL;
if (N.dim == 2)
{
DxfData dd(N);
ps = new PolySet();
ps->is2d = true;
dxf_tesselate(ps, &dd, 0, true, false, 0);
dxf_border_to_ps(ps, &dd);
}
if (N.dim == 3)
{
if (!N.p3.is_simple()) {
PRINTF("WARNING: Result of %s() isn't valid 2-manifold! Modify your design..", statement);
return NULL;
}
ps = new PolySet();
CGAL_Polyhedron P;
N.p3.convert_to_Polyhedron(P);
typedef CGAL_Polyhedron::Vertex Vertex;
typedef CGAL_Polyhedron::Vertex_const_iterator VCI;
typedef CGAL_Polyhedron::Facet_const_iterator FCI;
typedef CGAL_Polyhedron::Halfedge_around_facet_const_circulator HFCC;
for (FCI fi = P.facets_begin(); fi != P.facets_end(); ++fi) {
HFCC hc = fi->facet_begin();
HFCC hc_end = hc;
ps->append_poly();
do {
Vertex v = *VCI((hc++)->vertex());
double x = CGAL::to_double(v.point().x());
double y = CGAL::to_double(v.point().y());
double z = CGAL::to_double(v.point().z());
ps->append_vertex(x, y, z);
} while (hc != hc_end);
}
}
if (ps)
{
ps->convexity = convexity;
PolySet::ps_cache.insert(key, new PolySet::ps_cache_entry(ps->link()));
CSGTerm *term = new CSGTerm(ps, m, QString("n%1").arg(idx));
if (modinst->tag_highlight && highlights)
highlights->push_back(term->link());
if (modinst->tag_background && background) {
background->push_back(term);
return NULL;
}
return term;
}
print_messages_pop();
return NULL;
}
CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
return render_csg_term_from_nef(m, highlights, background, "render", this->convexity);
}
#else
CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
CSGTerm *t1 = NULL;
PRINT("WARNING: Found render() statement but compiled without CGAL support!");
foreach(AbstractNode * v, children) {
CSGTerm *t2 = v->render_csg_term(m, highlights, background);
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
}
}
if (modinst->tag_highlight && highlights)
highlights->push_back(t1->link());
if (t1 && modinst->tag_background && background) {
background->push_back(t1);
return NULL;
}
return t1;
}
#endif
#endif

43
src/CSGTermRenderer.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef CSGTERMRENDERER_H_
#define CSGTERMRENDERER_H_
#include <string>
#include <map>
#include <list>
#include <vector>
#include "visitor.h"
#include "node.h"
using std::string;
using std::map;
using std::list;
using std::vector;
class CSGTermRenderer : public Visitor
{
public:
CSGTermRenderer() {}
virtual ~CSGTermRenderer() {}
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 AbstractPolyNode &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 RenderNode &node);
private:
enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI};
void addToParent(const State &state, const AbstractNode &node);
void applyToChildren(const AbstractNode &node, CSGTermRenderer::CsgOp op);
const AbstractNode *root;
typedef list<const AbstractNode *> ChildList;
map<int, ChildList> visitedchildren;
map<int, class CSGTerm*> stored_term;
vector<CSGTerm*> *highlights;
vector<CSGTerm*> *background;
};
#endif

View File

@ -68,7 +68,6 @@ public:
QString subdiv_type;
int convexity, level;
cgaladv_type_e type;
virtual CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
};
AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
@ -131,32 +130,6 @@ void register_builtin_cgaladv()
builtin_modules["subdiv"] = new CgaladvModule(SUBDIV);
}
// FIXME: #ifdef ENABLE_CGAL
#if 0
CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
if (type == MINKOWSKI)
return render_csg_term_from_nef(m, highlights, background, "minkowski", this->convexity);
if (type == GLIDE)
return render_csg_term_from_nef(m, highlights, background, "glide", this->convexity);
if (type == SUBDIV)
return render_csg_term_from_nef(m, highlights, background, "subdiv", this->convexity);
return NULL;
}
#else // ENABLE_CGAL
CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
PRINT("WARNING: Found minkowski(), glide() or subdiv() statement but compiled without CGAL support!");
return NULL;
}
#endif // ENABLE_CGAL
std::string CgaladvNode::toString() const
{
std::stringstream stream;

View File

@ -19,8 +19,6 @@ public:
return visitor.visit(state, *this);
}
virtual std::string toString() const;
CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
};
#endif

View File

@ -51,32 +51,6 @@ AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *ins
return node;
}
CSGTerm *CsgNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
CSGTerm *t1 = NULL;
foreach (AbstractNode *v, children) {
CSGTerm *t2 = v->render_csg_term(m, highlights, background);
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
if (type == CSG_TYPE_UNION) {
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
} else if (type == CSG_TYPE_DIFFERENCE) {
t1 = new CSGTerm(CSGTerm::TYPE_DIFFERENCE, t1, t2);
} else if (type == CSG_TYPE_INTERSECTION) {
t1 = new CSGTerm(CSGTerm::TYPE_INTERSECTION, t1, t2);
}
}
}
if (t1 && modinst->tag_highlight && highlights)
highlights->append(t1->link());
if (t1 && modinst->tag_background && background) {
background->append(t1);
return NULL;
}
return t1;
}
std::string CsgNode::toString() const
{
std::stringstream stream;

View File

@ -90,57 +90,6 @@ void AbstractNode::progress_report() const
progress_update(this, this->progress_mark);
}
static CSGTerm *render_csg_term_backend(const AbstractNode *that, bool intersect, double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background)
{
CSGTerm *t1 = NULL;
foreach(AbstractNode *v, that->children) {
CSGTerm *t2 = v->render_csg_term(m, highlights, background);
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
if (intersect)
t1 = new CSGTerm(CSGTerm::TYPE_INTERSECTION, t1, t2);
else
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
}
}
if (t1 && that->modinst->tag_highlight && highlights)
highlights->append(t1->link());
if (t1 && that->modinst->tag_background && background) {
background->append(t1);
return NULL;
}
return t1;
}
CSGTerm *AbstractNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
return render_csg_term_backend(this, false, m, highlights, background);
}
CSGTerm *AbstractIntersectionNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
return render_csg_term_backend(this, true, m, highlights, background);
}
CSGTerm *AbstractPolyNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
PolySet *ps = render_polyset(RENDER_OPENCSG);
return render_csg_term_from_ps(m, highlights, background, ps, modinst, idx);
}
CSGTerm *AbstractPolyNode::render_csg_term_from_ps(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, PolySet *ps, const ModuleInstantiation *modinst, int idx)
{
CSGTerm *t = new CSGTerm(ps, m, QString("n%1").arg(idx));
if (modinst->tag_highlight && highlights)
highlights->append(t->link());
if (modinst->tag_background && background) {
background->append(t);
return NULL;
}
return t;
}
std::ostream &operator<<(std::ostream &stream, const QString &str)
{
stream << str.toStdString();

View File

@ -51,9 +51,6 @@ public:
int idx; // Node index (unique per tree)
// FIXME: Rewrite to visitor
virtual class CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
// FIXME: Rewrite to visitor
#ifdef ENABLE_CGAL
class CSGTerm *render_csg_term_from_nef(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, const char *statement, int convexity) const;
@ -67,8 +64,6 @@ public:
virtual ~AbstractIntersectionNode() { };
virtual Response accept(const class State &state, class Visitor &visitor) const;
virtual std::string toString() const;
virtual CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
};
class AbstractPolyNode : public AbstractNode
@ -86,8 +81,6 @@ public:
empty PolySet if smth. is wrong, but don't return NULL unless we change the calling
strategy for this method. */
virtual class PolySet *render_polyset(render_mode_e mode) const = 0;
virtual CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
static CSGTerm *render_csg_term_from_ps(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, PolySet *ps, const ModuleInstantiation *modinst, int idx);
};
std::ostream &operator<<(std::ostream &stream, const AbstractNode &node);

View File

@ -77,132 +77,6 @@ void register_builtin_render()
builtin_modules["render"] = new RenderModule();
}
// FIXME: #ifdef ENABLE_CGAL
#if 0
CSGTerm *AbstractNode::render_csg_term_from_nef(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, const char *statement, int convexity) const
{
QString key = mk_cache_id();
if (PolySet::ps_cache.contains(key)) {
PRINT(PolySet::ps_cache[key]->msg);
return AbstractPolyNode::render_csg_term_from_ps(m, highlights, background,
PolySet::ps_cache[key]->ps->link(), modinst, idx);
}
print_messages_push();
CGAL_Nef_polyhedron N;
QString cache_id = mk_cache_id();
if (cgal_nef_cache.contains(cache_id))
{
PRINT(cgal_nef_cache[cache_id]->msg);
N = cgal_nef_cache[cache_id]->N;
}
else
{
PRINTF_NOCACHE("Processing uncached %s statement...", statement);
// PRINTA("Cache ID: %1", cache_id);
QApplication::processEvents();
QTime t;
t.start();
N = this->renderCSGMesh();
int s = t.elapsed() / 1000;
PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60);
}
PolySet *ps = NULL;
if (N.dim == 2)
{
DxfData dd(N);
ps = new PolySet();
ps->is2d = true;
dxf_tesselate(ps, &dd, 0, true, false, 0);
dxf_border_to_ps(ps, &dd);
}
if (N.dim == 3)
{
if (!N.p3.is_simple()) {
PRINTF("WARNING: Result of %s() isn't valid 2-manifold! Modify your design..", statement);
return NULL;
}
ps = new PolySet();
CGAL_Polyhedron P;
N.p3.convert_to_Polyhedron(P);
typedef CGAL_Polyhedron::Vertex Vertex;
typedef CGAL_Polyhedron::Vertex_const_iterator VCI;
typedef CGAL_Polyhedron::Facet_const_iterator FCI;
typedef CGAL_Polyhedron::Halfedge_around_facet_const_circulator HFCC;
for (FCI fi = P.facets_begin(); fi != P.facets_end(); ++fi) {
HFCC hc = fi->facet_begin();
HFCC hc_end = hc;
ps->append_poly();
do {
Vertex v = *VCI((hc++)->vertex());
double x = CGAL::to_double(v.point().x());
double y = CGAL::to_double(v.point().y());
double z = CGAL::to_double(v.point().z());
ps->append_vertex(x, y, z);
} while (hc != hc_end);
}
}
if (ps)
{
ps->convexity = convexity;
PolySet::ps_cache.insert(key, new PolySet::ps_cache_entry(ps->link()));
CSGTerm *term = new CSGTerm(ps, m, QString("n%1").arg(idx));
if (modinst->tag_highlight && highlights)
highlights->append(term->link());
if (modinst->tag_background && background) {
background->append(term);
return NULL;
}
return term;
}
print_messages_pop();
return NULL;
}
CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
return render_csg_term_from_nef(m, highlights, background, "render", this->convexity);
}
#else
CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
CSGTerm *t1 = NULL;
PRINT("WARNING: Found render() statement but compiled without CGAL support!");
foreach(AbstractNode * v, children) {
CSGTerm *t2 = v->render_csg_term(m, highlights, background);
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
}
}
if (modinst->tag_highlight && highlights)
highlights->append(t1->link());
if (t1 && modinst->tag_background && background) {
background->append(t1);
return NULL;
}
return t1;
}
#endif
std::string RenderNode::toString() const
{
std::stringstream stream;

View File

@ -14,7 +14,6 @@ public:
virtual std::string toString() const;
int convexity;
CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
};
#endif

View File

@ -228,41 +228,6 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
return node;
}
CSGTerm *TransformNode::render_csg_term(double c[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const
{
double x[20];
for (int i = 0; i < 16; i++)
{
int c_row = i%4;
int m_col = i/4;
x[i] = 0;
for (int j = 0; j < 4; j++)
x[i] += c[c_row + j*4] * m[m_col*4 + j];
}
for (int i = 16; i < 20; i++)
x[i] = m[i] < 0 ? c[i] : m[i];
CSGTerm *t1 = NULL;
foreach(AbstractNode *v, children)
{
CSGTerm *t2 = v->render_csg_term(x, highlights, background);
if (t2 && !t1) {
t1 = t2;
} else if (t2 && t1) {
t1 = new CSGTerm(CSGTerm::TYPE_UNION, t1, t2);
}
}
if (t1 && modinst->tag_highlight && highlights)
highlights->append(t1->link());
if (t1 && modinst->tag_background && background) {
background->append(t1);
return NULL;
}
return t1;
}
std::string TransformNode::toString() const
{
std::stringstream stream;

View File

@ -14,7 +14,6 @@ public:
virtual std::string toString() const;
double m[20];
virtual CSGTerm *render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const;
};
#endif

167
test-code/csgtermtest.cc Normal file
View File

@ -0,0 +1,167 @@
/*
* 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 "CSGTextRenderer.h"
#include "CSGTextCache.h"
#include "openscad.h"
#include "node.h"
#include "module.h"
#include "context.h"
#include "value.h"
#include "export.h"
#include "builtin.h"
#include "Tree.h"
#include <QApplication>
#include <QFile>
#include <QDir>
#include <QSet>
#include <getopt.h>
#include <assert.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
}
}
void csgTree(CSGTextCache &cache, const AbstractNode &root)
{
CSGTextRenderer renderer(cache);
Traverser render(renderer, root, Traverser::PRE_AND_POSTFIX);
render.execute();
}
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);
Tree tree;
tree.setRoot(root_node);
destroy_builtin_functions();
destroy_builtin_modules();
return rc;
}

105
test-code/csgtermtest.pro Normal file
View File

@ -0,0 +1,105 @@
DEFINES += OPENSCAD_VERSION=test
TEMPLATE = app
OBJECTS_DIR = objects
MOC_DIR = objects
UI_DIR = objects
RCC_DIR = objects
INCLUDEPATH += ../src
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/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/transformnode.h \
../src/rendernode.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/nodecache.h \
../src/importnode.h \
../src/state.h \
../src/PolySetRenderer.h \
../src/Tree.h \
../src/myqhash.h \
../src/CSGTermRenderer.h
SOURCES += csgtexttest.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/traverser.cc \
../src/PolySetRenderer.cc \
../src/Tree.cc \
../src/qhash.cc \
../src/CSGTermRenderer.cc