Created
July 25, 2016 01:04
-
-
Save bakineggs/4133662632c349c808d51189f57c397d to your computer and use it in GitHub Desktop.
making feet for my dining table
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
raise "Usage: ruby #{__FILE__} <roughing file> <finishing file>" unless ARGV.length == 2 | |
X_SIZE = 34.0 # leave 2" for mounting to spoil board | |
Y_SIZE = 3.5 | |
Z_SIZE = 3.5 | |
X_INCR = 0.001 | |
STUB_WIDTH = 1.625 | |
STUB_HEIGHT = 1.5625 | |
TOOL_DIAMETER = 0.25 | |
ROUNDING = 1000000.0 | |
MERGING_TOLERANCE = 0.00000000000000001 | |
raise 'X_SIZE is too small to make feet with this Y_SIZE and Z_SIZE' unless X_SIZE >= Z_SIZE * 2 + Y_SIZE * 3 | |
$stderr.puts 'X_SIZE is too small to make nice looking feet with this Y_SIZE and Z_SIZE' unless X_SIZE >= Z_SIZE * 2 + Y_SIZE * 5 | |
def z_func y | |
memoized = {} | |
buffer = Y_SIZE / 2 - Math.sqrt((Y_SIZE / 2) ** 2 - (y - Y_SIZE / 2) ** 2) | |
lambda do |x| | |
memoized[x] ||= | |
if x < Z_SIZE # the ramp | |
Z_SIZE - x | |
elsif x < Z_SIZE + buffer # the part in between the ramp and the start of the foot | |
0 | |
elsif x < Z_SIZE * 1.5 + buffer # the circular part at the end of the foot | |
Math.sqrt((Z_SIZE / 2) ** 2 - (x - (Z_SIZE * 1.5 + buffer)) ** 2) | |
elsif x < (X_SIZE - Y_SIZE) / 2 # the wave | |
x1 = Z_SIZE * 1.5 + buffer | |
z1 = Z_SIZE / 2 | |
x2 = (X_SIZE - Y_SIZE) / 2 | |
z2 = Z_SIZE | |
z1 + (z2 - z1) / 2 * Math.sin((Math::PI / (x2 - x1)) * x - Math::PI / 2 * ((x1 + x2) / (x2 - x1))) + (z2 - z1) / 2 | |
elsif x < (X_SIZE + Y_SIZE) / 2 # the mounting part | |
Z_SIZE # the mounting hole is made separately | |
elsif x < X_SIZE - (Z_SIZE * 1.5 + buffer) # the wave | |
x1 = (X_SIZE + Y_SIZE) / 2 | |
z1 = Z_SIZE | |
x2 = X_SIZE - (Z_SIZE * 1.5 + buffer) | |
z2 = Z_SIZE / 2 | |
z2 + (z1 - z2) / 2 * Math.sin((Math::PI / (x1 - x2)) * x - Math::PI / 2 * ((x1 + x2) / (x1 - x2))) + (z1 - z2) / 2 | |
elsif x < X_SIZE - (Z_SIZE + buffer) # the circular part at the end of the foot | |
Math.sqrt((Z_SIZE / 2) ** 2 - (x - (X_SIZE - (Z_SIZE * 1.5 + buffer))) ** 2) | |
elsif x < X_SIZE - Z_SIZE # the part in between the end of the foot and the ramp | |
0 | |
else # the ramp | |
Z_SIZE - (X_SIZE - x) | |
end | |
end | |
end | |
y_roughing_values = [] | |
y_finishing_values = [] | |
z_funcs = {} | |
y = Y_SIZE / 2 | |
while y < Y_SIZE + TOOL_DIAMETER / 2 | |
y_finishing_values.push y | |
y_roughing_values.push y | |
z_func = z_func y | |
z_funcs[y] = z_func | |
if y + TOOL_DIAMETER / 3 < Y_SIZE + TOOL_DIAMETER / 2 | |
y_roughing_values.push y + TOOL_DIAMETER / 3 | |
z_funcs[y + TOOL_DIAMETER / 3] = z_func | |
end | |
if y + TOOL_DIAMETER * 2 / 3 < Y_SIZE + TOOL_DIAMETER / 2 | |
y_roughing_values.push y + TOOL_DIAMETER * 2 / 3 | |
z_funcs[y + TOOL_DIAMETER * 2 / 3] = z_func | |
end | |
y += TOOL_DIAMETER | |
end | |
y = Y_SIZE / 2 | |
while y > TOOL_DIAMETER / -2 | |
if y == Y_SIZE / 2 | |
z_func = z_funcs[y] | |
else | |
y_finishing_values.unshift y | |
y_roughing_values.unshift y | |
z_func = z_func y | |
z_funcs[y] = z_func | |
end | |
if y - TOOL_DIAMETER / 3 > TOOL_DIAMETER / -2 | |
y_roughing_values.unshift y - TOOL_DIAMETER / 3 | |
z_funcs[y - TOOL_DIAMETER / 3] = z_func | |
end | |
if y - TOOL_DIAMETER * 2 / 3 > TOOL_DIAMETER / -2 | |
y_roughing_values.unshift y - TOOL_DIAMETER * 2 / 3 | |
z_funcs[y - TOOL_DIAMETER * 2 / 3] = z_func | |
end | |
y -= TOOL_DIAMETER | |
end | |
roughing_path = [[X_SIZE / 2, Y_SIZE / 2, Z_SIZE + TOOL_DIAMETER]] | |
z = Z_SIZE | |
while z > Z_SIZE - STUB_HEIGHT | |
z = [z - TOOL_DIAMETER, Z_SIZE - STUB_HEIGHT].max | |
min_x, max_x, min_y, max_y = X_SIZE / 2 + TOOL_DIAMETER / 3, X_SIZE / 2 - TOOL_DIAMETER / 3, Y_SIZE / 2 + TOOL_DIAMETER / 3, Y_SIZE / 2 | |
roughing_path.push [X_SIZE / 2, Y_SIZE / 2, roughing_path.last[2]] | |
roughing_path.push [X_SIZE / 2, Y_SIZE / 2, z] | |
until min_x == (X_SIZE - STUB_WIDTH + TOOL_DIAMETER) / 2 && max_x == (X_SIZE + STUB_WIDTH - TOOL_DIAMETER) / 2 && min_y == (Y_SIZE - STUB_WIDTH + TOOL_DIAMETER) / 2 && max_y == (Y_SIZE + STUB_WIDTH - TOOL_DIAMETER) / 2 | |
min_x = [min_x - TOOL_DIAMETER / 3, (X_SIZE - STUB_WIDTH + TOOL_DIAMETER) / 2].max | |
max_x = [max_x + TOOL_DIAMETER / 3, (X_SIZE + STUB_WIDTH - TOOL_DIAMETER) / 2].min | |
min_y = [min_y - TOOL_DIAMETER / 3, (Y_SIZE - STUB_WIDTH + TOOL_DIAMETER) / 2].max | |
max_y = [max_y + TOOL_DIAMETER / 3, (Y_SIZE + STUB_WIDTH - TOOL_DIAMETER) / 2].min | |
roughing_path.push [roughing_path.last[0], max_y, z] | |
roughing_path.push [min_x, roughing_path.last[1], z] | |
roughing_path.push [roughing_path.last[0], min_y, z] | |
roughing_path.push [max_x, roughing_path.last[1], z] | |
end | |
end | |
roughing_path.push [roughing_path.last[0], roughing_path.last[1], Z_SIZE + TOOL_DIAMETER] | |
roughing_path.push [0.0, 0.0, Z_SIZE + TOOL_DIAMETER] | |
min_z = Z_SIZE | |
forward = true | |
while min_z > 0 | |
min_z -= TOOL_DIAMETER | |
y_roughing_values.each do |y| | |
if forward | |
x = 0 | |
while x <= X_SIZE | |
z = [z_funcs[y].call(x) + TOOL_DIAMETER / 2, min_z].max | |
if x == 0 | |
roughing_path.push [roughing_path.last[0], roughing_path.last[1], [roughing_path.last[2], z].max] | |
end | |
roughing_path.push [x, y, z] | |
x += X_INCR | |
end | |
forward = false | |
else | |
x = X_SIZE | |
while x >= 0 | |
z = [z_funcs[y].call(x) + TOOL_DIAMETER / 2, min_z].max | |
if x == X_SIZE | |
roughing_path.push [roughing_path.last[0], roughing_path.last[1], [roughing_path.last[2], z].max] | |
end | |
roughing_path.push [x, y, z] | |
x -= X_INCR | |
end | |
forward = true | |
end | |
end | |
end | |
finishing_path = [[0.0, 0.0, Z_SIZE]] | |
forward = true | |
y_finishing_values.each do |y| | |
if forward | |
forward = false | |
x = 0 | |
while x <= X_SIZE | |
z = z_funcs[y].call x | |
if x == 0 | |
finishing_path.push [finishing_path.last[0], finishing_path.last[1], [finishing_path.last[2], z].max + TOOL_DIAMETER] | |
finishing_path.push [x, y, finishing_path.last[2]] | |
end | |
finishing_path.push [x, y, z] | |
x += X_INCR | |
end | |
else | |
x = X_SIZE | |
while x >= 0 | |
z = z_funcs[y].call x | |
if x == X_SIZE | |
finishing_path.push [finishing_path.last[0], finishing_path.last[1], [finishing_path.last[2], z].max + TOOL_DIAMETER] | |
finishing_path.push [x, y, finishing_path.last[2]] | |
end | |
finishing_path.push [x, y, z] | |
x -= X_INCR | |
end | |
forward = true | |
end | |
end | |
[[ARGV[0], roughing_path], [ARGV[1], finishing_path]].each do |filename, path| | |
new_path = path | |
path = [] | |
until new_path.length == path.length | |
path = new_path | |
new_path = [] | |
i = 0 | |
while i < path.length | |
new_path.push path[i] | |
i_before_changes = nil | |
until i == i_before_changes | |
i_before_changes = i | |
i += 1 while i < path.length - 1 && path[i][0] == path[i + 1][0] && path[i][1] == path[i + 1][1] && path[i][2] == path[i + 1][2] | |
i += 1 while i < path.length - 2 && | |
path[i + 1] != path[i + 2] && | |
((path[i + 1][1] - path[i][1]) * (path[i + 2][2] - path[i][2]) - (path[i + 2][1] - path[i][1]) * (path[i + 1][2] - path[i][2])).abs < MERGING_TOLERANCE && | |
((path[i + 2][0] - path[i][0]) * (path[i + 1][2] - path[i][2]) - (path[i + 1][0] - path[i][0]) * (path[i + 2][2] - path[i][2])).abs < MERGING_TOLERANCE && | |
((path[i + 1][0] - path[i][0]) * (path[i + 2][1] - path[i][1]) - (path[i + 2][0] - path[i][0]) * (path[i + 1][1] - path[i][1])).abs < MERGING_TOLERANCE | |
end | |
i += 1 | |
end | |
end | |
File.open filename, 'w' do |file| | |
file.puts 'IF %(25)=1 THEN GOTO UNIT_ERROR' | |
file.puts 'C#,90' | |
file.puts 'SO,1,1' | |
file.puts 'PAUSE 2' | |
file.puts 'MS,2.0,0.5' | |
path.each do |x, y, z| | |
file.puts "M3,#{(x * ROUNDING).round / ROUNDING},#{(y * ROUNDING).round / ROUNDING},#{(z * ROUNDING).round / ROUNDING}" | |
end | |
file.puts 'SO,1,0' | |
file.puts 'END' | |
file.puts 'UNIT_ERROR:' | |
file.puts 'C#,91' | |
file.puts 'END' | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment