solidruby 0.1.0

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.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.travis.yml +3 -0
  4. data/COPYING +674 -0
  5. data/Gemfile +2 -0
  6. data/Guardfile +24 -0
  7. data/LICENSE.md +675 -0
  8. data/README.md +180 -0
  9. data/Rakefile +10 -0
  10. data/bin/solidruby +61 -0
  11. data/examples/chamfered_cube.rb +39 -0
  12. data/examples/filleted_cube.rb +39 -0
  13. data/examples/gear.rb +11 -0
  14. data/examples/knurls.rb +12 -0
  15. data/examples/nut_support.rb +17 -0
  16. data/examples/openscad_examples/old/example001.rb +42 -0
  17. data/examples/openscad_examples/old/example002.rb +45 -0
  18. data/examples/openscad_examples/old/example003.rb +37 -0
  19. data/examples/openscad_examples/old/example004.rb +22 -0
  20. data/examples/openscad_examples/old/example005.rb +45 -0
  21. data/examples/openscad_examples/old/example006.rb +85 -0
  22. data/examples/openscad_examples/old/example007.dxf +2410 -0
  23. data/examples/openscad_examples/old/example007.rb +107 -0
  24. data/examples/openscad_examples/old/example008.rb +61 -0
  25. data/examples/openscad_examples/old/example009.dxf +3894 -0
  26. data/examples/openscad_examples/old/example009.rb.old +48 -0
  27. data/examples/openscad_examples/old/example010.dat +51 -0
  28. data/examples/openscad_examples/old/example010.rb +23 -0
  29. data/examples/openscad_examples/old/example011.rb +42 -0
  30. data/examples/openscad_examples/old/example012.rb +22 -0
  31. data/examples/openscad_examples/old/example012.stl +450 -0
  32. data/examples/openscad_examples/old/example013.dxf +2276 -0
  33. data/examples/openscad_examples/old/example013.rb +30 -0
  34. data/examples/openscad_examples/old/example014.rb +30 -0
  35. data/examples/openscad_examples/old/example015.rb +46 -0
  36. data/examples/openscad_examples/old/example016.rb +75 -0
  37. data/examples/openscad_examples/old/example016.stl +0 -0
  38. data/examples/pipe.rb +38 -0
  39. data/examples/pipe_bug.rb +16 -0
  40. data/examples/printed_gear.rb +12 -0
  41. data/examples/printed_gear2.rb +16 -0
  42. data/examples/printed_thread.rb +9 -0
  43. data/examples/printed_thread2.rb +13 -0
  44. data/examples/stack.rb +21 -0
  45. data/examples/threads.rb +183 -0
  46. data/examples/threads2.rb +93 -0
  47. data/examples/threads3.rb +46 -0
  48. data/lib/solidruby.rb +60 -0
  49. data/lib/solidruby/assemblies/assembly.rb +176 -0
  50. data/lib/solidruby/assemblies/bolt.rb +158 -0
  51. data/lib/solidruby/assemblies/gear.rb +131 -0
  52. data/lib/solidruby/assemblies/linear_bearing.rb +84 -0
  53. data/lib/solidruby/assemblies/nut.rb +153 -0
  54. data/lib/solidruby/assemblies/pipe.rb +153 -0
  55. data/lib/solidruby/assemblies/ruler.rb +44 -0
  56. data/lib/solidruby/assemblies/tslot.rb +141 -0
  57. data/lib/solidruby/assemblies/tslot_machining.rb +62 -0
  58. data/lib/solidruby/assemblies/washer.rb +57 -0
  59. data/lib/solidruby/bill_of_material.rb +43 -0
  60. data/lib/solidruby/csg_modelling/csg_modelling.rb +43 -0
  61. data/lib/solidruby/csg_modelling/difference.rb +41 -0
  62. data/lib/solidruby/csg_modelling/hull.rb +23 -0
  63. data/lib/solidruby/csg_modelling/intersection.rb +24 -0
  64. data/lib/solidruby/csg_modelling/minkowski.rb +23 -0
  65. data/lib/solidruby/csg_modelling/union.rb +41 -0
  66. data/lib/solidruby/csg_modifiers/color.rb +41 -0
  67. data/lib/solidruby/csg_modifiers/csg_modifier.rb +50 -0
  68. data/lib/solidruby/csg_modifiers/linear_extrude.rb +34 -0
  69. data/lib/solidruby/csg_modifiers/projection.rb +29 -0
  70. data/lib/solidruby/csg_modifiers/rotate_extrude.rb +30 -0
  71. data/lib/solidruby/extra.rb +58 -0
  72. data/lib/solidruby/helpers/chamfer.rb +27 -0
  73. data/lib/solidruby/helpers/fillet.rb +28 -0
  74. data/lib/solidruby/helpers/position.rb +267 -0
  75. data/lib/solidruby/helpers/rounded_cube.rb +37 -0
  76. data/lib/solidruby/helpers/triangle.rb +167 -0
  77. data/lib/solidruby/primitives/circle.rb +26 -0
  78. data/lib/solidruby/primitives/cube.rb +123 -0
  79. data/lib/solidruby/primitives/cylinder.rb +72 -0
  80. data/lib/solidruby/primitives/import.rb +42 -0
  81. data/lib/solidruby/primitives/polygon.rb +26 -0
  82. data/lib/solidruby/primitives/polyhedron.rb +30 -0
  83. data/lib/solidruby/primitives/primitive.rb +19 -0
  84. data/lib/solidruby/primitives/render.rb +48 -0
  85. data/lib/solidruby/primitives/sphere.rb +49 -0
  86. data/lib/solidruby/primitives/square.rb +88 -0
  87. data/lib/solidruby/primitives/surface.rb +44 -0
  88. data/lib/solidruby/primitives/text.rb +43 -0
  89. data/lib/solidruby/printed_thread.rb +163 -0
  90. data/lib/solidruby/rubyscad_bridge.rb +376 -0
  91. data/lib/solidruby/screw_thread.rb +170 -0
  92. data/lib/solidruby/solidruby.rb +150 -0
  93. data/lib/solidruby/solidruby_object.rb +176 -0
  94. data/lib/solidruby/transformations/mirror.rb +22 -0
  95. data/lib/solidruby/transformations/rotate.rb +22 -0
  96. data/lib/solidruby/transformations/scale.rb +22 -0
  97. data/lib/solidruby/transformations/transformation.rb +29 -0
  98. data/lib/solidruby/transformations/translate.rb +32 -0
  99. data/lib/solidruby/version.rb +18 -0
  100. data/lib/templates/assembly.tt +13 -0
  101. data/lib/templates/gitignore.tt +3 -0
  102. data/lib/templates/guardfile.tt +4 -0
  103. data/lib/templates/main.tt +20 -0
  104. data/lib/templates/params.tt +3 -0
  105. data/lib/templates/printed.tt +9 -0
  106. data/manual/manual.html +417 -0
  107. data/solidruby.gemspec +35 -0
  108. metadata +277 -0
@@ -0,0 +1,376 @@
1
+ # This file is part of SolidRuby.
2
+ #
3
+ # SolidRuby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # SolidRuby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with SolidRuby. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+ #
17
+ # This code is based on RubyScad (https://github.com/cjbissonnette/RubyScad)
18
+ # which is GPLv3
19
+ #
20
+ require 'matrix'
21
+
22
+ module SolidRuby
23
+ class RubyScadBridge
24
+ START_BLOCK = '{'.freeze
25
+ END_BLOCK = '}'.freeze
26
+ TAB_SIZE = 3
27
+ PAD = 0.01
28
+ FP_P = 3
29
+
30
+ CUBE_STR = 'cube(%<args>s);'.freeze
31
+ SPHERE_STR = 'sphere(%<args>s);'.freeze
32
+ CYLINDER_STR = 'cylinder(%<args>s);'.freeze
33
+ POLYHEDRON_STR = 'polyhedron(%<args>s);'.freeze
34
+ SQUARE_STR = 'square(%<args>s);'.freeze
35
+ CIRCLE_STR = 'circle(%<args>s);'.freeze
36
+ POLYGON_STR = 'polygon(%<args>s);'.freeze
37
+ TRANSLATE_STR = 'translate(%<args>s)'.freeze
38
+ ROTATE_STR = 'rotate(%<args>s)'.freeze
39
+ SCALE_STR = 'scale(%<args>s)'.freeze
40
+ MIRROR_STR = 'mirror(%<args>s)'.freeze
41
+ MULTMATRIX_STR = 'multmatrix(%<args>s)'.freeze
42
+ COLOR_STR = 'color(%<args>s)'.freeze
43
+ UNION_STR = 'union(%<args>s)'.freeze
44
+ DIFFERENCE_STR = 'difference(%<args>s)'.freeze
45
+ INTERSECTION_STR = 'intersection(%<args>s)'.freeze
46
+ RENDER_STR = 'render(%<args>s)'.freeze
47
+ MINKOWSKI_STR = 'minkowski(%<args>s)'.freeze
48
+ HULL_STR = 'hull(%<args>s)'.freeze
49
+ BACKGROUND_STR = '%'.freeze
50
+ DEBUG_STR = '#'.freeze
51
+ ROOT_STR = '!'.freeze
52
+ DISABLE_STR = '*'.freeze
53
+ IMPORT_STR = 'import(%<args>s);'.freeze
54
+ SURFACE_STR = 'surface(%<args>s);'.freeze
55
+ LINEAR_EXTRUDE_STR = 'linear_extrude(%<args>s)'.freeze
56
+ ROTATE_EXTRUDE_STR = 'rotate_extrude(%<args>s)'.freeze
57
+ PROJECTION_STR = 'projection(%<args>s)'.freeze
58
+ TEXT_STR = 'text(%<args>s);'.freeze
59
+
60
+ INCLUDE_STR = 'include <%<file>s>'.freeze
61
+ USE_STR = 'use <%<file>s>'.freeze
62
+ ECHO_STR = 'echo(%<string>s);'.freeze
63
+ FA_STR = '$fa = %<value>s;'.freeze
64
+ FS_STR = '$fs = %<value>s;'.freeze
65
+ FN_STR = '$fn = %<value>s;'.freeze
66
+
67
+ def fa(value)
68
+ format_output FA_STR % { value: value }
69
+ end
70
+
71
+ def fs(value)
72
+ format_output FS_STR % { value: value }
73
+ end
74
+
75
+ def fn(value)
76
+ format_output FN_STR % { value: value }
77
+ end
78
+
79
+ def include_scad(file)
80
+ format_output INCLUDE_STR % { file: file }
81
+ end
82
+
83
+ def use(file)
84
+ format_output USE_STR % { file: file }
85
+ end
86
+
87
+ def echo(*args)
88
+ format_output ECHO_STR % { string: args.join(', ') }
89
+ end
90
+
91
+ def projection(args = {}, &block)
92
+ format_command PROJECTION_STR, args, &block
93
+ end
94
+
95
+ def linear_extrude(args = {}, &block)
96
+ str_end = args.include?(:file) ? ';' : ''
97
+ format_command LINEAR_EXTRUDE_STR.concat(str_end), args, &block
98
+ end
99
+
100
+ def rotate_extrude(args = {}, &block)
101
+ str_end = args.include?(:file) ? ';' : ''
102
+ format_command ROTATE_EXTRUDE_STR.concat(str_end), args, &block
103
+ end
104
+
105
+ def import(args = {})
106
+ format_command IMPORT_STR, args
107
+ end
108
+
109
+ def difference(&block)
110
+ format_command DIFFERENCE_STR, &block
111
+ end
112
+
113
+ def union(&block)
114
+ format_command UNION_STR, &block
115
+ end
116
+
117
+ def intersection(&block)
118
+ format_command INTERSECTION_STR, &block
119
+ end
120
+
121
+ def render(args = {}, &block)
122
+ format_command RENDER_STR, args, &block
123
+ end
124
+
125
+ def minkowski(&block)
126
+ format_command MINKOWSKI_STR, &block
127
+ end
128
+
129
+ def hull(&block)
130
+ format_command HULL_STR, &block
131
+ end
132
+
133
+ def background
134
+ format_output BACKGROUND_STR
135
+ yield if block_given?
136
+ end
137
+
138
+ def debug
139
+ format_output DEBUG_STR
140
+ yield if block_given?
141
+ end
142
+
143
+ def root
144
+ format_output ROOT_STR
145
+ yield if block_given?
146
+ end
147
+
148
+ def disable
149
+ format_output DISABLE_STR
150
+ yield if block_given?
151
+ end
152
+
153
+ def cube(args = {})
154
+ format_command CUBE_STR, args
155
+ end
156
+
157
+ def sphere(args = {})
158
+ if args.include?(:d)
159
+ args[:r] = args[:d] / 2.0
160
+ args.delete(:d)
161
+ end
162
+ format_command SPHERE_STR, args
163
+ end
164
+
165
+ def polyhedron(args = {})
166
+ format_command POLYHEDRON_STR, args
167
+ end
168
+
169
+ def square(args = {})
170
+ format_command SQUARE_STR, args
171
+ end
172
+
173
+ def circle(args = {})
174
+ if args.include?(:d)
175
+ args[:r] = args[:d] / 2.0
176
+ args.delete(:d)
177
+ end
178
+ format_command CIRCLE_STR, args
179
+ end
180
+
181
+ def polygon(args = {})
182
+ format_command POLYGON_STR, args
183
+ end
184
+
185
+ def surface(args = {})
186
+ format_command SURFACE_STR, args
187
+ end
188
+
189
+ def cylinder(args = {})
190
+ if args.include?(:d)
191
+ args[:r] = args[:d] / 2.0
192
+ args.delete(:d)
193
+ end
194
+ if args.include?(:d1)
195
+ args[:r1] = args[:d1] / 2.0
196
+ args.delete(:d1)
197
+ end
198
+ if args.include?(:d2)
199
+ args[:r2] = args[:d2] / 2.0
200
+ args.delete(:d2)
201
+ end
202
+ format_command CYLINDER_STR, args
203
+ end
204
+
205
+ def text(args = {})
206
+ format_command TEXT_STR, args
207
+ end
208
+
209
+ def rotate(args = {}, &block)
210
+ vector_input(args, :a)
211
+ format_command ROTATE_STR, args, &block
212
+ end
213
+
214
+ def translate(args = {}, &block)
215
+ delete_from(args, :z) if args[:z] == 0
216
+ vector_input(args, :v)
217
+ format_command TRANSLATE_STR, args, &block
218
+ end
219
+
220
+ def scale(args = {}, &block)
221
+ vector_input(args, :v)
222
+ format_command SCALE_STR, args, &block
223
+ end
224
+
225
+ def mirror(args = {}, &block)
226
+ vector_input(args, :v)
227
+ format_command MIRROR_STR, args, &block
228
+ end
229
+
230
+ def multmatrix(args = {}, &block)
231
+ format_command MULTMATRIX_STR, args, &block
232
+ end
233
+
234
+ def color(args = {}, &block)
235
+ if args.include?(:color)
236
+ args[:color] = "\"#{args[:color]}\""
237
+ else
238
+ args[:color] = [args.fetch(:r, 0), args.fetch(:g, 0), args.fetch(:b, 0), args.fetch(:a, 1)].to_s
239
+ end
240
+ delete_from(args, :r, :g, :b, :a)
241
+ format_command(COLOR_STR, args[:color], &block)
242
+ end
243
+
244
+ def format_command(cmd_str, args = {}, &block)
245
+ if args.is_a? String
246
+ arg_str = args
247
+ else
248
+ arg_str = args.collect do
249
+ |k, v| "#{format_key(k)} = #{format_value(v)}"
250
+ end
251
+ .sort_by{ |x| ['$fn', '$fa', '$fs', 'cen', 'con'].include?(x[0..2]) ? ('z' + x) : x }
252
+ .join(', ')
253
+ end
254
+ format_block cmd_str % { args: arg_str }, &block
255
+ end
256
+
257
+ def format_key(key)
258
+ key = key.to_s
259
+ key.prepend('$') if key.match('^f[asn]$')
260
+ key
261
+ end
262
+
263
+ def format_value(var)
264
+ if var.nil?
265
+ "nil"
266
+ elsif var.is_a?(Vector) || var.is_a?(Matrix) || var.is_a?(Array)
267
+ res = []
268
+ var.to_a.each do |v|
269
+ res << format_value(v)
270
+ end
271
+ res.to_s.gsub('"', "").gsub('\\', '')
272
+ elsif var.is_a? String
273
+ '"' + var + '"'
274
+ elsif var.is_a? Float
275
+ "%.#{FP_P}f" % var.round(FP_P).to_s
276
+ else
277
+ var.to_s
278
+ end
279
+ end
280
+
281
+ def delete_from(hash, *keys)
282
+ keys.each { |k| hash.delete(k) }
283
+ end
284
+
285
+ def vector_input(args, element)
286
+ unless args.include?(element)
287
+ args[element] = [args.fetch(:x, 0), args.fetch(:y, 0)]
288
+ args[element].push(args[:z]) if args.include?(:z)
289
+ delete_from(args, :x, :y, :z)
290
+ end
291
+ end
292
+
293
+ def new_line
294
+ format_output "\n"
295
+ end
296
+
297
+ def start_block
298
+ format_output START_BLOCK
299
+ end
300
+
301
+ def end_block
302
+ format_output END_BLOCK
303
+ end
304
+
305
+ def end_all_blocks
306
+ end_block while @@tab_level > 0
307
+ end
308
+
309
+ def space_string(str, tab_level)
310
+ ((' ' * TAB_SIZE) * tab_level) + str
311
+ end
312
+
313
+ def raw_output(str)
314
+ str
315
+ end
316
+
317
+ def format_output(str)
318
+ str
319
+ end
320
+
321
+ def format_block(output_str)
322
+ output_str
323
+ end
324
+
325
+ def self.start_output
326
+ @@output_file ||= nil
327
+ if ARGV[0] && ARGV[0].include?('.scad')
328
+ @@output_file = ARGV[0]
329
+ ARGV.shift
330
+ end
331
+ if @@output_file
332
+ File.open(@@output_file, 'w') do |f|
333
+ f.puts "//created with rubyscad #{VERSION}\n\n"
334
+ end
335
+ end
336
+ end
337
+
338
+ def self.extended(_mod)
339
+ start_output
340
+ end
341
+
342
+ def self.included(_mod)
343
+ start_output
344
+ end
345
+
346
+ start_output if __FILE__ == $PROGRAM_NAME
347
+
348
+ def lookup(x, points)
349
+ xmin = 0.0
350
+ xmax = 0.0
351
+ points.keys.sort.reverse_each do |k|
352
+ if k <= x
353
+ xmin = k
354
+ break
355
+ end
356
+ end
357
+ points.keys.sort.each do |k|
358
+ if k >= x
359
+ xmax = k
360
+ break
361
+ end
362
+ end
363
+ return points[xmax] if x == xmax
364
+ return points[xmin] if x == xmin
365
+ points[xmin] + (((x - xmin) * (points[xmax] - points[xmin])) / (xmax - xmin))
366
+ end
367
+
368
+ def dxf_cross(_args = {})
369
+ 0.0
370
+ end
371
+
372
+ def dxf_dim(_args = {})
373
+ 0.0
374
+ end
375
+ end
376
+ end
@@ -0,0 +1,170 @@
1
+ # This file is part of SolidRuby.
2
+ #
3
+ # SolidRuby is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # SolidRuby is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with SolidRuby. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ module SolidRuby::ScrewThreads
17
+ class ScrewThread
18
+ # I would name this Thread but that's already taken by something else
19
+
20
+ attr_accessor :x, :y, :z, :size, :depth, :face
21
+
22
+ def initialize(args = {})
23
+ @x = args[:x] || 0
24
+ @y = args[:y] || 0
25
+ @z = args[:z] || 0
26
+ @depth = args[:depth]
27
+ @size = args[:size]
28
+ @face = args[:face] || :top
29
+ end
30
+
31
+ def rotation
32
+ case @face.to_s
33
+ when 'top'
34
+ {}
35
+ when 'bottom'
36
+ { y: 180 }
37
+ when 'left'
38
+ { y: -90 }
39
+ when 'right'
40
+ { y: 90 }
41
+ when 'front' # checkme
42
+ { x: 90 }
43
+ when 'back'
44
+ { x: -90 }
45
+ end
46
+ end
47
+
48
+ def show
49
+ cylinder(d: @size, h: @depth).rotate(rotation).translate(x: @x, y: @y, z: @z).color(r: 130, g: 130, b: 130)
50
+ end
51
+
52
+ def output
53
+ show
54
+ end
55
+
56
+ def orientation_swap_to(coords, rotation)
57
+ return [coords[0], coords[2], -coords[1]] if rotation[:x].to_i == -90
58
+ return [coords[0], -coords[2], coords[1]] if rotation[:x].to_i == 90
59
+ return [coords[2], coords[1], coords[0]] if rotation[:y].to_i == -90
60
+ return [-coords[2], coords[1], -coords[0]] if rotation[:y].to_i == 90
61
+
62
+ coords
63
+ end
64
+
65
+ def position_on(other_thread, rotation = {})
66
+ if other_thread.is_a? Bolt
67
+ # we assume that a bolt is always centered and center the object on
68
+ # the screwthread position
69
+ { x: -@x, y: -@y, z: -@z }
70
+ else
71
+ # on a screwthread find out its position and orientation
72
+ oc = other_thread.x, other_thread.y, other_thread.z
73
+ oc = orientation_swap_to(oc, rotation)
74
+ { x: @x - oc[0], y: @y - oc[1], z: @z - oc[2] }
75
+ end
76
+ end
77
+ end
78
+
79
+ def create_bolts(face, obj1, obj2, args = {})
80
+ # make a obj1-=obj2 with bolts corresponding to the height of obj1
81
+
82
+ if face.nil? || obj1.nil? || obj2.nil?
83
+ raise 'usage: create_bolts(face,obj1,obj2,args={}) - args can include (obj1.)height and bolt_height'
84
+ return
85
+ end
86
+
87
+ # we need to know obj1 height (if not supplied by user)
88
+ #TODO: Rescuing like this is not good practise
89
+ height ||= args[:height]
90
+ case face.to_s
91
+ when 'top'
92
+ height ||= obj1.z rescue nil
93
+ when 'bottom'
94
+ height ||= obj1.z rescue nil
95
+ when 'left'
96
+ height ||= obj1.x rescue nil
97
+ when 'right'
98
+ height ||= obj1.x rescue nil
99
+ when 'front'
100
+ height ||= obj1.y rescue nil
101
+ when 'back'
102
+ height ||= obj1.y rescue nil
103
+ end
104
+ height ||= obj1.height rescue nil
105
+
106
+ if height.nil?
107
+ raise "the object we're substracting from doesn't have a height defined; please define manually"
108
+ return
109
+ end
110
+
111
+ # lets check if the obj2 responds to the threads_[face] method
112
+
113
+ meth = "threads_#{face}"
114
+
115
+ unless obj2.respond_to?(meth)
116
+ raise "The object you're trying to get bolts from doesn't supply any on the face '#{face}'. Please add a method #{meth} to this object"
117
+ return
118
+ end
119
+ holes = obj2.send(meth)
120
+
121
+ return if holes.nil?
122
+
123
+ # let the user either define bolt_heights as integer, array or none (will be guessed)
124
+ if args[:bolt_height].is_a? Array
125
+ bolt_heights = args[:bolt_height]
126
+ if bolt_heights.size != holes.size
127
+ raise "object has #{holes.size} threads for bolts but you supplied #{bolt_heights.size}"
128
+ return
129
+ end
130
+ else
131
+ bolt_heights = []
132
+ holes.each do |hole|
133
+ bolt_heights << if args[:bolt_height]
134
+ args[:bolt_height]
135
+ else
136
+ (height + hole.depth).floor
137
+ end
138
+ end
139
+ end
140
+
141
+ ret = []
142
+ holes.each_with_index do |hole, i|
143
+ bolt = Bolt.new(hole.size, bolt_heights[i], washer: args[:washer])
144
+ case face
145
+ when 'top'
146
+ bolt.transformations << Rotate.new(x: 180)
147
+ bolt.transformations << Translate.new(x: hole.x, y: hole.y, z: hole.z + height)
148
+ when 'bottom'
149
+ bolt.transformations << Translate.new(x: hole.x, y: hole.y, z: hole.z)
150
+ when 'left'
151
+ bolt.transformations << Rotate.new(y: 90)
152
+ bolt.transformations << Translate.new(x: hole.x, y: hole.y, z: hole.z)
153
+ when 'right'
154
+ bolt.transformations << Rotate.new(y: -90)
155
+ bolt.transformations << Translate.new(x: hole.x + height, y: hole.y, z: hole.z)
156
+ when 'front'
157
+ bolt.transformations << Rotate.new(x: -90)
158
+ bolt.transformations << Translate.new(x: hole.x, y: hole.y, z: hole.z)
159
+ when 'back'
160
+ bolt.transformations << Rotate.new(x: 90)
161
+ bolt.transformations << Translate.new(x: hole.x, y: hole.y + height, z: hole.z)
162
+ end
163
+ bolt.transformations += obj2.transformations unless obj2.transformations.nil?
164
+
165
+ ret << bolt
166
+ end
167
+
168
+ ret
169
+ end
170
+ end