Skip to content

Instantly share code, notes, and snippets.

@bakineggs
Created July 25, 2016 01:04
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 bakineggs/4133662632c349c808d51189f57c397d to your computer and use it in GitHub Desktop.
Save bakineggs/4133662632c349c808d51189f57c397d to your computer and use it in GitHub Desktop.
making feet for my dining table
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