Carlos Une: 1 New module: +star 4 files changed, 250 insertions(+), 4 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~tomterl/public-inbox/patches/50935/mbox | git am -3Learn more about email & git
--- README.org | 8 +- man/thp.1.scd | 2 + man/thpd.5.scd | 31 +++++++ mods/star+star.ha | 213 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 4 deletions(-) create mode 100644 mods/star+star.ha diff --git a/README.org b/README.org index 809b97d..488ae9a 100644 --- a/README.org +++ b/README.org @@ -32,16 +32,16 @@ one patche applied (as of now): To build thp with all modules included, you need libgit2 and your platforms libgit2-dev equivalent installed, then issued #+BEGIN_SRC sh :exports code -make EXTRA_MODS="project git clock timer shind uptime moon sun" -make EXTRA_MODS="project git clock timer shind uptime moon sun" test +make EXTRA_MODS="project git clock timer shind uptime moon sun star" +make EXTRA_MODS="project git clock timer shind uptime moon sun star" test make PREFIX="${HOME}" install #+END_SRC To build with just the modules you use in your spec, use ~MODS~: #+BEGIN_SRC sh :exports code -make MODS="path host project timer uptime moon sun" -make MODS="path host project timer uptime moon sun" test +make MODS="path host project timer uptime moon sun star" +make MODS="path host project timer uptime moon sun star" test make PREFIX="${HOME}" install #+END_SRC diff --git a/man/thp.1.scd b/man/thp.1.scd index cd6a11f..f070fe2 100644 --- a/man/thp.1.scd +++ b/man/thp.1.scd @@ -110,6 +110,8 @@ All modules are optionally compiled into the server executable. *sunrise* and *sunset* display the time of sunrise and sunset, respectively. The location and time format can be configured. See thpd(5). +*star* displays the position of a star as seen by an observer on Earth. + # STYLES Available colors are: black, red, green, yellow, blue, magenta, cyan, white, diff --git a/man/thpd.5.scd b/man/thpd.5.scd index 1673a01..6808162 100644 --- a/man/thpd.5.scd +++ b/man/thpd.5.scd @@ -204,6 +204,37 @@ sunrise.layout=%H:%M| sunset.layout=%H:%M| ``` +## star + +Display the position of a star as seen by an observer on Earth. + +- name[=Antares] + Star name. + +- ra[=16h29m24.0s] + Right ascension coordinate. + +- dec[=-26d25m55.0s] + Declination coordinate. + +- ao[=N] + Azimuth origin. Azimuth is usually measured from the north direction. +To measure azimuth from the south, define ao=S. + +- layout[=${NAME}(${AZIMUTH}°,${ALTITUDE}°)] + Format string. + +Note: The observer's coordinates on Earth are defined in the _sun_ section. + +*example*: + +``` +[star] +name=Betelgeuse +ra=5h55m10.3s +dec=+7d24m25.4s +``` + # SEE ALSO *thpd*(1) *thp*(1) *thp*(5) diff --git a/mods/star+star.ha b/mods/star+star.ha new file mode 100644 index 0000000..7ced726 --- /dev/null +++ b/mods/star+star.ha @@ -0,0 +1,213 @@ +// Author: Carlos Une <une@fastmail.fm> +// Maintainer: Carlos Une <une@fastmail.fm> +// SPDX-FileCopyrightText: 2024 Carlos Une <une@fastmail.fm> +// SPDX-License-Identifier: GPL-3.0-or-later +// Compute star position. The error in the calculation is approximately ±1 arcminute +// relative to the true value. +use config; +use env; +use fmt; +use io; +use math; +use memio; +use regex; +use strconv; +use strings; +use strings::template; +use time::date; + +// Default observer coordinates. (São Paulo/BR) +def DEFAULT_LATITUDE = "-23.5898764"; +def DEFAULT_LONGITUDE = "-46.6589231"; +// Default star coordinates. (Antares/Alpha Scorpii) +def DEFAULT_STAR_NAME = "Antares"; +def DEFAULT_STAR_RA = "16h29m24.0s"; +def DEFAULT_STAR_DEC = "-26d25m55.0s"; +def DEFAULT_STAR_LAYOUT = "${NAME}(${AZIMUTH}°,${ALTITUDE}°)"; +// Standard epoch +def J2000: f64 = 2451545.0; +type azimuth_origin = enum { north, south }; +type invalid = !void; +type coordinate_error = (regex::error | strconv::error | invalid); + +type starconfig = struct { + lat: f64, + lon: f64, + name: str, + ra: f64, + dec: f64, + ao: azimuth_origin, + template: template::template, +}; + +// Parse right ascension coordinate. +// Example Input: "5h55m10.3053s"; Output: 88.79293875 [decimal degrees] +fn parse_ra(s: str) (f64 | coordinate_error) = { + let re = regex::compile(`([[:digit:]]{1,2})h([[:digit:]]{1,2})m([[:digit:]]{1,2}\.[[:digit:]]+)s`)?; + defer regex::finish(&re); + let cap = regex::findall(&re, s); + defer regex::result_freeall(cap); + + if (len(cap) == 1) { + let ra = 15.0*strconv::stof64(cap[0][1].content)? + + 15.0*strconv::stof64(cap[0][2].content)?/60.0 + + 15.0*strconv::stof64(cap[0][3].content)?/3600.0; + if (ra <= 360.0) { + return ra; + }; + }; + return invalid; +}; + +// Parse declination coordinate. +// Example Input: "+7d24m25.426s"; Output: 7.407062777777778 [decimal degrees] +fn parse_dec(s: str) (f64 | coordinate_error) = { + let re = regex::compile(`([-+]?[[:digit:]]{1,2})d([[:digit:]]{1,2})m([[:digit:]]{1,2}\.[[:digit:]]+)s`)?; + defer regex::finish(&re); + let cap = regex::findall(&re, s); + defer regex::result_freeall(cap); + + if (len(cap) == 1) { + let degree = strconv::stof64(cap[0][1].content)?; + let dec = math::signf64(degree): f64 *(math::absf64(degree) + + strconv::stof64(cap[0][2].content)?/60.0 + + strconv::stof64(cap[0][3].content)?/3600.0); + if (dec >= -90.0 && dec <= 90.0) { + return dec; + }; + }; + return invalid; +}; + +fn read_starconfig() (starconfig | error) = { + let lat = match (strconv::stof64(config::setting("sun.latitude", DEFAULT_LATITUDE))) { + case let x: f64 => yield x; + case => return "mod_star:invalid latitude"; + }; + let lon = match (strconv::stof64(config::setting("sun.longitude", DEFAULT_LONGITUDE))) { + case let x: f64 => yield x; + case => return "mod_star:invalid longitude"; + }; + let ra = match (parse_ra(config::setting("star.ra", DEFAULT_STAR_RA))) { + case let r: f64 => yield r; + case => return "mod_star:invalid right ascension"; + }; + let dec = match (parse_dec(config::setting("star.dec", DEFAULT_STAR_DEC))) { + case let d: f64 => yield d; + case => return "mod_star:invalid declination"; + }; + let ao = switch (config::setting("star.ao", "N")) { + case "N" => yield azimuth_origin::north; + case "S" => yield azimuth_origin::south; + case => return "mod_star:invalid azimuth_origin"; + }; + return starconfig { + lat = lat, + lon = lon, + name = config::setting("star.name", DEFAULT_STAR_NAME), + ra = ra, + dec = dec, + ao = ao, + template = template::compile(config::setting("star.layout", DEFAULT_STAR_LAYOUT))! }; +}; + +@init fn register_star() void = { + register("star", &mod_star); +}; + +export fn mod_star(pe: *env::env) str = { + let cfg = match (read_starconfig()) { + case let c: starconfig => yield c; + case let e: error => return strings::dup(e); + }; + let JD = julian_day(date::now()); + let (alpha, delta) = precess(cfg.ra, cfg.dec, JD); + let (az, alt) = to_horizontal(JD, cfg.lat, cfg.lon, alpha, delta, cfg.ao); + let sink = memio::dynamic(); + match (template::execute(&cfg.template, &sink, ("NAME", cfg.name), + ("AZIMUTH", az: int), ("ALTITUDE", alt: int))) { + case size => + return memio::string(&sink)!; + case io::error => + return strings::dup("mod_star:template::execute() failed"); + }; +}; + +// Compute the effects of precession on equatorial coordinates (α, δ). +// Precession Model: IAU 1976. +// Equinox J2000, FK5 reference frame. +// Reference: Meeus, J. — 'Astronomical Algorithms, 1991' +fn precess(alpha: f64, delta: f64, JD: f64) (f64, f64) = { + let t = (JD - J2000)/36525.0; + let tt = t*t; + let ttt = tt*t; + // Euler angles (ζ, z, θ). + let zeta = 2306.2181*t + 0.30188*tt + 0.017998*ttt; + let z = 2306.2181*t + 1.09468*tt + 0.018203*ttt; + let theta = 2004.3109*t - 0.42665*tt - 0.041833*ttt; + let arcsecond = 1.0/3600.0; + z *= arcsecond; + alpha = rad(alpha); + delta = rad(delta); + zeta = rad(zeta*arcsecond); + theta = rad(theta*arcsecond); + let A = math::cosf64(delta)*math::sinf64(alpha + zeta); + let B = math::cosf64(theta)*math::cosf64(delta)*math::cosf64(alpha + zeta) - math::sinf64(theta)*math::sinf64(delta); + let C = math::sinf64(theta)*math::cosf64(delta)*math::cosf64(alpha + zeta) + math::cosf64(theta)*math::sinf64(delta); + let alpha2 = deg(math::atan2f64(A, B)) + z; + if (alpha2 < 0.0) { alpha2 += 360.0; }; + return (alpha2, deg(math::asinf64(C))); +}; + +// Compute horizontal coordinates (azimuth, altitude). +// Reference: Meeus, J. — 'Astronomical Algorithms, 1991' +fn to_horizontal(JD: f64, lat: f64, lon: f64, alpha: f64, delta: f64, ao: azimuth_origin = azimuth_origin::north) (f64, f64) = { + let mst = mean_sidereal_time_gmst(JD); + let H = rad(mst + lon - alpha); + lat = rad(lat); + delta = rad(delta); + let A = deg(math::atan2f64(math::sinf64(H), math::cosf64(H)*math::sinf64(lat) - math::tanf64(delta)*math::cosf64(lat))); + let sinh = math::sinf64(lat)*math::sinf64(delta) + math::cosf64(lat)*math::cosf64(delta)*math::cosf64(H); + let h = deg(math::asinf64(sinh)); + if (ao == azimuth_origin::north) { + A += 180.0; // azimuth measured from the north + }; + if (A > 360.0) { A -= 360.0; }; + return (A, h); +}; + +// Compute Julian Day +fn julian_day(d: date::date) f64 = { + let Y = date::year(&d); + let M = date::month(&d); + let D = date::day(&d); + let H = date::hour(&d); + let MIN = date::minute(&d); + let S = date::second(&d): f64 + date::nanosecond(&d): f64/1.0e9; + return julian_day_ymd(Y, M, D) + ((H*3600 + MIN*60): f64 + S)/86400.0; +}; + +// Compute Julian Day +// Reference: Meeus, J. — 'Astronomical Algorithms, 1991' +fn julian_day_ymd(Y: int, M: int, D: int) f64 = { + if (M <= 2) { + Y -= 1; + M += 12; + }; + let A = Y/100; + let B = if (Y > 1582 || (Y == 1582 && (M > 10 || (M == 10 && D > 4)))) { + yield 2 - A + A/4; + } else { + yield 0; + }; + return (365.25 * (Y + 4716): f64): int: f64 + (30.6001 * (M + 1): f64): int: f64 + D: f64 + B: f64 - 1524.5; +}; + +// Mean sidereal time at Greenwich — GMST +// Reference: Meeus, J. — 'Astronomical Algorithms, 1991' +fn mean_sidereal_time_gmst(JD: f64) f64 = { + let T = (JD - J2000)/36525.0; + let r = math::modf64(280.46061837 + 360.98564736629 * (JD - J2000) + (0.000387933*T*T) - (T*T*T)/38710000.0, 360.0); + if (r < 0.0) r += 360.0; + return r; +}; -- 2.39.2