Pythonで線分の中点を再帰的に求める

2-3.Perl/Python/Ruby

アニメ『ポケットモンスター サン&ムーン』(2016)

サトシがまったくの別人のように見えてたので。従兄弟の話かなんかだと思ってたんですが、名前がサトシ。
おんなじ名前の従兄弟って。

どういうことなんだか、気になりすぎてネットで調べてみたら、サン&ムーンでキャラクターデザインが一新されたんですね。
声優が一新されるのと一緒で、時間がたてば、だんだん慣れてきますね。

サトシはポケモンマスターを目指して毎年いろいろなことをして向上していますが、今回はポケモンスクールで学園生活を送ります。

本ブログではコマンドの達人に向けて日々勉強していますが、より効率的にコンピュータを使うには、数学的知識も不可欠です。いきなり数学に入ると挫折しそうなので、数学用語に慣れるところから始めようかと思います。
今回は、「線分」って用語と「中点」って用語を使ってみましょう。

線分とは
ある2点に挟まれた直線部分

中点とは
ある2点を両端とする線分上の、両端から等しい距離にある点

中点を求める計算をしてみましょう。

座標(x1,y1)から(x2,y2)までの線分ABの中点Cの座標を得るには、長さlを求めて、その半分の長さを(x1,y1)に足しこみます。

座標リスト[(x1,y1),(x2,y2)]を元に再帰的に中点座標をリスト化します。pythonでは、リストを引数で渡すと、参照渡しされるので、元リストも変更になります。

takk@deb8:~$ cat -n monsterball.py
     1	from PIL import Image,ImageDraw
     2	
     3	def div_pos(num,lis):
     4		if num>0:
     5			(x1,y1)=lis[0]
     6			ind=1
     7			for (x2,y2) in lis[1:]:
     8				x=x2-x1; y=y2-y1
     9				lis.insert(ind,((x1+x/2),(y1+y/2)))
    10				ind=ind+2
    11				x1=x2; y1=y2
    12			div_pos(num-1,lis)
    13	
    14	poslist=[(0,0),(511,511)]
    15	div_pos(2,poslist)

10行目では、リストに中点を挿入した後、リストのインデックスが1つ増えるため、indに2を足しています。

print poslistすると以下のような結果が得られます。中点座標3つが増えています。

[(0, 0), (127, 127), (255, 255), (383, 383), (511, 511)]

ではこの関数で生成したリストを使ってモンスターボールを描いてみましょう。

    16	
    17	red=(255,0,0)
    18	white=(255,255,255)
    19	black=(0,0,0)
    20	
    21	img=Image.new("RGB",(512,512), black)
    22	draw=ImageDraw.Draw(img)
    23	
    24	(x1,y1)=poslist[0]
    25	for (x2,y2) in poslist[1:]:
    26		draw.ellipse((x1,y1,x2,y2), fill=red)
    27		draw.chord((x1,y1,x2,y2), 0, 180, outline=black, fill=white)
    28		x=(x2-x1)/3; y=(y2-y1)/3
    29		draw.ellipse((x1+x,y1+y,x2-x,y2-y), outline=black, fill=white)
    30		x1=x2; y1=y2
    31	
    32	img.save("monsterball.png")

本スクリプトを実行するには、Pillowを使うのでインストールしておきます。

# apt-get intall python-pip
# pip install pillow

monsterball.pyを実行すると、下のようなPNG画像が生成されます。

15行目の分割数を増やすと、モンスターボールも増えていきます。

コメント

タイトルとURLをコピーしました