Last active
August 29, 2015 13:56
-
-
Save tompng/9268475 to your computer and use it in GitHub Desktop.
AAを3Dに http://twitpic.com/dx0yhb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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