天泣記

2010-10-23 (Sat)

#1

Tufte の話でよく紹介される、ナポレオンのロシア遠征みたいなのを描いてみたらどうなるだろうかと思って、そのプリミティブとして太さが変わる線の書き方を考えてみる。

太さが変わる線を、平面上の二つの(半径が異なる)円をつなぐと考える。cairo では (というか API の元ネタは PostScript だと思うが) 中心・半径・角度を指定して円弧をかけるので、問題は角度である。

頭の中でしばらく考えたがわからなかったので仕方なく実際に図を描いて解いた。

circle2.png

#!/usr/bin/ruby1.8

require 'cairo'

format = Cairo::FORMAT_ARGB32
width = 300
height = 200

surface = Cairo::ImageSurface.new(format, width, height)
context = Cairo::Context.new(surface)

context.set_source_rgb(1, 1, 1)
context.rectangle(0, 0, width, height)
context.fill

x1, y1 = width * 0.2, height * 0.7
r1 = height * 0.2
x2, y2 =  width * 0.9, height * 0.2
r2 = height * 0.05

la = Math.hypot(x2-x1, y2-y1)
dr = r1-r2
lb = Math.sqrt(la*la - dr*dr)
tu = Math.atan2(y2-y1, x2-x1)
tv = Math.atan2(lb, dr)
ta = tu + tv
tb = tu - tv

context.set_source_rgb(0.8, 0.8, 0.8)

context.move_to(x1, y1)
context.arc(x1, y1, r1, ta, tb)
context.fill

context.move_to(x2, y2)
context.arc(x2, y2, r2, tb, ta)
context.fill

context.set_source_rgb(0.4, 0.4, 0.4)
context.set_line_width(1)
context.arc(x1, y1, r1, 0, Math::PI*2)
context.stroke
context.arc(x2, y2, r2, 0, Math::PI*2)
context.stroke

context.set_source_rgb(1, 0, 0)
context.set_line_width(4)
context.arc(x1, y1, r1, ta, tb)
context.arc(x2, y2, r2, tb, ta)
context.close_path
context.stroke

surface.write_to_png("circle2.png")
system("feh circle2.png")

[latest]


田中哲