jenncad 1.0.0.pre.alpha1 → 1.0.0.pre.alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/jenncad.gemspec +2 -1
- data/lib/jenncad/default_profile.rb +2 -2
- data/lib/jenncad/exporters/openscad.rb +248 -0
- data/lib/jenncad/part.rb +5 -2
- data/lib/jenncad/patches/array.rb +27 -6
- data/lib/jenncad/primitives/boolean_object.rb +11 -1
- data/lib/jenncad/primitives/cube.rb +25 -18
- data/lib/jenncad/primitives/cylinder.rb +36 -8
- data/lib/jenncad/primitives/rounded_cube.rb +7 -10
- data/lib/jenncad/primitives/subtract_object.rb +17 -13
- data/lib/jenncad/primitives.rb +22 -0
- data/lib/jenncad/shortcuts.rb +26 -35
- data/lib/jenncad/thing.rb +58 -38
- data/lib/jenncad/transformation/color.rb +179 -0
- data/lib/jenncad/version.rb +1 -1
- data/lib/jenncad.rb +4 -29
- metadata +19 -5
- data/lib/jenncad/jenncad.rb +0 -3
- data/lib/jenncad/openscad.rb +0 -274
data/lib/jenncad/openscad.rb
DELETED
@@ -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
|