参考資料
1.日の出・日の入りの計算: 天体の出没時刻の求め方 長沢工(地人書館)
リンク
2.NASA Eclips - POLYNOMIAL EXPRESSIONS FOR DELTA T (ΔT)3.国土交通省 国土地理院 - サーバサイドで経緯度から標高を求めるプログラム
年 : $year$
月 : $month$
日 : $day$
時 : $hour$
分 : $min$
秒 : $sec$
経度: $\lambda$(東経を正にとる)
緯度: $\varphi$(北緯を正にとる)
標高: $H [m]$
$month \leqq 2$ のとき、
$Y = year - 2001$
$M = month + 12$
$D = day$
$3 \leqq month \leqq 12$ のとき、
$Y = year - 2000$
$M = month$
$D = day$
J2000.0(2000年1月1日力学時正午)からの経過日数の計算要素
なお、$\left[ \dfrac{3(M+1)}{5} \right]$ と $\left[ \dfrac{Y}{4} \right]$ はガウス記号。
例えば、$\left[1.618\right]=1$、 $\left[3.1415\right]=3$、 $\left[-0.7\right]=-1$、 $\left[-13.2\right]=-14$
経過時間の日単位変換補整
地球の自転遅れ補正値 $DT$
計算要素
$y' \leqq -500$ のとき、
$-500 \leqq y' < 500$ のとき、
$500 \leqq y' < 1600$ のとき、
$1600 \leqq y' < 1700$ のとき、
$1700 \leqq y' < 1800$ のとき、
$1800 \leqq y' < 1860$ のとき、
$1860 \leqq y' < 1900$ のとき、
$1900 \leqq y' < 1920$ のとき、
$1920 \leqq y' < 1941$ のとき、
$1941 \leqq y' < 1961$ のとき、
$1961 \leqq y' < 1986$ のとき、
$1986 \leqq y' < 2005$ のとき、
$2005 \leqq y' < 2050$ のとき、
$2050 \leqq y' < 2150$ のとき、
$2150 \leqq y'$ のとき、
$1955 \leqq y' \leqq 2005$のとき、
$DT = DT_0$
$y' < 1955$ または $2005 < y'$のとき、
J2000.0(2000年1月1日力学時正午からの経過日数): $K$
$K = K' + d + \dfrac{DT}{86400}$
時刻変数: $T$
$T = \dfrac{K}{365.25}$
黄道傾角: $e$
$e = 23.439291 - 0.000130042 T$
太陽の視黄経: $\lambda_{S2}$
$0 \leqq \lambda_S$ のとき、
$\lambda_S < 0$ のとき、
ただし、 $mod$ は余りを表す記号。
例えば、 $(5 \quad mod \quad 2) = 1$、 $(17 \quad mod \quad 3) = 2$
恒星時: $\theta_2$
$0 \leqq \theta$ のとき、
$\theta < 0$ のとき、
太陽の赤経 $\alpha_2$
$0 \leqq \alpha$ のとき、
$ \alpha < 0$ のとき、
$0 \leqq \lambda_{s2} < 180$ のとき、
$180 \leqq \lambda_{s2} < 360$ のとき、
$\alpha_2 = \alpha_1 + 180$
赤緯: $\delta$
時角: $t$
$t = \theta_2 - \alpha_2$
高度: $h$
大気差: $R$
${\bf SunAngle} = h + R$
$0 \leqq A$ のとき、
${\bf Houikaku } = A$
$ A < 0 $ のとき、
${\bf Houikaku }= A+360$
また、太陽出没高度の算出のため、
太陽距離 $r$
視半径 $S = \left( \dfrac{16}{60} + \dfrac{1.18}{3600} \right) \times \dfrac{1}{r} $
大気差 $R_2 = \dfrac{35}{60} + \dfrac{8}{3600}$
視差 $ \Pi = \dfrac{8.794148}{3600} \times \dfrac{1}{r}$
地平線の伏角 $E = \dfrac{2.12}{60} \sqrt{H}$
出没高度 $ k = \Pi - S - E - R_2$
${\bf SunAngle}$と比較する場合には視差を2重にカウントすることになるため、
視差の差を打ち消すために$R$ を加算した値を $k_2$ とすると、
$ k_2 = \Pi - S - E - R_2 + R$
ここで、$ GAP = |{\bf SunAngle} - k_2|$ とする。
以上のすべての計算を、
0時00分00秒から23時59分59秒に至るまで、全ての時刻で計算を実施したとき、
$0 < {\bf Houikaku }< 180$ で $ {\bf GAP }$ の値が最小となる時刻が「日の出時刻」
$180 < {\bf Houikaku }< 360$ で $ {\bf GAP }$ の値が最小となる時刻が「日の入時刻」
${\bf Houikaku }= 180$ の時の時刻が「南中時刻」
「南中時刻」の時の $ {\bf SunAngle }$ の値が「南中高度」
以下に、本サイトの太陽高度を求めているjavascript及びhtmlのコードをそのまま載せます。
興味のある方はご参考ください。(Copyright © Airmanship.jp 2024)
sunangle.js
document.addEventListener("DOMContentLoaded", function() {
// 日付を取得する要素
var inputdate = document.getElementById('set_date');
// idが"mainbutton"の要素を取得する
var mainButton = document.getElementById("mainbutton");
var mainButton2 = document.getElementById("mainbutton2");
// idが"sunangle"の要素を取得する
var sunanglevalue;
function readInputValue() {
// 入力要素を取得
var sunangle = document.getElementById('sunangle');
// 入力値を取得
sunanglevalue = parseFloat(sunangle.value);
}
// mainButtonがクリックされたときの処理を定義する
mainButton.addEventListener("click", function() {
// calculate1() を呼び出す
calculate1();
});
// mainButton2がクリックされたときの処理を定義する
mainButton2.addEventListener("click", function() {
// calculate2() を呼び出す
calculate2();
});
// mainButtonがクリックされたときの処理
function calculate1() {
// 結果を保存するための配列
var results = [];
// lat_1 および lng_1 の取得
var lat_1 = parseFloat(document.getElementById("lat_1").innerText);
var lng_1 = parseFloat(document.getElementById("lng_1").innerText);
// sunanglevalueを取得
readInputValue();
var dateValue, y, m, D, M, Y, Kdash, ydash, dT_0,dT;
dateValue = new Date(inputdate.value);
y = dateValue.getFullYear(); // 年
m = dateValue.getMonth() + 1; // 月 (0-11で返されるため、+1する)
D = dateValue.getDate(); // 日
if (m < 3) {
M = m + 12;
Y = y - 2001;
} else {
M = m;
Y = y - 2000;
}
Kdash = 365 * Y + 30 * M + D - 33.875 + Math.floor(3 * (M + 1) / 5) + Math.floor(Y / 4);
ydash = y + (m - 0.5) / 12;
if (ydash < -500) {
dT_0 = -20 + 32 * Math.pow((ydash - 1820) / 100, 2);
} else if (ydash >= -500 && ydash < 500) {
dT_0 = 10583.6 - 1014.41 * (ydash / 100) + 33.78311 * Math.pow(ydash / 100, 2) - 5.952053 * Math.pow(ydash / 100, 3) - 0.1798452 * Math.pow(ydash / 100, 4) + 0.022174192 * Math.pow(ydash / 100, 5) + 0.0090316521 * Math.pow(ydash / 100, 6);
} else if (ydash >= 500 && ydash < 1600) {
dT_0 = 1574.2 - 556.01 * ((ydash - 1000) / 100) + 71.23472 * Math.pow((ydash - 1000) / 100, 2) + 0.319781 * Math.pow((ydash - 1000) / 100, 3) - 0.8503463 * Math.pow((ydash - 1000) / 100, 4) - 0.005050998 * Math.pow((ydash - 1000) / 100, 5) + 0.0083572073 * Math.pow((ydash - 1000) / 100, 6);
} else if (ydash >= 1600 && ydash < 1700) {
dT_0 = 120 - 0.9808 * (ydash - 1600) - 0.01532 * Math.pow((ydash - 1600), 2) + Math.pow((ydash - 1600), 3) / 7129;
} else if (ydash >= 1700 && ydash < 1800) {
dT_0 = 8.83 + 0.1603 * (ydash - 1700) - 0.0059285 * Math.pow((ydash - 1700), 2) + 0.00013336 * Math.pow((ydash - 1700), 3) - Math.pow((ydash - 1700), 4) / 1174000;
} else if (ydash >= 1800 && ydash < 1860) {
dT_0 = 13.72 - 0.332447 * (ydash - 1800) + 0.0068612 * Math.pow((ydash - 1800), 2) + 0.0041116 * Math.pow((ydash - 1800), 3) - 0.00037436 * Math.pow((ydash - 1800), 4) + 0.0000121272 * Math.pow((ydash - 1800), 5) - 0.0000001699 * Math.pow((ydash - 1800), 6) + 0.000000000875 * Math.pow((ydash - 1800), 7);
} else if (ydash >= 1860 && ydash < 1900) {
dT_0 = 7.62 + 0.5737 * (ydash - 1860) - 0.251754 * Math.pow((ydash - 1860), 2) + 0.01680668 * Math.pow((ydash - 1860), 3) - 0.0004473624 * Math.pow((ydash - 1860), 4) + Math.pow((ydash - 1860), 5) / 233174;
} else if (ydash >= 1900 && ydash < 1920) {
dT_0 = -2.79 + 1.494119 * (ydash - 1900) - 0.0598939 * Math.pow((ydash - 1900), 2) + 0.0061966 * Math.pow((ydash - 1900), 3) - 0.000197 * Math.pow((ydash - 1900), 4);
} else if (ydash >= 1920 && ydash < 1941) {
dT_0 = 21.2 + 0.84493 * (ydash - 1920) - 0.0761 * Math.pow((ydash - 1920), 2) + 0.0020936 * Math.pow((ydash - 1920), 3);
} else if (ydash >= 1941 && ydash < 1961) {
dT_0 = 29.07 + 0.407 * (ydash - 1950) - Math.pow((ydash - 1950), 2) / 233 + Math.pow((ydash - 1950), 3) / 2547;
} else if (ydash >= 1961 && ydash < 1986) {
dT_0 = 45.45 + 1.067 * (ydash - 1975) - Math.pow((ydash - 1975), 2) / 260 - Math.pow((ydash - 1975), 3) / 718;
} else if (ydash >= 1986 && ydash < 2005) {
dT_0 = 63.86 + 0.3345 * (ydash - 2000) - 0.060374 * Math.pow((ydash - 2000), 2) + 0.0017275 * Math.pow((ydash - 2000), 3) + 0.000651814 * Math.pow((ydash - 2000), 4) + 0.00002373599 * Math.pow((ydash - 2000), 5);
} else if (ydash >= 2005 && ydash < 2050) {
dT_0 = 62.92 + 0.32217 * (ydash - 2000) + 0.005589 * Math.pow((ydash - 2000), 2);
} else if (ydash >= 2050 && ydash < 2150) {
dT_0 = -20 + 32 * Math.pow((ydash - 1820) / 100, 2) - 0.5628 * (2150 - ydash);
} else if (ydash >= 2150) {
dT_0 = -20 + 32 * Math.pow((ydash - 1820) / 100, 2);
}
if (1955 <= ydash && ydash <= 2005) {
dT = dT_0;
}else{
dT = dT_0-0.000012935*Math.pow(ydash-1955,2);
}
for (var hour = 0; hour < 24; hour++) {
for (var minute = 0; minute < 60; minute++) {
for (var second = 0; second <= 59; second += 1) {
// 時間の計算を行う
var small_d = (hour + minute / 60 + second / 3600) / 24;
// 時刻変数T
var T = (Kdash + small_d + dT / 86400) / 365.25;
// 黄道傾角e
var e = 23.439291 - 0.000130042 * T;
// 視黄経λs2
var ramda_s = 280.4603 + 360.00769 * T
+ (1.9146 - 0.00005 * T) * Math.sin((357.538 + 359.991 * T) * Math.PI / 180)
+ 0.02 * Math.sin((355.05 + 719.981 * T) * Math.PI / 180) + 0.0048 * Math.sin((234.95 + 19.341 * T) * Math.PI / 180)
+ 0.002 * Math.sin((247.1 + 329.64 * T) * Math.PI / 180) + 0.0018 * Math.sin((297.8 + 4452.67 * T) * Math.PI / 180)
+ 0.0018 * Math.sin((251.3 + 0.2 * T) * Math.PI / 180) + 0.0015 * Math.sin((343.2 + 450.37 * T) * Math.PI / 180)
+ 0.0013 * Math.sin((81.4 + 225.18 * T) * Math.PI / 180) + 0.0008 * Math.sin((132.5 + 659.29 * T) * Math.PI / 180)
+ 0.0007 * Math.sin((153.3 + 90.38 * T) * Math.PI / 180) + 0.0007 * Math.sin((206.8 + 30.35 * T) * Math.PI / 180)
+ 0.0006 * Math.sin((29.8 + 337.18 * T) * Math.PI / 180) + 0.0005 * Math.sin((207.4 + 1.5 * T) * Math.PI / 180)
+ 0.0005 * Math.sin((291.2 + 22.81 * T) * Math.PI / 180) + 0.0004 * Math.sin((234.9 + 315.56 * T) * Math.PI / 180)
+ 0.0004 * Math.sin((157.3 + 299.3 * T) * Math.PI / 180) + 0.0004 * Math.sin((21.1 + 720.02 * T) * Math.PI / 180)
+ 0.0003 * Math.sin((352.5 + 1079.97 * T) * Math.PI / 180) + 0.0003 * Math.sin((329.7 + 44.43 * T) * Math.PI / 180);
var ramda_s2;
if (ramda_s >= 0) {
ramda_s2 = ramda_s % 360;
}else{
ramda_s2 = ramda_s % 360 + 360;
}
// 恒星時Θ2
var theta = 325.4606 + 360.007700536 * T + 0.00000003879 * Math.pow(T,2) + 360 * small_d + lng_1;
var theta_2;
if (theta >= 0) {
theta_2 = theta % 360;
}else{
theta_2 = theta % 360 + 360;
}
// 太陽の黄緯β=0なので、赤経α
var alpha = Math.atan(Math.tan(ramda_s2 / 180 * Math.PI) * Math.cos(e / 180 * Math.PI)) * 180 / Math.PI;
var alpha1;
if (alpha >= 0) {
alpha1 = alpha % 180;
}else{
alpha1 = alpha % 180 + 180;
}
var alpha2;
if (ramda_s2 >= 0 && ramda_s2 < 180) {
alpha2 = alpha1;
} else if (ramda_s2 >= 180 && ramda_s2 < 360) {
alpha2 = alpha1 + 180;
}
// 赤緯δ
var delta = Math.asin(Math.sin(ramda_s2 / 180 * Math.PI) * Math.sin(e / 180 * Math.PI)) * 180 / Math.PI;
// 時角
var small_t = theta_2 - alpha2;
// 高度
var small_h = Math.asin(Math.sin(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI)
+ Math.cos(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI)) / Math.PI * 180;
// 大気差
var R = 0.0167 / (Math.tan((small_h + 8.6 / (small_h + 4.4)) * Math.PI / 180));
// 方位角
var large_A = Math.atan((-Math.cos(delta / 180 * Math.PI) * Math.sin(small_t / 180 * Math.PI)) / (Math.sin(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) - Math.cos(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI))) * 180 / Math.PI;
if ((Math.sin(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) - Math.cos(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI)) < 0) {
large_A = Math.atan((-Math.cos(delta / 180 * Math.PI) * Math.sin(small_t / 180 * Math.PI)) / (Math.sin(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) - Math.cos(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI))) * 180 / Math.PI + 180;
}
var houikaku;
if (large_A < 0) {
houikaku = large_A + 360;
} else {
houikaku = large_A;
}
var result0 = small_h + R;
var result1 = Math.floor(result0 * 10000) / 10000; // 小数点第4位以下を切り捨てる
var result2 = Math.abs(sunanglevalue - result0);
results.push({
hour: hour,
minute: minute,
second: second,
houikaku: houikaku,
result0: result0,
result1: result1,
result2: result2,
});
}
}
}
// 結果表示の準備
var resultDiv = document.getElementById('result');
resultDiv.innerHTML = ''; // まずは結果をリセット
var resultDiv2 = document.getElementById('result2');
resultDiv2.innerHTML = ''; // まずは結果をリセット
// 0 <= houikaku < 180 の検索高度
var def_angle1 = Infinity;
var minResult1 = null;
results.forEach(function(item) {
if (item.houikaku >= 0 && item.houikaku < 180 && item.result2 < def_angle1) {
def_angle1 = item.result2;
minResult1 = item;
}
});
// 180 <= houikaku < 360 の検索高度
var def_angle2 = Infinity;
var minResult2 = null;
results.forEach(function(item) {
if (item.houikaku >= 180 && item.houikaku < 360 && item.result2 < def_angle2) {
def_angle2 = item.result2;
minResult2 = item;
}
});
// 最大となる太陽高度を設定
var max_angle = 0;
var maxResult = null;
results.forEach(function(item) {
if (item.result0 > max_angle) {
max_angle = item.result0;
maxResult = item;
}
});
// 表示
//見つからなかった場合はメッセージを表示
if (sunanglevalue > maxResult.result0) {
resultDiv.innerHTML += "太陽高度はそこまで上がりません
";
}
// 0 <= houikaku < 180 の検索高度を表示
if (sunanglevalue <= maxResult.result0) {
resultDiv.innerHTML +=
minResult1.hour + "時" + minResult1.minute + "分" + minResult1.second + "秒 " + minResult1.result1 + "
";
}
// 180 <= houikaku < 360 の検索高度を表示
if (sunanglevalue <= maxResult.result0) {
resultDiv.innerHTML +=
minResult2.hour + "時" + minResult2.minute + "分" + minResult2.second + "秒 " + minResult2.result1 + "
";
}
}
// mainButton2がクリックされたときの処理
function calculate2() {
// 結果を保存するための配列
var results = [];
// lat_1 および lng_1 および hgt_1 の取得
var lat_1 = parseFloat(document.getElementById("lat_1").innerText);
var lng_1 = parseFloat(document.getElementById("lng_1").innerText);
var hgt_1_0 = document.getElementById("hgt_1").innerText.trim();
var hgt_1 = isNaN(parseFloat(hgt_1_0)) ? 0 : parseFloat(hgt_1_0);
// 各InputValueを(特にsunanglevalue)を取得
readInputValue();
var dateValue, y, m, D, M, Y, Kdash, ydash, dT_0,dT;
dateValue = new Date(inputdate.value);
y = dateValue.getFullYear(); // 年
m = dateValue.getMonth() + 1; // 月 (0-11で返されるため、+1する)
D = dateValue.getDate(); // 日
if (m < 3) {
M = m + 12;
Y = y - 2001;
} else {
M = m;
Y = y - 2000;
}
Kdash = 365 * Y + 30 * M + D - 33.875 + Math.floor(3 * (M + 1) / 5) + Math.floor(Y / 4);
ydash = y + (m - 0.5) / 12;
if (ydash < -500) {
dT_0 = -20 + 32 * Math.pow((ydash - 1820) / 100, 2);
} else if (ydash >= -500 && ydash < 500) {
dT_0 = 10583.6 - 1014.41 * (ydash / 100) + 33.78311 * Math.pow(ydash / 100, 2) - 5.952053 * Math.pow(ydash / 100, 3) - 0.1798452 * Math.pow(ydash / 100, 4) + 0.022174192 * Math.pow(ydash / 100, 5) + 0.0090316521 * Math.pow(ydash / 100, 6);
} else if (ydash >= 500 && ydash < 1600) {
dT_0 = 1574.2 - 556.01 * ((ydash - 1000) / 100) + 71.23472 * Math.pow((ydash - 1000) / 100, 2) + 0.319781 * Math.pow((ydash - 1000) / 100, 3) - 0.8503463 * Math.pow((ydash - 1000) / 100, 4) - 0.005050998 * Math.pow((ydash - 1000) / 100, 5) + 0.0083572073 * Math.pow((ydash - 1000) / 100, 6);
} else if (ydash >= 1600 && ydash < 1700) {
dT_0 = 120 - 0.9808 * (ydash - 1600) - 0.01532 * Math.pow((ydash - 1600), 2) + Math.pow((ydash - 1600), 3) / 7129;
} else if (ydash >= 1700 && ydash < 1800) {
dT_0 = 8.83 + 0.1603 * (ydash - 1700) - 0.0059285 * Math.pow((ydash - 1700), 2) + 0.00013336 * Math.pow((ydash - 1700), 3) - Math.pow((ydash - 1700), 4) / 1174000;
} else if (ydash >= 1800 && ydash < 1860) {
dT_0 = 13.72 - 0.332447 * (ydash - 1800) + 0.0068612 * Math.pow((ydash - 1800), 2) + 0.0041116 * Math.pow((ydash - 1800), 3) - 0.00037436 * Math.pow((ydash - 1800), 4) + 0.0000121272 * Math.pow((ydash - 1800), 5) - 0.0000001699 * Math.pow((ydash - 1800), 6) + 0.000000000875 * Math.pow((ydash - 1800), 7);
} else if (ydash >= 1860 && ydash < 1900) {
dT_0 = 7.62 + 0.5737 * (ydash - 1860) - 0.251754 * Math.pow((ydash - 1860), 2) + 0.01680668 * Math.pow((ydash - 1860), 3) - 0.0004473624 * Math.pow((ydash - 1860), 4) + Math.pow((ydash - 1860), 5) / 233174;
} else if (ydash >= 1900 && ydash < 1920) {
dT_0 = -2.79 + 1.494119 * (ydash - 1900) - 0.0598939 * Math.pow((ydash - 1900), 2) + 0.0061966 * Math.pow((ydash - 1900), 3) - 0.000197 * Math.pow((ydash - 1900), 4);
} else if (ydash >= 1920 && ydash < 1941) {
dT_0 = 21.2 + 0.84493 * (ydash - 1920) - 0.0761 * Math.pow((ydash - 1920), 2) + 0.0020936 * Math.pow((ydash - 1920), 3);
} else if (ydash >= 1941 && ydash < 1961) {
dT_0 = 29.07 + 0.407 * (ydash - 1950) - Math.pow((ydash - 1950), 2) / 233 + Math.pow((ydash - 1950), 3) / 2547;
} else if (ydash >= 1961 && ydash < 1986) {
dT_0 = 45.45 + 1.067 * (ydash - 1975) - Math.pow((ydash - 1975), 2) / 260 - Math.pow((ydash - 1975), 3) / 718;
} else if (ydash >= 1986 && ydash < 2005) {
dT_0 = 63.86 + 0.3345 * (ydash - 2000) - 0.060374 * Math.pow((ydash - 2000), 2) + 0.0017275 * Math.pow((ydash - 2000), 3) + 0.000651814 * Math.pow((ydash - 2000), 4) + 0.00002373599 * Math.pow((ydash - 2000), 5);
} else if (ydash >= 2005 && ydash < 2050) {
dT_0 = 62.92 + 0.32217 * (ydash - 2000) + 0.005589 * Math.pow((ydash - 2000), 2);
} else if (ydash >= 2050 && ydash < 2150) {
dT_0 = -20 + 32 * Math.pow((ydash - 1820) / 100, 2) - 0.5628 * (2150 - ydash);
} else if (ydash >= 2150) {
dT_0 = -20 + 32 * Math.pow((ydash - 1820) / 100, 2);
}
if (1955 <= ydash && ydash <= 2005) {
dT = dT_0;
}else{
dT = dT_0-0.000012935*Math.pow(ydash-1955,2);
}
// 時間毎にの計算を行う
for (var hour = 0; hour < 24; hour++) {
for (var minute = 0; minute < 60; minute++) {
for (var second = 0; second <= 59; second += 1) {
var small_d = (hour + minute / 60 + second / 3600) / 24;
var T = (Kdash + small_d + dT / 86400) / 365.25;
var e = 23.439291 - 0.000130042 * T;
var ramda_s = 280.4603 + 360.00769 * T
+ (1.9146 - 0.00005 * T) * Math.sin((357.538 + 359.991 * T) * Math.PI / 180)
+ 0.02 * Math.sin((355.05 + 719.981 * T) * Math.PI / 180) + 0.0048 * Math.sin((234.95 + 19.341 * T) * Math.PI / 180)
+ 0.002 * Math.sin((247.1 + 329.64 * T) * Math.PI / 180) + 0.0018 * Math.sin((297.8 + 4452.67 * T) * Math.PI / 180)
+ 0.0018 * Math.sin((251.3 + 0.2 * T) * Math.PI / 180) + 0.0015 * Math.sin((343.2 + 450.37 * T) * Math.PI / 180)
+ 0.0013 * Math.sin((81.4 + 225.18 * T) * Math.PI / 180) + 0.0008 * Math.sin((132.5 + 659.29 * T) * Math.PI / 180)
+ 0.0007 * Math.sin((153.3 + 90.38 * T) * Math.PI / 180) + 0.0007 * Math.sin((206.8 + 30.35 * T) * Math.PI / 180)
+ 0.0006 * Math.sin((29.8 + 337.18 * T) * Math.PI / 180) + 0.0005 * Math.sin((207.4 + 1.5 * T) * Math.PI / 180)
+ 0.0005 * Math.sin((291.2 + 22.81 * T) * Math.PI / 180) + 0.0004 * Math.sin((234.9 + 315.56 * T) * Math.PI / 180)
+ 0.0004 * Math.sin((157.3 + 299.3 * T) * Math.PI / 180) + 0.0004 * Math.sin((21.1 + 720.02 * T) * Math.PI / 180)
+ 0.0003 * Math.sin((352.5 + 1079.97 * T) * Math.PI / 180) + 0.0003 * Math.sin((329.7 + 44.43 * T) * Math.PI / 180);
var ramda_s2;
if (ramda_s >= 0) {
ramda_s2 = ramda_s % 360;
}else{
ramda_s2 = ramda_s % 360 + 360;
}
// 太陽距離
var small_r = Math.pow(10 , (
(0.007256 - 0.0000002 * T) * Math.sin((267.54 + 359.991 * T) * Math.PI / 180)
+ 0.000091 * Math.sin((265.1 + 719.98 * T) * Math.PI / 180)
+ 0.000030
+ 0.000013 * Math.sin((27.8 + 4452.67 * T) * Math.PI / 180)
+ 0.000007 * Math.sin((254 + 450.4 * T) * Math.PI / 180)
+ 0.000007 * Math.sin((156 + 329.6 * T) * Math.PI / 180)
));
// 視半径
var large_S = (16/60+1.18/3600)/small_r;
// 大気差
var large_R1 = 35/60+8/3600;
// 視差
var large_pi_shisa = (8.794148/3600)/small_r;
// 地平線の伏角
var large_E = 2.12/60*Math.sqrt(hgt_1);
// 恒星時Θ2
var theta = 325.4606 + 360.007700536 * T + 0.00000003879 * Math.pow(T,2) + 360 * small_d + lng_1;
var theta_2;
if (theta >= 0) {
theta_2 = theta % 360;
}else{
theta_2 = theta % 360 + 360;
}
// 太陽の黄緯β=0なので、赤経α
var alpha = Math.atan(Math.tan(ramda_s2 / 180 * Math.PI) * Math.cos(e / 180 * Math.PI)) * 180 / Math.PI;
var alpha1;
if (alpha >= 0) {
alpha1 = alpha % 180;
}else{
alpha1 = alpha % 180 + 180;
}
var alpha2;
if (ramda_s2 >= 0 && ramda_s2 < 180) {
alpha2 = alpha1;
} else if (ramda_s2 >= 180 && ramda_s2 < 360) {
alpha2 = alpha1 + 180;
}
// 赤緯δ
var delta = Math.asin(Math.sin(ramda_s2 / 180 * Math.PI) * Math.sin(e / 180 * Math.PI)) * 180 / Math.PI;
// 時角
var small_t = theta_2 - alpha2;
// 高度
var small_h = Math.asin(Math.sin(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI)
+ Math.cos(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI)) / Math.PI * 180;
// 大気差
var R = 0.0167 / (Math.tan((small_h + 8.6 / (small_h + 4.4)) * Math.PI / 180));
// 出没高度
var small_k = large_pi_shisa -large_S - large_E - large_R1 + R;
// 方位角
var large_A = Math.atan((-Math.cos(delta / 180 * Math.PI) * Math.sin(small_t / 180 * Math.PI)) / (Math.sin(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) - Math.cos(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI))) * 180 / Math.PI;
if ((Math.sin(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) - Math.cos(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI)) < 0) {
large_A = Math.atan((-Math.cos(delta / 180 * Math.PI) * Math.sin(small_t / 180 * Math.PI)) / (Math.sin(delta / 180 * Math.PI) * Math.cos(lat_1 / 180 * Math.PI) - Math.cos(delta / 180 * Math.PI) * Math.sin(lat_1 / 180 * Math.PI) * Math.cos(small_t / 180 * Math.PI))) * 180 / Math.PI + 180;
}
var houikaku;
if (large_A < 0) {
houikaku = large_A + 360;
} else {
houikaku = large_A;
}
var houikaku2 = Math.round(houikaku * 10) / 10;
var houikaku3 = Math.abs(houikaku-180);//0度で180、90度で90、180度で0、270度で90、360度で180
var result0 = small_h + R;
var result1 = Math.round(result0 * 10000) / 10000;
var result2 = Math.abs(sunanglevalue - result0);
var result3 = Math.abs(result0-small_k);
if ((small_k < result0 && second === 0)
|| (small_k - 0.003 <= result0 && result0 <= small_k + 0.003)
|| (sunanglevalue - 0.003 <= result0 && result0 <= sunanglevalue + 0.003)
|| (houikaku >= 179.995 && houikaku <= 180.005)) {
results.push({
hour: hour,
minute: minute,
second: second,
result0: result0, //太陽高度
result1: result1, //太陽高度(小数点第5位で四捨五入)
result2: result2, //太陽高度と検索高度の差
result3: result3, //太陽高度と日の出・日の入り高度の差
small_k: small_k, //日の出・日の入り高度の差
houikaku: houikaku, //方位角
houikaku2: houikaku2, //方位角(小数点第2位で四捨五入)
houikaku3: houikaku3, //方位角と180の差
});
}
}
}
}
// 0 <= houikaku < 180 の検索高度
var def_angle1 = Infinity;
var minResult1 = null;
results.forEach(function(item) {
if (item.houikaku >= 0 && item.houikaku < 180 && item.result2 < def_angle1) {
def_angle1 = item.result2; // 太陽高度と検索高度の差がより小さいときに代入
minResult1 = item;
}
});
// 180 <= houikaku < 360 の検索高度
var def_angle2 = Infinity;
var minResult2 = null;
results.forEach(function(item) {
if (item.houikaku >= 180 && item.houikaku < 360 && item.result2 < def_angle2) {
def_angle2 = item.result2; // 太陽高度と検索高度の差がより小さいときに代入
minResult2 = item;
}
});
//南中
var def_houi_180 = 180;
var minResult3 = null;
results.forEach(function(item) {
if (item.houikaku3 < def_houi_180) {
def_houi_180 = item.houikaku3; // 180と方位角の差がより小さいと代入
minResult3 = item;
}
});
//日の出
var def_sunrise1 = Infinity;
var minResult4 = null;
results.forEach(function(item) {
if (item.houikaku >= 0 && item.houikaku < 180 && item.result3 < def_sunrise1) {
def_sunrise1 = item.result3; // 太陽高度と日の出時の太陽高度の差がより小さいと代入
minResult4 = item;
}
});
//日の入り
var def_sunrise2 = Infinity;
var minResult5 = null;
results.forEach(function(item) {
if (item.houikaku >= 180 && item.houikaku < 360 && item.result3 < def_sunrise2) {
def_sunrise2 = item.result3;// 太陽高度と日の入り時の太陽高度の差がより小さいと代入
minResult5 = item;
}
});
// 結果を表示する準備
var resultDiv = document.getElementById('result2');
resultDiv.innerHTML = ''; // 結果をリセット
// 配列から抽出
var filteredResults = results.filter(function(item) {
return item.result0 > minResult4.result0 && item.second===0 || // 日の出の太陽高度より高く、秒の値が0のセット
item.result0 === minResult4.result0 || // 日の出
item.result0 === minResult5.result0 || // 日の入り
item.result0 === minResult1.result0 || // 検索高度1
item.result0 === minResult2.result0 || // 検索高度2
item.result0 === minResult3.result0 ; // 南中
});
// 結果を表示する
if (filteredResults.length > 0) {
filteredResults.forEach(function(item) {
resultDiv.innerHTML +=
item.hour + "時" +
item.minute + "分" +
((item.result0 === minResult4.result0) ? item.second+"秒" : "") + // 日の出
((item.result0 === minResult5.result0) ? item.second+"秒" : "") + // 日の入り
((item.result0 === minResult1.result0) ? item.second+"秒" : "") + // 検索高度1
((item.result0 === minResult2.result0) ? item.second+"秒" : "") + // 検索高度2
((item.result0 === minResult3.result0) ? item.second+"秒" : "") + // 南中
"" + " " +
item.result1 + " " +
item.houikaku2 +
((item.result0 === minResult4.result0) ? " 日の出時刻" : "")+"" +
((item.result0 === minResult1.result0) ? " 〇〇〇〇〇" : "")+"" +
((item.result0 === minResult3.result0) ? " 南中高度・南中時刻" : "")+"" +
((item.result0 === minResult2.result0) ? " 〇〇〇〇〇" : "")+"" +
((item.result0 === minResult5.result0) ? " 日の入り時刻" : "")+""+"
";
});
}
}
});
sunangleform.js
function init() {
//Leafletの初期化
var map = L.map('mapcontainer', { zoomControl: false });
map.setView([35.684, 139.753], 9);
//タイルの設定
//Google Satellite
var tile1 = L.tileLayer('https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', {
attribution: "© Google"
}).addTo(map);
//淡色地図
var tile2 = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png', {
attribution: "出典:地理院タイル https://maps.gsi.go.jp/development/ichiran.html"
});
//白地図
var tile3 = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/blank/{z}/{x}/{y}.png', {
attribution: "出典:地理院タイル https://maps.gsi.go.jp/development/ichiran.html"
});
//Google Maps
var tile4 = L.tileLayer('https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', {
attribution: "© Google"
});
//Google Satellite Hybrid
var tile5 = L.tileLayer('https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}', {
attribution: "© Google"
});
//OpenStreetMap
var tile6 = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '©OpenStreetMap'
});
//タイル表示
L.control.layers({
"Google Satellite": tile1,
"淡色地図": tile2,
"白地図": tile3,
"Google Maps": tile4,
"Google Satellite Hybrid": tile5,
"OpenStreetMap": tile6
}).addTo(map);
//マーカー(KML)の表示
fetch('data.kml')
.then(res => res.text())
.then(kmltext => {
const _parser = new DOMParser();
const _kml = _parser.parseFromString(kmltext, 'text/xml');
const _track = new L.KML(_kml);
map.addLayer(_track);
})
.catch(error => {
console.error('KMLデータの取得に失敗しました:', error);
});
//縮尺の表示
L.control.scale({ maxWidth: 200, position: 'bottomright', imperial: false }).addTo(map);
//拡大縮小ボタンの表示
L.control.zoom({ position: 'topright' }).addTo(map);
//Leafletでクリックした地図の緯度と経度を取得
let popup = L.popup();
map.on("click", (e)=>{
let clr_result = document.getElementById('result');
clr_result.innerHTML = ''; // 結果をリセット
let clr_result2 = document.getElementById('result2');
clr_result2.innerHTML = ''; // 結果をリセット
let lat_0 = e.latlng.lat;
let lng_0 = e.latlng.lng;
let lat_1 = document.getElementById("lat_1");
lat_1.innerHTML = lat_0;
let lat_2 = document.getElementById("lat_2");
let lat_2_sec = ((lat_0 - parseInt(lat_0)) * 60 - parseInt((lat_0 - parseInt(lat_0)) * 60)) * 60;
lat_2.innerHTML = parseInt(lat_0) + "度 " + parseInt((lat_0 - parseInt(lat_0)) * 60) + "分 " + lat_2_sec.toFixed(2) + "秒";
let lng_1 = document.getElementById("lng_1");
lng_1.innerHTML = lng_0;
let lng_2 = document.getElementById("lng_2");
let lng_2_sec = ((lng_0 - parseInt(lng_0)) * 60 - parseInt((lng_0 - parseInt(lng_0)) * 60)) * 60;
lng_2.innerHTML = parseInt(lng_0) + "度 " + parseInt((lng_0 - parseInt(lng_0)) * 60) + "分 " + lng_2_sec.toFixed(2) + "秒";
// 地理院地図サーバから標高を求める http://maps.gsi.go.jp/development/elevation_s.html
let hight_0 = 'https://cyberjapandata2.gsi.go.jp/general/dem/scripts/getelevation.php?lon=' + lng_0 + '&lat=' + lat_0;
fetch(hight_0)
.then((response) => {
return response.text();
})
.then((text) => {
var results = JSON.parse(text);
let str = Math.round(lat_0*100000)/100000 + ", " + Math.round(lng_0*100000)/100000 + ", " + Math.round(results.elevation/0.3048*10)/10 + ' ft';
popup.setLatLng(e.latlng).setContent(str).openOn(map);
let hgt_1 = document.getElementById("hgt_1");
hgt_1.innerHTML = Math.round(results.elevation*10)/10 + ' m';
let hgt_2 = document.getElementById("hgt_2");
hgt_2.innerHTML = Math.round(results.elevation/0.3048*10)/10 + ' ft';
})
});
}
// 日付をデフォルトで本日に設定
var today = new Date();
var dd = String(today.getDate()).padStart(2, '0');
var mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0!
var yyyy = today.getFullYear();
today = yyyy + '-' + mm + '-' + dd;
document.getElementById("set_date").value = today;
// 日付を変更したときの動作
document.getElementById('set_date').addEventListener('change', function() {
let clr_result = document.getElementById('result');
clr_result.innerHTML = ''; // 結果をリセット
let clr_result2 = document.getElementById('result2');
clr_result2.innerHTML = ''; // 結果をリセット
});
// 太陽高度のボタンを押したときの動作
document.getElementById('btn30').addEventListener('click', function() {
document.getElementById('sunangle').value = "30";
let clr_result = document.getElementById('result');
clr_result.innerHTML = ''; // 結果をリセット
let clr_result2 = document.getElementById('result2');
clr_result2.innerHTML = ''; // 結果をリセット
});
document.getElementById('btn25').addEventListener('click', function() {
document.getElementById('sunangle').value = "25";
let clr_result = document.getElementById('result');
clr_result.innerHTML = ''; // 結果をリセット
let clr_result2 = document.getElementById('result2');
clr_result2.innerHTML = ''; // 結果をリセット
});
// 検索高度を変更したときの動作
document.getElementById('sunangle').addEventListener('change', function() {
let clr_result = document.getElementById('result');
clr_result.innerHTML = ''; // 結果をリセット
let clr_result2 = document.getElementById('result2');
clr_result2.innerHTML = ''; // 結果をリセット
});
sunangle.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>太陽高度から時間を計算するやつ</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<body class="sb-nav-fixed" onload="init()">
<nav class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
<!-- Navbar Brand-->
<a class="navbar-brand ps-3" href="sunangle.html">太陽高度 から 時間 を計算するやつ</a>
</nav>
<div id="layoutSidenav">
<div id="layoutSidenav_content">
<main>
<div class="container-fluid px-4">
<div class="row">
<div class="col-xl-7">
<div id="mapcontainer" style="width:100%;height:77vh;"></div>
<div class="d-none d-xl-block">
<br>
参考資料<br>
1.日の出・日の入りの計算: 天体の出没時刻の求め方 長沢工(地人書館)<br>
2.NASA Eclips - <a href="https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html">POLYNOMIAL EXPRESSIONS FOR DELTA T (ΔT)</a><br>
<a href="https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html"><img src="images/NASA_Eclipse.jpg" alt=""></a><br><br>
</div><br>
</div>
<div class="col-xl-5">
<!-- 日付 -->
<div class="input-group col">
<label class="input-group-text">日付</label>
<input type="date" id="set_date"/>
</div>
<p></p>
<!-- 太陽高度 -->
<div class="input-group col">
<label class="input-group-text">太陽高度:</label>
<input type="number" value="30" id="sunangle"/>
<input type="button" value="30" id="btn30"/>
<input type="button" value="25" id="btn25"/>
</div>
<p></p>
<!-- 緯度 -->
<div class="input-group col">
緯度:
<span id="lat_1"></span>
<span id="lat_2"></span>
</div>
<p></p>
<!-- 経度 -->
<div class="input-group col">
経度:
<span id="lng_1"></span>
<span id="lng_2"></span>
</div>
<p></p>
<!-- 標高 -->
<div class="input-group col">
標高:
<span id="hgt_1"></span>
<span id="hgt_2"></span>
</div>
<p></p>
<input type="button" class="btn btn-outline-primary" value="↓↓↓ 計算する ↓↓↓" id="mainbutton"/> <a href='sunangle_formula.html' target='_blank'>計算式</a>
<p></p>
<!-- 結果 -->
<span id="result"></span>
<p></p><br>
<input type="button" class="btn btn-outline-primary" value="詳細を確認する" id="mainbutton2" />
<p>(時間,太陽高度,方位角)</p>
<span id="result2"></span><br><br>
<div class="d-xl-none">
<br>
参考資料<br>
1.日の出・日の入りの計算: 天体の出没時刻の求め方 長沢工(地人書館)<br>
2.NASA Eclips - <a href="https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html">POLYNOMIAL EXPRESSIONS FOR DELTA T (ΔT)</a><br>
<a href="https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html"><img src="images/NASA_Eclipse.jpg" alt="" style="width:90%;"></a>
<br><br><br>
</div>
</div>
</div>
</div>
</main>
<footer class="py-2 bg-light mt-auto fixed-bottom">
<div class="container-fluid px-4">
<div class="d-flex align-items-center justify-content-between small">
<div class="text-muted">Copyright © Airmanship.jp 2024</div>
</div>
</div>
</footer>
</div>
</div>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<script src="js/sunangle.js"></script>
<script src="js/L.KML.js"></script>
<script src="js/sunangleform.js"></script>
</body>
</html>