Skip to content

Instantly share code, notes, and snippets.

@tompng
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompng/9268475 to your computer and use it in GitHub Desktop.
Save tompng/9268475 to your computer and use it in GitHub Desktop.
require './hoge'
Printer3D.generate 'out.stl' do
x------------------------------x
x-!--------------------------!-x
x--!!!--------------------!!!--x
x---!!!------------------!!!---x
x---!!!------------------!!!---x
x----!!!----------------!!!----x
x----!!!----------------!!!----x
x-----!!!--------------!!!-----x
x------!!!------------!!!------x
x-------!!!----------!!!-------x
x--------!!!!------!!!!--------x
x---------!!!!!!!!!!!!---------x
x----------!!!!!!!!!!----------x
x---------!!!!!!!!!!!!---------x
x------!!!!!!!!!!!!!!!!!!------x
x------------------------------x
end
class STL
def initialize options={}, &block
@buffer = []
name = options[:name] || 'object'
stlputs "solid #{name}"
begin
instance_eval &block
ensure
stlputs "endsolid #{name}"
end
if options && options[:io]
options[:io].write data
elsif options && options[:file]
File.open(options[:file],'w'){|f|f.write data}
end
end
def data
@buffer.join "\n"
end
private
def stlputs str
@buffer << str
end
def face p1,p2,p3,flip=false
p2,p3=p3,p2 if flip
stlputs "facet normal 0 0 0"
stlputs "outer loop"
[p1,p2,p3].each do |p|
stlputs "vertex #{p[:x].round 4} #{p[:y].round 4} #{p[:z].round 4}"
end
stlputs "endloop"
stlputs "endfacet"
end
end
module Printer3D
class Segment
attr_accessor :data
def initialize parent
@parent = parent
self.data = []
end
def -@
data.unshift false
self
end
def +@
data.unshift true
self
end
def !@
+self
end
def - right
@parent << (-right).data
end
def + right
@parent << (+right).data
end
end
class Generator
attr_accessor :lines
def initialize
@lines = []
end
def x
Segment.new self
end
def << data
def data.to_s
map{|b|b ? '!' : '-'}.join
end
lines << data
end
def show
puts lines.map(&:to_s)
end
def rectangle!
raise 'not rectangle' unless lines.all?{|line|line.size == width}
end
def symmetric!
lines.each_with_index do |line, index|
if line.reverse != line
raise "not symmetric: (#{index+1})#{line}"
end
end
end
def width
lines.first.size
end
def height
lines.size
end
def get x, y
lines[y][x] if (0...width).include?(x) && (0...height).include?(y)
end
def outlines
paths = []
links = []
link_hash = {}
center = (width-1) / 2.0
add=->p1, p2, dir{
args = [[p1[0]-center, p1[1]], [p2[0]-center, p2[1]], dir]
links << args
link_hash[args.first] ||= []
link_hash[args.first] << args
}
width.times{|x|height.times{|y|
next unless get x, y
d=0.5
add[[x-d,y-d],[x-d,y+d],0] if !get x-1, y
add[[x+d,y+d],[x+d,y-d],2] if !get x+1, y
add[[x+d,y-d],[x-d,y-d],3] if !get x, y-1
add[[x-d,y+d],[x+d,y+d],1] if !get x, y+1
}}
until links.empty?
link = links.pop
path = []
while link = link_hash[link[1]].sort_by{|a|(a[2]-link[2]+1+4)%4}.first
path << link[0]
links.delete link
link_hash[link[0]].delete link
end
paths << path
end
paths
end
end
class << self
def interpolate outline, step
out = []
outline.size.times{|i|
p=outline[i-1]
q=outline[i]
step.times{|j|
t=j.fdiv step
out << 2.times.map{|i|p[i]*(1-t)+q[i]*t}
}
}
out
end
def smooth outline, range
out=[]
weight=->a{(a**2-(range+1)**2)**2}
sum = (-range..range).map{|i|weight[i]}.inject(:+)
outline.size.times{|i|
out[i]=2.times.map{|axis|
(-range..range).map{|j|
weight[j]*outline[(i+j)%outline.size][axis]
}.inject(:+)/sum
}
}
out
end
def generate file, &block
gen = Generator.new
gen.instance_eval &block
gen.symmetric!
gen.rectangle!
smoothed_outlines = gen.outlines.map{|o|smooth(interpolate(o,4),8)}
gen.show
STL.new file: file do
hoge = ->(p,q){
return if p[0]<=0 && q[0]<=0
p=[0,(q[0]*p[1]-p[0]*q[1])/(q[0]-p[0])] if p[0]<0
q=[0,(q[0]*p[1]-p[0]*q[1])/(q[0]-p[0])] if q[0]<0
n = 100
n.times{|t|
th1 = 2*Math::PI*t/n
th2 = 2*Math::PI*(t+1)/n
c1, s1 = Math.cos(th1), Math.sin(th1)
c2, s2 = Math.cos(th2), Math.sin(th2)
ps = [
{x: p[0]*c1, y: p[0]*s1, z: -p[1]},
{x: p[0]*c2, y: p[0]*s2, z: -p[1]},
{x: q[0]*c2, y: q[0]*s2, z: -q[1]},
{x: q[0]*c1, y: q[0]*s1, z: -q[1]}
]
face ps[0], ps[1], ps[2]
face ps[0], ps[2], ps[3]
}
}
smoothed_outlines.each{|outline|
outline.size.times{|i|
hoge[outline[i-1],outline[i]]
}
}
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment