Skip to content

Instantly share code, notes, and snippets.

@User4574
Created March 21, 2022 18:55
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 User4574/4145fe2a087521f7310f9c98f8835759 to your computer and use it in GitHub Desktop.
Save User4574/4145fe2a087521f7310f9c98f8835759 to your computer and use it in GitHub Desktop.
A laser-cuttable circular slide rule generator
#!/usr/bin/env ruby
Maths = Math
Radius = ARGV.shift&.to_f || 50.0
Ring = ARGV.shift&.to_f || 15.0
Decimals = 6
Origin_x = Radius + Ring + 1
Origin_y = Radius + Ring + 1
Page_x = 2 * 2 * Origin_x
Page_y = 2 * Origin_y
def a_preamble(page_x, page_y)
puts <<-EOT % [page_x, page_y, page_x, page_y]
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="%dmm"
height="%dmm"
viewBox="0 0 %d %d"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
>
<g>
EOT
end
def a_postamble
puts <<-EOT
</g>
</svg>
EOT
end
def a_circle(origin_x, origin_y, radius)
puts <<-EOT % [origin_x, origin_y, radius, radius]
<ellipse
style="fill:none;stroke:#FF0000;stroke-width:0.1"
cx="%.6f"
cy="%.6f"
rx="%.6f"
ry="%.6f"
/>
EOT
end
def a_mark(xf, yf, xt, yt)
puts <<-EOT % [xf, yf, xt, yt]
<path
style="fill:none;stroke:#0000FF;stroke-width:0.1"
d="M %.6f,%.6f %.6f,%.6f"
/>
EOT
end
def a_label(origin_x, origin_y, radius, heading, mod, ticktext)
xt = origin_x + (radius * Maths.cos(heading) * (1 + mod))
yt = origin_y + (radius * Maths.sin(heading) * (1 + mod))
puts <<-EOT % [xt, yt, ticktext]
<text
xml:space="preserve"
style="fill:#000000;stroke:none;font-size:1.5px;font-family:'Google Sans'"
x="%.6f"
y="%.6f"
text-anchor="middle"
>%s</text>
EOT
end
def a_double_label(origin_x, origin_y, radius, heading, mod, ticktext)
a_label(origin_x, origin_y, radius, heading, -mod, ticktext)
a_label(origin_x, origin_y, radius, heading, mod, ticktext)
end
def a_tick(mantissa, exponent, origin_x, origin_y, radius, intervals)
scale = Maths::PI * 2 / intervals
(0..0.9).step(0.1).each do |sub|
tick = mantissa * (10 ** exponent) + sub
heading = scale * (exponent + Maths.log10(mantissa + sub))
adj = case mantissa + sub
when *[1.0,5.0]
0.06
when *[2.0,3.0,4.0,6.0,7.0,8.0,9.0]
0.04
else
0.02
end
xi = origin_x + (radius * Maths.cos(heading) * (1 - adj))
yi = origin_y + (radius * Maths.sin(heading) * (1 - adj))
xo = origin_x + (radius * Maths.cos(heading) * (1 + adj))
yo = origin_y + (radius * Maths.sin(heading) * (1 + adj))
ticktext = if tick == 1.0
"#{tick.to_i}(#{"0" * intervals})"
else
"#{tick.to_i}"
end
a_mark(xi, yi, xo, yo)
a_double_label(origin_x, origin_y, radius, heading, adj + 0.04, ticktext) if sub == 0
end
end
def a_scale(origin_x, origin_y, radius, intervals)
intervals.times do |exponent|
(1..9).each do |mantissa|
a_tick(mantissa, exponent, origin_x, origin_y, radius, intervals)
end
end
end
a_preamble(Page_x + 1, Page_y + 1)
a_circle(Origin_x, Origin_y, Radius)
a_circle(Origin_x, Origin_y, Radius + Ring)
a_circle(Origin_x + (2 * (Radius + Ring + 1)), Origin_y, Radius + Ring)
a_circle(Origin_x, Origin_y, Radius - Ring)
a_double_label(Origin_x, Origin_y, Radius - Ring, 0.05, 0.1, "x")
a_scale(Origin_x, Origin_y, Radius - Ring, 1)
a_double_label(Origin_x, Origin_y, Radius, 0.04, 0.1, "x^2")
a_scale(Origin_x, Origin_y, Radius, 2)
a_postamble
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment