rubyscad 1.0.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.
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: []