マイコン宇宙講座-惑星の連続した動きを描くⅠ

水星から火星までの連続した動きを描きます。ただし、N-BASICのコードと異なり、リアルタイムに描くのではなくプロット終了後の軌道を描いたものを表示する形になります。これはグラフィックライブラリの使用上の制限ですので仕方がありません。ただ、アニメーション的に表示はできます。ですが、「マイコン宇宙講座」のように跡を残しながらの表示にはなりません。常に新しく描くということになりますので跡を残すということができないのです。ですから、描かれるのはプロット終了後になります。

プログラムは「太陽系惑星の位置表示」のm31.pyとほとんど同じですが、動きを表すためにループ処理を付け加えています。プロット期間は80日、プロット間隔は10日です。そのため、木星から冥王星まではほとんど動きがありません。また、連続した動きを描いているため、シンボルとして描いていません。

メインルーチン m32.py

# m32.py
# マイコン宇宙講座
# 3-2 太陽系の惑星位置表示プログラム
# 水星-火星の連続した動きを描く
from PIL import Image, ImageDraw, ImageFont
from tkinter.constants import SOLID
import tkinter as tk
import math
import lib


# 太陽系を表示する
def display_solar_system():
    global photo

    std = editbox.get()

    # 入力されていない時は何にもしない
    if std != '':
        dy, dt = std.split(',')
        dy = float(dy)
        dt = float(dt)

        jd, yy, mm, dd, hh, ms, ss = lib.mjd(dy, dt)

        drawing_solar_system(jd, yy, mm, dd, lib.T)

        # 保存された画像を表示
        photo = tk.PhotoImage(file='./images/solar_move_01.png')
        canvas.create_image(1, 1, image=photo, anchor=tk.NW)

        # テキストボックスの中身をクリア
        editbox.delete(0, tk.END)

    # 日付と時刻の入力欄にフォーカスをセット
    editbox.focus_set()


# 太陽系を描く
def drawing_solar_system(jd, yy, mm, dd, t):
    img = Image.new('RGB', (642, 402), (0, 0, 0))
    draw = ImageDraw.Draw(img)

    # フォント名は実行環境に合わせて変更すること
    # TrueTypeの等幅フォント名を指定する
    font1 = ImageFont.truetype('TakaoGothic.ttf', 16)
    font2 = ImageFont.truetype('TakaoGothic.ttf', 12)

    # 太陽と惑星のカラーパレット
    planet_color = [
        '#ff0000',
        '#FFD7A0',
        '#FAAF3C',
        '#37AAE1',
        '#FF5050',
        '#B9BEB4',
        '#C8A05F',
        '#A0C8FA',
        '#3232E1',
        '#E6B96E'
    ]

    # 画面補正値
    pwx = 4
    pwy = 4

    # 画面上の太陽の位置
    mx = 412
    my = 200
    sx = 110
    sy = 110

    # フレームを描く
    draw.rectangle((0, 0, 640, 400))
    draw.line((224, 0, 224, 400))
    draw.line((0, 220, 224, 220))

    # Sun
    draw.ellipse((mx - 4, my - 4, mx + 4, my + 4), fill=(255, 0, 0))  # メイン画面
    draw.ellipse((sx - 4, sy - 4, sx + 4, sy + 4), fill=(255, 0, 0))  # サブ画面

    # 春分点の方向(メイン画面)
    for ln in range(418, 620, 10):
        draw.line((ln, 200, ln + 5, 200))
    draw.line((625, 200, 620, 195))
    draw.line((625, 200, 620, 205))

    # 春分点の方向(サブ画面)
    for ln in range(114, 210, 5):
        draw.line((ln, 110, ln + 2, 110))
    draw.line((214, 110, 209, 105))
    draw.line((214, 110, 209, 115))

    # タイトルの表示
    draw.text((400, 380), 'SOLAR SYSTEM', font=font1)

    # 年月日の表示
    datestr = str('%4d年 %2d月 %2d日' % (yy, mm, dd))
    draw.text((65, 230), datestr, font=font2)

    # 惑星名とシンボルを描画
    draw.text((10, 270), 'P', font=font2)
    draw.text((10, 285), 'L SUN------(   ) MERCURY------(   )', font=font2)
    draw.text((10, 300), 'A VENUS----(   ) EARTH--------(   )', font=font2)
    draw.text((10, 315), 'N MARS-----(   ) JUPITER------(   )', font=font2)
    draw.text((10, 330), 'E SATURN---(   ) URANUS-------(   )', font=font2)
    draw.text((10, 345), 'T NEPTUNE--(   ) PLUTO--------(   )', font=font2)
    draw.text((10, 360), 'S', font=font2)

    # 太陽
    drawing_planet_symbol(0, 91, 291, planet_color[0], draw)
    # 水星
    drawing_planet_symbol(1, 204, 291, planet_color[1], draw)
    # 金星
    drawing_planet_symbol(2, 91, 306, planet_color[2], draw)
    # 地球
    drawing_planet_symbol(3, 204, 306, planet_color[3], draw)
    # 火星
    drawing_planet_symbol(4, 91, 321, planet_color[4], draw)
    # 木星
    drawing_planet_symbol(5, 204, 321, planet_color[5], draw)
    # 土星
    drawing_planet_symbol(6, 91, 336, planet_color[6], draw)
    # 天王星
    drawing_planet_symbol(7, 204, 336, planet_color[7], draw)
    # 海王星
    drawing_planet_symbol(8, 91, 351, planet_color[8], draw)
    # 冥王星
    drawing_planet_symbol(9, 204, 351, planet_color[9], draw)

    # 期間日数
    ja = jd + 80.0

    while jd < ja:
        # 惑星の位置計算
        t1 = jd - 33281.92334
        t1 = t1 * (2.737909288e-5 + 1.260132857e-17 * t1)
        t2 = t1 * t1

        for pn in range(1, 10):
            e, m, p, n, i, a, rd = lib.mean_elements(pn, t1, t2)
            ec = e
            mo = m / (2.0 * math.pi)
            mo = 2.0 * math.pi * (mo - int(mo))

            ss, cc, ff = lib.kepler(mo, ec)

            b = a * math.sqrt(1 - ec * ec)
            ss = b * ss
            cc = a * ff

            tt = lib.quadrant(ss, cc)

            v = tt
            r = math.sqrt(ss * ss + cc * cc)
            pp = n + p
            vv = v + pp
            r0 = 15
            if pn > 4:
                r0 = 0.9
            rr = r0 * r
            x = rr * math.cos(vv)
            y = rr * math.sin(vv)
            y = -y
            if pn <= 4:
                # 水星-火星はサブ画面へ
                x2 = int((x * pwx) + sx)
                y2 = int((y * pwy) + sy - 4)
            else:
                # 木星-冥王星はメイン画面へ
                x2 = int((x * pwx) + mx)
                y2 = int((y * pwy) + my)

            # 惑星を描く
            draw.rectangle((x2 - 2, y2 - 2, x2 + 2, y2 + 2), fill=planet_color[pn])

        # 期間のステップ日数
        jd += 10.0

    # 年月日を表示
    yy, mm, dd = lib.jdate(jd, t)
    display_date(jd, t, draw, font2)

    # 画像を保存
    # 必ずPNG形式で保存
    img.save('./images/solar_move_01.png')


# 惑星のシンボルを描く
def drawing_planet_symbol(p, x, y, color, draw):
    draw.ellipse((x - 4, y - 4, x + 4, y + 4), fill=color)
    if p == 6:
        draw.line((x - 8, y, x + 8, y), fill=color)


# ユリウス日から年月日を返す
def display_date(jd, t, draw, fonts):
    yy, mm, dd = lib.jdate(jd, t)
    # 年月日の表示
    datestr = str('%4d年 %2d月 %2d日' % (yy, mm, dd))
    draw.text((65, 380), datestr, font=fonts)


# メイン
root = tk.Tk()
root.resizable(False, False)
root.geometry('642x440')
root.title('マイコン宇宙講座 - 水星から火星の連続した動きを描く')

canvas = tk.Canvas(root, width=640, height=400, bg='black')
canvas.pack(anchor=tk.NW)

label = tk.Label(root, text='DATE AND TIME(JST):')
label.place(x=10, y=410)

editbox = tk.Entry(root, relief=SOLID)
editbox.place(x=155, y=408, width=140, height=24)

button = tk.Button(root, text='表示', width=6, relief=SOLID, cursor='hand1', command=display_solar_system)
button.place(x=480, y=407)

button = tk.Button(root, text='閉じる', width=6, relief=SOLID, cursor='hand1', command=root.destroy)
button.place(x=558, y=407)

# 日付と時刻の入力欄にフォーカスをセット
editbox.focus_set()

root.mainloop()

例題 2000年1月1日9時00分00秒(JST)から80日間の水星から火星までの動きを描いてみよう。

DATE AND TIME(JST)に20000101,090000と入力して、[表示]をクリックすると、80日間の水星から火星までの軌道が描かれます。

水星から火星までの連続した軌道
水星から火星までの連続した軌道