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