マイコン宇宙講座-星占い

ある日の惑星がどの黄道12星座に位置しているか表示します。黄道12星座はよく星占いで使用されます。いわゆる誕生日の星座ということです。黄道とは見かけ上の太陽が天球上を移動する経路のことです。惑星も黄道に沿って移動します。黄道の通り道にある星座は、牡羊座、牡牛座、双子座、蟹座、獅子座、乙女座、天秤座、蠍座、射手座、山羊座、水瓶座、魚座の12星座あり、これを黄道12星座と呼んでいます。たとえば、1月生まれの人の星座は山羊座というように誕生日と星座は紐付けられています。占いでは星座と水星から土星までの惑星の位置で判断しているようです。専門ではないのでわかりませんが、詳しくは専門書を読んでみるとよいでしょう。

プログラムを実行するには星座データが必要になります。星座データは下記のGitHubからダウンロードしてください。さすがにデータを当ブログに掲載するのは無理がありましたのでダウンロードできるようにしました。星座ごとのデータがCSV形式で収められています。

https://github.com/kotetsu1701a/msc-data

使用するにはプログラムがある同じディレクトリにseizaというフォルダを作成し、その中にファイルを配置してください。

サブルーチン ecliptic_coordinates

# KOUDO ZAHYO
def ecliptic_coordinates(ra, dc, K):
    lx = math.cos(dc) * math.cos(ra)
    ly = math.sin(dc) * K[5] + math.cos(dc) * math.sin(ra) * K[4]
    lz = math.sin(dc) * K[4] - math.cos(dc) * math.sin(ra) * K[5]

    ss = ly
    cc = lx

    lp = quadrant(ss, cc)

    ss = lz
    cc = lx / math.cos(lp)
    bp = math.atan(ss / cc)

    return lp, bp

メインルーチン m39.py

出力はターミナルとウィンドウの2箇所に行われます。ターミナルには惑星の位置、ウィンドウには星座と惑星の位置が描かれます。描画部分を「惑星の位置計算Ⅰ」のm35.pyに追加しています。

# m39.py
# マイコン宇宙講座
# 3-9 星占いプログラム
from PIL import Image, ImageDraw, ImageFont
from tkinter.constants import SOLID
import tkinter as tk
import csv
import math
import lib


M2PI = 2.0 * math.pi

x = [[0 for i in range(10)] for j in range(4)]
f = [0, 0, 0, 0]
q = [0, 0, 0, 0]

print()
std = input('DATE AND TIME(JST) ? ')
dy, dt = std.split(',')
dy = float(dy)
dt = float(dt)

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

print('\n')
print('  Date= %5d 年 %2d 月 %2d 日  Time= %2d 時 %2d 分 %2.1f 秒\n' % (yy, mm, dd, hh, ms, ss))
print('         MJD=%12.2f ET\n' % (jd))
print(' Planets        R.A.  (1950.0)  Decl.         Distance')
print(' ------------------------------------------------------')
print('                h   m            。  ,              AU')

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)
    f, q = lib.eph_const(p, n, i, lib.K)

    ec = e
    mo = M2PI * (m / (M2PI) - int(m / (M2PI)))

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

    b = a * math.sqrt(1.0 - e * e)
    for n in range(1, 4):
        f[n] = a * f[n]
        q[n] = b * q[n]

    # 惑星座標の計算
    for n in range(1, 4):
        x[n][pn] = ff * f[n] + ss * q[n]

for n in range(1, 4):
    x[n][3] = - (x[n][3])

for pn in range(1, 10):
    if pn != 3:
        for n in range(1, 4):
            x[n][pn] = x[n][pn] + x[n][3]

# 惑星の赤経・赤緯の計算
for pn in range(1, 10):
    cc = x[1][pn]
    ss = x[2][pn]

    tt = lib.quadrant(ss, cc)
    ra = tt

    cc = x[1][pn] / math.cos(ra)
    ss = x[3][pn]

    dc = math.atan(ss / cc)
    ra *= lib.K[3] / 15.0
    dc *= lib.K[3]
    ds = math.sqrt(x[1][pn]**2 + x[2][pn]**2 + x[3][pn]**2)

    rh = int(ra)
    rm = 60.0 * (ra - rh)
    dh = int(abs(dc))
    dm = 60.0 * (abs(dc) - dh)
    dh = lib.sgn(dc) * dh
    print(' %-7s      %02d  %05.2f       %+03d  %04.1f       %8.5f' % (lib.PL[pn], rh, rm, dh, dm, ds))

print(' ------------------------------------------------------')
print('\n')


# --- メインプログラム m35.pyの後ろに追加 ---
def drawing_frame(yy, mm, dd, ii, frame_color, planet_color, fonts, draw):
    seiza = [
        # リバース開始位置(x), 文字位置(x,y), 星座名
        [0, 0, 0, ''],
        [496, 535, 352, 'うお座'],
        [376, 404, 352, 'おひつじ座'],
        [256, 290, 352, 'おうし座'],
        [136, 167, 352, 'ふたご座'],
        [496, 535, 224, 'かに座'],
        [376, 415, 224, 'しし座'],
        [256, 295, 224, 'おとめ座'],
        [136, 160, 224, 'てんびん座'],
        [496, 530, 96, 'さそり座'],
        [376, 415, 96, 'いて座'],
        [256, 295, 96, 'やぎ座'],
        [136, 160, 96, 'みずがめ座']
    ]

    # フレームの描画
    # 星座
    draw.rectangle((136, 8, 616, 88), outline=frame_color, width=2)
    for ln in range(136, 520, 120):
        draw.line((ln, 8, ln, 88), fill=frame_color, width=2)
    draw.rectangle((136, 136, 616, 216), outline=frame_color, width=2)
    for ln in range(136, 520, 120):
        draw.line((ln, 136, ln, 216), fill=frame_color, width=2)
    draw.rectangle((136, 264, 616, 344), outline=frame_color, width=2)
    for ln in range(136, 520, 120):
        draw.line((ln, 264, ln, 344), fill=frame_color, width=2)

    # 説明文
    draw.rectangle((1, 8, 128, 344), outline=frame_color, width=2)
    draw.line((1, 128, 128, 128), fill=frame_color, width=2)
    draw.line((1, 180, 128, 180), fill=frame_color, width=2)
    draw.line((1, 304, 128, 304), fill=frame_color, width=2)

    # 日付・太陽と惑星の記号・タイトル
    datestr = str('%4d年%02d月%02d日' % (yy, mm, dd))
    timestr = str('%02d時%02d分' % (hh, ms))
    draw.text((16, 50), datestr, font=fonts)
    draw.text((36, 70), timestr, font=fonts)
    draw.text((8, 147), '太陽と惑星の記号', font=fonts)
    draw.text((8, 190), '太陽 -------(   )', font=fonts)
    draw.text((8, 208), '水星 -------(   )', font=fonts)
    draw.text((8, 226), '金星 -------(   )', font=fonts)
    draw.text((8, 244), '火星 -------(   )', font=fonts)
    draw.text((8, 262), '木星 -------(   )', font=fonts)
    draw.text((8, 280), '土星 -------(   )', font=fonts)
    draw.text((16, 317), 'マイコン星占い', font=fonts)

    # 太陽
    drawing_planet_symbol(0, 109, 197, planet_color[0], draw)
    # 水星
    drawing_planet_symbol(1, 109, 215, planet_color[1], draw)
    # 金星
    drawing_planet_symbol(2, 109, 233, planet_color[2], draw)
    # 火星
    drawing_planet_symbol(4, 109, 251, planet_color[4], draw)
    # 木星
    drawing_planet_symbol(5, 109, 269, planet_color[5], draw)
    # 土星
    drawing_planet_symbol(6, 109, 287, planet_color[6], draw)

    # 星座名の表示
    for i in range(1, 13):
        draw.text((seiza[i][1], seiza[i][2]), seiza[i][3], font=fonts)

    # リバース表示
    rev_x = seiza[ii][0]
    rev_y = seiza[ii][2]
    draw.rectangle((rev_x, rev_y, rev_x + 120, rev_y + 15), fill=(255, 255, 255))
    draw.text((seiza[ii][1], seiza[ii][2]), seiza[ii][3], font=fonts, fill=(0, 0, 0))


def drawing_constellation(seiza_color, draw):
    # 星座データファイル名
    seiza_file = [
        'aquarius.csv',
        'capricorn.csv',
        'sagittarius.csv',
        'scorpio.csv',
        'libra.csv',
        'virgo.csv',
        'leo.csv',
        'cancer.csv',
        'gemini.csv',
        'taurus.csv',
        'aries.csv',
        'pisces.csv'
    ]

    # 星座データの読み込み
    for file_name in seiza_file:
        fp = open('./seiza/' + file_name, 'r')
        reader = csv.reader(fp)

        for data in reader:
            x = int(data[0]) * 4 + 136
            y = int(data[1]) * 4

            draw.rectangle((x - 2, y - 2, x + 2, y + 2), fill=seiza_color)

        fp.close()


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


root = tk.Tk()
root.resizable(False, False)
root.geometry('640x440')
root.title('マイコン宇宙講座 - 星占いプログラム')

img = Image.new('RGB', (642, 402), (0, 0, 0))
draw = ImageDraw.Draw(img)

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

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

# カラーパレット
seiza_color = (255, 255, 255)
frame_color = (255, 255, 255)
planet_color = [
    '#FF0000',
    '#FFD7A0',
    '#FAAF3C',
    '#FF0000',
    '#FF5050',
    '#B9BEB4',
    '#C8A05F',
]

# 計算
cc = x[1][3]
ss = x[2][3]

tt = lib.quadrant(ss, cc)

ra = tt
cc = x[1][3] / math.cos(ra)
ss = x[3][3]
dc = math.atan(ss / cc)

lp, bp = lib.ecliptic_coordinates(ra, dc, lib.K)

lp *= lib.K[3] / 15.0
ii = int(lp / 2 + 2)
if ii > 12:
    ii -= 12

# フレーム描画
drawing_frame(yy, mm, dd, ii, frame_color, planet_color, fonts, draw)

# 黄道12星座プロット
drawing_constellation(seiza_color, draw)

for pn in range(1, 7):
    cc = x[1][pn]
    ss = x[2][pn]

    tt = lib.quadrant(ss, cc)

    ra = tt
    cc = x[1][pn] / math.cos(ra)
    ss = x[3][pn]
    dc = math.atan(ss / cc)

    lp, bp = lib.ecliptic_coordinates(ra, dc, lib.K)

    lp *= lib.K[3] / 15.0
    bp *= lib.K[3]

    if pn == 3:
        lp += 2
    else:
        lp += 1
    if lp > 24:
        lp -= 24
    if lp > 16:
        lx = 16
        ly = 2
    else:
        if lp > 8:
            lx = 8
            ly = 10
        else:
            lx = 0
            ly = 18

    x1 = lp - lx
    x1 = int(x1 * 7.5)
    px = int(76 - x1)

    # switchかcase文があればいいのに
    if bp > 4:
        y1 = -2
    else:
        if bp > 2:
            y1 = -1
        else:
            if bp > 0:
                y1 = 0
            else:
                if bp > -2:
                    y1 = 1
                else:
                    if bp > -4:
                        y1 = 2
                    else:
                        y1 = 3
    py = int(ly + y1)
    # + 8しているのはY方向が0から開始ではなく8から開始しているための補正
    drawing_planet_symbol(pn, px * 8, py * 16 + 8, planet_color[pn], draw)

# 描画した星座の画像を保存
img.save('./images/seiza.png')

# 星座表示
photo = tk.PhotoImage(file='./images/seiza.png')
canvas.create_image(1, 1, image=photo, anchor=tk.NW)

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

root.mainloop()

例題 マイコン誌「RAM」(廣済堂 1978-1984)の創刊号が出版された1978年1月25日の太陽と惑星をプロットしてみよう。

DATE AND TIME(JST) ? 19780125,100000


  Date=  1978 年  1 月 25 日  Time= 10 時  0 分 0.0 秒

         MJD=    43533.04 ET

 Planets        R.A.  (1950.0)  Decl.         Distance
 ------------------------------------------------------
                h   m            。  ,              AU
 MERCURY      19  00.84       -23  04.5        1.22850
 VENUS        20  30.48       -20  05.5        1.71211
 EARTH        20  26.59       -19  11.0        0.98448
 MARS         08  12.94       +24  28.5        0.65709
 JUPITER      05  45.65       +23  14.0        4.33296
 SATURN       10  06.43       +13  15.2        8.30790
 URANUS       14  55.97       -16  21.6       18.79461
 NEPTUNE      17  01.54       -21  18.9       30.94264
 PLUTO        13  28.93       +09  18.4       30.08724
 ------------------------------------------------------
1978年1月25日の太陽と惑星の位置
1978年1月25日の太陽と惑星の位置