1 #include "CSGTextRenderer.h"
2 
3 #include <string>
4 #include <map>
5 #include <list>
6 #include "state.h"
7 #include "ModuleInstantiation.h"
8 
9 #include "csgops.h"
10 #include "transformnode.h"
11 
12 #include <sstream>
13 #include <iostream>
14 #include <assert.h>
15 
isCached(const AbstractNode & node)16 bool CSGTextRenderer::isCached(const AbstractNode &node)
17 {
18 	return this->cache.contains(node);
19 }
20 
21 /*!
22 	Modifies target by applying op to target and src:
23 	target = target [op] src
24  */
25 void
process(string & target,const string & src,OpenSCADOperator op)26 CSGTextRenderer::process(string &target, const string &src, OpenSCADOperator op)
27 {
28 // 	if (target.dim != 2 && target.dim != 3) {
29 // 		assert(false && "Dimension of Nef polyhedron must be 2 or 3");
30 // 	}
31 
32 	switch (op) {
33 	case OpenSCADOperator::UNION:
34 		target += "+" + src;
35 		break;
36 	case OpenSCADOperator::INTERSECTION:
37 		target += "*" + src;
38 		break;
39 	case OpenSCADOperator::DIFFERENCE:
40 		target += "-" + src;
41 		break;
42 	case OpenSCADOperator::MINKOWSKI:
43 		target += "M" + src;
44 		break;
45 	default:
46 		assert(false);
47 	}
48 }
49 
applyToChildren(const AbstractNode & node,OpenSCADOperator op)50 void CSGTextRenderer::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
51 {
52 	std::stringstream stream;
53 	stream << node.name() << node.index();
54 	string N = stream.str();
55 	if (this->visitedchildren[node.index()].size() > 0) {
56 		// FIXME: assert that cache contains nodes in code below
57 		bool first = true;
58 		for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
59 				 iter != this->visitedchildren[node.index()].end();
60 				 iter++) {
61 			const AbstractNode *chnode = *iter;
62 			assert(this->cache.contains(*chnode));
63 			// FIXME: Don't use deep access to modinst members
64 			if (chnode->modinst->tag_background) continue;
65 			if (first) {
66 				N += "(" + this->cache[*chnode];
67 // 				if (N.dim != 0) first = false; // FIXME: when can this happen?
68 				first = false;
69 			} else {
70 				process(N, this->cache[*chnode], op);
71 			}
72 			chnode->progress_report();
73 		}
74 		N += ")";
75 	}
76 	this->cache.insert(node, N);
77 }
78 
79 /*
80 	Typical visitor behavior:
81 	o In prefix: Check if we're cached -> prune
82 	o In postfix: Check if we're cached -> don't apply operator to children
83 	o In postfix: addToParent()
84  */
85 
visit(State & state,const AbstractNode & node)86 Response CSGTextRenderer::visit(State &state, const AbstractNode &node)
87 {
88 	if (state.isPrefix() && isCached(node)) return Response::PruneTraversal;
89 	if (state.isPostfix()) {
90 		if (!isCached(node)) applyToChildren(node, OpenSCADOperator::UNION);
91 		addToParent(state, node);
92 	}
93 	return Response::ContinueTraversal;
94 }
95 
visit(State & state,const AbstractIntersectionNode & node)96 Response CSGTextRenderer::visit(State &state, const AbstractIntersectionNode &node)
97 {
98 	if (state.isPrefix() && isCached(node)) return Response::PruneTraversal;
99 	if (state.isPostfix()) {
100 		if (!isCached(node)) applyToChildren(node, OpenSCADOperator::INTERSECTION);
101 		addToParent(state, node);
102 	}
103 	return Response::ContinueTraversal;
104 }
105 
visit(State & state,const CsgOpNode & node)106 Response CSGTextRenderer::visit(State &state, const CsgOpNode &node)
107 {
108 	if (state.isPrefix() && isCached(node)) return Response::PruneTraversal;
109 	if (state.isPostfix()) {
110 		if (!isCached(node)) {
111 			applyToChildren(node, node.type);
112 		}
113 		addToParent(state, node);
114 	}
115 	return Response::ContinueTraversal;
116 }
117 
visit(State & state,const TransformNode & node)118 Response CSGTextRenderer::visit(State &state, const TransformNode &node)
119 {
120 	if (state.isPrefix() && isCached(node)) return Response::PruneTraversal;
121 	if (state.isPostfix()) {
122 		if (!isCached(node)) {
123 			// First union all children
124 			applyToChildren(node, OpenSCADOperator::UNION);
125 			// FIXME: Then apply transform
126 		}
127 		addToParent(state, node);
128 	}
129 	return Response::ContinueTraversal;
130 }
131 
132 // FIXME: RenderNode: Union over children + some magic
133 // FIXME: CgaladvNode: Iterate over children. Special operation
134 
135 // FIXME: Subtypes of AbstractPolyNode:
136 // ProjectionNode
137 // DxfLinearExtrudeNode
138 // DxfRotateExtrudeNode
139 // (SurfaceNode)
140 // (PrimitiveNode)
visit(State & state,const AbstractPolyNode & node)141 Response CSGTextRenderer::visit(State &state, const AbstractPolyNode &node)
142 {
143 	if (state.isPrefix() && isCached(node)) return Response::PruneTraversal;
144 	if (state.isPostfix()) {
145 		if (!isCached(node)) {
146 
147 	// FIXME: Manage caching
148 	// FIXME: Will generate one single Nef polyhedron (no csg ops necessary)
149 
150 			string N = node.name();
151 			this->cache.insert(node, N);
152 
153 // 		std::cout << "Insert: " << N << "\n";
154 // 		std::cout << "Node: " << cacheid.toStdString() << "\n\n";
155 		}
156 		addToParent(state, node);
157 	}
158 
159 	return Response::ContinueTraversal;
160 }
161 
162 /*!
163 	Adds ourself to out parent's list of traversed children.
164 	Call this for _every_ node which affects output during the postfix traversal.
165 */
addToParent(const State & state,const AbstractNode & node)166 void CSGTextRenderer::addToParent(const State &state, const AbstractNode &node)
167 {
168 	assert(state.isPostfix());
169 	this->visitedchildren.erase(node.index());
170 	if (state.parent()) {
171 		this->visitedchildren[state.parent()->index()].push_back(&node);
172 	}
173 }
174