マイコン宇宙講座-太陽系惑星の位置表示
指定した日付の太陽系9惑星の軌道上の位置を表示します。計算は指定した日付の惑星の軌道要素からサブルーチンkeplerから離心近点離角を計算します。さらに真近点離角と動径を求め、グラフィック上位置に変換します。基本的にはこういった流れです(実際はもう少し複雑)。マイコン宇宙講座はPC-8001のグラフィックを利用して描いています。ですが、解像度としては160×100であり、現状のHDグラフィックだととても小さすぎてしまいます。そこで、これを640×400に補正して表示することにします。
メインルーチン m31.py
# m31.py
# マイコン宇宙講座
# 3-1 太陽系の惑星位置表示プログラム
from PIL import Image, ImageDraw, ImageFont
from tkinter.constants import SOLID
import tkinter as tk
import math
import lib
M2PI = 2.0 * math.pi
# 太陽系を表示する
def display_solor_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_solor_system(jd, yy, mm, dd, lib.T)
# 保存された画像を表示
photo = tk.PhotoImage(file='./images/solor.png')
canvas.create_image(1, 1, image=photo, anchor=tk.NW)
# テキストボックスの中身をクリア
editbox.delete(0, tk.END)
# 日付と時刻の入力欄にフォーカスをセット
editbox.focus_set()
# 太陽系を描く
def drawing_solor_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), 'SOLOR 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)
# 惑星の位置計算
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 = M2PI * (m / (M2PI) - int(m / (M2PI)))
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)
# 惑星を描く
drawing_planet_symbol(pn, x2, y2, planet_color[pn], draw)
# 画像を保存
# 必ずPNG形式で保存
img.save('./images/solor.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, 230), 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_solor_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)における太陽系9惑星の位置を表示してみよう。
DATE AND TIME(JST)に20000101,090000と入力して、[表示]をクリックすると、その日の太陽系9惑星の軌道上の位置が描かれます。