Skip to content

Instantly share code, notes, and snippets.

@takehiko
Created March 24, 2015 21:38
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 takehiko/677b572965060f037346 to your computer and use it in GitHub Desktop.
Save takehiko/677b572965060f037346 to your computer and use it in GitHub Desktop.
Circle Trisection
#!/usr/bin/env ruby
# ruby circle3.rb
# creates Quadrant3.png, Circle3L.png, Circle3C.png, and Circle3Lrotate.png.
# rmagick required (gem install rmagick)
require "rmagick"
require "bigdecimal"
require "bigdecimal/newton"
BigDecimal.limit(6)
# http://ipafont.ipa.go.jp/#en
$font = ENV.key?("FONT") ? ENV["FONT"] : "ipaexg.ttf"
class Arcsolver
# Solve \frac{1}{2}x + \frac{1}{4}\sin 2x - c = 0
include Newton
def initialize(c_ = nil, x0_ = nil)
@zero = BigDecimal.new("0.0")
@one = BigDecimal.new("1.0")
@two = BigDecimal.new("2.0")
@ten = BigDecimal.new("10.0")
@eps = BigDecimal.new("1.0e-6")
@c = c_ ? BigDecimal.new(c_, 6) : BigDecimal.new(Math::PI, 6) / 4 / 2
@x0 = x0_ || @one / @two
puts "@c = #{@c}" if $DEBUG
solve
end
attr_reader :c, :x0
attr_reader :zero, :one, :two, :ten, :eps
def values(x)
[(x[0] + Math.sin(@two * x[0]) / @two) / @two - @c]
end
def solve
a = [@x0]
nlsolve(self, a)
@rad = a[0]
@deg = @rad * 180 / Math::PI
@x = BigDecimal(Math.sin(@rad.to_f), 6)
self
end
attr_reader :rad, :deg, :x
end
class Quadrant3
include Magick
def initialize(opt = {})
@arc1 = opt[:a1] || Arcsolver.new(BigDecimal.new(Math::PI, 6) / 12, BigDecimal.new("0.5"))
@arc2 = opt[:a2] || Arcsolver.new(BigDecimal.new(Math::PI, 6) / 6, BigDecimal.new("0.5"))
@width = 320
@height = 320
@margin = @margin2 = 20
@origin_x = @margin + @margin2
@origin_y = @height - @margin - @margin2
@unitlen = @width - @margin * 2 - @margin2 * 2
@filename = opt[:filename] || self.class.to_s + ".png"
@opt_nocolor = opt[:nocolor]
end
def start
puts "making #{@filename}..."
nc = @opt_nocolor
@image = Image.new(@width, @height) do
self.quality = 95
self.background_color = nc ? "white" : "#f0f0ff"
end
x1 = @arc1.x
y1 = Math.sqrt(1 - x1 * x1)
x2 = @arc2.x
y2 = Math.sqrt(1 - x2 * x2)
rr = [@unitlen, @unitlen].join(",")
unless @opt_nocolor
d = Draw.new
d.fill = "#ccccff"
d.stroke = "none"
d.path("M#{u(0, 0)} L#{u(x1, 0)} L#{u(x1, y1)} A#{rr},0,0,0,#{u(0, 1)} Z")
d.draw(@image)
d = Draw.new
d.fill = "#ccffcc"
d.stroke = "none"
d.path("M#{u(x1, 0)} L#{u(x2,0)} L#{u(x2,y2)} A#{rr},0,0,0,#{u(x1,y1)} Z")
d.draw(@image)
d = Draw.new
d.fill = "#ffcccc"
d.stroke = "none"
d.path("M#{u(x2,0)} L#{u(1,0)} A#{rr},0,0,0,#{u(x2,y2)} Z")
d.draw(@image)
end
d = Draw.new
d.fill = "none"
d.stroke = "black"
d.stroke_width = 2
d.line(*t(-0.1, 0, 1.1, 0))
d.polyline(*t(1.1 - 0.03, -0.02, 1.1, 0, 1.1 - 0.03, 0.02))
d.line(*t(0, -0.1, 0, 1.1))
d.polyline(*t(-0.02, 1.1 - 0.03, 0, 1.1, 0.02, 1.1 - 0.03))
d.arc(*t(-1, -1, 1, 1), 270, 360)
d.line(*t(x1, 0, x1, y1))
d.line(*t(x2, 0, x2, y2))
d.draw(@image)
d = Draw.new
d.font($font)
d.pointsize(18)
d.fill = "black"
d.text(*t(x1 - 0.03, -0.08), '"x1"')
d.text(*t(x2 - 0.03, -0.08), '"x2"')
d.text(*t(-0.07, -0.08), '"O"')
d.text(*t(1.07, 0.03), '"x"')
d.text(*t(0.03, 1.06), '"y"')
d.text(*t(0.97, -0.08), '"1"')
d.text(*t(-0.05, 0.96), '"1"')
d.draw(@image)
@image.write(@filename)
@image.destroy!
self
end
def t(*param)
a = []
while param.length >= 2
i = param.shift
j = param.shift
x = i * @unitlen + @margin + @margin2
y = @height - @margin - @margin2 - j * @unitlen
a << x << y
end
return a
end
def u(*param); t(*param).join(","); end
end
class Circle3L
include Magick
def initialize(opt = {})
@arc1 = opt[:a1] || Arcsolver.new(BigDecimal.new(Math::PI, 6) / 12, BigDecimal.new("0.5"))
@arc2 = opt[:a2] || Arcsolver.new(BigDecimal.new(Math::PI, 6) / 6, BigDecimal.new("0.5"))
@width = 320
@height = 320
@margin = 16
@origin_x = @width / 2
@origin_y = @height / 2
@unitlen = (@width - @margin * 2) / 2
@filename = opt[:filename] || self.class.to_s + ".png"
@opt_nocolor = opt[:nocolor]
end
def start
puts "making #{@filename}..."
nc = @opt_nocolor
@image = Image.new(@width, @height) do
self.quality = 95
self.background_color = nc ? "white" : "#f0f0ff"
end
y1 = @arc1.x
x1 = Math.sqrt(1 - y1 * y1)
x2, y2 = 0, -1
rr = [@unitlen, @unitlen].join(",")
unless @opt_nocolor
d = Draw.new
d.fill = "#ffcccc"
d.stroke = "none"
d.path("M#{u(x1,y1)} A#{rr},0,0,0,#{u(-x1,y1)} Z")
d.draw(@image)
d = Draw.new
d.fill = "#ccffcc"
d.stroke = "none"
d.path("M#{u(0, y1)} L#{u(-x1,y1)} A#{rr},0,0,0,#{u(0,y2)} Z")
d.draw(@image)
d = Draw.new
d.fill = "#ccccff"
d.stroke = "none"
d.path("M#{u(0,y1)} L#{u(0, y2)} A#{rr},0,0,0,#{u(x1,y1)} Z")
d.draw(@image)
end
d = Draw.new
d.fill = "none"
d.stroke = "black"
d.stroke_width = 2.5
d.arc(*t(-1, -1, 1, 1), 0, 360)
d.line(*t(-x1, y1, x1, y1))
d.line(*t(0, -1, 0, y1))
d.draw(@image)
@image.write(@filename)
@image.destroy!
self
end
def t(*param)
a = []
while param.length >= 2
i = param.shift
j = param.shift
x = @origin_x + i * @unitlen
y = @origin_y - j * @unitlen
a << x << y
end
return a
end
def u(*param); t(*param).join(","); end
end
class Circle3C
include Magick
def initialize(opt = {})
@arc1 = opt[:a1] || Arcsolver.new(BigDecimal.new(Math::PI, 6) / 12, BigDecimal.new("0.5"))
@arc2 = opt[:a2] || Arcsolver.new(BigDecimal.new(Math::PI, 6) / 6, BigDecimal.new("0.5"))
@width = 320
@height = 320
@margin = 16
@origin_x = @width / 2
@origin_y = @height / 2
@unitlen = (@width - @margin * 2) / 2
@filename = opt[:filename] || self.class.to_s + ".png"
@opt_nocolor = opt[:nocolor]
end
def start
puts "making #{@filename}..."
nc = @opt_nocolor
@image = Image.new(@width, @height) do
self.quality = 95
self.background_color = nc ? "white" : "#f0f0ff"
end
y1 = @arc2.x
x1 = Math.sqrt(1 - y1 * y1)
x2, y2 = 0, -1
x3, y3 = 0, 1 - (1 - y1) * 2
x4, y4 = 0, y3 + 1
rr = [@unitlen, @unitlen].join(",")
unless @opt_nocolor
d = Draw.new
d.fill = "#ffcccc"
d.stroke = "none"
d.path("M#{u(x1, y1)} A#{rr},0,0,0,#{u(-x1, y1)} A#{rr},0,0,0,#{u(x1, y1)} Z")
d.draw(@image)
d = Draw.new
d.fill = "#ccffcc"
d.stroke = "none"
d.path("M#{u(0, y3)} A#{rr},0,0,1,#{u(-x1, y1)} A#{rr},0,0,0,#{u(0, y2)} Z")
d.draw(@image)
d = Draw.new
d.fill = "#ccccff"
d.stroke = "none"
d.path("M#{u(0, y3)} A#{rr},0,0,0,#{u(x1,y1)} A#{rr},0,0,1,#{u(0, y2)} Z")
d.draw(@image)
end
d = Draw.new
d.fill = "none"
d.stroke = "black"
d.stroke_width = 2.5
d.arc(*t(-1, -1, 1, 1), 0, 360)
d.arc(*t(-1, y4 - 1, 1, y4 + 1), @arc2.deg, 180 - @arc2.deg)
d.line(*t(0, y2, 0, y3))
d.draw(@image)
@image.write(@filename)
@image.destroy!
self
end
def t(*param)
a = []
while param.length >= 2
i = param.shift
j = param.shift
x = @origin_x + i * @unitlen
y = @origin_y - j * @unitlen
a << x << y
end
return a
end
def u(*param); t(*param).join(","); end
end
class Circle3Lrotate
include Magick
def initialize(opt = {})
@src = opt[:src] || "Circle3L.png"
@filename = opt[:filename] || self.class.to_s + ".png"
end
def start
puts "making #{@filename}..."
@image = Image.read(@src).first
@image.rotate!(90)
@image.write(@filename)
@image.destroy!
self
end
end
if __FILE__ == $0
pi = BigDecimal.new(Math::PI, 6)
h = BigDecimal.new("0.5")
arc1 = Arcsolver.new(pi / 12, h)
arc2 = Arcsolver.new(pi / 6, h)
puts "x1 = #{arc1.x.to_s('f')}, theta1 = #{arc1.rad.to_s('f')} (#{arc1.deg.to_s('f')} deg.)"
puts "x2 = #{arc2.x.to_s('f')}, theta2 = #{arc2.rad.to_s('f')} (#{arc2.deg.to_s('f')} deg.)"
nc = false
Quadrant3.new(:a1 => arc1, :a2 => arc2, :nocolor => nc).start
Circle3L.new(:a1 => arc1, :a2 => arc2, :nocolor => nc).start
Circle3C.new(:a1 => arc1, :a2 => arc2, :nocolor => nc).start
Circle3Lrotate.new(:src => "Circle3L.png").start
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment