C++ - 日・月の出・南中・入時刻の計算!
Updated:
C++ で、日・月の出・南中・入時刻を計算してみました。(出・入はその時の方位角、南中はその時の高度も)
過去には Ruby, Fortran95 で行っています。
0. 前提条件
- Debian GNU/Linux 10.8 (64bit) での作業を想定。
- GCC 10.2.0 (G++ 10.2.0) (C++17) でのコンパイルを想定。
1. 計算方法について
- 計算アルゴリズムは、主に「日の出・日の入りの計算―天体の出没時刻の求め方」によるもの。(随所で改良している)
2. ソースコードの作成
ここでは、実行部分のみ掲載。(全てのコードは GitHub リポジトリとして公開している)
File: sun_moon.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/***********************************************************
日・月の出・南中・入時刻、
日・月の出・入方位角、
日・月の南中高度 の計算
DATE AUTHOR VERSION
2021.04.09 mk-mode.com 1.00 新規作成
Copyright(C) 2021 mk-mode.com All Rights Reserved.
------------------------------------------------------------
引数 : 99999999 [+-]999.99 [+-]999.99 [+]9999.99
第1: 日付 [必須]
計算対象の日付(グレゴリオ暦)を半角8桁数字で指定
第2: 緯度 [必須]
緯度を 度 で指定(度・分・秒は度に換算して指定すること)
(北緯はプラス、南緯はマイナス。桁数は特に制限なし)
第3: 経度 [必須]
経度を 度 で指定(度・分・秒は度に換算して指定すること)
(東経はプラス、西経はマイナス。桁数は特に制限なし)
第4: 標高 [必須]
標高をメートルで指定(マイナス値は指定不可)
(桁数は特に制限なし)
***********************************************************/
#include "calc.hpp"
#include "time.hpp"
#include <cstdlib> // for EXIT_XXXX
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
int main(int argc, char* argv[]) {
namespace ns = sun_moon;
std::string tm_str; // time string
unsigned int s_tm; // size of time string
struct timespec jst; // JST
struct tm t = {}; // for work
double lat; // latitude
double lng; // lngitude
double ht; // hight
char s_lat = 'N'; // N: 北緯, S: 南緯
char s_lng = 'E'; // E: 東経, W: 西経
struct ns::TmAh tm_ah_sr; // 日の出
struct ns::TmAh tm_ah_ss; // 日の入
struct ns::TmAh tm_ah_sm; // 日の南中
struct ns::TmAh tm_ah_mr; // 月の出
struct ns::TmAh tm_ah_ms; // 月の入
struct ns::TmAh tm_ah_mm; // 月の南中
try {
// コマンドライン引数取得
if (argc < 5) {
std::cout << "[USAGE] ./sun_moon YYYYMMDD LATITUDE LONGITUDE HEIGHT"
<< std::endl;
return EXIT_FAILURE;
}
// [日付]
tm_str = argv[1];
s_tm = tm_str.size();
if (s_tm > 8) {
std::cout << "[ERROR] Over 8-digits!" << std::endl;
return EXIT_FAILURE;
}
std::istringstream is(tm_str);
is >> std::get_time(&t, "%Y%m%d%H%M%S");
jst.tv_sec = mktime(&t);
jst.tv_nsec = 0;
// [緯度・経度・標高]
lat = std::stod(argv[2]);
lng = std::stod(argv[3]);
ht = std::stod(argv[4]);
if (lat < 0.0) {
s_lat = 'S';
lat = std::abs(lat);
}
if (lng < 0.0) {
s_lng = 'W';
lng = std::abs(lng);
}
// 各種計算
ns::Calc o_c(jst, lat, lng, ht);
tm_ah_sr = o_c.calc_sun(0); // 日の出
tm_ah_ss = o_c.calc_sun(1); // 日の入
tm_ah_sm = o_c.calc_sun(2); // 日南中
tm_ah_mr = o_c.calc_moon(0); // 月の出
tm_ah_ms = o_c.calc_moon(1); // 月の入
tm_ah_mm = o_c.calc_moon(2); // 月南中
std::cout << "[" << ns::gen_time_str(jst).substr(0, 10) << "JST "
<< std::fixed << std::setprecision(4)
<< lat << s_lat << " " << lng << s_lng << " " << ht << "m]"
<< std::endl;
std::cout << std::fixed << std::setprecision(2);
std::cout << "日の出 " << ns::gen_time_str(tm_ah_sr.time).substr(11, 8)
<< " (方位角 "
<< std::setw(6) << tm_ah_sr.ah << "°)"
<< std::endl;
std::cout << "日南中 " << ns::gen_time_str(tm_ah_sm.time).substr(11, 8)
<< " ( 高度 "
<< std::setw(6) << tm_ah_sm.ah << "°)"
<< std::endl;
std::cout << "日の入 " << ns::gen_time_str(tm_ah_ss.time).substr(11, 8)
<< " (方位角 "
<< std::setw(6) << tm_ah_ss.ah << "°)"
<< std::endl;
std::cout << "月の出 " << ns::gen_time_str(tm_ah_mr.time).substr(11, 8)
<< " (方位角 "
<< std::setw(6) << tm_ah_mr.ah << "°)"
<< std::endl;
std::cout << "日南中 " << ns::gen_time_str(tm_ah_mm.time).substr(11, 8)
<< " ( 高度 "
<< std::setw(6) << tm_ah_mm.ah << "°)"
<< std::endl;
std::cout << "月の入 " << ns::gen_time_str(tm_ah_ms.time).substr(11, 8)
<< " (方位角 "
<< std::setw(6) << tm_ah_ms.ah << "°)"
<< std::endl;
} catch (...) {
std::cerr << "EXCEPTION!" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
3. ソースコードのビルド(コンパイル&リンク)
- リポジトリに
Makefile
があるので、それを使用してmake
するだけ。(リビルドする際はmake clean
をしてから) - 上記の
Makefile
内では別途個別にインストールしたc++102
コマンドを使用しているが、通常はc++
であるので注意。
$ make
4. 準備
- うるう年ファイル
LEAP_SEC.txt
, DUT1 ファイルDUT1.txt
は適宜最新のものに更新すること。
5. 動作確認
コマンドライン引数に日付、緯度、経度、標高を 99999999 [+-]999.99 [+-]999.99 [+]9999.99
形式で指定して実行。(以下は、2021年5月1日、松江市役所の緯度・経度、標高1.5m で計算する例)
$ ./sun_moon 20210501 35.4681 133.0486 1.5
[2021-05-01JST 35.4681N 133.0486E 1.5000m]
日の出 05:16:11 (方位角 70.76°)
日南中 12:04:53 ( 高度 69.65°)
日の入 18:54:08 (方位角 289.46°)
月の出 23:50:10 (方位角 122.28°)
日南中 03:38:25 ( 高度 29.30°)
月の入 08:29:09 (方位角 237.86°)
- 第1: 日付 [必須]
計算対象の日付(グレゴリオ暦)を半角8桁数字で指定 - 第2: 緯度 [必須]
緯度を 度 で指定(度・分・秒は度に換算して指定すること)
(北緯はプラス、南緯はマイナス。桁数は特に制限なし) - 第3: 経度 [必須]
経度を 度 で指定(度・分・秒は度に換算して指定すること)
(東経はプラス、西経はマイナス。桁数は特に制限なし) - 第4: 標高 [必須]
標高をメートルで指定(マイナス値は指定不可)
(桁数は特に制限なし)
以上。
Comments