Created
March 24, 2015 21:38
-
-
Save takehiko/677b572965060f037346 to your computer and use it in GitHub Desktop.
Circle Trisection
This file contains hidden or 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 | |
| # 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