rubyscad 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,425 @@
1
+ RubyScad
2
+ ========
3
+
4
+ Ruby module to easily generate openscad scripts
5
+
6
+ General Usage
7
+
8
+ Requirements: Ruby 1.9.3
9
+
10
+ RubyScad is a ruby mixin module which provides functions which allow easy output of openscad scripts . To use simply "include" or "extend" the module into any class or module:
11
+
12
+
13
+ --------------------------------test.rb--------------------------------------
14
+
15
+ load "RubyScad.rb" #or use require but it must be in ruby's system path
16
+
17
+
18
+
19
+ module Test
20
+
21
+ extend RubyScad #extend makes all function available at the class level
22
+
23
+
24
+
25
+ def self.cone(base=5, height=10)
26
+
27
+ cylinder(r1: base, r2: 0, h:height)
28
+
29
+ end
30
+
31
+
32
+
33
+ cone(2, 4)
34
+
35
+ end
36
+
37
+ ----------------------------------------------------------------------------
38
+
39
+ from command line:
40
+
41
+ print to standard output: ruby test.rb
42
+
43
+ generate file: ruby test.rb "test.scad"
44
+
45
+ --------------------------------test2.rb------------------------------------
46
+
47
+ load "RubyScad.rb" #or use require but it must be in ruby's system path
48
+
49
+
50
+
51
+ class Test2
52
+
53
+ include RubyScad #includ makes function available within the class/module
54
+
55
+
56
+
57
+ def initialize(args={})
58
+
59
+ @radius = args.fetch(:radius, 3)
60
+
61
+ end
62
+
63
+
64
+
65
+ def render()
66
+
67
+ sphere(r:@radius)
68
+
69
+ end
70
+
71
+ end
72
+
73
+
74
+
75
+ Test2.new.render
76
+
77
+ ----------------------------------------------------------------------------
78
+
79
+ from command line:
80
+
81
+ print to standard output: ruby test2.rb
82
+
83
+ generate file: ruby test2.rb "test2.scad"
84
+
85
+
86
+
87
+
88
+
89
+ General Considerations:
90
+
91
+ -All arguments passed to rubyscad functions are passed as named hash values matching the openscad spec, exceptions are for functions fa, fs, fn, echo, include, and use (see below).
92
+
93
+ openscad: cube(6)
94
+
95
+ rubyscad: cube(size: 6)
96
+
97
+ -Any arguments may be passed to functions (with the exception of the ones noted above) but openscad may or may not use these values
98
+
99
+ -cube(openscadwontusethis: 5) will produce the following openscad
100
+
101
+ -cube(openscadwontusethis = 5);
102
+
103
+ nothing bad will happen here, the value will just have no effect
104
+
105
+ -$fn, $fs, $fa variables are passed without the '$'
106
+
107
+ openscad: sphere(4, $fn=12)
108
+
109
+ rubyscad: sphere(r: 4, fn: 12)
110
+
111
+ -Ruby's math functions use radians, openscad uses degrees, for ease I've added a 'radians' function to the numeric class so the following is possible
112
+
113
+ openscad: sin(15)
114
+
115
+ rubyscad: Math.sin(15.radians)
116
+
117
+ -All functions which take code blocks (union, difference, intersection, ...) can use the form "function() { code }" or "function()" with the following result
118
+
119
+ the code:
120
+
121
+ translate(x: 5)
122
+
123
+ cube(size: 7)
124
+
125
+ would produce:
126
+
127
+ translate([5,0,0])
128
+
129
+ cube(size = 7);
130
+
131
+ the code
132
+
133
+ translate(x: 5) {
134
+
135
+ cube(size: 7)
136
+
137
+ }
138
+
139
+ would produce:
140
+
141
+ translate([5,0,0]) {
142
+
143
+ cube(size = 7);
144
+
145
+ }
146
+
147
+
148
+
149
+ Openscad Functions:
150
+
151
+ ----------------------------------------------------------------------------
152
+
153
+ openscad: $fa = 0.2;
154
+
155
+ rubyscad: fa 0.2
156
+
157
+ ----------------------------------------------------------------------------
158
+
159
+ openscad: $fs = 2;
160
+
161
+ rubyscad: fs 2
162
+
163
+ ----------------------------------------------------------------------------
164
+
165
+ openscad: $fn = 5;
166
+
167
+ rubyscad: fn 5
168
+
169
+ ----------------------------------------------------------------------------
170
+
171
+ openscad: include <file.scad>
172
+
173
+ rubyscad: include_scad "file.scad"
174
+
175
+ ----------------------------------------------------------------------------
176
+
177
+ openscad: use <file.scad>
178
+
179
+ rubyscad: use "file.scad"
180
+
181
+ ----------------------------------------------------------------------------
182
+
183
+ openscad: echo(1,2,3);
184
+
185
+ rubyscad: echo 1, 2, 3
186
+
187
+ ----------------------------------------------------------------------------
188
+
189
+ openscad: %
190
+
191
+ rubyscad: background
192
+
193
+ ----------------------------------------------------------------------------
194
+
195
+ openscad: #
196
+
197
+ rubyscad: debug
198
+
199
+ ----------------------------------------------------------------------------
200
+
201
+ openscad: !
202
+
203
+ rubyscad: root
204
+
205
+ ----------------------------------------------------------------------------
206
+
207
+ openscad: *
208
+
209
+ rubyscad: disable
210
+
211
+ ----------------------------------------------------------------------------
212
+
213
+ openscad: projection([args]) [{ code }]
214
+
215
+ rubyscad: projection([args]) [{ code }]
216
+
217
+ ----------------------------------------------------------------------------
218
+
219
+ openscad: linear_extrude([args]) [{ code }]
220
+
221
+ rubyscad: linear_extrude([args]) [{ code }]
222
+
223
+ ----------------------------------------------------------------------------
224
+
225
+ openscad: rotate_extrude([args]) [{ code }]
226
+
227
+ rubyscad: rotate_extrude([args]) [{ code }]
228
+
229
+ ----------------------------------------------------------------------------
230
+
231
+ openscad: import([args])
232
+
233
+ rubyscad: import([args])
234
+
235
+ ----------------------------------------------------------------------------
236
+
237
+ openscad: difference() { code }
238
+
239
+ rubyscad: difference() { code }
240
+
241
+ ----------------------------------------------------------------------------
242
+
243
+ openscad: union() { code }
244
+
245
+ rubyscad: union() { code }
246
+
247
+ ----------------------------------------------------------------------------
248
+
249
+ openscad: intersection() { code }
250
+
251
+ rubyscad: intersection() { code }
252
+
253
+ ----------------------------------------------------------------------------
254
+
255
+ openscad: render([args]) [{ code }]
256
+
257
+ rubyscad: render([args]) [{ code }]
258
+
259
+ ----------------------------------------------------------------------------
260
+
261
+ openscad: minkowski() { code }
262
+
263
+ rubyscad: minkowski() { code }
264
+
265
+ ----------------------------------------------------------------------------
266
+
267
+ openscad: hull() { code }
268
+
269
+ rubyscad: hull() { code }
270
+
271
+ ----------------------------------------------------------------------------
272
+
273
+ openscad: cube([args])
274
+
275
+ rubyscad: cube([args])
276
+
277
+ ----------------------------------------------------------------------------
278
+
279
+ openscad: sphere([args])
280
+
281
+ rubyscad: sphere([args])
282
+
283
+ In addition to the normal arguments d: can also be provided instead of r: to
284
+
285
+ specify the diameter instead of the radius
286
+
287
+ ----------------------------------------------------------------------------
288
+
289
+ openscad: polyhedron([args])
290
+
291
+ rubyscad: polyhedron([args])
292
+
293
+ ----------------------------------------------------------------------------
294
+
295
+ openscad: square([args])
296
+
297
+ rubyscad: square([args])
298
+
299
+ ----------------------------------------------------------------------------
300
+
301
+ openscad: circle([args])
302
+
303
+ rubyscad: circle([args])
304
+
305
+ In addition to the normal arguments d: can also be provided instead of r: to
306
+
307
+ specify the diameter instead of the radius
308
+
309
+ ----------------------------------------------------------------------------
310
+
311
+ openscad: polygon([args])
312
+
313
+ rubyscad: polygon([args])
314
+
315
+ ----------------------------------------------------------------------------
316
+
317
+ openscad: surface([args])
318
+
319
+ rubyscad: surface([args])
320
+
321
+ ----------------------------------------------------------------------------
322
+
323
+ openscad: cylinder([args])
324
+
325
+ rubyscad: cylinder([args])
326
+
327
+ ----------------------------------------------------------------------------
328
+
329
+ openscad: rotate([args]) [{ code }]
330
+
331
+ rubyscad: rotate([args]) [{ code }]
332
+
333
+ In addition to the normal arguments x:, y:, and z: can be used instead of
334
+
335
+ the normal vector input
336
+
337
+ ----------------------------------------------------------------------------
338
+
339
+ openscad: translate([args]) [{ code }]
340
+
341
+ rubyscad: translate([args]) [{ code }]
342
+
343
+ In addition to the normal arguments x:, y:, and z: can be used instead of
344
+
345
+ the normal vector input
346
+
347
+ ----------------------------------------------------------------------------
348
+
349
+ openscad: scale([args]) [{ code }]
350
+
351
+ rubyscad: scale([args]) [{ code }]
352
+
353
+ In addition to the normal arguments x:, y:, and z: can be used instead of
354
+
355
+ the normal vector input
356
+
357
+ ----------------------------------------------------------------------------
358
+
359
+ openscad: mirror([args]) [{ code }]
360
+
361
+ rubyscad: mirror([args]) [{ code }]
362
+
363
+ In addition to the normal arguments x:, y:, and z: can be used instead of
364
+
365
+ the normal vector input
366
+
367
+ ----------------------------------------------------------------------------
368
+
369
+ openscad: multmatrix([args]) [{ code }]
370
+
371
+ rubyscad: multmatrix([args]) [{ code }]
372
+
373
+ ----------------------------------------------------------------------------
374
+
375
+ openscad: color([args]) [{ code }]
376
+
377
+ rubyscad: color([args]) [{ code }]
378
+
379
+ Instead of color: being a vector, r:, g:, b:, and a: can be provided
380
+
381
+
382
+
383
+ RubyScad Functions:
384
+
385
+ ----------------------------------------------------------------------------
386
+
387
+ format_command(cmd_str, args={}, &block)
388
+
389
+ an easy way to implement new openscad commands.
390
+
391
+ cmd_str should be in the form "func_name(%<args>);"
392
+
393
+ all arguments passed from "args" will be inserted into the <args> string modifier, if
394
+
395
+ a block is passed it will output between { }
396
+
397
+ ----------------------------------------------------------------------------
398
+
399
+ new_line
400
+
401
+ outputs a new line
402
+
403
+ ----------------------------------------------------------------------------
404
+
405
+ start_block
406
+
407
+ outputs a { at the correct tab level
408
+
409
+ ----------------------------------------------------------------------------
410
+
411
+ end_block
412
+
413
+ outputs a } at the correct tab level
414
+
415
+ ----------------------------------------------------------------------------
416
+
417
+ end_all_blocks
418
+
419
+ outputs a } for every open block
420
+
421
+ ----------------------------------------------------------------------------
422
+
423
+ format_output
424
+
425
+ outputs a string at the correct tab level
data/lib/RubyScad.rb ADDED
@@ -0,0 +1,349 @@
1
+ require 'matrix'
2
+
3
+ class Numeric
4
+ def radians
5
+ self * Math::PI / 180
6
+ end
7
+ end
8
+
9
+ class Float
10
+ FP_P = 3
11
+ def to_s
12
+ "%.#{FP_P}f" % self.round(FP_P)
13
+ end
14
+ end
15
+
16
+ module RubyScad
17
+ START_BLOCK = "{"
18
+ END_BLOCK = "}"
19
+ TAB_SIZE = 3
20
+ PAD = 0.01
21
+
22
+ CUBE_STR = "cube(%<args>s);"
23
+ SPHERE_STR = "sphere(%<args>s);"
24
+ CYLINDER_STR = "cylinder(%<args>s);"
25
+ POLYHEDRON_STR = "polyhedron(%<args>s);"
26
+ SQUARE_STR = "square(%<args>s);"
27
+ CIRCLE_STR = "circle(%<args>s);"
28
+ POLYGON_STR = "polygon(%<args>s);"
29
+ TRANSLATE_STR = "translate(%<args>s)"
30
+ ROTATE_STR = "rotate(%<args>s)"
31
+ SCALE_STR = "scale(%<args>s)"
32
+ MIRROR_STR = "mirror(%<args>s)"
33
+ MULTMATRIX_STR = "multmatrix(%<args>s)"
34
+ COLOR_STR = "color(%<args>s)"
35
+ UNION_STR = "union(%<args>s)"
36
+ DIFFERENCE_STR = "difference(%<args>s)"
37
+ INTERSECTION_STR = "intersection(%<args>s)"
38
+ RENDER_STR = "render(%<args>s)"
39
+ MINKOWSKI_STR = "minkowski(%<args>s)"
40
+ HULL_STR = "hull(%<args>s)"
41
+ BACKGROUND_STR = '%'
42
+ DEBUG_STR = '#'
43
+ ROOT_STR = '!'
44
+ DISABLE_STR = '*'
45
+ IMPORT_STR = "import(%<args>s);"
46
+ SURFACE_STR = "surface(%<args>s);"
47
+ LINEAR_EXTRUDE_STR = "linear_extrude(%<args>s)"
48
+ ROTATE_EXTRUDE_STR = "rotate_extrude(%<args>s)"
49
+ PROJECTION_STR = "projection(%<args>s)"
50
+
51
+ INCLUDE_STR = "include <%<file>s>"
52
+ USE_STR = "use <%<file>s>"
53
+ ECHO_STR = "echo(%<string>s);"
54
+ FA_STR = "$fa = %<value>s;"
55
+ FS_STR = "$fs = %<value>s;"
56
+ FN_STR = "$fn = %<value>s;"
57
+
58
+ def fa(value)
59
+ format_output FA_STR % {value: value}
60
+ end
61
+
62
+ def fs(value)
63
+ format_output FS_STR % {value: value}
64
+ end
65
+
66
+ def fn(value)
67
+ format_output FN_STR % {value: value}
68
+ end
69
+
70
+ def include_scad(file)
71
+ format_output INCLUDE_STR % {file: file}
72
+ end
73
+
74
+ def use(file)
75
+ format_output USE_STR % {file: file}
76
+ end
77
+
78
+ def echo(*args)
79
+ format_output ECHO_STR % {string: args.join(', ')}
80
+ end
81
+
82
+ def projection(args={}, &block)
83
+ format_command PROJECTION_STR, args, &block
84
+ end
85
+
86
+ def linear_extrude(args={}, &block)
87
+ str_end = args.include?(:file) ? ";" : ""
88
+ format_command LINEAR_EXTRUDE_STR.concat(str_end), args, &block
89
+ end
90
+
91
+ def rotate_extrude(args={}, &block)
92
+ str_end = args.include?(:file) ? ";" : ""
93
+ format_command ROTATE_EXTRUDE_STR.concat(str_end), args, &block
94
+ end
95
+
96
+ def import(args={})
97
+ format_command IMPORT_STR, args
98
+ end
99
+
100
+ def difference(&block)
101
+ format_command DIFFERENCE_STR, &block
102
+ end
103
+
104
+ def union(&block)
105
+ format_command UNION_STR, &block
106
+ end
107
+
108
+ def intersection(&block)
109
+ format_command INTERSECTION_STR, &block
110
+ end
111
+
112
+ def render(args={}, &block)
113
+ format_command RENDER_STR, args, &block
114
+ end
115
+
116
+ def minkowski(&block)
117
+ format_command MINKOWSKI_STR, &block
118
+ end
119
+
120
+ def hull(&block)
121
+ format_command HULL_STR, &block
122
+ end
123
+
124
+ def background()
125
+ format_output BACKGROUND_STR
126
+ yield if block_given?
127
+ end
128
+
129
+ def debug()
130
+ format_output DEBUG_STR
131
+ yield if block_given?
132
+ end
133
+
134
+ def root()
135
+ format_output ROOT_STR
136
+ yield if block_given?
137
+ end
138
+
139
+ def disable()
140
+ format_output DISABLE_STR
141
+ yield if block_given?
142
+ end
143
+
144
+ def cube(args={})
145
+ format_command CUBE_STR, args
146
+ end
147
+
148
+ def sphere(args={})
149
+ if args.include?(:d)
150
+ args[:r] = args[:d]/2.0
151
+ args.delete(:d)
152
+ end
153
+ format_command SPHERE_STR, args
154
+ end
155
+
156
+ def polyhedron(args={})
157
+ format_command POLYHEDRON_STR, args
158
+ end
159
+
160
+ def square(args={})
161
+ format_command SQUARE_STR, args
162
+ end
163
+
164
+ def circle(args={})
165
+ if args.include?(:d)
166
+ args[:r] = args[:d]/2.0
167
+ args.delete(:d)
168
+ end
169
+ format_command CIRCLE_STR, args
170
+ end
171
+
172
+ def polygon(args={})
173
+ format_command POLYGON_STR, args
174
+ end
175
+
176
+ def surface(args={})
177
+ format_command SURFACE_STR, args
178
+ end
179
+
180
+ def cylinder(args={})
181
+ format_command CYLINDER_STR, args
182
+ end
183
+
184
+ def rotate(args={}, &block)
185
+ vector_input(args, :a)
186
+ format_command ROTATE_STR, args, &block
187
+ end
188
+
189
+ def translate(args={}, &block)
190
+ vector_input(args, :v)
191
+ format_command TRANSLATE_STR, args, &block
192
+ end
193
+
194
+ def scale(args={}, &block)
195
+ vector_input(args, :v)
196
+ format_command SCALE_STR, args, &block
197
+ end
198
+
199
+ def mirror(args={}, &block)
200
+ vector_input(args, :v)
201
+ format_command MIRROR_STR, args, &block
202
+ end
203
+
204
+ def multmatrix(args={}, &block)
205
+ format_command MULTMATRIX_STR, args, &block
206
+ end
207
+
208
+ def color(args={}, &block)
209
+ args[:color] = [args.fetch(:r, 0), args.fetch(:g, 0), args.fetch(:b, 0), args.fetch(:a, 1)] unless args.include?(:color)
210
+ delete_from(args, :r, :g, :b, :a)
211
+ format_command COLOR_STR, args, &block
212
+ end
213
+
214
+ def format_command(cmd_str, args={}, &block)
215
+ arg_str = args.collect { |k, v| "#{format_key(k)} = #{format_value(v)}" }.join(', ')
216
+ format_block cmd_str % {args: arg_str}, &block
217
+ end
218
+
219
+ def format_key(key)
220
+ key = key.to_s
221
+ key.prepend('$') if key.match("^f[asn]$")
222
+ key
223
+ end
224
+
225
+ def format_value(var)
226
+ if var.is_a?(Vector) or var.is_a?(Matrix)
227
+ return var.to_a.to_s
228
+ elsif var.is_a? String
229
+ return '"' + var + '"'
230
+ else
231
+ return var.to_s
232
+ end
233
+ end
234
+
235
+ def delete_from(hash, *keys)
236
+ keys.each { |k| hash.delete(k) }
237
+ end
238
+
239
+ def vector_input(args, element)
240
+ unless args.include?(element)
241
+ args[element] = [args.fetch(:x, 0), args.fetch(:y, 0)]
242
+ args[element].push(args[:z]) if args.include?(:z)
243
+ delete_from(args, :x, :y, :z)
244
+ end
245
+ end
246
+
247
+ def format_block(output_str)
248
+ format_output output_str.concat(' ')
249
+ if block_given?
250
+ start_block
251
+ yield
252
+ end_block
253
+ else
254
+ new_line unless output_str.include?(';')
255
+ end
256
+ end
257
+
258
+ def new_line
259
+ format_output "\n"
260
+ end
261
+
262
+ def start_block()
263
+ format_output START_BLOCK
264
+ end
265
+
266
+ def end_block()
267
+ format_output END_BLOCK
268
+ end
269
+
270
+ def end_all_blocks()
271
+ end_block while @@tab_level > 0
272
+ end
273
+
274
+ def space_string(str, tab_level)
275
+ ((' '*TAB_SIZE)*tab_level) + str
276
+ end
277
+
278
+ def raw_output(str)
279
+ if @@output_file
280
+ File.open(@@output_file, 'a') { |f| f.print(str) }
281
+ else
282
+ print str
283
+ end
284
+ end
285
+
286
+ def format_output(str)
287
+ @@prev_output ||= ""
288
+ @@tab_level ||= 0
289
+ str.lines do |l|
290
+ l.concat("\n") if l.match('[;\}\{>]')
291
+ @@tab_level-=1 if(l.include?('}')) && @@tab_level > 0
292
+ l = space_string(l, @@tab_level) if @@prev_output.include?("\n")
293
+ raw_output(l)
294
+ @@tab_level+=1 if(l.include?('{'))
295
+ @@prev_output = l
296
+ end
297
+ end
298
+
299
+ def self.start_output
300
+ @@output_file = nil
301
+ if ARGV[0] && ARGV[0].include?(".scad")
302
+ @@output_file = ARGV[0]
303
+ ARGV.shift
304
+ end
305
+ if @@output_file
306
+ File.open(@@output_file, 'w') do |f|
307
+ f.puts "//created with rubyscad #{VERSION}\n\n"
308
+ end
309
+ end
310
+ end
311
+
312
+ def self.extended(mod)
313
+ start_output
314
+ mod.class_variable_set(:@@fa, 30)
315
+ end
316
+
317
+ def self.included(mod)
318
+ start_output
319
+ end
320
+
321
+ start_output if __FILE__== $0
322
+
323
+ def lookup(x, points)
324
+ xmin, xmax = [0.0, 0.0]
325
+ points.keys.sort.reverse_each do |k|
326
+ if k <= x
327
+ xmin = k
328
+ break
329
+ end
330
+ end
331
+ points.keys.sort.each do |k|
332
+ if k >= x
333
+ xmax = k
334
+ break
335
+ end
336
+ end
337
+ return points[xmax] if x == xmax
338
+ return points[xmin] if x == xmin
339
+ return points[xmin] + (((x - xmin) * (points[xmax] - points[xmin])) / (xmax - xmin))
340
+ end
341
+
342
+ def dxf_cross(args={})
343
+ return 0.0
344
+ end
345
+
346
+ def dxf_dim(args={})
347
+ return 0.0
348
+ end
349
+ end
@@ -0,0 +1,3 @@
1
+ module RubyScad
2
+ VERSION = "1.0.0"
3
+ end
data/lib/rubyscad.rb ADDED
@@ -0,0 +1,8 @@
1
+ # I put this file here to both make bundler happy with a gem named 'rubyscad'
2
+ # (all lowercase) and to provide a place to start breaking the project into
3
+ # smaller components.
4
+ #
5
+ # Hope that wasn't too presumptious :-\
6
+ require 'RubyScad'
7
+
8
+ require 'rubyscad/version'
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubyscad
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Curtis Bissonnette
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-20 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Ruby module to easily generate openscad scripts
15
+ email:
16
+ - cjbissonnette
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/rubyscad/version.rb
22
+ - lib/rubyscad.rb
23
+ - lib/RubyScad.rb
24
+ - README.md
25
+ homepage: http://github.com/cjbissonnette
26
+ licenses: []
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ none: false
33
+ requirements:
34
+ - - ! '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 1.8.24
46
+ signing_key:
47
+ specification_version: 3
48
+ summary: Ruby module to easily generate openscad scripts
49
+ test_files: []