commit 8975cbbf4cacb9ed0ed76c30eaf87fac7c6c72bb Author: Denis Knauf Date: Fri Mar 16 23:11:08 2012 +0100 openscad-lib and pandahome diff --git a/examples/pandahome.rb b/examples/pandahome.rb new file mode 100644 index 0000000..3a9f76c --- /dev/null +++ b/examples/pandahome.rb @@ -0,0 +1,54 @@ +#!/usr/bin/env ruby + +load 'openscad.rb' + +s = OpenSCAD.new + +def r code + OpenSCAD::Code.new code +end + +s.module :roundedBox, 'size[3]', :radius, :sidesonly do + s.rot = s[ [0,0,0], [90,0,90], [90,90,0] ] + s-:rot + s.if s.sidesonly do + s.cube s.size - s[s.radius*2,0,0], true + s.cube s.size - s[0,s.radius*2,0], true + s.for x: s[s.radius-s.size[0], -s.radius+s.size[0]]/2, + y: s[s.radius-s.size[1], -s.radius+s.size[1]]/2 do + s.translate( s[s.x,s.y,0]) { s.cylinder s: s.radius, h: s.size[2], center: true } + end + end + s.else do + s.cube s.size-s[0,s.radius,s.radius]*2, center: true + s.cube s.size-s[s.radius,0,s.radius]*2, center: true + s.cube s.size-s[s.radius,s.radius,0]*2, center: true + end + s.for axis: 0..2 do + s.for x: s.radius*s[1,-1] + s.size[s.axis]/2*s[-1,1], + y: s.radius*s[1,-1] + s.size[(s.axis+1)%3]/2*s[-1,1] do + s.rotate( (s+:rot)[s.axis]) do + s.translate s[s.x,s.y,0] do + s.cylinder h: s.size[(s.axis+2)%3]-s.radius*2, r: s.radius, center: true + end + end + end + end + s.for x: (s.radius*s[1,-1] + s.size[0]*s[-1,1]) /2, + y: (s.radius*s[1,-1] + s.size[1]*s[-1,1]) /2, + z: (s.radius*s[1,-1] + s.size[2]*s[-1,1]) /2 do + s.translate(s[s.x,s.y,s.z]) { s.sphere s.radius } + end +end + +s.body = s[ 114.3, 101.6, 40 ] +s.gap = 0.2 +s.thick = 1 +s.body_inner = s.body+s.gap +s.body_outer = s.body_inner+s.thick + +s.difference do + s.roundedBox s.body_outer, 2, true + s.translate( s[1,1,1] * s.thick) { s.roundedBox s.body_inner, 2, true } + s.translate( s[0,0,24]) { s.cube s[150,120,10], true } +end diff --git a/lib/openscad.rb b/lib/openscad.rb new file mode 100644 index 0000000..eb825fc --- /dev/null +++ b/lib/openscad.rb @@ -0,0 +1,179 @@ +#!/usr/bin/env ruby + +class OpenSCAD + def initialize indent = nil, &out + @indent, @out = indent || 0, out || STDOUT + @vars = {} + end + + def - var + var = var.to_s + self << __indent__ << var << ' = ' << @vars[var] << ";\n" + end + + def + code + Code.new code.to_s + end + + def << o, &block + if block_given? + yield self.class.new( @indent+1) + else + @out << o + end + end + + def __indent__ i = nil + @indent += i if i + "\t"*@indent + end + + def module meth, *args, &block + @vars = (vars = @vars).dup + args = args.collect do |arg| + arg = arg.to_s + dim = [] + while arg =~ /(.*)\[(\d+)\]$/ + dim.push $2.to_i + arg = $1 + end + arg = Code.new arg + gen = lambda do |ds, is| + if ds.empty? + Code.new "#{arg}#{is.collect{|i|"[#{i}]"}.join}" + else + d, *ds = ds + List[ *d.times.collect {|i| gen[ ds, is+[i]] }] + end + end + @vars[arg] = gen[dim,[]] + arg + end + method_missing "module #{meth}", *args, &(block||lambda{|*_,&e|}) + @vars = vars + end + + def method_missing meth, *args, &block + meth = meth.to_s + case meth + when /=$/ # setting variable + #self << __indent__ << meth << args[0].to_openscad << ";\n" + @vars[ meth[0...-1]] = args[0] + when *@vars.keys # reading variable + @vars[ meth] + else # method-calling + bkvars = @vars.dup + nargs = [] + args.each do |arg| + case arg + when Hash + arg.each do |k,v| + nargs.push "#{k}=#{v.to_openscad}" + @vars[k.to_s] = Code.new k.to_s + end + else nargs.push arg.to_openscad + end + end + join = case meth + when 'for' + r = ",\n" << __indent__(+2) + @indent -= 2 + r + else ', ' + end + self << __indent__ << meth + self << "(" << nargs.join( join) << ')' unless 'else' == meth + if block_given? + @indent += 1 + self << " {\n" + yield + @indent -= 1 + self << __indent__ << "}\n" + else + self << ";\n" + end + @vars = bkvars + end + end + + class List < Array + def self.[]( *as) super *as.collect {|v| Array === v ? self[ *v] : v } end + def depth() List === (o = self[0]) ? 1+o.depth : 1 end + def map( &e) dup.map! &e end + def collect( &e) dup.collect! &e end + + def operation o = nil, &e + o = case o + when List then o + when Array then self.class[ *o] + else o + end + if List === o + case depth <=> o.depth + when -1 then o.collect {|b| operation b, &e } + when 1 then collect {|a| a.operation o, &e } + else + case depth + when 1 then self.class[ *zip( o)].collect {|a,b| e[a,b] } + else self.class[ *zip( o)].collect {|a,b| a.operation b, &e } + end + end + else + case depth + when 1 then collect {|v| e[v,o] } + else collect {|v| v.operation o, &e } + end + end + end + + def s_operation( s, o) operation( o) {|a,b| Code.new "(#{a.to_openscad}#{s}#{b})" } end + def +( o) operation( o) {|a,b| a+b } end + def -( o) operation( o) {|a,b| a-b } end + def *( o) operation( o) {|a,b| a*b } end + def /( o) operation( o) {|a,b| a/b } end + def %( o) operation( o) {|a,b| a%b } end + def -@() operation {|a| -a } end + def +@() operation {|a| +a } end + + def [] i + case i + when Integer then super i + else Code.new "#{self.to_openscad}[#{i}]" + end + end + + def to_openscad + "[#{collect(&:to_openscad).join', '}]" + end + end + + class Code < String + def new( a) super a.to_s end + def to_openscad() to_s end + def s_operation s, o + case o + when List + o.operation( self) {|a,b| self.class.new "(#{b}#{s}#{a.to_openscad})" } + else self.class.new "(#{to_openscad}#{s}#{o.to_openscad})" + end + end + def +( o) 0 == o ? self : s_operation( :+, o) end + def -( o) 0 == o ? self : s_operation( :-, o) end + def *( o) 1 == o ? self : s_operation( :*, o) end + def /( o) 1 == o ? self : s_operation( :/, o) end + def %( o) s_operation( :%, o) end + def -@() s = self.dup; s[0,0] = '-'; s end + def +@() s = self.dup; s[0,0] = '+'; s end + def []( i) self.class.new "#{self}[#{i}]" end + end + + def []( *args) List[ *args] end +end + +class Object + def to_openscad() inspect end +end + +class Range + def to_openscad() "[#{self.begin}:#{self.end}]" end +end