刺し子模様をPythonで描く:基本1・麻の葉
刺し子をするときに,模様を手で描くのはなかなか大変。本を見て,これを刺したいと思ったとき,パソコンできれいに描けるとよい。
そんな要請で作ったのがCinderellaJapanの「刺し子模様を作る」のページ。
左上の三本線をクリックすると,さらにインデックスが表示される。
これは,CinderellaとCindyScriptで作ったもの。これをPythonで書きなおす。
ちょっとしたプログラミングの教材になる。部活動で使ってもよいだろう。
見出し画像が「麻の葉」という模様で,刺し子では基本的なものだ。刺し子では下絵を描いておいて,糸を刺していくのだが,一筆で描けるところを探して刺していく。ここで描くのはその下絵だが,刺し子以外でも日本伝統の図柄として利用できる。これをコンピュータで描くには,もとになる図形(基本パターン)を探し出して,それを描く関数を作り,繰り返しを使って全体を描いていく。縦横に並べていくので,刺し子と同様,同じ線を重ねて描かないような基本パターンを探し出す。これはちょっとしたパズルだ。
プログラムの構造は次のようにする。
(1) 描画する画面の設定:サイズなどを決める
(2) 描画関数を定義する:いろいろなパターンで共通に使える描画関数を定義
drawpattern(m,n) と下請けの draw(org,plist)
(3) 基本パターンを描くものを関数として定義する。 basicpattern(org)
(4) 基本パターンを移動する量と描画色を決めて,drawpattern() を呼び出す。
では,刺し子模様で最も基本的なこの「麻の葉」を描いてみよう。
(1) 描画する画面の設定
外部ライブラリの numpy と matplotlib をインポートする。
次は,描画する画面を 800×800 のサイズとし,横軸を0から20,縦軸も0から20 までとしたもの。描画したときの座標を確かめるには,目盛を表示して,plt.grid() も有効にする。軸の範囲を広げると,ひとつのパターンが小さく描かれる。
import numpy as np
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 8))
plt.axis([0, 20, 0, 20])
# plt.grid()
plt.xticks([]) # 目盛を非表示にする
plt.yticks([])
(2) 描画関数を定義する
いろいろな図柄で共通に使える描画関数を定義する。
draw(org,plist) は,基本パターンを描く関数 drawpattern(m,n) の下請けで,点のリスト plist を線分で結ぶ。org は描画時の原点。描画色 Drawcolor は平行移動量とともにあとで定義する。
drawpattern(m,n) は,基本パターンを横にm個,縦にn個描く。
中で使っている変数 Shiftx , Shifty は平行移動量で,あとで(関数の外で)定義する。basicpattern(org) が基本パターンを定義する関数だ。
# 点を線分で結ぶ
def draw(org, plist):
x = []
y = []
for pt in plist:
x.append(org[0]+pt[0])
y.append(org[1]+pt[1])
plt.plot(x, y, lw=1, color=Drawcolor)
# 横方向にm,縦方向にn個のパターンを描く
def drawpattern(m, n):
for x in range(m):
for y in range(n):
org = x*Shiftx + y*Shifty
basicpattern(org)
ここまでは,他の図柄でも共通に使う。画面のサイズと範囲は場合によって変えればよい。
(3) 基本パターンを関数として定義する
刺し子模様は,あるパターンの繰り返しである。それを「基本パターン」と呼ぼう。そのパターンを描く手続きを関数として定義する。全体を描くには,(2) で定義した drawpattern(m,n) で基本パターンを平行移動しながら繰り返し描く。
したがって,この関数が模様ごとに設計しなければならないものだ。
麻の葉の例で,その作り方を説明しよう。
麻の葉は正六角形を基本とする。次の模様から正六角形が見えるだろうか。
これを見て,基本パターンを考える。基本パターンはいろいろが取り方がある。たとえば次のように取り,点に名前を付け,その座標と線の引き方を決める。背景は普通の方眼ではなく,正三角形の斜眼になっているので,縦横の長さはあとでしっかり考えよう。(この図はCinderellaで描いた)
I とJ は抜かしている。
一筆書きで描けるところをまず拾う。たとえば
A, B, C, D, E, F, G, H, C, K, L, M, A, G
を結ぶ。
あとは,残りの EL,FM,CN を結べばよい。点のリストを与えて,線分で結ぶのが(2)で定義した関数 draw() だ。
正三角形の斜眼になるので,一目盛を1とすると,横2に対し,縦は√3 になる。そこで,r を√3として使う。点Bは(2,0),点Mは(1,√3),つまり(1,r)になる。
# 基本パターンをorgを原点として描く
def basicpattern(org):
r = np.sqrt(3)
A=[0, 0]
B=[2, 0]
C=[3, r]
D=[4, 0]
E=[6, 0]
F=[5, r]
G=[6, 2*r]
H=[4, 2*r]
K=[2, 2*r]
L=[0, 2*r]
M=[1, r]
N=[3, 3*r]
draw(org, [A, B, C, D, E, F, G, H, C, K, L, M, A, G])
draw(org, [E, L])
draw(org, [F, M])
draw(org, [C, N])
(4) 基本パターンを移動する量と描画色を決める
基本パターンの横幅はAからEまで6,縦幅はAからLまで2√3 なので,横につなげるには,原点(点Aの位置)を [6,0] に移動する。縦につなげるには,原点を [0,2√3] に移動する。
これを Shiftx, Shifty とする。
描画色はたとえば黒。これが Drawcolor。
基本パターンを横に4つ,縦に6つ描くことにして,drawpattern() を呼び出す。
画像ファイルに書き出すなら,plt.savefig() でファイル名を指定すればよい。
# 横方向のシフト量,縦方向のシフト量,描画色を定義して描く
Shiftx = np.array([6, 0])
Shifty = np.array([0, 2*np.sqrt(3)])
Drawcolor = 'k'
drawpattern(4, 6)
# plt.savefig("asaonoha.png")
plt.show()
空行を入れても 53行だ。
できたのが前の図。
飛び麻の葉
次に,飛び麻の葉を描く。色を緑にしてみた。
基本パターンは次のように作った。
こんどは真横ではなく,斜めに移動するので,
Shiftx = np.array([6, 2*np.sqrt(3)])
Shifty = np.array([0, 4*np.sqrt(3)])
とする。すると,右下が空いてくるので,描画面の原点をずらして
plt.axis([0, 20, 10, 30])
とする。このあたりが工夫のしどころ。
基本パターンの定義以降は次のようにした。
# 基本パターンをorgを原点として描く
def drawpat(org):
r = np.sqrt(3)
A=[0, r]
B=[2, r]
C=[3, 0]
D=[4, r]
E=[6, r]
F=[5, 2*r]
G=[3, 2*r]
H=[1, 2*r]
K=[0, 3*r]
L=[2, 3*r]
M=[4, 3*r]
N=[6, 3*r]
O=[3, 4*r]
draw(org, [A, B, C, D, E, F, N, M, O, L, K, H, A, N])
draw(org, [E, K])
draw(org, [C, O])
draw(org, [F, H])
draw(org, [B, M])
draw(org, [D, L])
# 横方向のシフト量,縦方向のシフト量,描画色を定義して描く
Shiftx = np.array([6, 2*np.sqrt(3)])
Shifty = np.array([0, 4*np.sqrt(3)])
Drawcolor = 'g'
drawpattern(4, 5)
以上が,折れ線で描くパターンの基本だ。
次回は円弧を使って描く方法を考える。