Created
March 21, 2022 18:55
-
-
Save User4574/4145fe2a087521f7310f9c98f8835759 to your computer and use it in GitHub Desktop.
A laser-cuttable circular slide rule generator
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
#!/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