jenncad 1.0.0.pre.alpha1 → 1.0.0.pre.alpha2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,274 +0,0 @@
1
- module JennCad
2
-
3
- class OpenScad
4
- def initialize(part, fn=64)
5
- @imports = []
6
- @modules = {}
7
- part = part.make_openscad_compatible
8
- @main = root(part, "$fn=#{fn};\n")
9
-
10
- @export = ""
11
- @imports.uniq.each do |val|
12
- @export += "use <#{val}.scad>\n"
13
- end
14
- @modules.each do |key, val|
15
- @export += val
16
- end
17
- @export += @main
18
- end
19
-
20
- def save(file)
21
- File.open(file,"w") do |f|
22
- f.puts @export
23
- end
24
- end
25
-
26
- def root(part, head="", tabindex=0)
27
- res = head
28
-
29
- res += transform(part) do
30
- parse(part, tabindex)
31
- end
32
- res
33
- end
34
-
35
- def transform(part, &block)
36
- res += handle_color(part)
37
- if part.transformations
38
- part.transformations.reverse.each do |trans|
39
- res += transformation(trans)
40
- end
41
- end
42
- res += block.yield
43
- end
44
-
45
- def print_tree(part, level=0)
46
- arr = []
47
- arr << parse(part) unless level == 0
48
- if part.respond_to?(:parts)
49
- part.parts.each do |p|
50
- arr << print_tree(p,level+1)
51
- end
52
- end
53
- arr
54
- end
55
-
56
-
57
- def parse(part, tabindex=0)
58
- case part
59
- when JennCad::OpenScadImport
60
- handle_import(part)
61
- when JennCad::Aggregation
62
- handle_aggregation(part)
63
- when JennCad::UnionObject
64
- cmd('union', nil, part.parts, tabindex)
65
- when JennCad::SubtractObject
66
- part.analyze_z_fighting
67
- cmd('difference', nil, part.parts, tabindex)
68
- when JennCad::IntersectionObject
69
- cmd('intersection', nil, part.parts, tabindex)
70
- when JennCad::HullObject
71
- cmd('hull', nil, part.parts, tabindex)
72
- when JennCad::Primitives::Circle
73
- cmd('circle', collect_params(part), nil, tabindex)
74
- when JennCad::Primitives::Cylinder
75
- cmd('cylinder', collect_params(part), nil, tabindex)
76
- when JennCad::Primitives::Sphere
77
- cmd('sphere', collect_params(part), nil, tabindex)
78
- when JennCad::Primitives::Cube
79
- handle_cube(part, tabindex)
80
- when JennCad::Primitives::LinearExtrude
81
- cmd('linear_extrude', part.openscad_params, part.parts, tabindex)
82
- when JennCad::Primitives::RotateExtrude
83
- cmd('rotate_extrude', part.openscad_params, part.parts, tabindex)
84
- when JennCad::Primitives::Projection
85
- cmd('projection', collect_params(part), part.parts, tabindex)
86
- when JennCad::Primitives::Polygon
87
- cmd('polygon', collect_params(part), nil, tabindex)
88
- else
89
- if part.respond_to?(:parts) && part.parts != nil && !part.parts.empty?
90
- res = ""
91
- part.parts.each do |p|
92
- res += root(p, "", tabindex)
93
- end
94
- return res
95
- elsif part.respond_to?(:part)
96
- return root(part.part, "", tabindex)
97
- end
98
- puts "no idea what to do with #{part.inspect}"
99
- return ""
100
- end
101
- end
102
-
103
- def fmt_params(args)
104
- return "" if args == nil
105
- if args.kind_of? String
106
- return "\"#{args}\""
107
- elsif args.kind_of? Array
108
- return args.map do |l|
109
- if l == nil
110
- 0
111
- elsif l.kind_of? Array
112
- l # skipping check of 2-dmin Arrays for now (used in multmatrix)
113
- elsif l.to_i == l.to_f
114
- l.to_i
115
- else
116
- l.to_f
117
- end
118
- end
119
- else
120
- res = []
121
- args.each do |k,v|
122
- if k.to_s == "fn"
123
- k = "$fn"
124
- end
125
- if v == nil
126
- next
127
- end
128
- if !v.kind_of?(Array) && !v.kind_of?(TrueClass) && !v.kind_of?(FalseClass) && v == v.to_i
129
- v = v.to_i
130
- end
131
- res << "#{k}=#{v}"
132
- end
133
- res.join(",")
134
- end
135
- end
136
-
137
- def cmd(name, args, items, tabindex = 0)
138
- items ||= []
139
- res = cmd_call(name,args)
140
- if items.size > 1
141
- res << "\n"
142
- res << tabs(tabindex) { "{\n" }
143
- items.each do |item|
144
- res << tabs(tabindex+1) do
145
- transform(item) do
146
- parse(item, tabindex+1)
147
- end
148
- end
149
- end
150
- res << tabs(tabindex) { "}\n" }
151
- elsif items.size == 1
152
- item = items.first
153
- res << transform(item) do
154
- parse(item, tabindex)
155
- end
156
- res << ";\n"
157
- else
158
- res << ";\n"
159
- end
160
- return res
161
- end
162
-
163
- def tabs(i, &block)
164
- " " * i + block.yield
165
- end
166
-
167
- def handle_import(part, tabindex=0)
168
- @imports << part.import
169
- return tabs(tabindex){ "#{part.name}(#{fmt_params(part.args)});\n" }
170
- end
171
-
172
- def handle_aggregation(part, tabindex=0)
173
- register_module(part) unless @modules[part.name]
174
- use_module(part.name, tabindex)
175
- end
176
-
177
- # check children for color values
178
- # if none of the children has a color value, we can apply color to this object and all children
179
- # if any of the children (excluding children of the kind of BooleanObject) has a color value (that is different from ours), we will apply a fallback color to all children that do not have a color value themselves.
180
-
181
- def handle_color(part)
182
- if part && part.respond_to?(:color) && part.color
183
- if part.respond_to?(:parts)
184
- if part.children_list(JennCad::Aggregation).map{|l| l.color != nil && l.color != part.color}.include?(true)
185
- part.children_list(JennCad::Aggregation).each do |child|
186
- if child.color == nil && child.color != part.color && !child.kind_of?(BooleanObject)
187
- child.set_option :fallback_color, part.color
188
- end
189
- end
190
- return ""
191
- end
192
- end
193
- end
194
- return apply_color(part)
195
- end
196
-
197
- def apply_color(part)
198
- if part && part.respond_to?(:color_or_fallback)
199
- color = part.color_or_fallback
200
- return "" if color == nil
201
- # Allowing color to be string, OpenScad compatible RGBA values of 0..1 or RGBA values of 0..255
202
- if color.kind_of?(Array) && color.map{|l| l.to_f > 1.0 ? true : false}.include?(true)
203
- color = color.map{|l| l.to_f/255.0}
204
- end
205
- return cmd_call("color", color)
206
- end
207
- return ""
208
- end
209
-
210
- def register_module(part)
211
- # can only accept aggregation
212
- @modules[part.name] = "module #{part.name}(){\n"
213
- @modules[part.name] += root(part.part)
214
- @modules[part.name] += "}\n"
215
- end
216
-
217
- def use_module(name, tabindex)
218
- tabs(tabindex){ cmd_call(name, nil).to_s+";" }
219
- end
220
-
221
- def cmd_call(name, args)
222
- args = fmt_params(args)
223
- return "#{name}(#{args})"
224
- end
225
-
226
- def collect_params(part)
227
- res = {}
228
- [:d, :r, :h, :r1, :r2, :d1, :d2, :size, :fn, :points].each do |var|
229
- if part.respond_to? var
230
- res[var] = part.send var
231
- end
232
- end
233
- res
234
- end
235
-
236
- def transformation(trans)
237
- case trans
238
- when JennCad::Move
239
- cmd_call("translate",trans.coordinates)
240
- when JennCad::Rotate
241
- cmd_call("rotate",trans.coordinates)
242
- when JennCad::Mirror
243
- cmd_call("mirror",trans.coordinates)
244
- when JennCad::Multmatrix
245
- cmd_call("multmatrix",trans.m)
246
- else
247
- puts "[openscad exporter] Unkown transformation #{trans.class}"
248
- ""
249
- end
250
- end
251
-
252
- # cubes are now centered in xy by default in jenncad
253
- # TODO: should this not be to_openscad in Cube?
254
- def handle_cube(part, tabindex)
255
- res = ""
256
- if part.option(:center)
257
- res += transformation(Move.new(x: -part.x/2.0, y: -part.y/2.0))
258
- else
259
- if part.option(:center_x)
260
- res += transformation(Move.new(x: -part.x/2.0))
261
- end
262
- if part.option(:center_y)
263
- res += transformation(Move.new(y: -part.y/2.0))
264
- end
265
- if part.option(:center_z)
266
- res += transformation(Move.new(z: -part.z/2.0))
267
- end
268
- end
269
-
270
- res += cmd('cube', collect_params(part), nil)
271
- end
272
-
273
- end
274
- end