パッポスの定理の図示


 
screen.rb

require 'bundler/setup'
require 'cairo'
require './cairo_gtk'
include Math

Width = 400; Height = 300
Xrange = [-10.0, 10.0]
ScaleX = ScaleY = Width / (Xrange[1] - Xrange[0])
CPX = 0; CPY = 0

Surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, Width, Height)
C = Cairo::Context.new(Surface)
C.set_source_rgb(0, 0, 0)
C.rectangle(0, 0, Width, Height)
C.fill

class WPoint
  def initialize(x, y)
    @x = x; @y = y
  end
  attr_reader :x, :y
  
  #WPointからPointを得る
  def get_point
    x = CPX + (@x - Width  / 2) / ScaleX
    y = CPY - (@y - Height / 2) / ScaleY
    Point.new(x, y)
  end
end

class Point
  def initialize(x, y)
    @x = x; @y = y
  end
  attr_reader :x, :y
  
   def self.wo
     WPoint.new(0, 0).get_point
   end
   
   def self.limit
     WPoint.new(Width, Height).get_point
   end
   
   def self.o
    Point.new(0, 0)
   end
   
   def *(n)
     Point.new(@x * n, @y * n)
   end
   
   def +(po)
     Point.new(@x + po.x, @y + po.y)
   end
   
  def -(po)
     Point.new(@x - po.x, @y - po.y)
   end
   
  #PointからWPointを得る
  def get_wpoint
    x = Width  / 2 + (@x - CPX) * ScaleX
    y = Height / 2 - (@y - CPY) * ScaleY
    WPoint.new(x, y)
  end
  
  def draw(color: [1, 0, 0])
    po = get_wpoint
    C.set_source_rgb(color[0], color[1], color[2])
    C.arc(po.x, po.y, 3, 0, 2 * Math::PI)
    C.fill
    self
  end
end

class Line
  def initialize(point, n)    #point, nはPointクラス(pointは直線上の一点、nは直線の方向ベクトル)
    @point = point
    @lx = point.x; @ly = point.y
    a = sqrt(n.x ** 2 + n.y ** 2)
    raise LineError, "The line does not exist." if a.zero?
    @nx = n.x / a; @ny = n.y / a
    @n = Point.new(@nx, @ny)
  end
  attr_reader :point, :n, :lx, :ly, :nx, :ny
  
  def draw(color: [1, 1, 1])
    p1 = (@point - @n * 1000).get_wpoint
    p2 = (@point + @n * 1000).get_wpoint
    C.set_source_rgb(color[0], color[1], color[2])
    C.move_to(p1.x, p1.y)
    C.line_to(p2.x, p2.y)
    C.stroke
    self
  end
end

class LineError < StandardError
end

#2点p1, p2を通る直線を与える
def points_make_line(p1, p2)
  Line.new(p1, p2 - p1)
end

#2直線l1, l2の交点を与える
def linecross_point(l1, l2)
  dt = l2.nx * l1.ny - l1.nx * l2.ny
  return nil if dt.zero?
  px = ((l2.nx * l2.ly - l2.ny * l2.lx) * l1.nx + (l1.ny * l1.lx - l1.nx * l1.ly) * l2.nx) / dt
  py = ((l2.ny * l1.lx + l2.nx * l2.ly) * l1.ny - (l1.nx * l1.ly + l1.ny * l2.lx) * l2.ny) / dt
  Point.new(px, py)
end

#引数のすべてのオブジェクトを表示
def objects_draw(*args)
  args.each {|po| po.draw}
end


#main
gray = [0.5, 0.5, 0.5]
blue = [0, 0, 1]

a1 = Point.new(-8, 3)
c1 = Point.new( 8, 7)
b1 = (a1 + c1) * 0.5

a2 = Point.new(-8, -6)
c2 = Point.new( 9, -5)
b2 = (a2 + c2) * 0.5

points_make_line(a1, c1).draw
points_make_line(a2, c2).draw

l1 = points_make_line(a1, b2).draw(color: gray)
l2 = points_make_line(a1, c2).draw(color: gray)

l3 = points_make_line(b1, c2).draw(color: gray)
l4 = points_make_line(b1, a2).draw(color: gray)

l5 = points_make_line(c1, a2).draw(color: gray)
l6 = points_make_line(c1, b2).draw(color: gray)

p = linecross_point(l1, l4)
q = linecross_point(l2, l5)
r = linecross_point(l3, l6)

points_make_line(p, r).draw(color: blue)

objects_draw(a1, b1, c1, a2, b2, c2, p, q, r)

cairo_gtk(Surface, Width, Height)

cairo_gtk.rb についてはこちら


パッポスの定理(その2)

上と異なっている部分のみ載せる。

b1 = Point.new(-6, 1)
c1 = Point.new( 8, 3)
a1 = b1 * 0.8 + c1 * 0.2

a2 = Point.new(-8, -6)
c2 = Point.new( 9, -6)
b2 = (a2 + c2) * 0.5