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: 標高 [必須]
     標高をメートルで指定(マイナス値は指定不可)
     (桁数は特に制限なし)

以上。





 

Sponsored Link

 

Comments