マイコン宇宙講座-月齢表示

月の形は見かけ上、新月から満月、満月から新月まで変化していきます。また、新月から満月までを上弦の月、満月から新月までを下弦の月と呼びます。月の形の変化を月の満ち欠けとよび、この月の満ち欠けを数値で表したものを月齢といいます。月齢は、新月からの経過日数を表していますので、約15日で満月になります(厳密に言うと14.8〜15.6)。そして、満月から新月まで経過日数は増えていき、再び新月で経過日数は0になります。

月齢の登場は暦と密接な関係にあり、現在は太陽を基準とした新暦が使われていますが、旧暦は月の満ち欠けを基準とした暦でした。現在では、月齢はあまり重要視されませんが、カレンダーによっては月齢が掲載されていることもありますし、天文現象カレンダーには月齢が記載されています。前記事「マイコン宇宙講座-月の高度・方位角計算」でも述べましたが、淡い天体を観測する上で月明かりの影響は大きいため、やはり月齢に注意して観測プランを立てるということになります。

メインルーチン m57.py

# m57.py
# マイコン宇宙講座
# 月齢表示プログラム
from PIL import Image, ImageDraw, ImageFont
from tkinter.constants import SOLID
import tkinter as tk
import lib
import math


M2PI = 2.0 * math.pi

# 計算する場所の経度・緯度・地名
lg = 139.745 / lib.K[3]
la = 35.654 / lib.K[3]
obs = '東京'

# 月齢を表示する
def display_moon_age():
    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)

        draw_moon_age(dy, jd, yy, mm, dd, hh, ms)

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

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

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


# 月齢を描く
def draw_moon_age(dy, jd, yy, mm, dd, hh, ms):
    ia = 0
    id = 0
    ha = 0
    hd = 0
    sg = 0

    dta = (jd - 15019.5) / 36525.0
    a, b, c, d, e, g, j, l, m, n, v, w = lib.argument(dta)

    # 月齢表示
    img = Image.new('RGB', (640, 400), (0, 0, 0))
    draw = ImageDraw.Draw(img)


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

    eg = d
    ge = eg / M2PI * 29.4
    cc = math.cos(eg)

    sdtime = '%4d年 %2d月 %2d日  %2d時 %2d分' % (yy, mm, dd, hh, ms)
    smoonage = '月齢 = 約 %4.1f' % (ge)
    draw.text((80, 16), sdtime, font=fonts)
    draw.text((88, 48), smoonage, font=fonts)

    il = 0
    for y in range(20, 80):
        lx = math.sqrt(-(math.pow((y - 50), 2)) + math.pow(30.0, 2))
        if eg > math.pi:
            lx *= -1
        x = int(80 + lx * cc)
        il = int(lx + 80)
        if il > 80:
            draw.line((x * 4, y * 4, il * 4, y * 4), width=4, fill=(255, 255, 255))
        else:
            draw.line((il * 4, y * 4, x * 4, y * 4), width=4, fill=(255, 255, 255))

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

    # 出没時刻の計算
    while True:
        sg = 0
        if ha > 15:
            sg = -1

        dta = (jd - 15019.5 + sg + ha / 24.0) / 36525.0
        a, b, c, d, e, g, j, l, m, n, v, w = lib.argument(dta)
        mx, my, mz = lib.moon(dta, a, b, d, e, n, g, w)

        r0 = c
        r1 = mx
        r2 = my
        r3 = mz

        ra, dc, dl = lib.positions(r0, r1, r2, r3)

        ds = dl / 23454.706
        rd = 0
        result = lib.appear(jd, lg, la, ra, dc, ds, rd, sg, hd, lib.K)

        flags = False
        while True:
            if hd == 1:
                break
            ta = result[0]
            if abs(ta - ha) < 2.0e-3:
                break
            if ia == 5:
                break
            ha = ta
            ia += 1
            flags = True
            break

        if flags:
            continue

        td = result[0]
        al = result[1]
        if hd == 0:
            hd = 1
            id = 0
            ha = 0
            continue
        if abs(td - ha) < 2.0e-3:
            break
        if id == 5:
            break
        ha = td
        id += 1
        continue

    ta1 = ta
    ta += 9
    if ta > 24:
        ta -= 24
    td1 = td
    td += 9
    if td > 24:
        td -= 24

    h1 = int(ta)
    m1 = 60.0 * (ta - h1)
    h2 = int(td)
    m2 = 60.0 * (td - h2)

    sfmt = '%s での  月の出: %2d 時  %4.1f 分    月の入: %2d 時  %4.1f 分' % (obs, h1, m1, h2, m2)
    if ia == 5:
        sfmt = '%s での  月の出: -- 時 --.- 分    月の入: %2d 時  %4.1f 分' % (obs, h2, m2)
    if id == 5:
        sfmt = '%s での  月の出: %2d 時  %4.1f 分    月の入: -- 時 --.-f 分' % (obs, h1, m1)
    draw.text((72, 368), sfmt, font=fonts)

    draw.text((400, 16), '月の入りでの', font=fonts)
    sfmt = '北からの方位角 = %5.1f 度' % (al * lib.K[3])
    draw.text((400, 32), sfmt, font=fonts)

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


# メイン
root = tk.Tk()
root.resizable(False, False)
root.geometry('640x440')
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=414)

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

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

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

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

root.mainloop()

例題 1981年1月1日21時の月齢を表示してみよう。