第8章の練習,投票


レコードとしてのPoint

class Point
  attr_accessor("x", "y")
end
p=Point.new()
p.x = 3
p.y = 4
p

Pointを扱う関数

def point_make(u,v)
  p = Point.new()
  p.x = u
  p.y = v
  p
end

def point_scale(p,s)
  point_make(p.x*s,p.y*s)
end

def point_add(p,q)
  point_make(p.x+q.x, p.y+q.y)
end

def point_interpolate(p,q,t)
  point_add(point_scale(p,1-t),
            point_scale(q,t))
end

def point_draw(p,a)
  if 0 <= p.y+0.5 && p.y+0.5 < a.   length() &&
     0 <= p.x+0.5 && p.x+0.5 < a[0].length()
    a[p.y+0.5][p.x+0.5]=1
  end
end

実行例

def make1d(n)
  a=Array.new(n)
  for i in 0..(n-1)
    a[i]=0
  end
  a
end
def make2d(h,w)
  b=Array.new(h)
  for i in 0..(h-1)
    b[i]=make1d(w)
  end  
  b
end
isrbを起動して以下の入力を与えてみる.
load "./point.rb"
load "./make2d.rb"
point_scale(point_make(3,4),0.5)
point_add(point_make(1,3),point_make(-2,4))
point_interpolate(point_make(1,3),point_make(-2,4),0.1)
a=make2d(20,20)
point_draw(point_make(15,5),a)
show(a)
以下のような結果が得られるはずである.
irb(main):004:0> point_scale(point_make(3,4),0.5)
=> #
irb(main):005:0> point_add(point_make(1,3),point_make(-2,4))
=> #
irb(main):006:0> point_interpolate(point_make(1,3),point_make(-2,4),0.1)
=> #
irb(main):007:0> a=make2d(20,20)
=> [[0, 0, .... ]]
irb(main):008:0> point_draw(point_make(15,5),a)
=> 1
irb(main):009:0> show(a)
=> nil

次の結果は何?

point_interpolate(point_make(-1,3),point_add(point_make(2,2),point_scale(point_make(3,4),0.4)),0.3).y

線分の描画

def max(x,y)
  if x>y
    x
  else
    y
  end
end
def abs(x)
  if x>=0
    x
  else
    -x
  end
end
def line_draw(p0,p1,a)
  n=max(abs(p1.x - p0.x), abs(p1.y - p0.y))
  for i in 0..n
    point_draw(point_interpolate(p0,p1,i*1.0/n), a)
  end
end
実行例
a=make2d(30,30)
line_draw(point_make(0,1),point_make(29,10),a)
show(a)

2次Bezier曲線の描画

def bezier_draw(p0,c,p1,a)
  n = 10
  prev = p0
  for i in 1..n
    t = i*1.0/n
    q0 = point_interpolate(p0, c,  t)
    q1 = point_interpolate(c,  p1, t)
    r  = point_interpolate(q0, q1, t)
    line_draw(prev, r, a)
    prev = r
  end
end
def make_points(xy)
  points = Array.new(xy.length()/2)
  for i in 0 .. points.length()-1
    points[i] = point_make(xy[2*i], xy[2*i+1])
  end
  points
end

def kana()
  a=make2d(400,400)
  p=make_points([208,70, 163,210, 56,317, 0,264, 
                  0,196, 115,50,  250,53, 353,67, 
                390,149, 412,268, 237,347])
  for i in 0..(p.length())/2-1
    bezier_draw(p[i*2], p[i*2+1], p[i*2+2], a)
  end
  show(a)
end

この絵を書くプログラムの穴埋め部分は?

def sim()
  a=make2d(400,400)
  p=make_points( 「ここを埋めてください」 )
  for i in 0..(p.length())/2-1
    bezier_draw(p[i*2],p[i*2+1],p[i*2+2],a)
  end
  show(a)
end
  1. [350,200,275,300,200,200,125,300,50,200]
  2. [50,200,125,100,200,200,275,100,300,200]
  3. [50,200,125,190,200,200,275,100,210,200]
  4. [50,200,125,210,200,200,275,100,190,200]
  5. [50,200,125,300,200,200,275,100,350,200]

def drawmoon()
  p0=Point.new(0,85)
  p1=Point.new(99,85)
  f=[Line.new(p0,p1), 
     Bezier.new(p0,Point.new(50,60),p1),
     Circle.new(Point.new(66,20),20)]
  a=make2d(100,100)
  drawall(f,a)
  show(a)
end

def drawall(elements,a)
  for i in 0..elements.length()-1
    elements[i].draw(a)
  end
  a
end

点を表すオブジェクト

class Point
  attr_accessor("x", "y")

  def initialize(u,v)
    self.x = u
    self.y = v
  end

  def scale(s)
    Point.new(self.x * s, self.y * s)
  end

  def add(q)
    Point.new(self.x + q.x, self.y + q.y)
  end

  def draw(a)
    if 0 <= self.y+0.5 && self.y+0.5 < a.   length() &&
       0 <= self.x+0.5 && self.x+0.5 < a[0].length()
      a[self.y+0.5][self.x+0.5]=1
    end
  end
end

線分を表すオブジェクト

load("./max.rb")
load("./abs.rb")
class Line
  attr_accessor("p0", "p1")

  def initialize(q,r)
    self.p0 = q
    self.p1 = r
  end

  def draw(a)
    n = max(abs(self.p1.x - self.p0.x),
            abs(self.p1.y - self.p0.y))
    for i in 0..n
      p = self.p0.interpolate(self.p1, i*1.0/n)
      p.draw(a)
    end
  end

  def turn(theta)
    self.p0 = self.p0.rotate(theta)
    self.p1 = self.p1.rotate(theta)
  end
end

練習

線分のクラス定義に,平行移動のためのメソッド add を加えなさい.add(q)を実行すると,両端点に点 qが足されるものとする.
load("./max.rb")
load("./abs.rb")
class Line
  attr_accessor("p0", "p1")

  def initialize(q,r)
    self.p0 = q
    self.p1 = r
  end

  def draw(a)
    n = max(abs(self.p1.x - self.p0.x),
            abs(self.p1.y - self.p0.y))
    for i in 0..n
      p = self.p0.interpolate(self.p1, i*1.0/n)
      p.draw(a)
    end
  end

  def turn(theta)
    self.p0 = self.p0.rotate(theta)
    self.p1 = self.p1.rotate(theta)
  end
  def add(q)
    # (穴埋め) self.p0 にself.p0をqだけ平行移動した点を代入する
    # (穴埋め) self.p1 にself.p1をqだけ平行移動した点を代入する
  end
end
実行例
irb(main):024:0> line=Line.new(Point.new(3,4),Point.new(5,6))
=> #<Line:0x123928 @p0=#<Point:0x123950 @x=3, @y=4>, @p1=#<Point:0x12393c @x=5, @y=6>>
irb(main):025:0> line.add(Point.new(-1,-2))
=> #<Point:0x117808 @x=4, @y=4>
irb(main):026:0> line
=> #<Line:0x123928 @p0=#<Point:0x123950 @x=2, @y=2>, @p1=#<Point:0x12393c @x=4, @y=4>>

継承を使ったBezier曲線クラスの定義

load("./oo-line.rb")
class Bezier < Line
  attr_accessor("p0", "c", "p1")
  
  def initialize(q,r,s)
    super(q,s)
    self.c  = r
  end

  def draw(a)
    n = 10
    prev = self.p0
    for i in 1..n
      t = i*1.0/n
      q0 = self.p0.interpolate(c,  t)
      q1 = self.c. interpolate(p1, t)
      r  = q0.interpolate(q1, t)
      Line.new(prev, r).draw(a)
      prev = r
    end
  end

  def turn(theta)
    super(theta)
    self.c = self.c.rotate(theta)
  end
end

多相性の利用例

def drawmoon()
  p0=Point.new(0,85)
  p1=Point.new(99,85)
  f=[Line.new(p0,p1), 
     Bezier.new(p0,Point.new(50,60),p1),
     Circle.new(Point.new(66,20),20)]
  a=make2d(100,100)
  drawall(f,a)
  show(a)
end

def drawall(elements,a)
  for i in 0..elements.length()-1
    elements[i].draw(a)
  end
  a
end