完成版「代数らせん」

2023.02.28 やっと「らせんアニメ」ができました。これまで作ってきた「らせん」に比べ、アルゴリズムを分かりやすくしました。巻数=4 のサンプルアニメと、ソースコードを記します。
2023.03.01 いろいろ設定できるように改良しました。「代数らせんアニメ」描画ソフトの完成版(by Kero)です。

# spiral-algebraic.py
# らせんを巻いていく。
# まず、「代数らせん」(アルキメデスのらせん)  2023.03.01  by Kero

import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import ArtistAnimation

# 描画画面設定。
fig, ax = plt.subplots(figsize=(8,2))
ax.set_aspect('equal') # 正方形の方眼紙。
artists = [] # パラパラ漫画設定。最初は白紙。

# 回転のマトリックス。
# 座標の列ベクトル群に左から掛けると図が原点中心に角度rdだけ右回転。
def A(rd):
    Am = np.array([[np.cos(rd), -np.sin(rd), 0],
                  [np.sin(rd),  np.cos(rd), 0],
                  [0., 0., 1.]])
    return Am
# x軸で反転させるマトリックス。
B = np.array([[1,0,0],[0,-1,0],[1,1,1]])

# 「代数らせん」関数(中心からの距離が等間隔 = 回転角と曲率半径が正比例)
# 原点に対して、回転角 ki、曲率半径 con*ki、比例定数 con の点を生成。
def rasenA(con, ki, r00):
    r = con * ki + r00
    x = r * np.sin(ki)
    y = r * np.cos(ki)
    z = np.array([[x],[y],[1]]) # らせんにこの新しい点を追加。
    return z

# らせんを描く準備。
su = input("何回巻きますか?:")
r0 = input("半径初期値 : ")
co = input("線間隔 : ") # 線間は等間隔。代数らせん特有項目。
xm = input("x軸長さ(空リターンで自動設定) : ")
ym = input("y軸長さ(空リターンで自動設定) : ")

suu = float(su) # 巻数の文字列から実数に変換。
tmk = 2 * np.pi * suu # トータルの巻角度。
kzm = tmk / 100 # トータル巻角度のキザミを100個とする。

r00 = float(r0) # 半径初期値。
con = 0.5 * float(co) / np.pi # 代数らせんの線間隔は等間隔。

mak2 = 0. # 回転した長さ。最初はゼロ。
ras = np.array([[0],[0],[1]]) # 原点を中心に「原らせん」を生成。

title = "Archimedean spiral.  turns= " + su + ", first radius= " + r0 + ", line space= " + co

# らせんを描く。
for ki in np.linspace(0, tmk, 100):
    # 【代数らせん】= rasenA
    z = rasenA(con, ki, r00)
    
    ras = np.append(ras, z, axis=1) # 原らせんに新たな点を追加。
    Am = A(ki) # アフィン変換の回転マトリックスを作る。角度ki右回転。
    ras2 = np.dot(Am, ras) # かいてーん!!
    z2 = ras2[:, -1:] # らせん終端(最外側)座標を取り出す。
    ras3 = ras2 - z2 # 終端を原点に平行移動。
    mak2 = mak2 + (con * ki + r00) * kzm # 回転した長さを積立て貯金。
    mak3 = np.array([[mak2],[0],[0]]) # それをベクトルにして。
    ras4 = ras3 + mak3 # 回転した長さ分だけ右に平行移動。
    ras5 = np.dot(B,ras4) # x軸で反転。
    
    ras6 = np.delete(ras5, 0, axis=1) # らせんの最初の座標を削除。

    artist= ax.plot(ras6[0], ras6[1], c='b') # グラフ表示。
    artists.append(artist) # 一コマをパラパラ漫画の1ページに収録。

# xy軸の設定。入力値を調べる。数値以外なら自動設定。
if xm.isnumeric():
    xmax = float(xm)
else:
    xmax = np.max(ras5[0]) * 1.1
if ym.isnumeric():
    ymax = float(ym)
else:
    ymax = np.max(ras5[1]) * 1.1

plt.xlim(0,xmax) # x軸の長さは、最終らせんのx最大値の1割増し。
plt.ylim(0,ymax) # y軸の長さは、最終らせんのy最大値の1割増し。
plt.text(0, ymax * 1.1, title)

# 以下はアニメの常套句。temakizushi.gif に保存。
anim = ArtistAnimation(fig, artists, interval=50, repeat=True)
anim.save('spiral-algebraic.gif', writer='pillow')
        
plt.show()
plt.close()

sys.exit()

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です