├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE.md ├── README.md ├── src ├── aberr.rs ├── angle.rs ├── asteroid.rs ├── atmos.rs ├── binary_star.rs ├── consts │ ├── mod.rs │ ├── wgs72.rs │ └── wgs84.rs ├── coords.rs ├── ecliptic.rs ├── interpol.rs ├── lib.rs ├── lunar.rs ├── misc.rs ├── nutation.rs ├── orbit │ ├── elliptic.rs │ ├── mod.rs │ ├── near_parabolic.rs │ └── parabolic.rs ├── parallax.rs ├── planet │ ├── VSOPD_87 │ │ ├── earth.rs │ │ ├── jupiter.rs │ │ ├── mars.rs │ │ ├── mercury.rs │ │ ├── mod.rs │ │ ├── neptune.rs │ │ ├── saturn.rs │ │ ├── uranus.rs │ │ └── venus.rs │ ├── earth.rs │ ├── jupiter │ │ ├── mod.rs │ │ └── moon.rs │ ├── mars.rs │ ├── mod.rs │ └── saturn │ │ ├── mod.rs │ │ ├── moon.rs │ │ └── ring.rs ├── pluto.rs ├── precess.rs ├── star.rs ├── sun.rs ├── time.rs ├── transit.rs └── util.rs └── tests ├── aberr.rs ├── earth.rs ├── ecliptic.rs ├── elliptic.rs ├── interpol.rs ├── jupiter.rs ├── lunar.rs ├── mars.rs ├── near_parabolic.rs ├── nutation.rs ├── parabolic.rs ├── parallax.rs ├── planet.rs ├── precess.rs ├── saturn.rs ├── star.rs ├── sun.rs ├── time.rs └── transit.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | rust: 8 | - stable 9 | - beta 10 | - nightly 11 | 12 | matrix: 13 | allow_failures: 14 | rust: 15 | - nightly 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | name = "astro" 4 | version = "2.0.0" 5 | authors = ["Saurav Sachidanand"] 6 | 7 | license = "MIT" 8 | 9 | repository = "https://www.github.com/saurvs/astro-rust" 10 | documentation = "https://saurvs.github.io/astro-rust" 11 | 12 | description = "Advanced algorithms for astronomy" 13 | keywords = ["astronomy", "algorithms", "ephemeris", "planet", "solar"] 14 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, 2016 Saurav Sachidanand 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # astro-rust [![](http://meritbadge.herokuapp.com/astro)](https://crates.io/crates/astro) [![](https://travis-ci.org/saurvs/astro-rust.svg?branch=master)](https://travis-ci.org/saurvs/astro-rust) [![](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/saurvs/astro-rust/blob/master/LICENSE.md) 2 | 3 | **Contents** 4 | 5 | [API Docs](https://saurvs.github.io/astro-rust/) 6 | 7 | * [About](#about) 8 | * [Usage](#usage) 9 | * [Contributing](#contributing) 10 | * [References](#references) 11 | 12 | ## About 13 | 14 | ```astro-rust``` is a library of advanced astronomical algorithms for the Rust programming language. 15 | 16 | Implemented algorithms include: 17 | 18 | * planetary and solar positioning by the complete set of elements of Bretagnon and Francou's VSP087 theory 19 | * lunar positioning by the principle elements of Chapront's ELP-2000/82 theory 20 | * satellite positioning for Saturn and Jupiter 21 | * finding Julian dates, sidereal time, dynamical time, equinoxes, rising and setting times, times of lunar phases 22 | * coordinate transformations 23 | * corrections for precession, nutation, parallax, aberration, atmospheric refraction 24 | * calculation of the physical ephemeris for Mars, Jupiter, and the rings of Saturn 25 | * finding position angles, illuminated fractions, visual magnitudes 26 | * and [much more](https://saurvs.github.io/astro-rust/). 27 | 28 | ## Usage 29 | 30 | * Add the dependency ```astro``` in your ```Cargo.toml``` 31 | ```toml 32 | [dependencies] 33 | astro = "2.0.0" 34 | ``` 35 | 36 | * Include the crate ```astro``` in your code 37 | ```rust 38 | extern crate astro; 39 | 40 | use astro::*; 41 | ``` 42 | 43 | * Specify your time of interest using the [Julian day](http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html) 44 | ```rust 45 | // for example, the time of the Apollo 11 moon landing 46 | 47 | let day_of_month = time::DayOfMonth{day : 20, 48 | hr : 20, 49 | min : 18, 50 | sec : 4.0, 51 | time_zone: 0.0}; 52 | 53 | let date = time::Date{year : 1969, 54 | month : 7, // July 55 | decimal_day: time::decimal_day(&day_of_month), 56 | cal_type : time::CalType::Gregorian}; 57 | 58 | let julian_day = time::julian_day(&date); 59 | 60 | // for higher accuracy in specifying the time of interest, 61 | // find the Julian Ephemeris day; this slightly differs from 62 | // the Julian day by ΔT, which is usually a few seconds. you 63 | // can get a reported value of it from the Astronomical 64 | // Almanac, or calculate it using the built-in function 65 | 66 | let delta_t = time::delta_t(date.year, date.month); 67 | 68 | let julian_ephm_day = time::julian_ephemeris_day(julian_day, delta_t); 69 | ``` 70 | 71 | * Find the position of the Sun and the Moon with respect to the Earth 72 | ```rust 73 | 74 | // geocentric ecliptic point and radius vector of the Sun 75 | let (sun_ecl_point, rad_vec_sun) = sun::geocent_ecl_pos(julian_day); 76 | 77 | // sun_ecl_point.long - ecliptic longitude (radians) 78 | // sun_ecl_point.lat - ecliptic latitude (radians) 79 | // rad_vec_sun - distance between the Sun and the Earth (AU) 80 | 81 | // and similarly for the Moon 82 | let (moon_ecl_point, rad_vec_moon) = lunar::geocent_ecl_pos(julian_day); 83 | 84 | ``` 85 | 86 | * Find the position of a planet with respect to the Sun 87 | ```rust 88 | // the heliocentric point and radius vector of a planet, like Jupiter 89 | let (jup_long, jup_lat, rad_vec) = planet::heliocent_pos(&planet::Planet::Jupiter, julian_day); 90 | 91 | // or neptune 92 | let (nep_long, nep_lat, rad_vec) = planet::heliocent_pos(&planet::Planet::Neptune, julian_day); 93 | 94 | // positioning for all the eight planets (and (the dwarf planet) Pluto) is supported 95 | let (plut_long, plut_lat, rad_vec) = pluto::heliocent_pos(julian_day); 96 | ``` 97 | 98 | * Find the geodesic distance between two locations on Earth 99 | ```rust 100 | // geodesic distance between the Observatoire de Paris and 101 | // the US Naval Observatory at Washington DC 102 | 103 | let paris = coords::GeographPoint{long: angle::deg_frm_dms(-2, 20, 14.0).to_radians(), 104 | lat : angle::deg_frm_dms(48, 50, 11.0).to_radians()}; 105 | 106 | let washington = coords::GeographPoint{long: angle::deg_frm_dms(77, 3, 56.0).to_radians(), 107 | lat : angle::deg_frm_dms(38, 55, 17.0).to_radians()}; 108 | 109 | // angle::deg_frm_dms() converts degrees expressed in degrees, 110 | // minutes and seconds into a fractional degree 111 | 112 | let distance = planet::earth::geodesic_dist(&paris, &washington); // in meters 113 | ``` 114 | 115 | * Convert equatorial coordinates to ecliptic coordinates 116 | ```rust 117 | // equatorial coordinates of the star Pollux 118 | 119 | let right_ascension = 116.328942_f64.to_radians(); 120 | let declination = 28.026183_f64.to_radians(); 121 | 122 | // mean obliquity of the ecliptic 123 | 124 | let oblq_eclip = 23.4392911_f64.to_radians(); 125 | 126 | // you can also get oblq_eclip from ecliptic::mn_oblq_IAU(julian_day) 127 | // for the Julian day on which the coordinates of the star 128 | // were observed 129 | 130 | // also make sure to type #[macro_use] before including the crate 131 | // to use macros 132 | 133 | // now, convert equatorial coordinates to ecliptic coordinates 134 | 135 | let (ecl_long, ecl_lat) = ecl_frm_eq!(right_ascension, declination, oblq_eclip); 136 | ``` 137 | 138 | * Convert equatorial coordinates to galactic coordinates 139 | ```rust 140 | // equatorial coordinates of the Nova Serpentis 1978 141 | 142 | let right_ascension = angle::deg_frm_hms(17, 48, 59.74).to_radians(); 143 | let declination = angle::deg_frm_dms(-14, 43, 8.2).to_radians(); 144 | 145 | // convert to galactic coordinates 146 | 147 | let (gal_long, gal_lat) = gal_frm_eq!(right_ascension, declination); 148 | ``` 149 | 150 | * Correct for nutation in different coordinate systems 151 | ```rust 152 | // nutation in ecliptic longitude and obliquity of the ecliptic 153 | let (nut_in_long, nut_in_oblq) = nutation::nutation(julian_day); 154 | 155 | // nutation in equatorial coordinates 156 | let (nut_in_asc, nut_in_dec) = nutation::nutation_in_eq_coords(julian_day); 157 | ``` 158 | 159 | ## Contributing 160 | 161 | Anyone interested to contribute in any way possible is encouraged to do so. Not all the algorithms in Meeus's book have been implemented yet. Documentation and tests need to be written for them as well. Refactored code and minor optimizations for the existing code are also welcome. 162 | 163 | The end goal (of this project) is to build a modern, well-tested, well-documented library of algorithms for future use in astronomy. And Rust is very much the right choice for building that. 164 | 165 | A fun suggestion is the addition of the recent [IAU 2000/2006 precession-nutation model](http://62.161.69.131/iers/conv2010/conv2010_c5.html). This method improves upon the existing model implemented here *"by taking into account the effect of mantle anelasticity, ocean tides, electromagnetic couplings produced between the fluid outer core and the mantle as well as between the solid inner core and fluid outer core"*. 166 | 167 | ## References 168 | 169 | The main reference used as the source of algorithms is the famous book *Astronomical Algorithms by Jean Meeus*, whose almost every chapter has been addressed here, with functions that are well-documented and tests that use example data from the book; in some cases, such as ΔT approximation and planetary heliocentric positioning, more accurate methods have been implemented. 170 | 171 | * Most algorithms: [Astronomical Algorithms, 2nd edition (Meeus)](http://www.willbell.com/math/mc1.htm) 172 | * Planetary heliocentric positioning: [VSOP87-D](http://cdsarc.u-strasbg.fr/viz-bin/qcat?VI/81/) 173 | * Approximating ΔT: [Five Millennium Canon of Solar Eclipses (Espenak and Meeus)](http://eclipse.gsfc.nasa.gov/SEcat5/deltatpoly.html) 174 | * Some physical constants: [World Geodetic System 1984](https://confluence.qps.nl/pages/viewpage.action?pageId=29855173) 175 | -------------------------------------------------------------------------------- /src/aberr.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Corrections for aberration 24 | 25 | use angle; 26 | use time; 27 | use coords; 28 | 29 | /** 30 | Computes solar aberration in ecliptic longitude 31 | 32 | # Returns 33 | 34 | * `abrr`: Solar aberration in ecliptic 35 | longitude *| in radians* 36 | 37 | # Arguments 38 | 39 | * `R`: Sun-Earth distance *| in AU* 40 | **/ 41 | #[inline(always)] 42 | pub fn sol_aberr(R: f64) -> f64 43 | { 44 | -angle::deg_frm_dms(0, 0, 20.4898).to_radians() / R 45 | } 46 | 47 | /** 48 | Computes stellar aberration in equatorial coordinates 49 | 50 | # Returns 51 | 52 | `(abrr_in_asc, abrr_in_dec)` 53 | 54 | * `abrr_in_asc`: Aberration in right ascension *| in radians* 55 | * `abrr_in_dec`: Aberration in declination *| in radians* 56 | 57 | # Arguments 58 | 59 | * `stell_eq_point`: Equatorial coordinates of the star *| in radians* 60 | * `JD` : Julian (Ephemeris) day 61 | **/ 62 | pub fn stell_aberr_in_eq_coords(stell_eq_point: &coords::EqPoint, 63 | JD: f64) -> (f64, f64) 64 | { 65 | let t = time::julian_cent(JD); 66 | 67 | let l2 = 3.1761467 + 1021.3285546*t; 68 | let l3 = 1.7534703 + 628.3075849*t; 69 | let l4 = 6.2034809 + 334.0612431*t; 70 | let l5 = 0.5995465 + 52.9690965*t; 71 | let l6 = 0.8740168 + 21.3299095*t; 72 | let l7 = 5.4812939 + 7.4781599*t; 73 | let l8 = 5.3118863 + 3.8133036*t; 74 | let l1 = 3.8103444 + 8399.6847337*t; 75 | let d = 5.1984667 + 7771.3771486*t; 76 | let m1 = 2.3555559 + 8328.6914289*t; 77 | let f = 1.6279052 + 8433.4661601*t; 78 | 79 | let mut x = 0.0; 80 | let mut y = 0.0; 81 | let mut z = 0.0; 82 | 83 | let mut A; 84 | let mut sinA; 85 | let mut cosA; 86 | 87 | // ROW 1 88 | A = l3; 89 | sinA = A.sin(); cosA = A.cos(); 90 | x += (-1719914.0 - 2.0*t)*sinA - 25.0*cosA; 91 | y += (25.0 - 13.0*t)*sinA + (1578089.0 + 156.0*t)*cosA; 92 | z += (10.0 + 32.0*t)*sinA + (684185.0 - 358.0*t)*cosA; 93 | 94 | // ROW 2 95 | A = 2.0 * l3; 96 | sinA = A.sin(); cosA = A.cos(); 97 | x += (6434.0 + 141.0*t)*sinA + (28007.0 - 107.0*t)*cosA; 98 | y += (25697.0 - 95.0*t)*sinA + (-5904.0 - 130.0*t)*cosA; 99 | z += (11141.0 - 48.0*t)*sinA + (-2559.0 - 55.0*t)*cosA; 100 | 101 | // ROW 3 102 | A = l5; 103 | sinA = A.sin(); cosA = A.cos(); 104 | x += 715.0*sinA; 105 | y += 6.0*sinA - 657.0*cosA; 106 | z += -15.0*sinA - 282.0*cosA; 107 | 108 | // ROW 4 109 | A = l1; 110 | sinA = A.sin(); cosA = A.cos(); 111 | x += 715.0*sinA; 112 | y += -656.0*cosA; 113 | z += -285.0*cosA; 114 | 115 | // ROW 5 116 | A = 3.0 * l3; 117 | sinA = A.sin(); cosA = A.cos(); 118 | x += (486.0 - 5.0*t)*sinA + (-236.0 - 4.0*t)*cosA; 119 | y += (-216.0 - 4.0*t)*sinA + (-446.0 + 5.0*t)*cosA; 120 | z += -94.0*sinA - 193.0*cosA; 121 | 122 | // ROW 6 123 | A = l6; 124 | sinA = A.sin(); cosA = A.cos(); 125 | x += 159.0*sinA; 126 | y += 2.0*sinA - 147.0*cosA; 127 | z += -6.0*sinA - 61.0*cosA; 128 | 129 | // ROW 7 130 | A = f; 131 | cosA = A.cos(); 132 | y += 26.0*cosA; 133 | z += -59.0*cosA; 134 | 135 | // ROW 8 136 | A = l1 + m1; 137 | sinA = A.sin(); cosA = A.cos(); 138 | x += 39.0*sinA; 139 | y += -36.0*cosA; 140 | z += -16.0*cosA; 141 | 142 | // ROW 9 143 | A = 2.0 * l5; 144 | sinA = A.sin(); cosA = A.cos(); 145 | x += 33.0*sinA - 10.0*cosA; 146 | y += -9.0*sinA - 30.0*cosA; 147 | z += -5.0*sinA - 13.0*cosA; 148 | 149 | // ROW 10 150 | A = 2.0*l3 - l5; 151 | sinA = A.sin(); cosA = A.cos(); 152 | x += 31.0*sinA + cosA; 153 | y += sinA - 28.0*cosA; 154 | z += -12.0*cosA; 155 | 156 | // ROW 11 157 | A = 3.0*l3 - 8.0*l4 + 3.0*l5; 158 | sinA = A.sin(); cosA = A.cos(); 159 | x += 8.0*sinA - 28.0*cosA; 160 | y += 25.0*sinA + 8.0*cosA; 161 | z += 11.0*sinA + 3.0*cosA; 162 | 163 | // ROW 12 164 | A = 5.0*l3 - 8.0*l4 + 3.0*l5; 165 | sinA = A.sin(); cosA = A.cos(); 166 | x += 8.0*sinA - 28.0*cosA; 167 | y += -25.0*sinA - 8.0*cosA; 168 | z += -11.0*sinA - 3.0*cosA; 169 | 170 | // ROW 13 171 | A = 2.0*l2 - l3; 172 | sinA = A.sin(); cosA = A.cos(); 173 | x += 21.0*sinA; 174 | y += -19.0*cosA; 175 | z += -8.0*cosA; 176 | 177 | // ROW 14 178 | A = l2; 179 | sinA = A.sin(); cosA = A.cos(); 180 | x += -19.0*sinA; 181 | y += 17.0*cosA; 182 | z += 8.0*cosA; 183 | 184 | // ROW 15 185 | A = l7; 186 | sinA = A.sin(); cosA = A.cos(); 187 | x += 17.0*sinA; 188 | y += -16.0*cosA; 189 | z += -7.0*cosA; 190 | 191 | // ROW 16 192 | A = l3 - 2.0*l5; 193 | sinA = A.sin(); cosA = A.cos(); 194 | x += 16.0*sinA; 195 | y += 15.0*cosA; 196 | z += sinA + 7.0*cosA; 197 | 198 | // ROW 17 199 | A = l8; 200 | sinA = A.sin(); cosA = A.cos(); 201 | x += 16.0*sinA; 202 | y += sinA - 15.0*cosA; 203 | z += -3.0*sinA - 6.0*cosA; 204 | 205 | // ROW 18 206 | A = l3 + l5; 207 | sinA = A.sin(); cosA = A.cos(); 208 | x += 11.0*sinA - cosA; 209 | y += -1.0*sinA - 10.0*cosA; 210 | z += -1.0*sinA - 5.0*cosA; 211 | 212 | // ROW 19 213 | A = 2.0 * (l2 - l3); 214 | sinA = A.sin(); cosA = A.cos(); 215 | x += -11.0*cosA; 216 | y += -10.0*sinA; 217 | z += -4.0*sinA; 218 | 219 | // ROW 20 220 | A = l3 - l5; 221 | sinA = A.sin(); cosA = A.cos(); 222 | x += -11.0*sinA - 2.0*cosA; 223 | y += -2.0*sinA + 9.0*cosA; 224 | z += -1.0*sinA + 4.0*cosA; 225 | 226 | // ROW 21 227 | A = 4.0*l3; 228 | sinA = A.sin(); cosA = A.cos(); 229 | x += -7.0*sinA - 8.0*cosA; 230 | y += -8.0*sinA + 6.0*cosA; 231 | z += 3.0 * (cosA - sinA); 232 | 233 | // ROW 22 234 | A = 3.0*l3 - 2.0*l5; 235 | sinA = A.sin(); cosA = A.cos(); 236 | x += -10.0*sinA; 237 | y += 9.0*cosA; 238 | z += 4.0*cosA; 239 | 240 | // ROW 23 241 | A = l2 - 2.0*l3; 242 | sinA = A.sin(); cosA = A.cos(); 243 | x += -9.0*sinA; 244 | y += -9.0*cosA; 245 | z += -4.0*cosA; 246 | 247 | // ROW 24 248 | A = 2.0*l2 - 3.0*l3; 249 | sinA = A.sin(); cosA = A.cos(); 250 | x += -9.0*sinA; 251 | y += -8.0*cosA; 252 | z += -4.0*cosA; 253 | 254 | // ROW 25 255 | A = 2.0*l6; 256 | sinA = A.sin(); cosA = A.cos(); 257 | x += -9.0*cosA; 258 | y += -8.0*sinA; 259 | z += -3.0*sinA; 260 | 261 | // ROW 26 262 | A = 2.0*l2 - 4.0*l3; 263 | sinA = A.sin(); cosA = A.cos(); 264 | x += -9.0*cosA; 265 | y += 8.0*sinA; 266 | z += 3.0*sinA; 267 | 268 | // ROW 27 269 | A = 3.0*l3 - 2.0*l4; 270 | sinA = A.sin(); cosA = A.cos(); 271 | x += 8.0*sinA; 272 | y += -8.0*cosA; 273 | z += -3.0*cosA; 274 | 275 | // ROW 28 276 | A = l1 + 2.0*d - m1; 277 | sinA = A.sin(); cosA = A.cos(); 278 | x += 8.0*sinA; 279 | y += -7.0*cosA; 280 | z += -3.0*cosA; 281 | 282 | // ROW 29 283 | A = 8.0*l2 - 12.0*l3; 284 | sinA = A.sin(); cosA = A.cos(); 285 | x += -4.0*sinA - 7.0*cosA; 286 | y += -6.0*sinA + 4.0*cosA; 287 | z += -3.0*sinA + 2.0*cosA; 288 | 289 | // ROW 30 290 | A = 8.0*l2 - 14.0*l3; 291 | sinA = A.sin(); cosA = A.cos(); 292 | x += -4.0*sinA - 7.0*cosA; 293 | y += 6.0*sinA - 4.0*cosA; 294 | z += 3.0*sinA - 2.0*cosA; 295 | 296 | // ROW 31 297 | A = 2.0*l4; 298 | sinA = A.sin(); cosA = A.cos(); 299 | x += -6.0*sinA - 5.0*cosA; 300 | y += -4.0*sinA + 5.0*cosA; 301 | z += 2.0 * (cosA - sinA); 302 | 303 | // ROW 32 304 | A = 3.0*l2 - 4.0*l3; 305 | sinA = A.sin(); cosA = A.cos(); 306 | x += -1.0 * (sinA + cosA); 307 | y += -2.0*sinA - 7.0*cosA; 308 | z += sinA - 4.0*cosA; 309 | 310 | // ROW 33 311 | A = 2.0 * (l3 - l5); 312 | sinA = A.sin(); cosA = A.cos(); 313 | x += 4.0*sinA - 6.0*cosA; 314 | y += -5.0*sinA - 4.0*cosA; 315 | z += -2.0 * (sinA + cosA); 316 | 317 | // ROW 34 318 | A = 3.0 * (l2 - l3); 319 | sinA = A.sin(); cosA = A.cos(); 320 | x += -7.0*cosA; 321 | y += -6.0*sinA; 322 | z += -3.0*sinA; 323 | 324 | // ROW 35 325 | A = 2.0 * (l3 - l4); 326 | sinA = A.sin(); cosA = A.cos(); 327 | x += 5.0 * (sinA - cosA); 328 | y += -4.0*sinA - 5.0*cosA; 329 | z += -2.0 * (sinA + cosA); 330 | 331 | // ROW 36 332 | A = l1 - 2.0*d; 333 | sinA = A.sin(); cosA = A.cos(); 334 | x += 5.0*sinA; 335 | y += -5.0*cosA; 336 | z += -2.0*cosA; 337 | 338 | let c = 17314463350.0; 339 | 340 | let (asc, dec) = (stell_eq_point.asc, stell_eq_point.dec); 341 | 342 | let delta_asc = (y*asc.cos() - x*asc.sin()) / (c*dec.cos()); 343 | let delta_dec = -(((x*asc.cos() + y*asc.sin())*dec.sin() - z*dec.cos())) / c; 344 | 345 | (delta_asc, delta_dec) 346 | } 347 | -------------------------------------------------------------------------------- /src/angle.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Angles for astronomy 24 | 25 | use std; 26 | 27 | pub const TWO_PI: f64 = 2.0 * std::f64::consts::PI; 28 | 29 | /** 30 | Computes the angular separation between two angular points 31 | 32 | # Arguments 33 | 34 | * `p1a1`: Angle 1 of point 1 *| in radians* 35 | * `p1a2`: Angle 2 of point 1 *| in radians* 36 | * `p2a1`: Angle 1 of point 2 *| in radians* 37 | * `p2a2`: Angle 2 of point 2 *| in radians* 38 | 39 | Angle 1 may be right ascension or longitude. 40 | Angle 2 may be declination or latitude. 41 | **/ 42 | #[inline] 43 | pub fn anglr_sepr(p1a1: f64, p1a2: f64, p2a1: f64, p2a2: f64) -> f64 44 | { 45 | ( 46 | p1a2.sin() * p2a2.sin() 47 | + p1a2.cos() * p2a2.cos() * (p1a1 - p2a1).cos() 48 | ).acos() 49 | } 50 | 51 | /** 52 | Computes an angle in degrees with decimals, from an angle 53 | expressed in degrees, arcminutes and arcseconds 54 | 55 | # Returns 56 | 57 | * `deg`: Angle in degrees with decimals 58 | 59 | # Arguments 60 | 61 | * `deg`: Degrees 62 | * `min`: Arcminutes 63 | * `sec`: Arcseconds 64 | **/ 65 | #[inline] 66 | pub fn deg_frm_dms(deg: i64, min: i64, sec: f64) -> f64 67 | { 68 | let (M, S) = 69 | if deg < 0 { (-min.abs(), -sec.abs()) } 70 | else { (min, sec) }; 71 | 72 | (deg as f64) + (M as f64)/60.0 + S/3600.0 73 | } 74 | 75 | /** 76 | Computes an angle expressed in degrees, arcminutes and 77 | arcseconds, from an angle in degrees with decimals 78 | 79 | # Returns 80 | 81 | `(deg, min, sec)` 82 | 83 | * `deg`: Degrees 84 | * `min`: Arcminutes 85 | * `sec`: Arcseconds 86 | 87 | # Arguments 88 | 89 | * `deg`: Angle in degrees with decimals 90 | **/ 91 | #[inline] 92 | pub fn dms_frm_deg(deg: f64) -> (i64, i64, f64) 93 | { 94 | let degree = deg as i64; 95 | 96 | let minutes = (deg - (degree as f64)) * 60.0; 97 | let minute = minutes as i64; 98 | 99 | let seconds = (minutes - (minute as f64)) * 60.0; 100 | 101 | (degree, minute, seconds) 102 | } 103 | 104 | /** 105 | Computes an angle in degrees with decimals, from an angle 106 | expressed in hours, minutes and seconds 107 | 108 | # Arguments 109 | 110 | * `hours`: Hours 111 | * `min`: Minutes 112 | * `sec`: Seconds 113 | **/ 114 | #[inline] 115 | pub fn deg_frm_hms(hour: i64, min: i64, sec: f64) -> f64 116 | { 117 | 15.0 * ((hour as f64) + (min as f64)/60.0 + sec/3600.0) 118 | } 119 | 120 | /** 121 | Computes an angle expressed in hours, minutes and 122 | seconds, from an angle in degrees with decimals 123 | 124 | # Returns 125 | 126 | `(deg, min, sec)` 127 | 128 | * `hour`: Hours 129 | * `min`: Minutes 130 | * `sec`: Seconds 131 | 132 | # Arguments 133 | 134 | * `deg`: Angle in degrees with decimals 135 | **/ 136 | #[inline] 137 | pub fn hms_frm_deg(deg: f64) -> (i64, i64, f64) 138 | { 139 | let hours = deg / 15.0; 140 | let hour = hours as i64; 141 | 142 | let minutes = (hours - (hour as f64)) * 60.0; 143 | let minute = minutes as i64; 144 | 145 | let seconds = (minutes - (minute as f64)) * 60.0; 146 | 147 | (hour, minute, seconds) 148 | } 149 | 150 | /** 151 | Computes the equivalent angle in [0, 360] degree range 152 | 153 | # Arguments 154 | 155 | * `angl`: Angle *| in degrees* 156 | **/ 157 | #[inline] 158 | pub fn limit_to_360(angl: f64) -> f64 159 | { 160 | let n = (angl / 360.0) as i64; 161 | let limited_angl = angl - (360.0 * (n as f64)); 162 | 163 | if limited_angl < 0.0 { limited_angl + 360.0 } 164 | else { limited_angl } 165 | } 166 | 167 | /** 168 | Computes the equivalent angle in [0, 2π] radian range 169 | 170 | # Arguments 171 | 172 | * `angl`: Angle *| in radians* 173 | **/ 174 | #[inline] 175 | pub fn limit_to_two_PI(angl: f64) -> f64 176 | { 177 | let n = (angl / TWO_PI) as i64; 178 | let limited_angl = angl - (TWO_PI * (n as f64)); 179 | 180 | if limited_angl < 0.0 { limited_angl + TWO_PI } 181 | else { limited_angl } 182 | } 183 | -------------------------------------------------------------------------------- /src/asteroid.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Diameters of asteroids 24 | 25 | /** 26 | Computes the diameter of an asteroid 27 | 28 | # Returns 29 | 30 | * `diameter`: Diameter of the asteroid *| in meters* 31 | 32 | # Arguments 33 | 34 | * `abs_mag`: Absolute magnitude of the asteroid 35 | * `albedo` : Reflective power of the asteroid 36 | **/ 37 | #[inline] 38 | pub fn diameter(abs_mag: f64, albedo: f64) -> f64 39 | { 40 | 1000.0 * 10_f64.powf ( 41 | 3.12 - abs_mag/5.0 - 0.217147*albedo.log10() 42 | ) 43 | } 44 | 45 | /** 46 | Computes the apparent diameter of an asteroid 47 | 48 | # Returns 49 | 50 | * `apparent_diameter`: Apparent diameter of the asteroid *| in meters* 51 | 52 | # Arguments 53 | 54 | * `true_diameter` : True diameter of the asteroid *| in kilometers* 55 | * `asteroid_earth_dist`: Asteroid-Earth distance *| in AU* 56 | **/ 57 | #[inline] 58 | pub fn apparent_diameter(true_diameter: f64, asteroid_earth_dist: f64) -> f64 59 | { 60 | 1.3788 * true_diameter/asteroid_earth_dist 61 | } 62 | -------------------------------------------------------------------------------- /src/atmos.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Corrections for atmospheric refraction 24 | 25 | use angle; 26 | use std::f64::consts::PI; 27 | 28 | /** 29 | Computes the refraction term for true altitudes greater than 15 30 | degrees 31 | 32 | # Returns 33 | 34 | * `refrac_term`: The refraction term *| in radians*, that needs to be 35 | subtracted from the apparent altitude to get the 36 | true altitude 37 | 38 | # Arguments 39 | 40 | * `apprnt_alt`: Apparent altitude *| in radians* 41 | **/ 42 | pub fn refrac_frm_apprnt_alt_15(apprnt_alt: f64) -> f64 43 | { 44 | let x = 45 | angle::deg_frm_dms(0, 0, 0.0668).to_radians() 46 | * (PI - apprnt_alt).tan(); 47 | 48 | angle::deg_frm_dms(0, 0, 58.294).to_radians() * (PI - apprnt_alt).tan() 49 | - x * x * x 50 | } 51 | 52 | /** 53 | Computes the refraction term for apparent altitudes greater than 15 54 | degrees 55 | 56 | # Returns 57 | 58 | * `refrac_term`: The refraction term *| in radians*, that needs to be 59 | added to the true altitude to get the apparent 60 | altitude 61 | 62 | # Arguments 63 | 64 | * `true_alt`: True altitude *| in radians* 65 | **/ 66 | pub fn refrac_frm_true_alt_15(true_alt: f64) -> f64 67 | { 68 | let x = 69 | angle::deg_frm_dms(0, 0, 0.0824).to_radians() 70 | * (PI - true_alt).tan(); 71 | 72 | angle::deg_frm_dms(0, 0, 58.276).to_radians() * (PI - true_alt).tan() 73 | - x * x * x 74 | } 75 | 76 | /** 77 | Computes the refraction term for true altitude 78 | 79 | # Returns 80 | 81 | * `refrac_term`: The refraction term *| in radians*, that needs to be 82 | subtracted from the apparent altitude to get the 83 | rue altitude 84 | 85 | The accuracy of `refrac_term` is upto 0.07 arcminutes. 86 | 87 | # Arguments 88 | 89 | * `apprnt_alt`: Apparent altitude *| in radians* 90 | **/ 91 | pub fn refrac_frm_apprnt_alt(apprnt_alt: f64) -> f64 92 | { 93 | if apprnt_alt == PI { 0.0 } 94 | else { 95 | let apprnt_alt_deg = apprnt_alt.to_degrees(); 96 | let a = apprnt_alt_deg + 7.31/(apprnt_alt_deg + 4.4); 97 | let R = 1.0 / a.to_radians().tan(); 98 | 99 | (R / 60.0).to_radians() 100 | } 101 | } 102 | 103 | /** 104 | Computes the refraction term for apparent altitude 105 | 106 | This function is consistent with `refrac_frm_apprnt_alt()` to 107 | within 4 arcseconds. 108 | 109 | # Returns 110 | 111 | * `refrac_term`: The refraction term *| in radians*, that needs to be 112 | added to the true altitude to get the apparent 113 | altitude 114 | 115 | # Arguments 116 | 117 | * `true_alt`: True altitude *| in radians* 118 | **/ 119 | pub fn refrac_frm_true_alt(true_alt: f64) -> f64 120 | { 121 | if true_alt == PI { 0.0 } 122 | else { 123 | let true_alt_deg = true_alt.to_degrees(); 124 | let a = true_alt_deg + 10.3/(true_alt_deg + 5.11); 125 | let R = 1.02 / a.to_radians().tan(); 126 | 127 | (R / 60.0).to_radians() 128 | } 129 | } 130 | 131 | /** 132 | Computes the refraction term modifier for local pressure 133 | 134 | # Returns 135 | 136 | * `refrac_term_modifier`: The value that needs to be multiplied by 137 | the refraction term to account for local 138 | pressure 139 | 140 | # Arguments 141 | 142 | * `pressure`: Local pressure *| in millibars* 143 | **/ 144 | #[inline(always)] 145 | pub fn refrac_by_pressr(pressure: f64) -> f64 146 | { 147 | pressure / 1010.0 148 | } 149 | 150 | /** 151 | Computes the refraction term modifier for local temperature 152 | 153 | # Returns 154 | 155 | * `refrac_term_modifier`: The value that needs to be multiplied by 156 | the refraction term to account for local 157 | temperature 158 | 159 | # Arguments 160 | 161 | * `temp`: Local temperature *| in kelvins* 162 | **/ 163 | #[inline(always)] 164 | pub fn refrac_by_temp(temp: f64) -> f64 165 | { 166 | 283.0 / temp 167 | } 168 | -------------------------------------------------------------------------------- /src/binary_star.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Binary stars 24 | 25 | use angle; 26 | 27 | /** 28 | Computes mean annual motion of companion star 29 | 30 | * `P`: Period of revolution of binary star 31 | (*mean solar year*) 32 | **/ 33 | 34 | #[inline] 35 | pub fn mn_ann_motion_of_compan(P: f64) -> f64 36 | { 37 | angle::TWO_PI / P 38 | } 39 | 40 | /** 41 | Computes mean anomaly of companion star 42 | 43 | # Arguments 44 | 45 | * `n`: Mean annual motion of companion star 46 | * `t`: Current time, given as year with 47 | decimals (eg: 1945.62) 48 | * `T`: Time of periastron passage, given as 49 | a year with decimals (eg: 1945.62) 50 | **/ 51 | 52 | #[inline] 53 | pub fn mn_anom_of_compan(n: f64, t: f64, T: f64) -> f64 54 | { 55 | n * (t - T) 56 | } 57 | 58 | /** 59 | Computes radius vector of a binary star 60 | 61 | # Arguments 62 | 63 | * `a` : Apparent semimajor axis 64 | * `e` : Eccentricity of true orbit 65 | * `ecc_anom`: Eccentric anomaly of binary star 66 | **/ 67 | 68 | #[inline] 69 | pub fn rad_vec(a: f64, e: f64, ecc_anom: f64) -> f64 70 | { 71 | a * (1.0 - e*ecc_anom.cos()) 72 | } 73 | 74 | /** 75 | Computes true anomaly of a binary star 76 | 77 | # Arguments 78 | 79 | * `e` : Eccentricity of true orbit 80 | * `ecc_anom`: Eccentric anomaly of binary star 81 | **/ 82 | 83 | #[inline] 84 | pub fn true_anom(e: f64, ecc_anom: f64) -> f64 85 | { 86 | 2.0 * ( 87 | ((1.0 + e)/(1.0 - e)).sqrt() * (ecc_anom / 2.0).tan() 88 | ).atan() 89 | } 90 | 91 | /** 92 | Computes apparent position angle of a binary star 93 | 94 | # Arguments 95 | 96 | * `asc_node_coords`: Position angle of ascending node 97 | * `true_anom` : True anomaly of binary star 98 | * `w` : Longitude of periastron 99 | * `i` : Inclination of true orbit to a 100 | plane at right angles to the 101 | line of sight *| in radians* 102 | **/ 103 | pub fn apprnt_coords_angl(asc_node_coords: f64, true_anom: f64, 104 | w: f64, i: f64) -> f64 105 | { 106 | let x = ( 107 | (true_anom + w).sin() * i.cos() 108 | ).atan2((true_anom + w).cos()); 109 | 110 | angle::limit_to_two_PI(x + asc_node_coords) 111 | } 112 | 113 | /** 114 | Computes angular separation of a binary star 115 | 116 | # Arguments 117 | 118 | * `rad_vec` : Radius vector of a binary star 119 | * `true_anom`: True anomaly of a binary star 120 | * `w` : Longitude of periastron 121 | * `i` : Inclination of true orbit to a 122 | plane at right angles to the 123 | line of sight *| in radians* 124 | **/ 125 | pub fn anglr_sepr(rad_vec: f64, true_anom: f64, w: f64, i: f64) -> f64 126 | { 127 | rad_vec * ( 128 | ((true_anom + w).sin() * i.cos()).powi(2) 129 | + (true_anom + w).cos().powi(2) 130 | ).sqrt() 131 | } 132 | 133 | /** 134 | Computes eccentricity of an apparent orbit 135 | 136 | # Arguments 137 | 138 | * `e`: Eccentricity of the true orbit 139 | * `i`: Inclination of true orbit 140 | to plane at right angles to line 141 | of sight *| in radians* 142 | * `w`: Longitude of periastron 143 | **/ 144 | pub fn ecc_of_apprnt_orb(e: f64, w: f64, i: f64) -> f64 145 | { 146 | let i_cos = i.cos(); 147 | let e_w_cos = e * w.cos(); 148 | let e_w_cos_sqr = e_w_cos * e_w_cos; 149 | 150 | let a = (1.0 - e_w_cos_sqr) * i_cos * i_cos; 151 | let b = e * w.sin() * e_w_cos * i_cos; 152 | let c = 1.0 - e_w_cos_sqr; 153 | let d = ((a - c)*(a - c) + 4.0*b*b).sqrt(); 154 | 155 | ((2.0 * d) / (a + c + d)).sqrt() 156 | } 157 | -------------------------------------------------------------------------------- /src/consts/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Some physical constants 24 | 25 | pub mod wgs72; 26 | pub mod wgs84; 27 | 28 | /// Gaussian gravitational constant *| in radians* 29 | pub const GAUSS_GRAV: f64 = 0.01720209895; 30 | 31 | /// Speed of light in vaccum *| in meters per second* 32 | pub const SPEED_OF_LIGHT: f64 = 299792458.0; 33 | 34 | /// Earth-Moon mass ratio 35 | pub const EARTH_MOON_MASS_RATIO: f64 = 81.3007; 36 | 37 | /// Sun-Earth mass ratio 38 | pub const SUN_EARTH_MASS_RATIO: f64 = 332946.0; 39 | -------------------------------------------------------------------------------- /src/consts/wgs72.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! World Geodetic System 1972 24 | 25 | /// Equatorial radius of the Earth (Semimajor axis) *| in meters* 26 | pub const EQUATORIAL_RADIUS: f64 = 6378135.0; 27 | 28 | /// Polar radius of the Earth (Semiminor axis) *| in meters* 29 | pub const POLAR_RADIUS: f64 = EQUATORIAL_RADIUS * (1.0 - FLATTENING); 30 | 31 | /// Flattening 32 | pub const FLATTENING: f64 = 1.0 / 298.26; 33 | 34 | /// Angular velocity of the Earth *| in radians / second* 35 | pub const ANGULAR_VELOCITY: f64 = 7.292115147e-5; 36 | 37 | /// Gravitational constant (including the mass of the Earth's 38 | /// atmosphere) *| in meters^3 / second^2* 39 | pub const GRAV_CONST: f64 = 3.986008e+14; 40 | -------------------------------------------------------------------------------- /src/consts/wgs84.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! World Geodetic System 1984 24 | 25 | /// Equatorial radius of the Earth (Semimajor axis) *| in meters* 26 | pub const EQUATORIAL_RADIUS: f64 = 6378137.0; 27 | 28 | /// Polar radius of the Earth (Semiminor axis) *| in meters* 29 | pub const POLAR_RADIUS: f64 = EQUATORIAL_RADIUS * (1.0 - FLATTENING); 30 | 31 | /// Flattening 32 | pub const FLATTENING: f64 = 1.0 / 298.257223563; 33 | 34 | /// Angular velocity of the Earth *| in radians / second* 35 | pub const ANGULAR_VELOCITY: f64 = 7.292115e-5; 36 | 37 | /// Gravitational constant (including the mass of the Earth's 38 | /// atmosphere) *| in meters^3 / second^2* 39 | pub const GRAV_CONST: f64 = 3.986004418e+14; 40 | -------------------------------------------------------------------------------- /src/ecliptic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! The Earth's ecliptic 24 | 25 | use angle; 26 | use std::f64::consts::PI; 27 | use time; 28 | 29 | /** 30 | Computes the mean obliquity of the ecliptic using 31 | J. Laskar's formula 32 | 33 | # Returns 34 | 35 | * `mn_oblq`: Mean obliquity of the ecliptic *| in radians* 36 | 37 | The accuracy of `mn_oblq` is estimated to be 0.01 arcseconds 38 | for 1000 years before and after 2000 AD, and a few arcseconds 39 | for 10000 years before and after 2000 AD. 40 | 41 | # Arguments 42 | 43 | * `JD`: Julian (Ephemeris) day 44 | **/ 45 | pub fn mn_oblq_laskar(JD: f64) -> f64 46 | { 47 | let u = time::julian_cent(JD) / 100.0; 48 | 49 | Horner_eval!( 50 | u, 51 | angle::deg_frm_dms(23, 26, 21.448), 52 | -angle::deg_frm_dms(0, 0, 4680.93), 53 | -angle::deg_frm_dms(0, 0, 1.55), 54 | angle::deg_frm_dms(0, 0, 1999.25), 55 | -angle::deg_frm_dms(0, 0, 51.38), 56 | -angle::deg_frm_dms(0, 0, 249.67), 57 | -angle::deg_frm_dms(0, 0, 39.05), 58 | angle::deg_frm_dms(0, 0, 7.12), 59 | angle::deg_frm_dms(0, 0, 27.87), 60 | angle::deg_frm_dms(0, 0, 5.79), 61 | angle::deg_frm_dms(0, 0, 2.45) 62 | ).to_radians() 63 | } 64 | 65 | /** 66 | Computes the mean obliquity of the ecliptic using 67 | the IAU formula 68 | 69 | # Returns 70 | 71 | * `mn_oblq`: Mean obliquity of the ecliptic *| in radians* 72 | 73 | The error in `mn_oblq` reaches 1 arcsecond over a period of 74 | 2000 years from 2000 AD, and about 10 arcseconds over a period of 75 | 4000 years from 2000 AD. 76 | 77 | # Arguments 78 | 79 | * `JD`: Julian (Ephemeris) day 80 | **/ 81 | pub fn mn_oblq_IAU(JD: f64) -> f64 82 | { 83 | let u = time::julian_cent(JD) / 100.0; 84 | 85 | Horner_eval!( 86 | u, 87 | angle::deg_frm_dms(23, 26, 21.448), 88 | -angle::deg_frm_dms(0, 0, 46.815), 89 | -angle::deg_frm_dms(0, 0, 0.00059), 90 | angle::deg_frm_dms(0, 0, 0.001813) 91 | ).to_radians() 92 | } 93 | 94 | /** 95 | Computes the longitudes of the two ecliptic points on 96 | a horizon on Earth 97 | 98 | # Returns 99 | 100 | `(long_point_1, long_point_2)` 101 | 102 | * `long_point_1`: Longitude of ecliptic point 1 *| in radians* 103 | * `long_point_2`: Longitude of ecliptic point 2 *| in radians* 104 | 105 | # Arguments 106 | 107 | * `oblq_eclip` : Obliquity of the ecliptic *| in radians* 108 | * `observer_lat`: The observer's geographical latitude *| in radians* 109 | * `loc_sidreal` : Local sidereal time *| in radians* 110 | **/ 111 | pub fn eclip_points_on_hz(oblq_eclip: f64, observer_lat: f64, 112 | loc_sidreal: f64) -> (f64, f64) 113 | { 114 | let p = (-loc_sidreal.cos()).atan2 ( 115 | oblq_eclip.sin() * observer_lat.tan() 116 | + oblq_eclip.cos() * loc_sidreal.sin() 117 | ); 118 | 119 | (p, p + PI) 120 | } 121 | 122 | /** 123 | Computes the angle between the ecliptic and a horizon 124 | on Earth 125 | 126 | # Returns 127 | 128 | * `angle`: Angle between the ecliptic and the horizon *| in radians* 129 | 130 | # Arguments 131 | 132 | * `oblq_eclip` : Obliquity of the ecliptic *| in radians* 133 | * `observer_lat`: The observer's geographical latitude *| in radians* 134 | * `loc_sidreal` : Local sidereal time *| in radians* 135 | **/ 136 | pub fn angl_betwn_eclip_and_hz(oblq_eclip: f64, observer_lat: f64, 137 | loc_sidreal: f64) -> f64 138 | { 139 | ( 140 | oblq_eclip.cos() * observer_lat.sin() 141 | - oblq_eclip.sin() * observer_lat.cos() * loc_sidreal.sin() 142 | ).acos() 143 | } 144 | -------------------------------------------------------------------------------- /src/interpol.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Interpolation of intermediate values of functions 24 | 25 | /** 26 | Interpolates an intermediate value of a function from three of it's 27 | given values 28 | 29 | # Returns 30 | 31 | * `interpol_val`: Intermediate value of the function 32 | 33 | # Arguments 34 | 35 | * `y1`: Value 1 of the function 36 | * `y2`: Value 2 of the function 37 | * `y3`: Value 3 of the function 38 | * `n` : Interpolating factor, measured from the central value 39 | `y2`, positively towards `y3` 40 | **/ 41 | 42 | #[inline] 43 | pub fn three_values(y1: f64, y2: f64, y3: f64, n: f64) -> f64 44 | { 45 | let a = y2 - y1; 46 | let b = y3 - y2; 47 | let c = b - a; 48 | 49 | y2 + n*(a + b + n*c)/2.0 50 | } 51 | 52 | /** 53 | Interpolates an intermediate value of a function from five of it's 54 | given values 55 | 56 | # Returns 57 | 58 | * `interpol_val`: Intermediate value of the function 59 | 60 | # Arguments 61 | 62 | * `y1`: Value 1 of the function 63 | * `y2`: Value 2 of the function 64 | * `y3`: Value 3 of the function 65 | * `y4`: Value 4 of the function 66 | * `y5`: Value 5 of the function 67 | * `n` : Interpolating factor, measured from the central value 68 | `y3`, positively towards `y4` 69 | **/ 70 | pub fn five_values(y1: f64, y2: f64, y3: f64, y4: f64, y5: f64, n: f64) -> f64 71 | { 72 | let a = y2 - y1; 73 | let b = y3 - y2; 74 | let c = y4 - y3; 75 | let d = y5 - y4; 76 | 77 | let e = b - a; 78 | let f = c - b; 79 | let g = d - c; 80 | 81 | let h = f - e; 82 | let j = g - f; 83 | 84 | let k = (j - h) / 12.0; 85 | let h_j_12 = (h + j) / 6.0; 86 | 87 | y3 + 88 | Horner_eval!( 89 | n, 90 | 0.0, 91 | b + c - h_j_12, 92 | f - k, 93 | h_j_12, 94 | k 95 | ) / 2.0 96 | } 97 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | #![allow(non_camel_case_types)] 25 | 26 | #[macro_use] 27 | pub mod util; 28 | 29 | #[macro_use] 30 | pub mod coords; 31 | pub mod aberr; 32 | pub mod angle; 33 | pub mod asteroid; 34 | pub mod atmos; 35 | pub mod binary_star; 36 | pub mod consts; 37 | pub mod ecliptic; 38 | pub mod interpol; 39 | pub mod lunar; 40 | pub mod misc; 41 | pub mod nutation; 42 | pub mod orbit; 43 | pub mod parallax; 44 | pub mod planet; 45 | pub mod pluto; 46 | pub mod precess; 47 | pub mod star; 48 | pub mod sun; 49 | pub mod time; 50 | pub mod transit; 51 | -------------------------------------------------------------------------------- /src/misc.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Miscellaneous routines 24 | 25 | /** 26 | Computes the parallactic angle of a celestial body 27 | 28 | # Returns 29 | 30 | * `parallac_angle`: Parallactic angle of the celestial 31 | body *| in radians* 32 | 33 | # Arguments 34 | 35 | * `observer_lat`: The observer's geographical latitude *| in radians* 36 | * `hour_angle` : Local hour angle *| in radians* 37 | * `dec` : Declination of the celestial body *| in radians* 38 | **/ 39 | #[inline] 40 | pub fn parllc_angl(observer_lat: f64, hour_angle: f64, dec: f64) -> f64 41 | { 42 | hour_angle.sin().atan2 ( 43 | observer_lat.tan() * dec.cos() 44 | - hour_angle.cos() * dec.sin() 45 | ) 46 | } 47 | 48 | /** 49 | Computes the parallactic angle of a celestial body on the 50 | horizon 51 | 52 | # Returns 53 | 54 | * `parallac_angle`: Parallactic angle of the celestial body 55 | on the horizon *| in radians* 56 | 57 | # Arguments 58 | 59 | * `observer_lat`: The observer's geographical latitude *| in radians* 60 | * `dec` : Declination of the celestial body *| in radians* 61 | **/ 62 | #[inline] 63 | pub fn parllc_angl_on_hz(observer_lat: f64, dec: f64) -> f64 64 | { 65 | (observer_lat.sin() / dec.cos()).acos() 66 | } 67 | -------------------------------------------------------------------------------- /src/nutation.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Corrections for nutation 24 | 25 | use angle; 26 | use time; 27 | use coords; 28 | 29 | /** 30 | Computes nutation in ecliptic longitude and obliquity 31 | 32 | # Returns 33 | 34 | `(nut_in_long, nut_in_oblq)` 35 | 36 | * `nut_in_long`: Nutation in ecliptic longitude *| in radians* 37 | * `nut_in_oblq`: Nutation in obliquity of the ecliptic *| in radians* 38 | 39 | # Arguments 40 | 41 | `JD`: Julian (Ephemeris) day 42 | **/ 43 | pub fn nutation(JD: f64) -> (f64, f64) 44 | { 45 | struct terms(i8, i8, i8, i8, i8, i32, i32, i32, i16); 46 | let terms_for_nutation = [ 47 | terms( 0, 0, 0, 0, 1, -171996, -1742, 92025, 89), 48 | terms(-2, 0, 0, 2, 2, -13187, -16, 5736, -31), 49 | terms( 0, 0, 0, 2, 2, -2274, -2, 977, -5), 50 | terms( 0, 0, 0, 0, 2, 2062, 2, -895, 5), 51 | terms( 0, 1, 0, 0, 0, 1426, -34, 54, -1), 52 | terms( 0, 0, 1, 0, 0, 712, 1, -7, 0), 53 | terms(-2, 1, 0, 2, 2, -517, 12, 224, -6), 54 | terms( 0, 0, 0, 2, 1, -386, -4, 200, 0), 55 | terms( 0, 0, 1, 2, 2, -301, 0, 129, -1), 56 | terms(-2, -1, 0, 2, 2, 217, -5, -95, 3), 57 | terms(-2, 0, 1, 0, 0, -158, 0, 0, 0), 58 | terms(-2, 0, 0, 2, 1, 129, 1, -70, 0), 59 | terms( 0, 0, -1, 2, 2, 123, 0, -53, 0), 60 | terms( 2, 0, 0, 0, 0, 63, 0, 0, 0), 61 | terms( 0, 0, 1, 0, 1, 63, 1, -33, 0), 62 | terms( 2, 0, -1, 2, 2, -59, 0, 26, 0), 63 | terms( 0, 0, -1, 0, 1, -58, -1, 32, 0), 64 | terms( 0, 0, 1, 2, 1, -51, 0, 27, 0), 65 | terms(-2, 0, 2, 0, 0, 48, 0, 0, 0), 66 | terms( 0, 0, -2, 2, 1, 46, 0, -24, 0), 67 | terms( 2, 0, 0, 2, 2, -38, 0, 16, 0), 68 | terms( 0, 0, 2, 2, 2, -31, 0, 13, 0), 69 | terms( 0, 0, 2, 0, 0, 29, 0, 0, 0), 70 | terms(-2, 0, 1, 2, 2, 29, 0, -12, 0), 71 | terms( 0, 0, 0, 2, 0, 26, 0, 0, 0), 72 | terms(-2, 0, 0, 2, 0, -22, 0, 0, 0), 73 | terms( 0, 0, -1, 2, 1, 21, 0, -10, 0), 74 | terms( 0, 2, 0, 0, 0, 17, -1, 0, 0), 75 | terms( 2, 0, -1, 0, 1, 16, 0, -8, 0), 76 | terms(-2, 2, 0, 2, 2, -16, 1, 7, 0), 77 | terms( 0, 1, 0, 0, 1, -15, 0, 9, 0), 78 | terms(-2, 0, 1, 0, 1, -13, 0, 7, 0), 79 | terms( 0, -1, 0, 0, 1, -12, 0, 6, 0), 80 | terms( 0, 0, 2, -2, 0, 11, 0, 0, 0), 81 | terms( 2, 0, -1, 2, 1, -10, 0, 5, 0), 82 | terms( 2, 0, 1, 2, 2, -8, 0, 3, 0), 83 | terms( 0, 1, 0, 2, 2, 7, 0, -3, 0), 84 | terms(-2, 1, 1, 0, 0, -7, 0, 0, 0), 85 | terms( 0, -1, 0, 2, 2, -7, 0, 3, 0), 86 | terms( 2, 0, 0, 2, 1, -7, 0, 3, 0), 87 | terms( 2, 0, 1, 0, 0, 6, 0, 0, 0), 88 | terms(-2, 0, 2, 2, 2, 6, 0, -3, 0), 89 | terms(-2, 0, 1, 2, 1, 6, 0, -3, 0), 90 | terms( 2, 0, -2, 0, 1, -6, 0, 3, 0), 91 | terms( 2, 0, 0, 0, 1, -6, 0, 3, 0), 92 | terms( 0, -1, 1, 0, 0, 5, 0, 0, 0), 93 | terms(-2, -1, 0, 2, 1, -5, 0, 3, 0), 94 | terms(-2, 0, 0, 0, 1, -5, 0, 3, 0), 95 | terms( 0, 0, 2, 2, 1, -5, 0, 3, 0), 96 | terms(-2, 0, 2, 0, 1, 4, 0, 0, 0), 97 | terms(-2, 1, 0, 2, 1, 4, 0, 0, 0), 98 | terms( 0, 0, 1, -2, 0, 4, 0, 0, 0), 99 | terms(-1, 0, 1, 0, 0, -4, 0, 0, 0), 100 | terms(-2, 1, 0, 0, 0, -4, 0, 0, 0), 101 | terms( 1, 0, 0, 0, 0, -4, 0, 0, 0), 102 | terms( 0, 0, 1, 2, 0, 3, 0, 0, 0), 103 | terms( 0, 0, -2, 2, 2, -3, 0, 0, 0), 104 | terms(-1, -1, 1, 0, 0, -3, 0, 0, 0), 105 | terms( 0, 1, 1, 0, 0, -3, 0, 0, 0), 106 | terms( 0, -1, 1, 2, 2, -3, 0, 0, 0), 107 | terms( 2, -1, -1, 2, 2, -3, 0, 0, 0), 108 | terms( 0, 0, 3, 2, 2, -3, 0, 0, 0), 109 | terms( 2, -1, 0, 2, 2, -3, 0, 0, 0), 110 | ]; 111 | 112 | let t = time::julian_cent(JD); 113 | 114 | let M1 = angle::limit_to_360( 115 | 134.96298 + t*(477198.867398 + t*(0.0086972 + t/56250.0)) 116 | ).to_radians(); 117 | let M = angle::limit_to_360( 118 | 357.52772 + t*(35999.05034 - t*(0.0001603 + t/300000.0)) 119 | ).to_radians(); 120 | let D = angle::limit_to_360( 121 | 297.85036 + t*(445267.11148 - t*(0.0019142 - t/189474.0)) 122 | ).to_radians(); 123 | let F = angle::limit_to_360( 124 | 93.27191 + t*(483202.017538 - t*(0.0036825 - t/327270.0)) 125 | ).to_radians(); 126 | let om = angle::limit_to_360( 127 | 125.04452 - t*(1934.136261 - t*(0.0020708 + t/450000.0)) 128 | ).to_radians(); 129 | 130 | let mut nut_in_long = 0.0; 131 | let mut nut_in_oblq = 0.0; 132 | 133 | let div = 0.0001/3600.0; 134 | 135 | for x in terms_for_nutation.iter() { 136 | let arg = 137 | (x.0 as f64) * D + 138 | (x.1 as f64) * M + 139 | (x.2 as f64) * M1 + 140 | (x.3 as f64) * F + 141 | (x.4 as f64) * om; 142 | 143 | nut_in_long += ((x.5 as f64) + t*(x.6 as f64)/10.0) * arg.sin() * div; 144 | nut_in_oblq += ((x.7 as f64) + t*(x.8 as f64)/10.0) * arg.cos() * div; 145 | } 146 | 147 | (nut_in_long.to_radians(), nut_in_oblq.to_radians()) 148 | } 149 | 150 | /** 151 | Computes nutation in equatorial coordinates 152 | 153 | # Returns 154 | 155 | `(nut_in_asc, nut_in_dec)` 156 | 157 | * `nut_in_asc`: Nutation in right ascension *| in radians* 158 | * `nut_in_dec`: Nutation in declination *| in radians* 159 | 160 | # Arguments 161 | 162 | * `eq_point` : Equatorial point uncorrected for nutation *| in radians* 163 | * `nut_in_long`: Nutation in longitude *| in radians* 164 | * `nut_in_oblq`: Nutation in obliquity *| in radians* 165 | * `tru_oblq` : True obliquity of the ecliptic *| in radians* 166 | 167 | The declination of `eq_point` should not be close to either of the 168 | two of the celestial poles, as the values of nutation returned here 169 | are only from first-order corrections. 170 | **/ 171 | pub fn nutation_in_eq_coords(eq_point: &coords::EqPoint, nut_in_long: f64, 172 | nut_in_oblq : f64, tru_oblq: f64) -> (f64, f64) 173 | { 174 | let (asc, dec) = (eq_point.asc, eq_point.dec); 175 | 176 | let nut_asc = nut_in_long * ( 177 | tru_oblq.cos() 178 | + tru_oblq.sin() * asc.sin() * dec.tan() 179 | ) - asc.cos() * dec.tan() * nut_in_oblq; 180 | 181 | let nut_dec = 182 | tru_oblq.sin() * asc.cos() * nut_in_long 183 | + asc.sin() * nut_in_oblq; 184 | 185 | (nut_asc, nut_dec) 186 | } 187 | -------------------------------------------------------------------------------- /src/orbit/elliptic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Elliptic orbits 24 | 25 | use orbit; 26 | use std::f64::consts::PI; 27 | 28 | /** 29 | Computes the true anomaly of a body in an elliptic orbit 30 | 31 | # Returns 32 | 33 | * `true_anom`: True anomaly of the body *| in radians* 34 | 35 | # Arguments 36 | 37 | * `ecc_anom`: Eccentric anomaly of the body *| in radians* 38 | * `ecc` : Eccentricity of the orbit 39 | **/ 40 | #[inline] 41 | pub fn true_anom(ecc_anom: f64, ecc: f64) -> f64 { 42 | 43 | 2.0 * ((1.0 + ecc).sqrt() * (ecc_anom/2.0).tan()).atan2 ( 44 | (1.0 - ecc).sqrt() 45 | ) 46 | 47 | } 48 | 49 | /** 50 | Computes the radius vector of a body in an elliptic orbit from it's 51 | eccentric anomaly 52 | 53 | # Returns 54 | 55 | * `rad_vec`: Radius vector of the body *| in AU* 56 | 57 | # Arguments 58 | 59 | * `ecc_anom`: Eccentric anomaly of the body *| in radians* 60 | * `a` : Semimajor axis of the orbit *| in AU* 61 | * `ecc` : Eccentricity of the orbit 62 | **/ 63 | #[inline] 64 | pub fn rad_vec_frm_ecc_anom(ecc_anom: f64, a: f64, ecc: f64) -> f64 { 65 | 66 | a * (1.0 - ecc*ecc_anom.cos()) 67 | 68 | } 69 | 70 | /** 71 | Computes the radius vector of a body in an elliptic orbit from it's 72 | true anomaly 73 | 74 | # Returns 75 | 76 | * `rad_vec`: Radius vector of the body *| in AU* 77 | 78 | # Arguments 79 | 80 | * `true_anom`: True anomaly of the body *| in radians* 81 | * `a` : Semimajor axis of the orbit *| in AU* 82 | * `ecc` : Eccentricity of the orbit 83 | **/ 84 | #[inline] 85 | pub fn rad_vec_frm_true_anom(true_anom: f64, a: f64, ecc: f64) -> f64 { 86 | a * (1.0 - ecc*ecc) / (1.0 + ecc*true_anom.cos()) 87 | } 88 | 89 | /** 90 | Computes the eccentric anomaly of a body in an elliptic orbit 91 | 92 | # Returns 93 | 94 | * `ecc_anom`: Eccentric anomaly of the body *| in radians* 95 | 96 | # Arguments 97 | 98 | * `mean_anom`: Mean anomaly of the body *| in radians* 99 | * `ecc` : Eccentricity of the orbit 100 | * `accuracy` : Desired accuracy for the eccentric anomaly. 101 | Eg: 0.000001 gives that much accuracy in radians. 102 | **/ 103 | pub fn ecc_anom(mean_anom: f64, ecc: f64, accuracy: f64) -> f64 { 104 | let mut prev_E = 0.0; 105 | let mut E = mean_anom; 106 | 107 | while (E - prev_E).abs() > accuracy { 108 | prev_E = E; 109 | E = mean_anom + ecc * E.sin(); 110 | } 111 | 112 | E 113 | } 114 | 115 | /** 116 | Computes the velocity of a body in an elliptic orbit 117 | 118 | # Returns 119 | 120 | * `velocity`: Instantaneous velocity of the body 121 | *| in kilometers per second* 122 | 123 | # Arguments 124 | 125 | * `r`: Radius vector of the body *| in AU* 126 | * `a`: Semimajor axis of orbit *| in AU* 127 | **/ 128 | #[inline] 129 | pub fn vel(r: f64, a:f64) -> f64 { 130 | 42.1219 * (1.0/r - 0.5/a).sqrt() 131 | } 132 | 133 | /** 134 | Computes the velocity of a body at perihelion in an elliptic orbit 135 | 136 | # Returns 137 | 138 | * `velocity`: Velocity of the body at perihelion 139 | *| in kilometers per second* 140 | 141 | # Arguments 142 | 143 | * `a`: Semimajor axis of orbit *| in AU* 144 | * `e`: Eccentricity of orbit 145 | **/ 146 | #[inline] 147 | pub fn perih_vel(a:f64, e:f64) -> f64 { 148 | 29.7847 * ( 149 | (1.0 + e) / ((1.0 - e) * a) 150 | ).sqrt() 151 | } 152 | 153 | /** 154 | Computes the velocity of a body at aphelion in an elliptic orbit 155 | 156 | # Returns 157 | 158 | * `velocity`: Velocity of the body at aphelion 159 | *| in kilometers per second* 160 | 161 | # Arguments 162 | 163 | * `a`: Semimajor axis of orbit *| in AU* 164 | * `e`: Eccentricity of orbit 165 | **/ 166 | #[inline] 167 | pub fn aph_vel(a:f64, e:f64) -> f64 { 168 | 29.7847 * ( 169 | (1.0 - e) / ((1.0 + e) * a) 170 | ).sqrt() 171 | } 172 | 173 | /** 174 | Computes the approximate length of an ellipse using the Ramanujan 175 | method 176 | 177 | # Returns 178 | 179 | * `approx_length`: An approximate value for the length of 180 | the ellipse (same unit as that of `a` 181 | and `b`), using a formula given by 182 | [Ramanujan](https://en.wikipedia.org/wiki/Srinivasa_Ramanujan) 183 | in 1914. 184 | 185 | The error in `approx_length` is: 186 | 187 | * 0% for a = b 188 | * 0.4155% for e = 1 189 | 190 | # Arguments 191 | 192 | * `a`: Semimajor axis of the ellipse (same unit as that of `b`) 193 | * `b`: Semiminor axis of the ellipse (same unit as that of `a`) 194 | **/ 195 | #[inline] 196 | pub fn length_ramanujan(a: f64, b: f64) -> f64 { 197 | PI * ( 198 | 3.0*(a + b) - ((a + 3.0*b) * (3.0*a + b)).sqrt() 199 | ) 200 | } 201 | 202 | /** 203 | Computes the approximate length of an ellipse 204 | 205 | # Returns 206 | 207 | * `approx_length`: An approximate value for the length of the ellipse 208 | (same unit as that of `a` and `b`) 209 | 210 | The error in `approx_length` is: 211 | 212 | * less than 0.001% if e < 0.88 213 | * less than 0.01% if e < 0.95 214 | * 1% if e = 0.9997 215 | * 3% if e = 1 216 | 217 | # Arguments 218 | 219 | * `a`: Semimajor axis of the ellipse (same unit as that of `b`) 220 | * `b`: Semiminor axis of the ellipse (same unit as that of `a`) 221 | **/ 222 | pub fn length(a: f64, b: f64) -> f64 { 223 | let A = (a + b) / 2.0; 224 | let G = (a * b).sqrt(); 225 | let H = (2.0 * a * b) / (a + b); 226 | 227 | PI * (21.0*A - 2.0*G - 3.0*H)/8.0 228 | } 229 | 230 | /** 231 | Computes the semimajor axis of an elliptic orbit 232 | 233 | # Arguments 234 | 235 | * `perih`: Perihelion of the orbit 236 | * `ecc` : Eccentricity of the orbit 237 | **/ 238 | #[inline(always)] 239 | pub fn semimaj_axis(perih: f64, ecc: f64) -> f64 { 240 | perih / (1.0 - ecc) 241 | } 242 | 243 | /** 244 | Computes the mean motion of an elliptic orbit 245 | 246 | # Returns 247 | 248 | * `mean_motion`: Mean motion of the orbit 249 | *| in radians per days of dynamical time* 250 | 251 | # Arguments 252 | 253 | * `semimaj_ax`: Semimajor axis of the orbit 254 | **/ 255 | #[inline(always)] 256 | pub fn mn_motion(semimaj_ax: f64) -> f64 { 257 | 0.01720209895 / semimaj_ax.powf(1.5) 258 | } 259 | 260 | /** 261 | Computes the time of passage of a body through a node of an elliptic 262 | orbit, and it's radius vector at that time 263 | 264 | # Returns 265 | 266 | `(time_of_pass, rad_vec)` 267 | 268 | * `time_of_pass`: Time of passage through the node, in Julian 269 | (Ephemeris) day 270 | * `rad_vec` : Radius vector of the body at the time of passage 271 | *| in AU* 272 | 273 | # Arguments 274 | 275 | * `w` : Argument of the perihelion *| in radians* 276 | * `n` : Mean motion of the orbit (*radians per day*) 277 | * `a` : Semimajor axis of the orbit *| in AU* 278 | * `e` : Eccentricity of the orbit 279 | * `T` : Time of passage in perihelion, in Julian (Ephemeris) day 280 | * `node`: `Ascend` or `Descend` node 281 | **/ 282 | #[inline] 283 | pub fn passage_through_node ( 284 | 285 | w : f64, 286 | n : f64, 287 | a : f64, 288 | e : f64, 289 | T : f64, 290 | node : &orbit::Node 291 | 292 | ) -> (f64, f64) { 293 | 294 | match *node { 295 | orbit::Node::Ascend => pass_through_node( - w, n, a, e, T), 296 | orbit::Node::Descend => pass_through_node(PI - w, n, a, e, T) 297 | } 298 | } 299 | 300 | fn pass_through_node ( 301 | 302 | v : f64, 303 | n : f64, 304 | a : f64, 305 | e : f64, 306 | T : f64 307 | 308 | ) -> (f64, f64) { 309 | 310 | let E = 2.0 * ((1.0 - e).sqrt() * (v/2.0).tan()).atan2((1.0 + e).sqrt()); 311 | let M = E - e*E.sin(); 312 | 313 | ( T + M/n, a*(1.0 - e*E.cos()) ) 314 | } 315 | -------------------------------------------------------------------------------- /src/orbit/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Elliptic, parabolic and near-parabolic orbits 24 | 25 | pub mod elliptic; 26 | pub mod parabolic; 27 | pub mod near_parabolic; 28 | 29 | /// Represents an orbital node 30 | pub enum Node { 31 | /// Ascending node 32 | Ascend, 33 | /// Descending node 34 | Descend 35 | } 36 | -------------------------------------------------------------------------------- /src/orbit/near_parabolic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Near-parabolic orbits 24 | 25 | use angle; 26 | use consts; 27 | 28 | /** 29 | Computes the true anomaly and radius vector of a body in a near-parabolic 30 | orbit at a given time 31 | 32 | # Returns 33 | 34 | `(true_anom, rad_vec)` 35 | 36 | * `true_anom`: True anomaly of the body at time `t` *| in radians* 37 | * `rad_vec` : Radius vector of the body at time `t` *| in AU* 38 | 39 | # Arguments 40 | 41 | * `t` : Time of interest, in Julian (Ephemeris) day 42 | * `T` : Time of passage through the perihelion, in Julian (Ephemeris) day 43 | * `ecc` : Eccentricity of the near-parabolic orbit 44 | * `q` : Perihelion distance *| in AU* 45 | * `accuracy`: Desired accuracy for the results. For example, passing `0.000001` 46 | gives that much accuracy in radians and AU. 47 | **/ 48 | pub fn true_anom_and_rad_vec<'a> ( 49 | 50 | t : f64, 51 | T : f64, 52 | ecc : f64, 53 | q : f64, 54 | accuracy : f64 55 | 56 | ) -> Result<(f64, f64), &'a str> { 57 | 58 | let days_frm_perih = t - T; 59 | 60 | if days_frm_perih == 0.0 { 61 | return Ok((0.0, q)) 62 | } 63 | 64 | let k = consts::GAUSS_GRAV; 65 | let d1 = 1000.0; 66 | 67 | let q1 = k * ((1.0 + ecc)/q).sqrt() / (2.0*q); 68 | let g = (1.0 - ecc) / (1.0 + ecc); 69 | 70 | let q2 = q1 * days_frm_perih; 71 | let mut s = 2.0 / (3.0 * q2.abs()); 72 | s = 2.0 / (2.0 * (s.atan() / 2.0).tan().cbrt().atan()).tan(); 73 | 74 | if days_frm_perih < 0.0 { s = -s; } 75 | if ecc != 1.0 { 76 | let mut l = 0.0; 77 | loop { 78 | let s0 = s; 79 | let mut z = 1.0; 80 | let y = s * s; 81 | let mut g1 = -y * s; 82 | let mut q3 = q2 + g*s*y*2.0/3.0; 83 | 84 | loop { 85 | z += 1.0; 86 | g1 = -g1 * g * y; 87 | let z1 = (z - (z + 1.0)*g) / (2.0*z + 1.0); 88 | let f = z1 * g1; 89 | q3 += f; 90 | if z > 50.0 || f.abs() > d1 { 91 | return Err("No convergence at orbit::near_parabolic::true_anom_and_rad_vec()"); 92 | } 93 | if f.abs() <= accuracy { break; } 94 | } 95 | 96 | l += 1.0; 97 | if l > 50.0 { 98 | return Err("No convergence at orbit::near_parabolic::true_anom_and_rad_vec()"); 99 | } 100 | 101 | loop { 102 | let s1 = s; 103 | s = (s*s*s*2.0/3.0 + q3)/(s*s + 1.0); 104 | if (s - s1).abs() <= accuracy { break; } 105 | } 106 | 107 | if (s - s0).abs() <= accuracy { break; } 108 | } 109 | } 110 | 111 | let v = angle::limit_to_two_PI(2.0 * s.atan()); 112 | let r = q * (1.0 + ecc) / (1.0 + ecc*v.cos()); 113 | 114 | Ok((v, r)) 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/orbit/parabolic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Parabolic orbits 24 | 25 | use std; 26 | use orbit; 27 | 28 | /** 29 | Computes the true anomaly and radius vector of a body in a parabolic 30 | orbit at a given time 31 | 32 | # Returns 33 | 34 | `(tru_anom, rad_vec)` 35 | 36 | * `true_anom`: True anomaly of the body at time `t` *| in radians* 37 | * `rad_vec` : Radius vector of the body at time `t` *| in AU* 38 | 39 | # Arguments 40 | 41 | * `t`: Time of interest, in Julian (Ephemeris) day 42 | * `T`: Time of passage through the perihelion, in Julian (Ephemeris) day 43 | * `q`: Perihelion distance *| in AU* 44 | **/ 45 | pub fn true_anom_and_rad_vec(t: f64, T: f64, q: f64) -> (f64, f64) { 46 | 47 | let W = 0.03649116245 * (t - T) / q.powf(1.5); 48 | let G = W / 2.0; 49 | let Y = (G + (G*G + 1.0).sqrt()).cbrt(); 50 | let s = Y - 1.0/Y; 51 | let v = 2.0 * s.atan(); 52 | let r = q * (1.0 + s*s); 53 | 54 | (v, r) 55 | 56 | } 57 | 58 | /** 59 | Computes the time of passage of a body through a node of a parabolic 60 | orbit and it's radius vector at that time 61 | 62 | # Returns 63 | 64 | `(time_of_pass, rad_vec)` 65 | 66 | * `time_of_pass`: Time of passage through the node, in Julian 67 | (Ephemeris) day 68 | * `rad_vec` : Radius vector of the body at the time of passage 69 | *| in AU* 70 | 71 | # Arguments 72 | 73 | * `w` : Argument of the perihelion *| in radians* 74 | * `q` : Perihelion distance *| in AU* 75 | * `T` : Time of passage in perihelion, in Julian (Ephemeris) day 76 | * `node`: `Ascend` or `Descend` node 77 | **/ 78 | 79 | #[inline] 80 | pub fn passage_through_node ( 81 | 82 | w : f64, 83 | q : f64, 84 | T : f64, 85 | node : &orbit::Node 86 | 87 | ) -> (f64, f64) { 88 | 89 | match *node { 90 | orbit::Node::Ascend => pass_through_node(-w, q, T), 91 | orbit::Node::Descend => pass_through_node(std::f64::consts::PI - w, q, T) 92 | } 93 | 94 | } 95 | 96 | fn pass_through_node(v: f64, q: f64, T: f64) -> (f64, f64) { 97 | 98 | let s = (v / 2.0).tan(); 99 | let T_node = T + q.powf(1.5) * (s * (s*s + 3.0)) * 27.403895; 100 | let rad_vec = q * (1.0 + s*s); 101 | 102 | (T_node, rad_vec) 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/parallax.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Find topocentric coordinates 24 | 25 | use angle; 26 | use coords; 27 | use planet; 28 | 29 | /** 30 | Computes the equatorial horizontal parallax of a celestial body 31 | 32 | # Returns 33 | 34 | * `eq_hz_parllx`: Equatorial horizontal parallax of the celestial 35 | body *| in radians* 36 | 37 | # Arguments 38 | 39 | * `dist_to_earth`: The celestial body's distance to the Earth *| in AU* 40 | **/ 41 | #[inline] 42 | pub fn eq_hz_parallax(dist_to_earth: f64) -> f64 43 | { 44 | (angle::deg_frm_dms(0, 0, 8.794).to_radians().sin() / dist_to_earth).asin() 45 | } 46 | 47 | /** 48 | Computes the topocentric equatorial coordinates of a celestial body 49 | 50 | # Returns 51 | 52 | * `topocent_eq_point`: Topocentric equatorial point of the 53 | celestial body *| in radians* 54 | 55 | # Arguments 56 | 57 | * `eq_point` : Equatorial point of the celestial body 58 | *| in radians* 59 | * `eq_hz_parllx` : Equatorial horizontal parallax of the celestial 60 | body *| in radians* 61 | * `geograph_point` : Geographic point of the observer *| in radians* 62 | * `observer_ht` : Height of the observer above sea level 63 | *| in meters* 64 | * `greenw_sidr`: Sidereal time at Greenwhich *| in radians* 65 | **/ 66 | pub fn topocent_eq_coords(eq_point: &coords::EqPoint, 67 | eq_hz_parllx: f64, 68 | geograph_point: &coords::GeographPoint, 69 | observer_ht: f64, 70 | greenw_sidr: f64) -> coords::EqPoint 71 | { 72 | let (rho_sin, rho_cos) = planet::earth::rho_sin_cos_phi ( 73 | geograph_point.lat, observer_ht 74 | ); 75 | 76 | let geocent_hr_angl = coords::hr_angl_frm_observer_long ( 77 | greenw_sidr, geograph_point.long, eq_point.asc 78 | ); 79 | 80 | let eq_hz_parllx_sin = eq_hz_parllx.sin(); 81 | 82 | let del_asc = (-rho_cos * eq_hz_parllx_sin * geocent_hr_angl.sin()).atan2( 83 | eq_point.dec.cos() 84 | - rho_cos * eq_hz_parllx_sin * geocent_hr_angl.cos() 85 | ); 86 | 87 | let dec_1 = ( 88 | (eq_point.dec.sin() - rho_sin * eq_hz_parllx_sin) * del_asc.cos() 89 | ).atan2( 90 | eq_point.dec.cos() 91 | - rho_cos * eq_hz_parllx_sin * geocent_hr_angl.cos() 92 | ); 93 | 94 | coords::EqPoint { 95 | asc: eq_point.asc + del_asc, 96 | dec: dec_1 97 | } 98 | } 99 | 100 | /** 101 | Computes the topocentric ecliptic coordinates of a celestial body 102 | 103 | # Returns 104 | 105 | `(topocent_ecl_point, topocent_geocent_semidia)` 106 | 107 | * `topocent_ecl_point` : Topocentric ecliptic point of the 108 | celestial body *| in radians* 109 | * `topocent_geocent_semidia`: Topocentric semidiameter of the 110 | celestial body *| in radians* 111 | 112 | # Arguments 113 | 114 | * `ecl_point` : Ecliptic point of the celestial body *| in radians* 115 | * `eq_hz_parllx` : Equatorial horizontal parallax of the celestial 116 | body *| in radians* 117 | * `geograph_point`: Geographic point of the observer *| in radians* 118 | * `observer_ht` : Height of the observer above sea level *| in meters* 119 | * `loc_sidr` : Local sidereal time *| in radians* 120 | * `eclip_oblq` : Obliquity of the ecliptic *| in radians* 121 | * `geocent_semdia` : Geocentric semidiameter of the celestial body *| in radians* 122 | **/ 123 | pub fn topopcent_ecl_coords(ecl_point: &coords::EclPoint, 124 | eq_hz_parllx: f64, 125 | geograph_point: &coords::GeographPoint, 126 | observer_ht: f64, 127 | loc_sidr: f64, 128 | eclip_oblq: f64, 129 | geocent_semdia: f64) -> (coords::EclPoint, f64) 130 | { 131 | let (rho_sin, rho_cos) = planet::earth::rho_sin_cos_phi ( 132 | geograph_point.lat, observer_ht 133 | ); 134 | 135 | let eq_hz_parllx_sin = eq_hz_parllx.sin(); 136 | let loc_sidr_sin = loc_sidr.sin(); 137 | 138 | let eclip_oblq_sin = eclip_oblq.sin(); 139 | let eclip_oblq_cos = eclip_oblq.cos(); 140 | 141 | let ecl_point_lat_cos = ecl_point.lat.cos(); 142 | 143 | let N = 144 | ecl_point.long.cos() * ecl_point_lat_cos 145 | - rho_cos * eq_hz_parllx_sin * loc_sidr.cos(); 146 | 147 | let ecl_long_1 = ( 148 | ecl_point.long.sin() * ecl_point_lat_cos 149 | - eq_hz_parllx_sin * ( 150 | rho_sin * eclip_oblq_sin + 151 | rho_cos * eclip_oblq_cos * loc_sidr_sin 152 | ) 153 | ).atan2(N); 154 | 155 | let ecl_lat_1 = ( 156 | ecl_long_1.cos() * ( 157 | ecl_point.lat.sin() 158 | - eq_hz_parllx_sin * ( 159 | rho_sin * eclip_oblq_cos - 160 | rho_cos * eclip_oblq_sin * loc_sidr_sin 161 | ) 162 | ) 163 | ).atan2(N); 164 | 165 | let geocent_semdia_1 = ( 166 | ecl_long_1.cos() * ecl_lat_1.cos() * geocent_semdia.sin() / N 167 | ).asin(); 168 | 169 | ( 170 | coords::EclPoint { 171 | long: angle::limit_to_two_PI(ecl_long_1), 172 | lat: ecl_lat_1 173 | }, 174 | geocent_semdia_1 175 | ) 176 | } 177 | -------------------------------------------------------------------------------- /src/planet/VSOPD_87/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod mercury; 2 | pub mod venus; 3 | pub mod earth; 4 | pub mod mars; 5 | pub mod jupiter; 6 | pub mod saturn; 7 | pub mod uranus; 8 | pub mod neptune; 9 | -------------------------------------------------------------------------------- /src/planet/earth.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! The Earth 24 | 25 | use coords; 26 | use angle; 27 | use time; 28 | 29 | /** 30 | Returns the flattening factor of the Earth 31 | 32 | Reference: [World Geodetic System 1984](https://confluence.qps.nl/pages/viewpage.action?pageId=29855173) 33 | **/ 34 | #[inline(always)] 35 | pub fn flat_fac() -> f64 { 36 | 1.0 / 298.257223563 37 | } 38 | 39 | /** 40 | Returns the equatorial radius of the Earth *| in kilometers* 41 | 42 | Reference: [World Geodetic System 1984](https://confluence.qps.nl/pages/viewpage.action?pageId=29855173) 43 | **/ 44 | #[inline(always)] 45 | pub fn eq_rad() -> f64 { 46 | 6378.137 47 | } 48 | 49 | /** 50 | Returns the polar radius of the Earth *| in kilometers* 51 | 52 | Calculated using [`FlatteningFactor()`](./fn.FlatteningFactor.html) and 53 | [`eq_radius()`](./fn.eq_radius.html) 54 | **/ 55 | #[inline] 56 | pub fn pol_rad() -> f64 { 57 | eq_rad() * (1.0 - flat_fac()) 58 | } 59 | 60 | /** 61 | Returns the eccentricity of the Earth's meridian 62 | **/ 63 | #[inline] 64 | pub fn ecc_of_meridian() -> f64 { 65 | (flat_fac() * (2.0 - flat_fac())).sqrt() 66 | } 67 | 68 | /** 69 | Computes a low accuracy geodesic distance between two points 70 | on the Earth's surface *| in kilometers* 71 | 72 | Assumes that the Earth is a sphere. 73 | 74 | # Arguments 75 | 76 | * `p1`: `GeographPoint` 1 77 | * `p2`: `GeographPoint` 2 78 | **/ 79 | #[inline] 80 | pub fn approx_geodesic_dist(p1: &coords::GeographPoint, p2: &coords::GeographPoint) -> f64 { 81 | 82 | 6371.0 * p1.anglr_sepr(&p2) 83 | 84 | } 85 | 86 | /** 87 | Computes a high accuracy geodesic distance between two points on the Earth's 88 | surface *| in kilometers* 89 | 90 | # Arguments 91 | 92 | * `p1`: `GeographPoint` 1 93 | * `p2`: `GeographPoint` 2 94 | **/ 95 | pub fn geodesic_dist ( 96 | 97 | p1 : &coords::GeographPoint, 98 | p2 : &coords::GeographPoint 99 | 100 | ) -> f64 { 101 | 102 | let f = (p1.lat + p2.lat)/2.0; 103 | let g = (p1.lat - p2.lat)/2.0; 104 | let lam = (p1.long - p2.long)/2.0; 105 | 106 | let s = (g.sin() * lam.cos()).powi(2) + (f.cos() * lam.sin()).powi(2); 107 | let c = (g.cos() * lam.cos()).powi(2) + (f.sin() * lam.sin()).powi(2); 108 | let om = ((s / c).sqrt()).atan(); 109 | 110 | let r = (s * c).sqrt() / om; 111 | let d = 2.0 * om * eq_rad(); 112 | 113 | let h1 = (3.0*r - 1.0)/(2.0 * c); 114 | let h2 = (3.0*r + 1.0)/(2.0 * s); 115 | 116 | d * ( 117 | 1.0 118 | + flat_fac() * h1 * (f.sin() * g.cos()).powi(2) 119 | - flat_fac() * h2 * (f.cos() * g.sin()).powi(2) 120 | ) 121 | 122 | } 123 | 124 | /** 125 | Computes two quantities that are used elsewhere in the library 126 | 127 | # Returns 128 | 129 | `Rho` here denotes the distance from the Earth's center to a point 130 | on the ellipsoid, and `Phi` here denotes the geocentric latitude, 131 | both of an observer on the Earth's surface. 132 | 133 | `rho_sin_phi, rho_cos_phi` 134 | 135 | * `rho_sin_phi`: Rho sin phi 136 | * `rho_cos_phi`: Rho cos phi 137 | 138 | # Arguments 139 | 140 | * `geograph_lat`: Observer's geographic latitude *| in radians* 141 | * `height` : Observer's height above sea level *(meters)* 142 | **/ 143 | pub fn rho_sin_cos_phi(geograph_lat: f64, height: f64) -> (f64, f64) { 144 | 145 | let u = (geograph_lat.tan() * pol_rad()/eq_rad()).atan(); 146 | let x = height / (eq_rad() * 1000.0); 147 | 148 | let rho_sin_phi = (u.sin() * pol_rad()/eq_rad()) + (geograph_lat.sin() * x); 149 | let rho_cos_phi = u.cos() + (geograph_lat.cos() * x); 150 | 151 | (rho_sin_phi, rho_cos_phi) 152 | 153 | } 154 | 155 | /** 156 | Computes the distance from the Earth's center to a point on the 157 | ellipsoid 158 | 159 | # Returns 160 | 161 | * `rho`: Distance from the Earth's center to the point on the 162 | ellipsoid (*fraction of the equatorial radius*) 163 | 164 | # Arguments 165 | 166 | * `geograph_lat`: Geographic latitude of a point on the 167 | ellipsoid *| in radians* 168 | **/ 169 | pub fn rho(geograph_lat: f64) -> f64 { 170 | 171 | 0.9983271 172 | + 0.0016764 * (2.0 * geograph_lat).cos() 173 | - 0.0000035 * (4.0 * geograph_lat).cos() 174 | 175 | } 176 | 177 | /// Returns the rotational angular velocity of the Earth 178 | /// *| in radian per second* 179 | #[inline(always)] 180 | pub fn rot_angular_velocity() -> f64 { 181 | 0.00007292114992 182 | } 183 | 184 | /** 185 | Computes the radius of the parallel of a latitude 186 | 187 | # Returns 188 | 189 | * `rad`: Radius of the parallel of the latitude 190 | *| in kilometers* 191 | 192 | # Arguments 193 | 194 | * `geograph_lat`: Geographic latitude of a point 195 | on the ellipsoid *| in radians* 196 | **/ 197 | pub fn rad_of_parll_lat(geograph_lat: f64) -> f64 { 198 | 199 | let e = ecc_of_meridian(); 200 | 201 | eq_rad() * geograph_lat.cos() / 202 | (1.0 - (e * geograph_lat.sin()).powi(2)).sqrt() 203 | 204 | } 205 | 206 | /** 207 | Computes the linear velocity of a point at a latitude 208 | 209 | # Returns 210 | 211 | * `lin_vel`: Linear velocity at the latitude 212 | (kilometers per second*) 213 | 214 | # Arguments 215 | 216 | * `geograph_lat`: Geographic latitude of a point on 217 | the ellipsoid *| in radians* 218 | **/ 219 | #[inline(always)] 220 | pub fn linear_velocity_at_lat(geograph_lat: f64) -> f64 { 221 | 222 | rot_angular_velocity() * rad_of_parll_lat(geograph_lat) 223 | 224 | } 225 | 226 | /** 227 | Computes the radius of curvature of the Earth's meridian 228 | at a latitude 229 | 230 | # Returns 231 | 232 | * `rad`: Radius of curvature of the Earth's meridian at the 233 | latitude *| in kilometers* 234 | 235 | # Arguments 236 | 237 | * `geograph_lat`: Geographic latitude of a point on the 238 | ellipsoid *| in radians* 239 | **/ 240 | pub fn rad_curv_of_meridian(lat: f64) -> f64 { 241 | 242 | let e = ecc_of_meridian(); 243 | 244 | eq_rad() * (1.0 - e*e) / 245 | (1.0 - (e * lat.sin()).powi(2)).powf(1.5) 246 | 247 | } 248 | 249 | /** 250 | Computes the difference between the geographic latitude and 251 | geocentric latitude 252 | 253 | # Returns 254 | 255 | * `diff`: Geographic latitude minus geocentric latitude 256 | *| in radians* 257 | 258 | # Arguments 259 | 260 | * `geograph_lat`: Geographic latitude *| in radians* 261 | **/ 262 | pub fn geograph_geocent_lat_diff(geograph_lat: f64) -> f64 { 263 | 264 | angle::deg_frm_dms(0, 0, 692.73) * (2.0 * geograph_lat).sin() 265 | - angle::deg_frm_dms(0, 0, 1.16) * (4.0 * geograph_lat).sin() 266 | 267 | } 268 | 269 | /** 270 | Computes the equation of time *| in radians* 271 | 272 | # Arguments 273 | 274 | * `JD` : Julian (Ephemeris) day 275 | * `sun_asc` : Right ascension of the Sun *| in radians* 276 | * `nut_log` : Nutation correction for longitude *| in radians* 277 | * `tru_oblq`: True obliquity of the ecliptic *| in radians* 278 | **/ 279 | pub fn equation_of_time ( 280 | 281 | JD : f64, 282 | sun_asc : f64, 283 | nut_long : f64, 284 | tru_oblq : f64 285 | 286 | ) -> f64 { 287 | 288 | let t = time::julian_mill(JD); 289 | let L = angle::limit_to_360( 290 | 280.4664567 + 291 | t * (360007.6982779 + 292 | t * (0.030328 + 293 | t * (1.0/49931.0 - 294 | t * (1.0/15300.0 + 295 | t / 2000000.0))))); 296 | 297 | ( 298 | L - 0.0057183 - sun_asc.to_degrees() 299 | + nut_long.to_degrees() * tru_oblq.cos() 300 | ).to_radians() 301 | 302 | } 303 | 304 | /** 305 | Computes the angle between diurnal path and the horizon 306 | 307 | # Returns 308 | 309 | * `angl`: Angle between the diurnal path of a celestial 310 | body and the horizon *| in radians* 311 | 312 | # Arguments 313 | 314 | * `dec` : Declination of the celestial body 315 | *| in radians* 316 | * `observer_lat`: Observer's geographic latitude 317 | *| in radians* 318 | **/ 319 | pub fn angl_betwn_diurnal_path_and_hz(dec: f64, observer_lat: f64) -> f64 { 320 | 321 | let B = dec.tan() * observer_lat.tan(); 322 | let C = (1.0 - B*B).sqrt(); 323 | 324 | (C * dec.cos()).atan2(observer_lat.tan()) 325 | 326 | } 327 | -------------------------------------------------------------------------------- /src/planet/jupiter/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Jupiter 24 | 25 | pub mod moon; 26 | 27 | use angle; 28 | use nutation; 29 | use planet; 30 | use coords; 31 | 32 | /** 33 | Computes Jupiter's equatorial semidiameter 34 | 35 | # Returns 36 | 37 | * `eq_semidia`: Equatorial semidiameter *| in radians per AU* 38 | 39 | # Arguments 40 | 41 | * `jup_earth_dist`: Jupiter-Earth distance *| in AU* 42 | **/ 43 | #[inline(always)] 44 | pub fn eq_semidiameter(jup_earth_dist: f64) -> f64 { 45 | 46 | angle::deg_frm_dms(0, 0, 98.44).to_radians() / jup_earth_dist 47 | 48 | } 49 | 50 | /** 51 | Computes Jupiter's polar semidiameter 52 | 53 | # Returns 54 | 55 | * `pol_semidia`: Polar semidiameter *| in radians per AU* 56 | 57 | # Arguments 58 | 59 | * `jup_earth_dist`: Jupiter-Earth distance *| in AU* 60 | **/ 61 | #[inline(always)] 62 | pub fn pol_semidiameter(jup_earth_dist: f64) -> f64 { 63 | 64 | angle::deg_frm_dms(0, 0, 92.06).to_radians() / jup_earth_dist 65 | 66 | } 67 | 68 | /// Holds Jupiter's ephemeris values for physical observations 69 | #[derive(Debug)] 70 | pub struct Ephemeris { 71 | /// Jupiter-centric declination of the Earth 72 | pub De : f64, 73 | /// Jupiter-centric declination of the Sun 74 | pub Ds : f64, 75 | /// Geocentric position angle of Jupiter's northern 76 | /// rotation pole, or also called, position angle 77 | /// of the axis 78 | pub P : f64, 79 | /// Longitude of the central meridian for Rotational System I 80 | pub w1 : f64, 81 | /// Longitude of the central meridian for Rotational System II 82 | pub w2 : f64, 83 | } 84 | 85 | /** 86 | Return quantites used in the ephemeris for physical observations 87 | of Jupiter 88 | 89 | # Returns 90 | 91 | * `ephemeris`: Jupiter's ephemeris. *All angles are in radians* 92 | 93 | # Arguments 94 | 95 | * `JD` : Julian (Ephemeris) day 96 | * `mn_oblq` : Mean obliquity of the ecliptic on `JD` *| in radians* 97 | * `nut_in_long`: Nutation in ecliptic longitude on `JD` *| in radians* 98 | * `nut_in_oblq`: Nutation in obliquity of the ecliptic on `JD` *| in radians* 99 | **/ 100 | pub fn ephemeris ( 101 | 102 | JD : f64, 103 | mn_oblq : f64, 104 | nut_in_long : f64, 105 | nut_in_oblq : f64 106 | 107 | ) -> Ephemeris { 108 | 109 | let d = JD - 2433282.5; 110 | let T1 = d / 36525.0; 111 | 112 | let asc0 = (268.0 + 0.1061*T1).to_radians(); 113 | let dec0 = (64.5 - 0.0164*T1).to_radians(); 114 | 115 | let W1 = angle::limit_to_360(17.710 + 877.90003539*d).to_radians(); 116 | let W2 = angle::limit_to_360(16.838 + 870.27003539*d).to_radians(); 117 | 118 | let (l0, b0, R) = planet::heliocent_coords(&planet::Planet::Earth, JD); 119 | 120 | let (mut l, mut b, mut r) = (0.0, 0.0, 0.0); 121 | let mut x; 122 | let mut y; 123 | let mut z; 124 | let mut jup_earth_dist = 0.0; 125 | let mut light_time = 0.0; 126 | 127 | let mut i: u8 = 1; 128 | while i <= 2 { 129 | 130 | let (new_l, new_b, new_r) = planet::heliocent_coords(&planet::Planet::Jupiter, JD - light_time); 131 | l = new_l; b = new_b; r = new_r; 132 | 133 | let (new_x, new_y, new_z) = planet::geocent_ecl_rect_coords(l0, b0, R, l, b, r); 134 | x = new_x; y = new_y; z = new_z; 135 | 136 | jup_earth_dist = planet::dist_frm_ecl_rect_coords(x, y, z); 137 | light_time = planet::light_time(jup_earth_dist); 138 | 139 | i += 1; 140 | 141 | } 142 | 143 | l -= 0.01299_f64.to_radians()*jup_earth_dist / (r*r); 144 | let (x, y, z) = planet::geocent_ecl_rect_coords(l0, b0, R, l, b, r); 145 | jup_earth_dist = planet::dist_frm_ecl_rect_coords(x, y, z); 146 | 147 | let asc_s = (mn_oblq.cos()*l.sin() - mn_oblq.sin()*b.tan()).atan2(l.cos()); 148 | let dec_s = (mn_oblq.cos()*b.sin() + mn_oblq.sin()*b.cos()*l.sin()).asin(); 149 | 150 | let D_s = (-dec0.sin()*dec_s.sin() - dec0.cos()*dec_s.cos()*(asc0 - asc_s).cos()).asin(); 151 | 152 | let u = y*mn_oblq.cos() - z*mn_oblq.sin(); 153 | let v = y*mn_oblq.sin() + z*mn_oblq.cos(); 154 | let mut asc = u.atan2(x); 155 | let mut dec = v.atan2((x*x + u*u).sqrt()); 156 | let zeta = 157 | (dec0.sin()*dec.cos()*(asc0 - asc).cos() - dec.sin()*dec0.cos()) 158 | .atan2(dec.cos()*(asc0 - asc).sin()); 159 | 160 | let D_e = (-dec0.sin()*dec.sin() - dec0.cos()*dec.cos()*(asc0 - asc).cos()).asin(); 161 | 162 | let mut w1 = angle::limit_to_360(W1.to_degrees() - zeta.to_degrees() - 5.07033*jup_earth_dist); 163 | let mut w2 = angle::limit_to_360(W2.to_degrees() - zeta.to_degrees() - 5.02626*jup_earth_dist); 164 | 165 | let mut C = 166 | 57.2958 * (2.0*r*jup_earth_dist + R*R - r*r - jup_earth_dist*jup_earth_dist) 167 | / (4.0 * r * jup_earth_dist); 168 | if (l - l0).sin() < 0.0 { 169 | C *= -1.0 170 | } 171 | w1 = (w1 + C).to_radians(); 172 | w2 = (w2 + C).to_radians(); 173 | 174 | let tru_oblq = mn_oblq + nut_in_oblq; 175 | 176 | let q = 0.005693_f64.to_radians(); 177 | asc += q * (asc.cos()*l0.cos()*tru_oblq.cos() + asc.sin()*l0.sin()) / dec.cos(); 178 | dec += q * ( l0.cos()*tru_oblq.cos()*(tru_oblq.tan()*dec.cos() 179 | - asc.sin()*asc.cos()) 180 | + asc.cos()*dec.sin()*l0.sin()); 181 | 182 | let (asc_nut, dec_nut) = nutation::nutation_in_eq_coords( 183 | &coords::EqPoint{asc: asc, dec: dec}, 184 | nut_in_long, 185 | nut_in_oblq, 186 | tru_oblq 187 | ); 188 | let asc1 = asc + asc_nut; 189 | let dec1 = dec + dec_nut; 190 | 191 | let (asc0_nut, dec0_nut) = nutation::nutation_in_eq_coords ( 192 | &coords::EqPoint{asc: asc0, dec: dec0}, 193 | nut_in_long, 194 | nut_in_oblq, 195 | tru_oblq 196 | ); 197 | let asc01 = asc0 + asc0_nut; 198 | let dec01 = dec0 + dec0_nut; 199 | 200 | let P = (dec01.cos() * (asc01 - asc1).sin()) 201 | .atan2(dec01.sin()*dec1.cos() - dec01.cos()*dec1.sin()*(asc01 - asc1).cos()); 202 | 203 | Ephemeris { 204 | De: D_e, 205 | Ds: D_s, 206 | P : P, 207 | w1: w1, 208 | w2: w2 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /src/planet/jupiter/moon.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! The four Galilean moons 24 | 25 | /* 26 | 27 | Meeus referrs to the moons as Satellites I, II, III and IV. 28 | Wikipedia says satellite I is Io, II is Europa, III is Ganymede 29 | and IV is Callisto. That mapping is used. 30 | 31 | */ 32 | 33 | /// Represents a Galilean moon 34 | pub enum Moon { 35 | /// Io 36 | Io, 37 | /// Europa 38 | Europa, 39 | /// Ganymede 40 | Ganymede, 41 | /// Callisto 42 | Callisto 43 | } 44 | 45 | /** 46 | Computes the apparent rectangular coordinates for a Galilean moon 47 | 48 | This function implements the low accuracy method described in Meeus's 49 | book, that is *"sufficient for identifying the satellites at the 50 | telescope, or drawing a wavy-line diagram showing their positions with 51 | respect to Jupiter"* 52 | 53 | # Returns 54 | 55 | `(X, Y)` 56 | 57 | The rectangular coordinates returned give the apparent position of a moon, 58 | with respect to Jupiter, as seen from Earth. The `X` and `Y` 59 | coordinates are measured from the center of the disk of Jupiter, in units 60 | of Jupiter's equatorial radius. 61 | 62 | `X` is measured positively to the west of Jupiter, and negatively to the 63 | east. The x-axis coincides with Jupiter's equator. 64 | 65 | `Y` is measured positively to the north of Jupiter, and negatively to 66 | the south. The y-axis coincides with Jupiter's axis of rotation. 67 | 68 | # Arguments 69 | 70 | * `JD` : Julian (Ephemeris) day 71 | * `moon`: The [Moon](./enum.Moon.html) 72 | **/ 73 | pub fn apprnt_rect_coords(JD: f64, moon: &Moon) -> (f64, f64) { 74 | 75 | let d = JD - 2451545.0; 76 | let V = (172.74 + 0.00111588*d).to_radians(); 77 | let M = (357.529 + 0.9856003*d).to_radians(); 78 | let N = (20.02 + 0.0830853*d + 0.329*V.sin()).to_radians(); 79 | let J = (66.115 + 0.9025179*d - 0.329*V.sin()).to_radians(); 80 | let A = (1.915*M.sin() + 0.02*(2.0*M).sin()).to_radians(); 81 | let B = (5.555*N.sin() + 0.168*(2.0*N).sin()).to_radians(); 82 | let K = J + A - B; 83 | let R = 1.00014 - 0.01671*M.cos() - 0.00014*(2.0*M).cos(); 84 | let r = 5.20872 - 0.25208*N.cos() - 0.00611*(2.0*N).cos(); 85 | let delta = (r*r + R*R - 2.0*r*R*K.cos()).sqrt(); 86 | 87 | let phi = (R*K.sin()/delta).asin(); 88 | 89 | let d_minus_delta_by_173 = d - delta/173.0; 90 | let phi_minus_B = phi - B; 91 | 92 | let u1 = (163.8069 + 203.4058646*d_minus_delta_by_173).to_radians() + phi_minus_B; 93 | let u2 = (358.414 + 101.2916335*d_minus_delta_by_173).to_radians() + phi_minus_B; 94 | let u3 = (5.7176 + 50.234518*d_minus_delta_by_173).to_radians() + phi_minus_B; 95 | 96 | let mut u = match moon { 97 | &Moon::Io => u1, 98 | &Moon::Europa => u2, 99 | &Moon::Ganymede => u3, 100 | &Moon::Callisto => (224.8092 + 21.48798*d_minus_delta_by_173).to_radians() + phi_minus_B, 101 | }; 102 | 103 | let G = (331.18 + 50.310482*d_minus_delta_by_173).to_radians(); 104 | let H = (87.45 + 21.569231*d_minus_delta_by_173).to_radians(); 105 | 106 | u += (match moon { 107 | &Moon::Io => 0.473 * (2.0*(u1 - u2)).sin(), 108 | &Moon::Europa => 1.065 * (2.0*(u2 - u3)).sin(), 109 | &Moon::Ganymede => 0.165 * G.sin(), 110 | &Moon::Callisto => 0.843 * H.sin(), 111 | }).to_radians(); 112 | 113 | let r_moon = match moon { 114 | &Moon::Io => (5.9057 - 0.0244*(2.0*(u1 - u2)).cos()), 115 | &Moon::Europa => (9.3966 - 0.0882*(2.0*(u2 - u3)).cos()), 116 | &Moon::Ganymede => (14.9883 - 0.0216*G.cos()), 117 | &Moon::Callisto => (26.3627 - 0.1939*H.cos()), 118 | }; 119 | 120 | let lambda = (34.35 + 0.083091*d + 0.329*V.sin()).to_radians() + B; 121 | let Ds = (3.12 * (lambda + 42.8_f64.to_radians()).sin()).to_radians(); 122 | let De = Ds - ( 123 | 2.22*phi.sin()*(lambda + 22_f64.to_radians()).cos() 124 | + 1.3*(r - delta)*(lambda - 100.5_f64.to_radians()).sin()/delta 125 | ).to_radians(); 126 | 127 | let X = r_moon * u.sin(); 128 | let Y = -r_moon * u.cos() * De.sin(); 129 | 130 | (X, Y) 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/planet/mars.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Mars 24 | 25 | use angle; 26 | use planet; 27 | use time; 28 | use coords; 29 | 30 | /** 31 | Returns the equatorial coordinates of Mars's north pole for the epoch 32 | J1950.0 33 | 34 | # Returns 35 | 36 | * `eq_coords`: Equatorial coordinates of Mars's north pole for the 37 | epoch J1950.0 *| in radians* 38 | **/ 39 | #[inline(always)] 40 | pub fn north_pol_eq_coords_J1950() -> coords::EqPoint { 41 | 42 | coords::EqPoint { 43 | asc: 317.342_f64.to_radians(), 44 | dec: 52.7110_f64.to_radians() 45 | } 46 | 47 | } 48 | 49 | /** 50 | Returns the equatorial coordinates of Mars's north pole for the epoch 51 | J2000.0 52 | 53 | # Returns 54 | 55 | * `eq_coords`: Equatorial coordinates of Mars's north pole for the 56 | epoch J2000.0 *| in radians* 57 | **/ 58 | #[inline(always)] 59 | pub fn north_pol_eq_coords_J2000() -> coords::EqPoint { 60 | 61 | coords::EqPoint { 62 | asc: 317.681_f64.to_radians(), 63 | dec: 52.8860_f64.to_radians() 64 | } 65 | 66 | } 67 | 68 | /** 69 | Computes the ecliptic coordinates of Mars's north pole, referred to 70 | the mean equinox of the date 71 | 72 | # Returns 73 | 74 | * `ecl_coords`: Ecliptic coordinates of Mars's north pole 75 | *| in radians* 76 | 77 | # Arguments 78 | 79 | * `JC`: Julian (Ephemeris) century 80 | **/ 81 | #[inline(always)] 82 | pub fn north_pol_ecl_coords(JC: f64) -> coords::EclPoint { 83 | 84 | coords::EclPoint { 85 | long: (352.9065 + 1.17330*JC).to_radians(), 86 | lat: (63.28180 - 0.00394*JC).to_radians() 87 | } 88 | 89 | } 90 | 91 | /// Holds Mar's ephemeris values for physical observations 92 | #[derive(Debug)] 93 | pub struct Ephemeris { 94 | /// Mars-centric declination of the Earth 95 | pub De: f64, 96 | /// Mars-centric declination of the Sun 97 | pub Ds: f64, 98 | /// Geocentric position angle of Mars's northern rotation pole, 99 | /// or also called the position angle of the axis 100 | pub P : f64, 101 | /// Angular amount of the greatest defect of illumination 102 | pub q : f64, 103 | /// Longitude of the central meridian, as seen from the Earth 104 | pub w : f64, 105 | /// Apparent diameter of Mars 106 | pub d : f64, 107 | } 108 | 109 | /** 110 | Computes quantites used in the ephemeris for physical observations of 111 | Mars 112 | 113 | # Returns 114 | 115 | * `ephemeris`: Mar's ephemeris. *All angles are in radians* 116 | 117 | # Arguments 118 | 119 | * `JD` : Julian (Ephemeris) day 120 | * `north_pole_ecl_coords`: Ecliptic coordinates of Mars's north pole 121 | on `JD` *| in radians* 122 | * `mn_oblq` : Mean obliquity of the ecliptic on `JD` 123 | *| in radians* 124 | * `nut_in_long` : Nutation in ecliptic longitude on `JD` 125 | *| in radians* 126 | * `nut_in_oblq` : Nutation in obliquity of the ecliptic on 127 | `JD` *| in radians* 128 | **/ 129 | pub fn ephemeris ( 130 | 131 | JD : f64, 132 | north_pole_ecl_coords : &coords::EclPoint, 133 | mn_oblq : f64, 134 | nut_in_long : f64, 135 | nut_in_oblq : f64 136 | 137 | ) -> Ephemeris { 138 | 139 | let (mut lambda0, beta0) = (north_pole_ecl_coords.long, north_pole_ecl_coords.lat); 140 | 141 | let (l0, b0, R) = planet::heliocent_coords(&planet::Planet::Earth, JD); 142 | 143 | let (mut l, mut b, mut r) = (0.0, 0.0, 0.0); 144 | let (mut x, mut y, mut z) = (0.0, 0.0, 0.0); 145 | let mut mars_earth_dist = 0.0; 146 | let mut light_time = 0.0; 147 | 148 | let mut i: u8 = 1; 149 | while i <= 2 { 150 | 151 | let (new_l, new_b, new_r) = planet::heliocent_coords(&planet::Planet::Mars, JD - light_time); 152 | l = new_l; b = new_b; r = new_r; 153 | 154 | let (new_x, new_y, new_z) = planet::geocent_ecl_rect_coords(l0, b0, R, l, b, r); 155 | x = new_x; y = new_y; z = new_z; 156 | 157 | mars_earth_dist = planet::dist_frm_ecl_rect_coords(x, y, z); 158 | light_time = planet::light_time(mars_earth_dist); 159 | 160 | i += 1; 161 | 162 | } 163 | 164 | let (mut lambda, mut beta) = planet::ecl_coords_frm_ecl_rect_coords(x, y, z); 165 | 166 | let D_e = ( 167 | -beta0.sin() * beta.sin() - 168 | beta0.cos() * beta.cos() * (lambda0 - lambda).cos() 169 | ).asin(); 170 | 171 | let JC = time::julian_cent(JD); 172 | let N = (49.5581 + 0.7721*JC).to_radians(); 173 | 174 | let l1 = l - (0.00697 / r).to_radians(); 175 | let b1 = b - (0.000225 * (l - N).cos()/r).to_radians(); 176 | let D_s = ( 177 | -beta0.sin() * b1.sin() 178 | - beta0.cos() * b1.cos() * (lambda0 - l1).cos() 179 | ).asin(); 180 | 181 | let W = angle::limit_to_360( 182 | 11.504 183 | + 350.89200025 * (JD - light_time - 2433282.5) 184 | ).to_radians(); 185 | 186 | let asc0 = coords::asc_frm_ecl(lambda0, beta0, mn_oblq); 187 | let dec0 = coords::dec_frm_ecl(lambda0, beta0, mn_oblq); 188 | 189 | let u = y*mn_oblq.cos() - z*mn_oblq.sin(); 190 | let v = y*mn_oblq.sin() + z*mn_oblq.cos(); 191 | let asc = u.atan2(x); 192 | let dec = v.atan2((x*x + u*u).sqrt()); 193 | let zeta = ( 194 | dec0.sin() * dec.cos() * (asc0 - asc).cos() 195 | - dec.sin() * dec0.cos() 196 | ).atan2(dec.cos() * (asc0 - asc).sin()); 197 | let w = W - zeta; 198 | 199 | lambda += 0.005693_f64.to_radians() * (l0 - lambda).cos()/beta.cos(); 200 | beta += 0.005693_f64.to_radians() * (l0 - lambda).sin() * beta.sin(); 201 | 202 | lambda += nut_in_long; 203 | lambda0 += nut_in_long; 204 | let true_oblq = mn_oblq + nut_in_oblq; 205 | 206 | let asc01 = coords::asc_frm_ecl(lambda0, beta0, true_oblq); 207 | let dec01 = coords::dec_frm_ecl(lambda0, beta0, true_oblq); 208 | let asc1 = coords::asc_frm_ecl(lambda, beta, true_oblq); 209 | let dec1 = coords::dec_frm_ecl(lambda, beta, true_oblq); 210 | 211 | let P = (dec01.cos() * (asc01 - asc1).sin()).atan2 ( 212 | dec01.sin() * dec1.cos() 213 | - dec01.cos() * dec1.sin() * (asc01 - asc1).cos() 214 | ); 215 | 216 | let d = 217 | angle::deg_frm_dms(0, 0, 9.36).to_radians() 218 | / mars_earth_dist; 219 | let k = planet::illum_frac_frm_dist(r, mars_earth_dist, R); 220 | let q = (1.0 - k) * d; 221 | 222 | Ephemeris { 223 | De: D_e, 224 | Ds: D_s, 225 | P: P, 226 | q: q, 227 | w: w, 228 | d: d 229 | } 230 | 231 | } 232 | -------------------------------------------------------------------------------- /src/planet/saturn/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Saturn 24 | 25 | use angle; 26 | 27 | pub mod moon; 28 | pub mod ring; 29 | 30 | /** 31 | Computes Saturn's apparent magnitude using G. Muller's formula 32 | 33 | # Returns 34 | 35 | * `app_mag`: Apparent magnitude of Saturn *| in radians* 36 | 37 | # Arguments 38 | 39 | * `delta` : Saturn-Earth distance *| in AU* 40 | * `r` : Saturn-Sun distance *| in AU* 41 | * `deltaU`: Difference between Saturnicentric longitudes of 42 | the Sun and the Earth, measured in the plane of 43 | Saturn's ring *| in radians* 44 | * `B` : Saturnicentric latitude of the Earth *| in radians* 45 | **/ 46 | pub fn apprnt_mag_muller(delta: f64, r: f64, delU: f64, B: f64) -> f64 { 47 | 48 | - 8.68 49 | + 5.0*(r*delta).log10() 50 | + 0.044*delU.abs() 51 | - 2.6*B.abs().sin() 52 | + 1.25*B.sin().powi(2) 53 | 54 | } 55 | 56 | /** 57 | Computes Saturn's apparent magnitude using the Astronomical 58 | Almanac's formula adopted in 1984 59 | 60 | # Returns 61 | 62 | * `app_mag`: Apparent magnitude of Saturn *| in radians* 63 | 64 | # Arguments 65 | 66 | * `delta` : Saturn-Earth distance *| in AU* 67 | * `r` : Saturn-Sun distance *| in AU* 68 | * `deltaU`: Difference between Saturnicentric longitudes of 69 | the Sun and the Earth, measured in the plane of 70 | Saturn's ring *| in radians* 71 | * `B` : Saturnicentric latitude of the Earth *| in radians* 72 | **/ 73 | pub fn apprnt_mag_84(delta: f64, r: f64, delU: f64, B: f64) -> f64 { 74 | 75 | - 8.88 76 | + 5.0*(r*delta).log10() 77 | + 0.044*delU.abs() 78 | - 2.6*B.abs().sin() 79 | + 1.25*B.sin().powi(2) 80 | 81 | } 82 | 83 | #[inline(always)] 84 | fn equatorial_unit_semidiameter() -> f64 { 85 | 86 | angle::deg_frm_dms(0, 0, 82.73).to_radians() 87 | 88 | } 89 | 90 | #[inline(always)] 91 | fn polar_unit_semidiameter() -> f64 { 92 | 93 | angle::deg_frm_dms(0, 0, 73.82).to_radians() 94 | 95 | } 96 | 97 | /** 98 | Computes Saturn's polar semidiameter 99 | 100 | # Returns 101 | 102 | * `pol_semidiameter`: Polar semidiameter *| in radians per AU* 103 | 104 | # Arguments 105 | 106 | * `saturn_earth_dist`: Saturn-Earth distance *| in AU* 107 | * `earth_lat` : Saturnicentric latitude of Earth *| in radians* 108 | **/ 109 | pub fn pol_semidiameter(saturn_earth_dist: f64, earth_lat: f64) -> f64 { 110 | 111 | let a = equatorial_unit_semidiameter(); 112 | let b = polar_unit_semidiameter(); 113 | let k = 1.0 - (b/a).powi(2); 114 | 115 | (a / saturn_earth_dist) * (1.0 - k*earth_lat.cos().powi(2)).sqrt() 116 | 117 | } 118 | 119 | /** 120 | Computes Saturn's equatorial semidiameter 121 | 122 | # Returns 123 | 124 | * `eq_semidiameter`: Equatorial semidiameter *| in radians per AU* 125 | 126 | # Arguments 127 | 128 | * `saturn_earth_dist`: Saturn-Earth distance *| in AU* 129 | **/ 130 | #[inline(always)] 131 | pub fn eq_semidiameter(saturn_earth_dist: f64) -> f64 { 132 | 133 | equatorial_unit_semidiameter() / saturn_earth_dist 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/planet/saturn/ring.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! The ring system of Saturn 24 | 25 | use angle; 26 | use coords; 27 | use planet; 28 | use time; 29 | 30 | #[inline] 31 | pub fn inc(JC: f64) -> f64 { 32 | 33 | ( 34 | 28.075216 35 | - JC * ( 36 | 0.012998 37 | + JC * 0.000004 38 | ) 39 | ).to_radians() 40 | 41 | } 42 | 43 | #[inline] 44 | pub fn ascend_node(JC: f64) -> f64 { 45 | 46 | ( 47 | 169.50847 48 | + JC * ( 49 | 1.394681 50 | + JC * 0.000412 51 | ) 52 | ).to_radians() 53 | 54 | } 55 | 56 | /// Holds the elements for the ring system of Saturn 57 | #[derive(Debug)] 58 | pub struct Elements { 59 | /// Saturnicentric latitude of the Earth, referred to the plane 60 | /// of the ring 61 | pub B : f64, 62 | /// Saturnicentric latitude of the Sun, referred to the plane of 63 | /// the ring 64 | pub B1 : f64, 65 | /// Geocentric position angle of the northern semiminor axis of 66 | /// the apparent ellipse of the ring of the axis 67 | pub P : f64, 68 | /// Difference between Saturnicentric longitudes of the Sun and 69 | /// the Earth, measured in the plane of the ring 70 | pub deltaU : f64, 71 | /// Major axis of the outer edge of the outer ring 72 | pub a : f64, 73 | /// Minor axis of the outer edge of the outer ring 74 | pub b : f64 75 | } 76 | 77 | /** 78 | Computes the elements for the ring system of Saturn 79 | 80 | # Returns 81 | 82 | `elements`: Elements for the ring system. *All angles are in radians* 83 | 84 | # Arguments 85 | 86 | * `JD` : Julian (Ephemeris) day 87 | * `nut_in_long`: Nutation in longitude on `JD` *| in radians* 88 | * `true_oblq` : True obliquity of the ecliptic on `JD` *| in radians* 89 | **/ 90 | pub fn elements(JD: f64, nut_in_long: f64, true_oblq: f64) -> Elements { 91 | 92 | let (l0, b0, R) = planet::heliocent_coords(&planet::Planet::Earth, JD); 93 | 94 | let (mut l, mut b, mut r) = (0.0, 0.0, 0.0); 95 | let (mut x, mut y, mut z) = (0.0, 0.0, 0.0); 96 | let mut saturn_earth_dist = 0.0; 97 | let mut light_time = 0.0; 98 | 99 | let mut i: u8 = 1; 100 | while i <= 2 { 101 | 102 | let (new_l, new_b, new_r) = 103 | planet::heliocent_coords(&planet::Planet::Saturn, JD - light_time); 104 | l = new_l; b = new_b; r = new_r; 105 | 106 | let (new_x, new_y, new_z) = 107 | planet::geocent_ecl_rect_coords(l0, b0, R, l, b, r); 108 | x = new_x; y = new_y; z = new_z; 109 | 110 | saturn_earth_dist = planet::dist_frm_ecl_rect_coords(x, y, z); 111 | light_time = planet::light_time(saturn_earth_dist); 112 | 113 | i += 1; 114 | 115 | } 116 | 117 | let JC = time::julian_cent(JD); 118 | let inc = inc(JC); 119 | let ascend_node = ascend_node(JC); 120 | 121 | let (mut lambda, mut beta) = planet::ecl_coords_frm_ecl_rect_coords(x, y, z); 122 | let B = ( inc.sin() * beta.cos() * (lambda - ascend_node).sin() 123 | - inc.cos() * beta.sin() 124 | ).asin(); 125 | let semi_maj = angle::deg_frm_dms(0, 0, 375.35).to_radians() / saturn_earth_dist; 126 | let semi_min = semi_maj * B.abs().sin(); 127 | 128 | let N = (113.6655 + 0.8771*JC).to_radians(); 129 | 130 | let l1 = l - (0.01759/r).to_radians(); 131 | let b1 = b - (0.000764*(l - N).cos()/r).to_radians(); 132 | 133 | let B1 = ( 134 | inc.sin() * b1.cos() * (l1 - ascend_node).sin() 135 | - inc.cos() * b1.sin() 136 | ).asin(); 137 | let U1 = ( 138 | inc.sin() * b1.sin() 139 | + inc.cos() * b1.cos() * (l1 - ascend_node).sin() 140 | ).atan2( 141 | b1.cos() * (l1 - ascend_node).cos() 142 | ); 143 | let U2 = ( 144 | inc.sin() * beta.sin() 145 | + inc.cos() * beta.cos() * (lambda - ascend_node).sin() 146 | ).atan2( 147 | beta.cos() * (lambda - ascend_node).cos() 148 | ); 149 | let deltaU = (U1 - U2).abs(); 150 | 151 | let mut lambda0 = ascend_node - 90.0_f64.to_radians(); 152 | let beta0 = 90.0_f64.to_radians() - inc; 153 | 154 | let q = 0.005693_f64.to_radians(); 155 | lambda += q * (l0 - lambda).cos() / beta.cos(); 156 | beta += q * (l0 - lambda).sin() * beta.sin(); 157 | 158 | lambda0 += nut_in_long; 159 | lambda += nut_in_long; 160 | 161 | let asc0 = coords::asc_frm_ecl(lambda0, beta0, true_oblq); 162 | let dec0 = coords::dec_frm_ecl(lambda0, beta0, true_oblq); 163 | let asc = coords::asc_frm_ecl(lambda, beta, true_oblq); 164 | let dec = coords::dec_frm_ecl(lambda, beta, true_oblq); 165 | 166 | let P = (dec0.cos() * (asc0 - asc).sin()) 167 | .atan2(dec0.sin()*dec.cos() - dec0.cos()*dec.sin()*(asc0 - asc).cos()); 168 | 169 | Elements { 170 | B : B, 171 | B1 : B1, 172 | P : P, 173 | deltaU : deltaU, 174 | a : semi_maj, 175 | b : semi_min 176 | } 177 | 178 | } 179 | 180 | #[inline(always)] 181 | pub fn inn_edge_outer_ring(a: f64, b: f64) -> (f64, f64) { 182 | 183 | (a * 0.8801, b * 0.8801) 184 | 185 | } 186 | 187 | #[inline(always)] 188 | pub fn out_edge_inner_ing(a: f64, b: f64) -> (f64, f64) { 189 | 190 | (a * 0.8599, b * 0.8599) 191 | 192 | } 193 | 194 | #[inline(always)] 195 | pub fn inn_edge_inner_ring(a: f64, b: f64) -> (f64, f64) { 196 | 197 | (a * 0.665, b * 0.665) 198 | 199 | } 200 | 201 | #[inline(always)] 202 | pub fn inn_edge_dusk_ring(a: f64, b: f64) -> (f64, f64) { 203 | 204 | (a * 0.5486, b * 0.5486) 205 | 206 | } 207 | -------------------------------------------------------------------------------- /src/pluto.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! The dwarf planet Pluto 24 | 25 | use angle; 26 | use time; 27 | 28 | /** 29 | Computes the geocentric equatorial semidiameter of Pluto 30 | 31 | # Returns 32 | 33 | * `semidiameter`: Geocentric equatorial semidiameter 34 | *| in radians per AU* 35 | 36 | # Arguments 37 | 38 | * `pluto_earth_dist`: Pluto-Earth distance *| in AU* 39 | **/ 40 | #[inline] 41 | pub fn semdiameter(pluto_earth_dist: f64) -> f64 42 | { 43 | angle::deg_frm_dms(0, 0, 2.07).to_radians() / pluto_earth_dist 44 | } 45 | 46 | /** 47 | Computes the apparent magnitude of Pluto using the Astronomical 48 | Almanac's method adopted in 1984 49 | 50 | # Returns 51 | 52 | * `app_mag`: Apparent magnitude of Pluto 53 | 54 | # Arguments 55 | 56 | * `delta`: Pluto-Earth distance *| in AU* 57 | * `r` : Pluto-Sun distance *| in AU* 58 | **/ 59 | #[inline] 60 | pub fn apprnt_mag_84(delta: f64, r: f64) -> f64 61 | { 62 | (r * delta).log10()*5.0 - 1.0 63 | } 64 | 65 | /** 66 | Computes the heliocentric coordinates of Pluto, referred to the 67 | standard equinox of J2000.0 68 | 69 | This function is valid only for the years 1885 AD to 2099 AD. 70 | 71 | # Returns 72 | 73 | `(long, lat, rad_vec)` 74 | 75 | * `long` : Heliocentric longitude of Pluto *| in radians* 76 | * `lat` : Heliocentric latitude of Pluto *| in radians* 77 | * `rad_vec`: Heliocentric radius vector of Pluto *| in AU* 78 | 79 | The error in 80 | 81 | * `long` is less than 0.07 arcseconds 82 | * `lat` is less than 0.02 arcseconds 83 | * `rad_vec` is less than 0.000006 AU 84 | 85 | # Arguments 86 | 87 | * `JD`: Julian (Ephemeris) day 88 | **/ 89 | pub fn heliocent_pos(JD: f64) -> (f64, f64, f64) 90 | { 91 | let JC = time::julian_cent(JD); 92 | 93 | struct terms(i8, i8, i8, f64, f64, f64, f64, f64, f64); 94 | let tuple_terms = [ 95 | terms(0, 0, 1, -19.799805, 19.850055, -5.452852, -14.974862, 6.6865439, 6.8951812), 96 | terms(0, 0, 2, 0.897144, -4.954829, 3.527812, 1.672790, -1.1827535, -0.0332538), 97 | terms(0, 0, 3, 0.611149, 1.211027, -1.050748, 0.327647, 0.1593179, -0.1438890), 98 | terms(0, 0, 4, -0.341243, -0.189585, 0.178690, -0.292153, -0.0018444, 0.0483220), 99 | terms(0, 0, 5, 0.129287, -0.034992, 0.018650, 0.100340, -0.0065977, -0.0085431), 100 | terms(0, 0, 6, -0.038164, 0.030893, -0.030697, -0.025823, 0.0031174, -0.0006032), 101 | terms(0, 1, -1, 0.020442, -0.009987, 0.004878, 0.011248, -0.0005794, 0.0022161), 102 | terms(0, 1, 0, -0.004063, -0.005071, 0.000226, -0.000064, 0.0004601, 0.0004032), 103 | terms(0, 1, 1, -0.006016, -0.003336, 0.00203, -0.000836, -0.0001729, 0.0000234), 104 | terms(0, 1, 2, -0.003956, 0.003039, 0.000069, -0.000604, -0.0000415, 0.0000702), 105 | terms(0, 1, 3, -0.000667, 0.003572, -0.000247, -0.000567, 0.0000239, 0.0000723), 106 | terms(0, 2, -2, 0.001276, 0.000501, -0.000057, 0.000001, 0.0000067, -0.0000067), 107 | terms(0, 2, -1, 0.001152, -0.000917, -0.000122, 0.000175, 0.0001034, -0.0000451), 108 | terms(0, 2, 0, 0.00063, -0.001277, -0.000049, -0.000164, -0.0000129, 0.0000504), 109 | terms(1, -1, 0, 0.002571, -0.000459, -0.000197, 0.000199, 0.000048, -0.0000231), 110 | terms(1, -1, 1, 0.000899, -0.001449, -0.000025, 0.000217, 0.0000002, -0.0000441), 111 | terms(1, 0, -3, -0.001016, 0.001043, 0.000589, -0.000248, -0.0003359, 0.0000265), 112 | terms(1, 0, -2, -0.002343, -0.001012, -0.000269, 0.000711, 0.0007856, -0.0007832), 113 | terms(1, 0, -1, 0.007042, 0.000788, 0.000185, 0.000193, 0.0000036, 0.0045763), 114 | terms(1, 0, 0, 0.001199, -0.000338, 0.000315, 0.000807, 0.0008663, 0.0008547), 115 | terms(1, 0, 1, 0.000418, -0.000067, -0.00013, -0.000043, -0.0000809, -0.0000769), 116 | terms(1, 0, 2, 0.00012, -0.000274, 0.000005, 0.000003, 0.0000263, -0.0000144), 117 | terms(1, 0, 3, -0.00006, -0.000159, 0.000002, 0.000017, -0.0000126, 0.0000032), 118 | terms(1, 0, 4, -0.000082, -0.000029, 0.000002, 0.000005, -0.0000035, -0.0000016), 119 | terms(1, 1, -3, -0.000036, -0.000029, 0.000002, 0.000003, -0.0000019, -0.0000004), 120 | terms(1, 1, -2, -0.00004, 0.000007, 0.000003, 0.000001, -0.0000015, 0.0000008), 121 | terms(1, 1, -1, -0.000014, 0.000022, 0.000002, -0.000001, -0.0000004, 0.0000012), 122 | terms(1, 1, 0, 0.000004, 0.000013, 0.000001, -0.000001, 0.0000005, 0.0000006), 123 | terms(1, 1, 1, 0.000005, 0.000002, 0.0, -0.000001, 0.0000003, 0.0000001), 124 | terms(1, 1, 3, -0.000001, 0.0, 0.0, 0.0, 0.0000006, -0.0000002), 125 | terms(2, 0, -6, 0.000002, 0.0, 0.0, -0.000002, 0.0000002, 0.0000002), 126 | terms(2, 0, -5, -0.000004, 0.000005, 0.000002, 0.000002, -0.0000002, -0.0000002), 127 | terms(2, 0, -4, 0.000004, -0.000007, -0.000007, 0.0, 0.0000014, 0.0000013), 128 | terms(2, 0, -3, 0.000014, 0.000024, 0.00001, -0.000008, -0.0000063, 0.0000013), 129 | terms(2, 0, -2, -0.000049, -0.000034, -0.000003, 0.00002, 0.0000136, -0.0000236), 130 | terms(2, 0, -1, 0.000163, -0.000048, 0.000006, 0.000005, 0.0000273, 0.0001065), 131 | terms(2, 0, 0, 0.000009, -0.000024, 0.000014, 0.000017, 0.0000251, 0.0000149), 132 | terms(2, 0, 1, -0.000004, 0.000001, -0.000002, 0.0, -0.0000025, -0.0000009), 133 | terms(2, 0, 2, -0.000003, 0.000001, 0.0, 0.0, 0.0000009, -0.0000002), 134 | terms(2, 0, 3, 0.000001, 0.000003, 0.0, 0.0, -0.0000008, 0.0000007), 135 | terms(3, 0, -2, -0.000003, -0.000001, 0.0, 0.000001, 0.0000002, -0.000001), 136 | terms(3, 0, -1, 0.000005, -0.000003, 0.0, 0.0, 0.0000019, 0.0000035), 137 | terms(3, 0, 0, 0.0, 0.0, 0.000001, 0.0, 0.000001, 0.0000003) 138 | ]; 139 | 140 | let j = 34.350 + 3034.9057 * JC; 141 | let s = 50.080 + 1222.1138 * JC; 142 | let p = 238.96 + 144.96000 * JC; 143 | 144 | let mut long = (238.958116f64 + 144.96 * JC).to_radians(); 145 | let mut lat = -3.908239_f64.to_radians(); 146 | let mut r = 40.7241346; 147 | 148 | for x in tuple_terms.iter() { 149 | let alpha = ((x.0 as f64)*j + (x.1 as f64)*s + (x.2 as f64)*p).to_radians(); 150 | let alpha_sin = alpha.sin(); 151 | let alpha_cos = alpha.cos(); 152 | 153 | long += x.3.to_radians()*alpha_sin + x.4.to_radians()*alpha_cos; 154 | lat += x.5.to_radians()*alpha_sin + x.6.to_radians()*alpha_cos; 155 | r += x.7*alpha_sin + x.8*alpha_cos; 156 | } 157 | 158 | (long, lat, r) 159 | } 160 | 161 | /** 162 | Returns the mean orbital elements of Pluto near 2000 AD 163 | 164 | # Returns 165 | 166 | `(a, e, i, omega, w)` 167 | 168 | * `a` : Semimajor axis of the orbit *| in AU* 169 | * `e` : Eccentricity of the orbit 170 | * `i` : Inclination of the plane of the orbit with the 171 | plane of the ecliptic *| in radians* 172 | * `omega`: Longitude of the ascending node *| in radians* 173 | * `w` : Argument of the perihelion *| in radians* 174 | **/ 175 | pub fn mn_orb_elements_2000AD() -> (f64, f64, f64, f64, f64) 176 | { 177 | ( 178 | 039.543, // a 179 | 000.249, // e 180 | 017.140_f64.to_radians(), // i 181 | 110.307_f64.to_radians(), // omega 182 | 113.768_f64.to_radians() // w 183 | ) 184 | } 185 | -------------------------------------------------------------------------------- /src/precess.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Corrections for precession 24 | 25 | use angle; 26 | use std; 27 | use time; 28 | 29 | /** 30 | Computes annual precession in equatorial coordinates towards a new 31 | epoch 32 | 33 | # Returns 34 | 35 | `(ann_precess_asc, ann_precess_dec)` 36 | 37 | * `ann_precess_asc`: Annual precession in right ascension towards 38 | the new epoch *| in radians* 39 | * `ann_precess_dec`: Annual precession in declination towards 40 | the new epoch *| in radians* 41 | 42 | In the case of a star, the precession returned here does not take 43 | into account it's annual proper motion. The annual proper motion 44 | in right ascension and declination must simply be added to the 45 | corresponding annual precession returned here in order to reduce 46 | the equatorial coordinates to the new epoch. 47 | 48 | # Arguments 49 | 50 | * `asc`: Right ascension for the old epoch *| in radians* 51 | * `dec`: Declination for the old epoch *| in radians*. Shouldn't 52 | be too close to the celestial poles of the Earth. 53 | * `JD` : Julian (Ephemeris) day corresponding to the new epoch. 54 | Shouldn't be more than a few hundred years away from 55 | the old epoch. 56 | **/ 57 | pub fn annual_precess(asc: f64, dec: f64, JD: f64) -> (f64, f64) 58 | { 59 | let JC = time::julian_cent(JD); 60 | 61 | let m = ( 62 | angle::deg_frm_hms(0, 0, 3.07496) 63 | + angle::deg_frm_hms(0, 0, 0.00186) * JC 64 | ).to_radians(); 65 | 66 | let n = ( 67 | angle::deg_frm_hms(0, 0, 1.33621) 68 | - angle::deg_frm_hms(0, 0, 0.00057) * JC 69 | ).to_radians(); 70 | 71 | (m + n*asc.sin()*dec.tan(), n * asc.cos()) 72 | } 73 | 74 | /** 75 | Computes equatorial coordinates reduced to a different epoch 76 | 77 | # Returns 78 | 79 | `(new_asc, new_dec)` 80 | 81 | * `new_asc`: Right ascension in the new epoch *| in radians* 82 | * `new_dec`: Declination in the new epoch *| in radians* 83 | 84 | # Arguments 85 | 86 | * `old_asc`: Right ascension in the old epoch *| in radians*, 87 | referred to the FK5 system 88 | * `old_dec`: Declination in the old epoch *| in radians*, 89 | referred to the FK5 system 90 | * `JD1` : Julian (Ephemeris) day corresponding to the old epoch 91 | * `JD2` : Julian (Ephemeris) day corresponding to the new epoch 92 | **/ 93 | pub fn precess_eq_coords(old_asc: f64, 94 | old_dec: f64, 95 | JD1: f64, 96 | JD2: f64) -> (f64, f64) 97 | { 98 | let T = time::julian_cent(JD1); 99 | let t = (JD2 - JD1) / 36525.0; 100 | 101 | let x = t * (angle::deg_frm_dms(0, 0, 2306.2181) + 102 | T * (angle::deg_frm_dms(0, 0, 1.39656) - 103 | T*angle::deg_frm_dms(0, 0, 0.000139))); 104 | let xi = (x + t*t*((angle::deg_frm_dms(0, 0, 0.30188) - 105 | T*angle::deg_frm_dms(0, 0, 0.000344)) + 106 | t*angle::deg_frm_dms(0, 0, 0.017998))).to_radians(); 107 | 108 | let zeta = (x + t*t*((angle::deg_frm_dms(0, 0, 1.09468) - 109 | T*angle::deg_frm_dms(0, 0, 0.000066)) + 110 | t*angle::deg_frm_dms(0, 0, 0.018203))).to_radians(); 111 | 112 | let y = T * angle::deg_frm_dms(0, 0, 0.000217); 113 | let theta = (t * (angle::deg_frm_dms(0, 0, 2004.3109) + 114 | T * (angle::deg_frm_dms(0, 0, 0.8533) - y) - 115 | t * ((angle::deg_frm_dms(0, 0, 0.42665) + y) + 116 | t*angle::deg_frm_dms(0, 0, 0.041833)))).to_radians(); 117 | 118 | let A = old_dec.cos() * (old_asc + xi).sin(); 119 | 120 | let B = 121 | theta.cos() * old_dec.cos() * (old_asc + xi).cos() 122 | - theta.sin() * old_dec.sin(); 123 | 124 | let C = 125 | theta.sin() * old_dec.cos() * (old_asc + xi).cos() 126 | + theta.cos() * old_dec.sin(); 127 | 128 | (A.atan2(B) + zeta, C.asin()) 129 | } 130 | 131 | /** 132 | Computes equatorial coordinates, from coordinates referred to the 133 | FK4 system, reduced to a different epoch 134 | 135 | # Returns 136 | 137 | `(new_asc, new_dec)` 138 | 139 | * `new_asc`: Right ascension in the new epoch *| in radians* 140 | * `new_dec`: Declination in the new epoch *| in radians* 141 | 142 | # Arguments 143 | 144 | * `old_asc`: Right ascension in the old epoch *| in radians*, 145 | referred to the FK4 system 146 | * `old_dec`: Declination for in old epoch *| in radians*, 147 | referred to the FK4 system 148 | * `JD1` : Julian (Ephemeris) day corresponding to the old epoch 149 | * `JD2` : Julian (Ephemeris) day corresponding to the new epoch 150 | **/ 151 | pub fn precess_eq_coords_FK5(old_asc: f64, 152 | old_dec: f64, 153 | JD1: f64, 154 | JD2: f64) -> (f64, f64) 155 | { 156 | let T = (JD1 - 2415020.3135) / 36524.2199; 157 | let t = (JD2 - JD1) / 36524.2199; 158 | 159 | let xi = t * ( 160 | angle::deg_frm_dms(0, 0, 2304.25) + T*angle::deg_frm_dms(0, 0, 1.396) 161 | + t * ( 162 | angle::deg_frm_dms(0, 0, 0.302) + t*angle::deg_frm_dms(0, 0, 0.018) 163 | ) 164 | ); 165 | 166 | let zeta = 167 | xi 168 | + t * t * ( 169 | angle::deg_frm_dms(0, 0, 0.791) + t*angle::deg_frm_dms(0, 0, 0.001) 170 | ); 171 | 172 | let theta = t * ( 173 | angle::deg_frm_dms(0, 0, 2004.682) 174 | - T * angle::deg_frm_dms(0, 0, 0.853) 175 | - t * ( 176 | angle::deg_frm_dms(0, 0, 0.426) 177 | + t * angle::deg_frm_dms(0, 0, 0.042) 178 | ) 179 | ); 180 | 181 | let A = old_dec.cos() * (old_asc + xi).sin(); 182 | 183 | let B = 184 | theta.cos() * old_dec.cos() * (old_asc + xi).cos() 185 | - theta.sin() * old_dec.sin(); 186 | 187 | let C = 188 | theta.sin() * old_dec.cos() * (old_asc + xi).cos() 189 | + theta.cos() * old_dec.sin(); 190 | 191 | (A.atan2(B) + zeta, C.asin()) 192 | } 193 | 194 | /** 195 | Computes ecliptic coordinates reduced to a different epoch 196 | 197 | # Returns 198 | 199 | `(new_long, new_lat)` 200 | 201 | * `new_long`: Ecliptic longitude in the new epoch *| in radians* 202 | * `new_lat` : Ecliptic latitude in the new epoch *| in radians* 203 | 204 | # Arguments 205 | 206 | * `old_long`: Ecliptic longitude in the old epoch *| in radians* 207 | * `old_lat` : Ecliptic latitude in the old epoch *| in radians* 208 | * `JD_old` : Julian (Ephemeris) day corresponding to the old epoch 209 | * `JD_new` : Julian (Ephemeris) day corresponding to the new epoch 210 | **/ 211 | pub fn precess_ecl_coords(old_long: f64, 212 | old_lat: f64, 213 | JD_old: f64, 214 | JD_new: f64) -> (f64, f64) 215 | { 216 | let T = time::julian_cent(JD_old); 217 | let t = (JD_new - JD_old) / 36525.0; 218 | 219 | let (nu, Pi, rho) = angles_for_ecl_change(t, T); 220 | 221 | let A = 222 | nu.cos() * old_lat.cos() * (Pi - old_long).sin() 223 | - nu.sin() * old_lat.sin(); 224 | 225 | let B = old_lat.cos() * (Pi - old_long).cos(); 226 | 227 | let C = 228 | nu.cos() * old_lat.sin() 229 | + nu.sin() * old_lat.cos() * (Pi - old_long).sin(); 230 | 231 | let new_long = rho + Pi - A.atan2(B); 232 | let new_lat = C.asin(); 233 | 234 | (new_long, new_lat) 235 | } 236 | 237 | #[inline] 238 | fn angles_for_ecl_change(t: f64, T: f64) -> (f64, f64, f64) 239 | { 240 | let x = T * angle::deg_frm_dms(0, 0, 0.000598); 241 | let nu = ( 242 | t * ( 243 | angle::deg_frm_dms(0, 0, 47.0029) 244 | - T * (angle::deg_frm_dms(0, 0, 0.06603) - x) 245 | + t * ( 246 | (angle::deg_frm_dms(0, 0, -0.03302) + x) 247 | + t * angle::deg_frm_dms(0, 0, 0.00006) 248 | ) 249 | ) 250 | ).to_radians(); 251 | 252 | let Pi = ( 253 | 174.876384 254 | + T * ( 255 | angle::deg_frm_dms(0, 0, 3289.4789) 256 | + T * angle::deg_frm_dms(0, 0, 0.60622) 257 | ) 258 | - t * ( 259 | ( 260 | angle::deg_frm_dms(0, 0, 869.8089) 261 | + T * angle::deg_frm_dms(0, 0, 0.50491) 262 | ) 263 | - t * angle::deg_frm_dms(0, 0, 0.03536) 264 | ) 265 | ).to_radians(); 266 | 267 | let y = T * angle::deg_frm_dms(0, 0, 0.000042); 268 | let rho = ( 269 | t * ( 270 | angle::deg_frm_dms(0, 0, 5029.0966) 271 | + T * (angle::deg_frm_dms(0, 0, 2.22226) - y) 272 | + t * ( 273 | (angle::deg_frm_dms(0, 0, 1.11113) - y) 274 | - t * angle::deg_frm_dms(0, 0, 0.000006) 275 | ) 276 | ) 277 | ).to_radians(); 278 | 279 | (nu, Pi, rho) 280 | } 281 | 282 | /** 283 | Computes orbital elements reduced to a different equinox 284 | 285 | # Returns 286 | 287 | `(new_inc, new_arg_perih, new_long_ascend_node)` 288 | 289 | * `new_inc` : Inclination in the new 290 | equinox *| in radians* 291 | * `new_arg_perih` : Argument of perihelion in the 292 | new equinox *| in radians* 293 | * `new_long_ascend_node`: Longitude of ascending node in 294 | the new equinox *| in radians* 295 | 296 | # Arguments 297 | 298 | * `old_inc` : Inclination in the old equinox *| in radians* 299 | * `old_arg_perih` : Argument of perihelion in the old 300 | equinox *| in radians* 301 | * `old_long_ascend_node`: Longitude of ascending node in the old 302 | equinox *| in radians* 303 | * `JD1` : Julian (Ephemeris) day corresponding to the old 304 | equinox 305 | * `JD2` : Julian (Ephemeris) day corresponding to the new 306 | equinox 307 | **/ 308 | pub fn precess_orb_elements(old_inc: f64, 309 | old_arg_perih: f64, 310 | old_long_ascend_node: f64, 311 | JD1: f64, 312 | JD2: f64) -> (f64, f64, f64) 313 | { 314 | let T = time::julian_cent(JD1); 315 | let t = (JD2 - JD1) / 36525.0; 316 | 317 | let (nu, Pi, rho) = angles_for_ecl_change(t, T); 318 | 319 | let new_inc; 320 | let new_long_ascend_node; 321 | let phi = Pi + rho; 322 | 323 | if old_inc == 0.0 { 324 | new_inc = nu; 325 | new_long_ascend_node = phi + std::f64::consts::PI; 326 | } else { 327 | let A = old_inc.sin() * (old_long_ascend_node - Pi).sin(); 328 | 329 | let B = 330 | -nu.sin() * old_inc.cos() 331 | + nu.cos() * old_inc.sin() * (old_long_ascend_node - Pi).cos(); 332 | 333 | new_inc = (A*A + B*B).sqrt().asin(); 334 | new_long_ascend_node = phi + A.atan2(B); 335 | } 336 | 337 | let delta_w = 338 | (-nu.sin() * (old_long_ascend_node - Pi).sin()/new_inc.sin()).asin(); 339 | 340 | (new_inc, old_arg_perih + delta_w, new_long_ascend_node) 341 | } 342 | -------------------------------------------------------------------------------- /src/star.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Stars 24 | 25 | /** 26 | Computes the combined magnitude of two stars 27 | 28 | # Arguments 29 | 30 | * `m1`: Magnitude of star 1 31 | * `m2`: Magnitude of star 2 32 | **/ 33 | #[inline] 34 | pub fn combined_mag(m1: f64, m2: f64) -> f64 35 | { 36 | m2 - 2.5 * (brightness_ratio(m1, m2) + 1.0) 37 | } 38 | 39 | /** 40 | Computes the combined magnitude of two or more stars 41 | 42 | # Arguments 43 | 44 | * `m`: Array of magnitudes of stars 45 | **/ 46 | pub fn combined_mag_of_many(m: &[f64]) -> f64 47 | { 48 | let mut sum = 0.0; 49 | 50 | for i in m.iter() { 51 | sum += 10_f64.powf(-0.4 * i); 52 | } 53 | 54 | -2.5 * sum.log10() 55 | } 56 | 57 | /** 58 | Computes the brightness ratio of two stars 59 | 60 | # Arguments 61 | 62 | * `m1`: Magnitude of star 1 63 | * `m2`: Magnitude of star 2 64 | **/ 65 | #[inline] 66 | pub fn brightness_ratio(m1: f64, m2: f64) -> f64 67 | { 68 | 10.0_f64.powf(0.4 * (m2 - m1)) 69 | } 70 | 71 | /** 72 | Computes the difference in magnitude of two stars 73 | 74 | # Arguments 75 | 76 | * `br`: Brightness ratio of two stars 77 | **/ 78 | #[inline] 79 | pub fn mag_diff(br: f64) -> f64 80 | { 81 | 2.5 * br.log10() 82 | } 83 | 84 | /** 85 | Computes the absolute magnitude of a star from its parallax 86 | 87 | # Arguments 88 | 89 | * `par`: Parallax of the star 90 | * `am`: Apparent magnitude of the star 91 | **/ 92 | #[inline] 93 | pub fn abs_mag_frm_parallax(par: f64, am: f64) -> f64 94 | { 95 | am + 5.0 + 5.0*(par.to_degrees() * 3600.0).log10() 96 | } 97 | 98 | /** 99 | Computes the absolute magnitude of a star from its distance from earth 100 | 101 | # Arguments 102 | 103 | * `d`: The star's to earth *(parsecs)* 104 | * `am`: Apparent magnitude of the star 105 | **/ 106 | 107 | #[inline] 108 | pub fn abs_mag_frm_dist(d: f64, am: f64) -> f64 109 | { 110 | am + 5.0 - 5.0*d.log10() 111 | } 112 | 113 | /** 114 | Computes the angle between a vector from a star to the 115 | north celestial pole of the Earth and a vector from the 116 | same star to the north pole of the ecliptic 117 | 118 | # Returns 119 | 120 | * `angle`: The desired angle *| in radians* 121 | 122 | # Arguments 123 | 124 | * `eclip_long`: The star's ecliptical longitude *| in radians* 125 | * `eclip_lat`: The star's ecliptical latitude *| in radians* 126 | * `oblq_eclip`: Obliquity of the ecliptic *| in radians* 127 | **/ 128 | 129 | #[inline] 130 | pub fn angl_between_north_celes_and_eclip_pole(eclip_long: f64, 131 | eclip_lat: f64, 132 | oblq_eclip: f64) -> f64 133 | { 134 | (eclip_long.cos() * oblq_eclip.tan()).atan2 ( 135 | eclip_lat.sin() * eclip_long.sin() * oblq_eclip.tan() 136 | - eclip_lat.cos() 137 | ) 138 | } 139 | 140 | /** 141 | Computes the equatorial coordinates of a star at 142 | at a different time from it's motion in space 143 | 144 | This function Computes the equatorial coordinates 145 | of a star at a different time by taking into account 146 | it's proper motion, distance and radial velocity. 147 | 148 | # Returns 149 | 150 | `(new_asc, new_dec)` 151 | 152 | * `new_asc`: Right ascension at the different 153 | time *| in radians* 154 | * `new_dec`: Declination at the different 155 | time *| in radians* 156 | 157 | # Arguments 158 | 159 | * `asc0`: Right ascension of the star initially *| in radians* 160 | * `dec0`: Declination of the star initially *| in radians* 161 | * `r`: Distance of the star (*parsecs*) 162 | * `delta_r`: Radial velocity of the star (*parsecs/second*) 163 | * `proper_motion_asc`: Proper motion of the star in right ascension 164 | *| in radians* 165 | * `proper_motion_dec`: Proper motion of the star in declination 166 | *| in radians* 167 | * `t`: Decimal years from the inital time; negative in the past 168 | and positive in the future 169 | **/ 170 | pub fn eq_coords_frm_motion(asc0: f64, 171 | dec0: f64, 172 | r: f64, 173 | delta_r: f64, 174 | proper_motion_asc: f64, 175 | proper_motion_dec: f64, 176 | t: f64) -> (f64, f64) 177 | { 178 | let x = r * dec0.cos() * asc0.cos(); 179 | let y = r * dec0.cos() * asc0.sin(); 180 | let z = r * dec0.sin(); 181 | 182 | let delta_asc = 3600.0 * proper_motion_asc.to_degrees()/13751.0; 183 | let delta_dec = 3600.0 * proper_motion_dec.to_degrees()/206265.0; 184 | 185 | let delta_x = (x / r)*delta_r - z*delta_dec*asc0.cos() - y*delta_asc; 186 | let delta_y = (y / r)*delta_r - z*delta_dec*asc0.sin() + x*delta_asc; 187 | let delta_z = (z / r)*delta_r + r*delta_dec*dec0.cos(); 188 | 189 | let x1 = x + t*delta_x; 190 | let y1 = y + t*delta_y; 191 | let z1 = z + t*delta_z; 192 | 193 | let asc = y1.atan2(x1); 194 | let dec = z1.atan2((x1*x1 + y1*y1).sqrt()); 195 | 196 | (asc, dec) 197 | } 198 | 199 | pub fn proper_motion_in_eq_coords(asc: f64, 200 | dec: f64, 201 | pmotion_asc: f64, 202 | pmotion_dec: f64, 203 | ecl_lat: f64, 204 | oblq_eclip: f64) -> (f64, f64) 205 | { 206 | let ecl_lat_cos = ecl_lat.cos(); 207 | 208 | let pmotion_long = ( 209 | pmotion_dec * oblq_eclip.sin() * asc.cos() 210 | + pmotion_asc * dec.cos() * ( 211 | oblq_eclip.cos() * dec.cos() 212 | + oblq_eclip.sin() * dec.sin() * asc.sin() 213 | ) 214 | ) / (ecl_lat_cos * ecl_lat_cos); 215 | 216 | let pmotion_lat = ( 217 | pmotion_dec * ( 218 | oblq_eclip.cos() * dec.cos() 219 | + oblq_eclip.sin() * dec.sin() * asc.sin() 220 | ) 221 | - pmotion_asc * oblq_eclip.sin() * asc.cos() * dec.cos() 222 | ) / ecl_lat_cos; 223 | 224 | (pmotion_long, pmotion_lat) 225 | } 226 | -------------------------------------------------------------------------------- /src/sun.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! The Sun 24 | 25 | use angle; 26 | use time; 27 | use std; 28 | use planet; 29 | use coords; 30 | 31 | /** 32 | Computes the Sun's equatorial semidiameter 33 | 34 | # Arguments 35 | 36 | * `sun_earth_dist`: Sun-Earth distance *| in AU* 37 | **/ 38 | #[inline] 39 | pub fn semidiameter(sun_earth_dist: f64) -> f64 { 40 | 41 | angle::deg_frm_dms(0, 0, 959.63) / sun_earth_dist 42 | 43 | } 44 | 45 | /** 46 | Computes the Sun's geocentric ecliptic position, referred to the mean 47 | equinox of the date 48 | 49 | # Returns 50 | 51 | `(sun_ecl_point, sun_earth_dist)` 52 | 53 | * `sun_ecl_point` : Ecliptic point of the Sun *| in radians* 54 | * `sun_earth_dist`: Sun-Earth distance *| in AU* 55 | 56 | # Arguments 57 | 58 | * `JD`: Julian (Ephemeris) day 59 | **/ 60 | pub fn geocent_ecl_pos(JD: f64) -> (coords::EclPoint, f64) { 61 | 62 | let (L, B, R) = planet::heliocent_coords(&planet::Planet::Earth, JD); 63 | 64 | let ecl_point = coords::EclPoint { 65 | long: angle::limit_to_two_PI(L + std::f64::consts::PI), 66 | lat: angle::limit_to_two_PI(-B) 67 | }; 68 | 69 | (ecl_point, R) 70 | 71 | } 72 | 73 | /** 74 | Computes the Sun's geocentric ecliptic coordinates converted to the 75 | FK5 system 76 | 77 | # Returns 78 | 79 | `(ecl_long_FK5, ecl_lat_FK5)` 80 | 81 | * `ecl_long_FK5`: Ecliptic longitude of the Sun *| in radians*, 82 | converted to the FK5 system 83 | * `ecl_lat_FK5` : Ecliptic latitude of the Sun *| in radians*, 84 | converted to the FK5 system 85 | 86 | # Arguments 87 | 88 | * `JD` : Julian (Ephemeris) day 89 | * `ecl_long`: Ecliptic longitude of the Sun on `JD` 90 | *| in radians*, referred to the mean equinox 91 | of the date 92 | * `ecl_lat` : Ecliptic latitude of the Sun `JD` 93 | *| in radians*, referred to the mean equinox 94 | of the date 95 | **/ 96 | pub fn ecl_coords_to_FK5(JD: f64, ecl_long: f64, ecl_lat: f64) -> (f64, f64) { 97 | 98 | let ecl_long_FK5 = 99 | ecl_long 100 | - angle::deg_frm_dms(0, 0, 0.09033).to_radians(); 101 | 102 | let JC = time::julian_cent(JD); 103 | let lambda1 = 104 | ecl_long 105 | - JC * (1.397 + JC*0.00031).to_radians(); 106 | 107 | let ecl_lat_FK5 = 108 | ecl_lat 109 | + angle::deg_frm_dms(0, 0, 0.03916).to_radians() * ( 110 | lambda1.cos() - lambda1.sin() 111 | ); 112 | 113 | (ecl_long_FK5, ecl_lat_FK5) 114 | 115 | } 116 | 117 | /** 118 | Computes the Sun's geocentric rectangular coordinates, referred to 119 | the mean equinox of the date 120 | 121 | # Returns 122 | 123 | `(x, y z)` 124 | 125 | * `x`: The X coordinate *| in AU* 126 | * `y`: The Y coordinate *| in AU* 127 | * `z`: The Z coordinate *| in AU* 128 | 129 | * The positive x-axis is directed towards the Earth's vernal equinox 130 | (0 degrees longitude) 131 | * The positive y-axis lies in the plane of the Earth's equator and is 132 | directed towards 90 degrees longitude 133 | * The positive z-axis is directed towards the Earth's northern 134 | celestial pole 135 | 136 | # Arguments 137 | 138 | * `sun_geo_long`: The Sun's geometric longitude *| in radians*, 139 | *without* corrections for nutation and abberation 140 | * `sun_geo_lat` : The Sun's geometric latitude *| in radians*, 141 | *without* corrections for nutation and abberation 142 | * `sun_rad_vec` : The Sun's geometric radius vector *| in AU* 143 | * `mn_oblq` : Mean obliquity of the ecliptic 144 | **/ 145 | pub fn geocent_rect_coords ( 146 | 147 | sun_geo_long : f64, 148 | sun_geo_lat : f64, 149 | sun_rad_vec : f64, 150 | mn_oblq : f64 151 | 152 | ) -> (f64, f64, f64) { 153 | 154 | let x = sun_rad_vec * sun_geo_lat.cos() * sun_geo_long.cos(); 155 | 156 | let y = sun_rad_vec * ( 157 | sun_geo_lat.cos() * sun_geo_long.sin() * mn_oblq.cos() 158 | - sun_geo_lat.sin() * mn_oblq.sin() 159 | ); 160 | 161 | let z = sun_rad_vec * ( 162 | sun_geo_lat.cos() * sun_geo_long.sin() * mn_oblq.sin() 163 | + sun_geo_lat.sin() * mn_oblq.cos() 164 | ); 165 | 166 | (x, y, z) 167 | 168 | } 169 | 170 | /** 171 | Return quantites used in the ephemeris for physical observations of 172 | the Sun 173 | 174 | # Returns 175 | 176 | `(P, B0, L0)` 177 | 178 | * `P` : Position angle of the northern extremity of the axis of 179 | rotation, measured eastwards from the North point of the 180 | solar disk *| in radians* 181 | * `B0`: Heliographic latitude of the center of the solar 182 | disk *| in radians* 183 | * `L0`: Heliographic longitude of the center of the solar 184 | disk *| in radians* 185 | 186 | # Arguments 187 | 188 | * `JD` : Julian (Ephemeris) day 189 | * `app_long`: Apparent longitude of the Sun *| in radians*, 190 | including the effect of abberation and *not* that 191 | of nutation 192 | * `app_long_with_nut`: Apparent longitude of the Sun *| in radians*, 193 | including the effect of abberation *and* that 194 | of nutation 195 | * `oblq_eclip`: True obliquity of the ecliptic *| in radians* 196 | **/ 197 | pub fn ephemeris ( 198 | 199 | JD : f64, 200 | app_long : f64, 201 | app_long_with_nut : f64, 202 | oblq_eclip : f64 203 | 204 | ) -> (f64, f64, f64) { 205 | 206 | let theta = angle::limit_to_360((JD - 2398220.0) * 360.0/25.38).to_radians(); 207 | let I = 7.25_f64.to_radians(); 208 | let K = (73.6667 + 1.3958333*(JD - 2396758.0)/36525.0).to_radians(); 209 | 210 | let z = app_long - K; 211 | let sin_z = z.sin(); 212 | let cos_z = z.cos(); 213 | 214 | let mut x = (-app_long_with_nut.cos() * oblq_eclip.tan()).atan(); 215 | let mut y = (-cos_z * I.tan()).atan(); 216 | x = magnitude_limited_to_less_than_PI(x); 217 | y = magnitude_limited_to_less_than_PI(y); 218 | 219 | let B_0 = (sin_z * I.sin()).asin(); 220 | let nu = (-sin_z * I.cos()).atan2(-cos_z); 221 | let L_0 = angle::limit_to_two_PI(nu - theta); 222 | 223 | let P = x + y; 224 | 225 | (P, B_0, L_0) 226 | 227 | } 228 | 229 | #[inline] 230 | fn magnitude_limited_to_less_than_PI(a: f64) -> f64 { 231 | 232 | let PI_INTO_THREE_BY_TWO = std::f64::consts::PI * 3.0/2.0; 233 | 234 | if a > PI_INTO_THREE_BY_TWO { a - angle::TWO_PI } 235 | else { a } 236 | 237 | } 238 | 239 | /** 240 | Computes an approximate time for the beginning of a solar synodic 241 | rotation 242 | 243 | # Returns 244 | 245 | * `JD`: The Julian Day corresponding to the approximate time for 246 | the beginning of a solar synodic rotation 247 | 248 | Between the years 1850 and 2100, `JD` will be in less than 0.002 days 249 | in error. 250 | 251 | # Arguments 252 | 253 | * `C`: Carrington's synodic rotation number 254 | **/ 255 | pub fn synodic_rot(C: i64) -> f64 { 256 | 257 | let M = (281.96 + 26.882476*(C as f64)).to_radians(); 258 | 259 | 2398140.227 + 27.2752316*(C as f64) 260 | + 0.1454 * M.sin() 261 | - 0.0085 * (2.0 * M).sin() 262 | - 0.0141 * (2.0 * M).cos() 263 | 264 | } 265 | -------------------------------------------------------------------------------- /src/transit.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Time of rise, transit and set for a celestial body 24 | 25 | use angle; 26 | use coords; 27 | use interpol; 28 | 29 | /// Represents a celestial body in transit 30 | pub enum TransitBody { 31 | /// A star or a planet 32 | StarOrPlanet, 33 | /// The Sun 34 | Sun, 35 | /// The Moon 36 | Moon 37 | } 38 | 39 | /// Represents a transit type 40 | pub enum TransitType { 41 | /// Rise 42 | Rise, 43 | /// Transit at zenith 44 | Transit, 45 | /// Set 46 | Set 47 | } 48 | 49 | /** 50 | Computes the time of transit for a celestial body 51 | 52 | # Returns 53 | 54 | * `(hour, min, sec)`: Time of transit on the day of interest, in UTC 55 | 56 | # Arguments 57 | 58 | * `transit_type` : A `TransitType` 59 | * `transit_body` : The `TransitBody` 60 | * `geograph_point`: Geographic point of the observer *| in radians* 61 | 62 | Let `JD` be the Julian (Ephemeris) day of interest, 63 | 64 | * `eq_point1`: Equatorial point of the transit body on `JD - 1` *| in radians* 65 | * `eq_point2`: Equatorial point of the transit body on `JD` *| in radians* 66 | * `eq_point3`: Equatorial point of the transit body on `JD + 1` *| in radians* 67 | * `apprnt_greenwhich_sidr`: Apparent sidereal time at Greenwhich on `JD` *| in radians* 68 | * `delta_t`: ΔT for `JD` (Julian day) 69 | * `moon_eq_hz_parallax`: Equatorial horizontal parallax of the Moon on `JD` 70 | *| in radians*. *Pass a meaningfull value here only when* 71 | `TransitBody::Moon` *is passed for* `transit_body`. 72 | 73 | **/ 74 | pub fn time ( 75 | 76 | transit_type : &TransitType, 77 | transit_body : &TransitBody, 78 | geograph_point : &coords::GeographPoint, 79 | eq_point1 : &coords::EqPoint, 80 | eq_point2 : &coords::EqPoint, 81 | eq_point3 : &coords::EqPoint, 82 | apprnt_greenwhich_sidr : f64, 83 | delta_t : f64, 84 | moon_eq_hz_parallax : f64 85 | 86 | ) -> (i64, i64, f64) { 87 | 88 | let h0 = match transit_body { 89 | &TransitBody::StarOrPlanet => -0.5667_f64.to_radians(), 90 | &TransitBody::Sun => -0.8333_f64.to_radians(), 91 | &TransitBody::Moon => 0.7275 * moon_eq_hz_parallax 92 | - 0.5667_f64.to_radians(), 93 | }; 94 | 95 | let mut H0 = ( 96 | (h0.sin() - geograph_point.lat.sin() * eq_point2.dec.sin()) / 97 | (geograph_point.lat.cos() * eq_point2.dec.cos()) 98 | ).acos(); 99 | H0 = angle::limit_to_two_PI(H0); 100 | 101 | let mut m = m( 102 | &transit_type, H0, eq_point2.asc, geograph_point.long, 103 | apprnt_greenwhich_sidr); 104 | let theta0 = apprnt_greenwhich_sidr + m*360.985647_f64.to_radians(); 105 | 106 | let d = m + delta_t/86400.0; 107 | 108 | let asc = interpol::three_values(eq_point1.asc, eq_point2.asc, eq_point3.asc, d); 109 | 110 | let dec = match transit_type { 111 | &TransitType::Transit => 0.0, 112 | 113 | &TransitType::Rise => interpol::three_values( 114 | eq_point1.dec, eq_point2.dec, 115 | eq_point3.dec, d), 116 | 117 | &TransitType::Set => interpol::three_values( 118 | eq_point1.dec, eq_point2.dec, 119 | eq_point3.dec, d) 120 | }; 121 | 122 | let mut H = coords::hr_angl_frm_observer_long 123 | (theta0, geograph_point.long, asc).to_degrees(); 124 | H = angle::limit_to_360(H); 125 | if H > 180.0 { H -= 360.0; } 126 | H = H.to_radians(); 127 | 128 | let h = match transit_type { 129 | &TransitType::Transit => 0.0, 130 | &TransitType::Rise => coords::alt_frm_eq(H, dec, geograph_point.lat), 131 | &TransitType::Set => coords::alt_frm_eq(H, dec, geograph_point.lat) 132 | }; 133 | 134 | m += match transit_type { 135 | &TransitType::Transit => -H / angle::TWO_PI, 136 | &TransitType::Rise => (h - h0) / (angle::TWO_PI * dec.cos() * geograph_point.lat.cos() * H.sin()), 137 | &TransitType::Set => (h - h0) / (angle::TWO_PI * dec.cos() * geograph_point.lat.cos() * H.sin()) 138 | }; 139 | 140 | let h = 24.0 * m; 141 | let hour = h as i64; 142 | let m = (h - (hour as f64)) * 60.0; 143 | let minute = m as i64; 144 | let second = (m - (minute as f64)) * 60.0; 145 | 146 | (hour, minute, second) 147 | 148 | } 149 | 150 | #[inline] 151 | fn m ( 152 | 153 | transit_type : &TransitType, 154 | H0 : f64, 155 | asc : f64, 156 | L : f64, 157 | Theta0 : f64 158 | 159 | ) -> f64 { 160 | 161 | let mut m = (asc + L - Theta0)/angle::TWO_PI; 162 | let p = H0/angle::TWO_PI; 163 | 164 | m += match transit_type { 165 | &TransitType::Transit => 0.0, 166 | &TransitType::Rise => -p, 167 | &TransitType::Set => p 168 | }; 169 | 170 | if m < 0.0 { m += 1.0 } 171 | else if m > 1.0 { m -= 1.0 } 172 | 173 | m 174 | 175 | } 176 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | //! Some programming utilities 24 | 25 | /// Returns a float rounded upto a certain number of decimal digits 26 | #[inline] 27 | pub fn round_upto_digits(float: f64, decimal_digits: u32) -> f64 28 | { 29 | let mut d = 1.0; 30 | 31 | for _ in 1..(decimal_digits + 1) { 32 | d *= 10.0; 33 | } 34 | 35 | (float * d).round() / d 36 | } 37 | 38 | /** 39 | Evaluates a polynomial using Horner's algorithm 40 | 41 | # Arguments 42 | 43 | * `$x` : The value of the independent variable `f32 or f64` 44 | * `$c` : The constant term `f32 or f64` 45 | * `$($a),*`: Sequence of coefficient terms for `$x`, in ascending 46 | powers of `$x` 47 | **/ 48 | #[macro_export] 49 | macro_rules! Horner_eval 50 | { 51 | ($x:expr, $c:expr, $($a:expr),*) => 52 | { 53 | { 54 | let mut y = $c; 55 | let mut u = 1.0; 56 | $( 57 | u *= $x; 58 | y += u * $a; 59 | )* 60 | y 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/aberr.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn stell_aberr_in_eq_coords() { 30 | 31 | let d = time::Date { 32 | year : 2028, 33 | month : time::Month::Nov, 34 | decimal_day : 13.19, 35 | cal_type : time::CalType::Gregorian 36 | }; 37 | let stell_eq_point = coords::EqPoint{ 38 | asc: 41.0540613_f64.to_radians(), 39 | dec: 49.2277489_f64.to_radians() 40 | }; 41 | 42 | let (a, b) = aberr::stell_aberr_in_eq_coords ( 43 | &stell_eq_point, time::julian_day(&d) 44 | ); 45 | 46 | assert_eq!(util::round_upto_digits(a.to_degrees(), 7), 0.0083223); 47 | assert_eq!(util::round_upto_digits(b.to_degrees(), 7), 0.0018749); 48 | 49 | } 50 | -------------------------------------------------------------------------------- /tests/earth.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn rho_sin_cos_phi() { 30 | 31 | let (rho_sin_phi, rho_cos_phi) = planet::earth::rho_sin_cos_phi ( 32 | angle::deg_frm_dms(33, 21, 22.0).to_radians(), 1706.0 33 | ); 34 | 35 | assert_eq!( 36 | (util::round_upto_digits(rho_sin_phi, 6), 37 | util::round_upto_digits(rho_cos_phi, 6)), 38 | (0.546861, 0.836339) 39 | ); 40 | 41 | } 42 | 43 | #[test] 44 | fn geodesic_dist() { 45 | 46 | let paris = coords::GeographPoint { 47 | long: angle::deg_frm_dms(-2, 20, 14.0).to_radians(), 48 | lat : angle::deg_frm_dms(48, 50, 11.0).to_radians() 49 | }; 50 | 51 | let washington = coords::GeographPoint { 52 | long: angle::deg_frm_dms(77, 3, 56.0).to_radians(), 53 | lat : angle::deg_frm_dms(38, 55, 17.0).to_radians() 54 | }; 55 | 56 | let distance = planet::earth::geodesic_dist(&paris, &washington); 57 | assert_eq!(util::round_upto_digits(distance, 2), 6181.63); 58 | 59 | let approx_distance = planet::earth::approx_geodesic_dist ( 60 | &paris, &washington 61 | ); 62 | assert_eq!(util::round_upto_digits(approx_distance, 0), 6166.0); 63 | } 64 | 65 | #[test] 66 | fn radii() { 67 | 68 | let lat = 42_f64.to_radians(); 69 | 70 | let Rp = planet::earth::rad_of_parll_lat(lat); 71 | assert_eq!( 72 | util::round_upto_digits(Rp, 0), 73 | util::round_upto_digits(4747.001, 0) 74 | ); 75 | 76 | let lin_vel = planet::earth::linear_velocity_at_lat(lat); 77 | assert_eq!(util::round_upto_digits(lin_vel, 5), 0.34616); 78 | 79 | let Rm = planet::earth::rad_curv_of_meridian(lat); 80 | assert_eq!( 81 | util::round_upto_digits(Rm, 2), 82 | util::round_upto_digits(6364.033, 2) 83 | ); 84 | } 85 | -------------------------------------------------------------------------------- /tests/ecliptic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn mn_oblq_Laskar() { 30 | 31 | let (d, m, s) = angle::dms_frm_deg ( 32 | ecliptic::mn_oblq_laskar(2446895.5).to_degrees() 33 | ); 34 | 35 | assert_eq!((d, m, util::round_upto_digits(s, 3)), (23, 26, 27.407)); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /tests/elliptic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn ecc_anom() { 30 | 31 | let ecc_anom = orbit::elliptic::ecc_anom(5_f64.to_radians(), 0.1, 0.0000001); 32 | 33 | assert_eq!(util::round_upto_digits(ecc_anom.to_degrees(), 6), 5.554589); 34 | 35 | } 36 | 37 | #[test] 38 | fn vel() { 39 | 40 | let a = 17.9400782; 41 | let e = 0.96727426; 42 | let (vel_p, vel_a) = (orbit::elliptic::perih_vel(a, e), orbit::elliptic::aph_vel(a, e)); 43 | assert_eq!(util::round_upto_digits(vel_p, 2), 54.52); 44 | assert_eq!(util::round_upto_digits(vel_a, 2), 0.91); 45 | 46 | let V = orbit::elliptic::vel(1.0, a); 47 | assert_eq!(util::round_upto_digits(V, 2), 41.53); 48 | 49 | } 50 | 51 | #[test] 52 | fn passage_through_nodes() { 53 | 54 | let T = time::julian_day ( 55 | &time::Date{ 56 | year : 1986, 57 | month : time::Month::Feb, 58 | decimal_day : 9.45891, 59 | cal_type : time::CalType::Gregorian 60 | } 61 | ); 62 | let w = 111.84644_f64.to_radians(); 63 | let e = 0.96727426; 64 | let n = 0.01297082_f64.to_radians(); 65 | let a = 17.9400782; 66 | 67 | let (ascen, r_a) = orbit::elliptic::passage_through_node ( 68 | w, n, a, e, T, &orbit::Node::Ascend 69 | ); 70 | assert_eq!(util::round_upto_digits((T - ascen), 4), 92.2998); 71 | assert_eq!(util::round_upto_digits(r_a, 4), 1.8045); 72 | 73 | let (descend, r_b) = orbit::elliptic::passage_through_node ( 74 | w, n, a, e, T, &orbit::Node::Descend 75 | ); 76 | assert_eq!(util::round_upto_digits((T - descend), 4), -28.9105); 77 | assert_eq!(util::round_upto_digits(r_b, 4), 0.8493); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /tests/interpol.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | extern crate astro; 24 | 25 | use astro::*; 26 | 27 | #[test] 28 | fn three_values() { 29 | 30 | let y = interpol::three_values ( 31 | 0.884226, 32 | 0.877366, 33 | 0.870531, 34 | 0.18125 35 | ); 36 | 37 | assert_eq!(util::round_upto_digits(y, 6), 0.876125); 38 | 39 | } 40 | 41 | #[test] 42 | fn five_values() { 43 | 44 | let y = interpol::five_values ( 45 | 36.125, 46 | 24.606, 47 | 15.486, 48 | 8.694, 49 | 4.133, 50 | 0.2777778 51 | ); 52 | 53 | assert_eq!(util::round_upto_digits(y, 3), 13.369); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /tests/jupiter.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn ephemeris() { 30 | 31 | let mut ephemeris = planet::jupiter::ephemeris ( 32 | 2448972.50068, 33 | 23.4402069_f64.to_radians(), 34 | angle::deg_frm_dms(0, 0, 16.86).to_radians(), 35 | angle::deg_frm_dms(0, 0, -1.79).to_radians(), 36 | ); 37 | 38 | ephemeris.De = util::round_upto_digits(ephemeris.De.to_degrees(), 2); 39 | ephemeris.Ds = util::round_upto_digits(ephemeris.Ds.to_degrees(), 2); 40 | ephemeris.P = util::round_upto_digits(angle::limit_to_360(ephemeris.P.to_degrees()), 2); 41 | ephemeris.w1 = util::round_upto_digits(ephemeris.w1.to_degrees(), 0); 42 | ephemeris.w2 = util::round_upto_digits(ephemeris.w2.to_degrees(), 2); 43 | 44 | assert_eq!(ephemeris.De, -2.48); 45 | assert_eq!(ephemeris.Ds, -2.20); 46 | assert_eq!(ephemeris.P, 24.80); 47 | assert_eq!(ephemeris.w1, 268.0); 48 | assert_eq!(ephemeris.w2, 72.74); 49 | 50 | } 51 | 52 | #[test] 53 | fn moons() { 54 | 55 | let data = [ 56 | (-3.44, 0.21, planet::jupiter::moon::Moon::Io), 57 | (7.44, 0.25, planet::jupiter::moon::Moon::Europa), 58 | (1.24, 0.65, planet::jupiter::moon::Moon::Ganymede), 59 | (7.08, 1.1, planet::jupiter::moon::Moon::Callisto), 60 | ]; 61 | 62 | for tuple in data.iter() { 63 | let (X, Y) = planet::jupiter::moon::apprnt_rect_coords( 64 | 2448972.50068, &tuple.2 65 | ); 66 | 67 | assert_eq!(util::round_upto_digits(X, 2), tuple.0); 68 | assert_eq!(util::round_upto_digits(Y, 2), tuple.1); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /tests/lunar.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn geocent_ecl_pos() { 30 | 31 | let (moon_eq_point, rad_vec) = lunar::geocent_ecl_pos(2448724.5); 32 | 33 | assert_eq!( 34 | util::round_upto_digits(moon_eq_point.long.to_degrees(), 6), 35 | 133.162655 36 | ); 37 | assert_eq!( 38 | util::round_upto_digits(moon_eq_point.lat.to_degrees(), 6), 39 | -3.229126 40 | ); 41 | assert_eq!( 42 | util::round_upto_digits(rad_vec, 1), 368409.7 43 | ); 44 | 45 | } 46 | 47 | #[test] 48 | #[allow(unused_variables)] 49 | fn time_of_passage_through_nodes() { 50 | 51 | let date = time::Date { 52 | year : 1987, 53 | month : time::Month::May, 54 | decimal_day : 15.0, 55 | cal_type : time::CalType::Gregorian 56 | }; 57 | 58 | let (ascend_JD, desend_JD) = lunar::time_of_passage_through_nodes(&date); 59 | 60 | assert_eq!( 61 | util::round_upto_digits(ascend_JD, 5), 2446938.76803 62 | ); 63 | 64 | } 65 | 66 | #[test] 67 | fn liberations() { 68 | 69 | let day_of_month = time::DayOfMonth { 70 | day : 12, 71 | hr : 0, 72 | min : 0, 73 | sec : 0.0, 74 | time_zone : 0.0 75 | }; 76 | let date = time::Date { 77 | year : 1992, 78 | month : time::Month::Apr, 79 | decimal_day : time::decimal_day(&day_of_month), 80 | cal_type : time::CalType::Gregorian 81 | }; 82 | 83 | let (opt_long, opt_lat) = lunar::optical_libr ( 84 | time::julian_day(&date), 85 | 133.162655_f64.to_radians(), 86 | -3.229126_f64.to_radians() 87 | ); 88 | assert_eq!( 89 | util::round_upto_digits(opt_long.to_degrees(), 3), 90 | angle::limit_to_360(-1.206) 91 | ); 92 | assert_eq!( 93 | util::round_upto_digits(opt_lat.to_degrees(), 3), 4.194 94 | ); 95 | 96 | let (phy_long, phys_lat) = lunar::physical_libr ( 97 | time::julian_day(&date), 98 | 133.162655_f64.to_radians(), 99 | -3.229126_f64.to_radians(), 100 | opt_lat 101 | ); 102 | assert_eq!(util::round_upto_digits(phy_long.to_degrees(), 3), -0.025); 103 | assert_eq!(util::round_upto_digits(phys_lat.to_degrees(), 3), 0.006); 104 | 105 | } 106 | 107 | #[test] 108 | fn phases() { 109 | let date_last_quarter = time::Date { 110 | year : 2044, 111 | month : time::Month::Jan, 112 | decimal_day : 0.0, 113 | cal_type : time::CalType::Gregorian 114 | }; 115 | let JD_last_quarter = lunar::time_of_phase ( 116 | &date_last_quarter, &lunar::Phase::Last 117 | ); 118 | assert_eq!(util::round_upto_digits(JD_last_quarter, 5), 2467636.49186); 119 | 120 | let date_new_moon = time::Date { 121 | year : 1977, 122 | month : time::Month::Feb, 123 | decimal_day : 0.0, 124 | cal_type : time::CalType::Gregorian}; 125 | let JD_new_moon = lunar::time_of_phase(&date_new_moon, &lunar::Phase::New); 126 | assert_eq!(util::round_upto_digits(JD_new_moon, 5), 2443192.65118); 127 | } 128 | -------------------------------------------------------------------------------- /tests/mars.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn ephemeris() { 30 | 31 | let JD = 2448935.500638; 32 | let mut ephemeris = planet::mars::ephemeris( 33 | JD, 34 | &planet::mars::north_pol_ecl_coords(time::julian_cent(JD)), 35 | 23.44022_f64.to_radians(), 36 | angle::deg_frm_dms(0, 0, 15.42).to_radians(), 37 | angle::deg_frm_dms(0, 0, -1.0).to_radians(), 38 | ); 39 | 40 | ephemeris.De = util::round_upto_digits(ephemeris.De.to_degrees(), 2); 41 | ephemeris.Ds = util::round_upto_digits(ephemeris.Ds.to_degrees(), 2); 42 | ephemeris.P = util::round_upto_digits ( 43 | angle::limit_to_360(ephemeris.P.to_degrees()), 2 44 | ); 45 | ephemeris.w = util::round_upto_digits(ephemeris.w.to_degrees(), 1); 46 | 47 | assert_eq!(ephemeris.De, 12.44); 48 | assert_eq!(ephemeris.Ds, -2.76); 49 | assert_eq!(ephemeris.P, 347.64); 50 | assert_eq!(ephemeris.w, 111.5); 51 | 52 | let (h1, m1, s1) = angle::dms_frm_deg(ephemeris.d.to_degrees()); 53 | assert_eq!((h1, m1), (0, 0)); 54 | assert_eq!(util::round_upto_digits(s1, 2), 10.75); 55 | 56 | let (h2, m2, s2) = angle::dms_frm_deg(ephemeris.q.to_degrees()); 57 | assert_eq!((h2, m2), (0, 0)); 58 | assert_eq!(util::round_upto_digits(s2, 2), 1.06); 59 | } 60 | -------------------------------------------------------------------------------- /tests/near_parabolic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | extern crate astro; 24 | 25 | use astro::*; 26 | 27 | #[test] 28 | fn true_anom_and_rad_vec() { 29 | 30 | let (tru_anom, rad_vec) = orbit::near_parabolic::true_anom_and_rad_vec ( 31 | 138.4783, 0.0, 1.0, 0.921326, 0.0000001 32 | ).unwrap(); 33 | 34 | assert_eq!(util::round_upto_digits(tru_anom.to_degrees(), 5), 102.74426); 35 | assert_eq!(util::round_upto_digits(rad_vec, 6), 2.364192); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /tests/nutation.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn nutation() { 30 | 31 | let (nut_in_long, nut_in_oblq) = nutation::nutation(2446895.5); 32 | 33 | let (d1, m1, s1) = angle::dms_frm_deg(nut_in_long.to_degrees()); 34 | assert_eq!((d1, m1, util::round_upto_digits(s1, 3)), (0, 0, -3.788)); 35 | 36 | let (d2, m2, s2) = angle::dms_frm_deg(nut_in_oblq.to_degrees()); 37 | assert_eq!((d2, m2, util::round_upto_digits(s2, 3)), (0, 0, 9.443)); 38 | 39 | } 40 | 41 | #[test] 42 | fn nutation_in_eq_coords() { 43 | 44 | let eq_point = coords::EqPoint { 45 | asc: 41.5555635_f64.to_radians(), 46 | dec: 49.3503415_f64.to_radians() 47 | }; 48 | let (a, b) = nutation::nutation_in_eq_coords( 49 | &eq_point, 50 | angle::deg_frm_dms(0, 0, 14.861).to_radians(), 51 | angle::deg_frm_dms(0, 0, 2.705).to_radians(), 52 | 23.436_f64.to_radians() 53 | ); 54 | 55 | assert_eq!(util::round_upto_digits(a.to_degrees(), 7), 0.0044011); 56 | assert_eq!(util::round_upto_digits(b.to_degrees(), 7), 0.001727); 57 | 58 | } 59 | -------------------------------------------------------------------------------- /tests/parabolic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn true_anom_and_rad_vec() { 30 | 31 | let t_date = time::Date { 32 | year : 1998, 33 | month : time::Month::Aug, 34 | decimal_day : 5.0, 35 | cal_type : time::CalType::Gregorian 36 | }; 37 | let t = time::julian_day(&t_date); 38 | 39 | let T_date = time::Date { 40 | year : 1998, 41 | month : time::Month::Apr, 42 | decimal_day : 14.4358, 43 | cal_type : time::CalType::Gregorian 44 | }; 45 | let T = time::julian_day(&T_date); 46 | 47 | let (tru_anom, rad_vec) = orbit::parabolic::true_anom_and_rad_vec( 48 | t, T, 1.487469 49 | ); 50 | assert_eq!(util::round_upto_digits(tru_anom.to_degrees(), 5), 66.78862); 51 | assert_eq!(util::round_upto_digits(rad_vec, 6), 2.133911); 52 | 53 | } 54 | 55 | #[test] 56 | fn passage_through_nodes() { 57 | 58 | let T = time::julian_day(&time::Date{ 59 | year : 1989, 60 | month : time::Month::Aug, 61 | decimal_day : 20.291, 62 | cal_type : time::CalType::Gregorian 63 | }); 64 | let w = 154.9103_f64.to_radians(); 65 | let q = 1.324502; 66 | 67 | let (ascen, r_a) = orbit::parabolic::passage_through_node( 68 | w, q, T, &orbit::Node::Ascend 69 | ); 70 | assert_eq!(util::round_upto_digits((T - ascen), 2), 4354.65); 71 | assert_eq!(util::round_upto_digits(r_a, 2), 28.07); 72 | 73 | let (descend, r_b) = orbit::parabolic::passage_through_node( 74 | w, q, T, &orbit::Node::Descend 75 | ); 76 | assert_eq!(util::round_upto_digits((T - descend), 4), -28.3454); 77 | assert_eq!(util::round_upto_digits(r_b, 4), 1.3901); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /tests/parallax.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | extern crate astro; 24 | 25 | use astro::*; 26 | 27 | #[test] 28 | pub fn topocent_eq_coords() { 29 | 30 | let eq_point = coords::EqPoint{ 31 | asc: 339.530208_f64.to_radians(), 32 | dec: -15.771083_f64.to_radians() 33 | }; 34 | let geograph_point = coords::GeographPoint{ 35 | long: angle::deg_frm_hms(7, 47, 27.0).to_radians(), 36 | lat: 33.356111_f64.to_radians(), 37 | }; 38 | let topo_eq_point = parallax::topocent_eq_coords( 39 | &eq_point, 40 | angle::deg_frm_dms(0, 0, 23.592).to_radians(), 41 | &geograph_point, 42 | 1706.0, 43 | angle::deg_frm_hms(1, 40, 45.0).to_radians() 44 | ); 45 | 46 | let (h, m1, s1) = angle::hms_frm_deg(topo_eq_point.asc.to_degrees()); 47 | assert_eq!((h, m1, util::round_upto_digits(s1, 2)), (22, 38, 8.54)); 48 | 49 | let (d, m2, s2) = angle::dms_frm_deg(topo_eq_point.dec.to_degrees()); 50 | assert_eq!((d, m2, util::round_upto_digits(s2, 1)), (-15, -46, -30.0)); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /tests/planet.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | #[macro_use] 26 | extern crate astro; 27 | use astro::*; 28 | 29 | #[test] 30 | fn heliocent_coords() { 31 | 32 | let (mut L, mut B, mut R) = planet::heliocent_coords ( 33 | &planet::Planet::Venus, 2448976.5 34 | ); 35 | L = util::round_upto_digits(L.to_degrees(), 3); 36 | B = util::round_upto_digits(B.to_degrees(), 3); 37 | R = util::round_upto_digits(R, 5); 38 | assert_eq!( 39 | (L, B, R), 40 | (26.114, util::round_upto_digits(angle::limit_to_360(-2.6207), 3), 0.72460) 41 | ); 42 | 43 | } 44 | 45 | #[test] 46 | #[allow(unused_variables)] 47 | fn geocent_geomet_ecl_coords() { 48 | 49 | let (L, B, mut R, mut t) = planet::geocent_geomet_ecl_coords( 50 | 88.35704_f64.to_radians(), 51 | 0.00014_f64.to_radians(), 52 | 0.983824, 53 | 26.11428_f64.to_radians(), 54 | -2.6207_f64.to_radians(), 55 | 0.724603, 56 | ); 57 | R = util::round_upto_digits(R, 6); 58 | t = util::round_upto_digits(t, 7); 59 | 60 | assert_eq!((R, t), (0.910845, 0.0052606)); 61 | 62 | } 63 | 64 | #[test] 65 | fn ecl_coords_to_FK5() { 66 | 67 | let (FK5_long, FK5_lat) = planet::ecl_coords_to_FK5( 68 | 2448976.5, 69 | 313.07689_f64.to_radians(), 70 | -2.08489_f64.to_radians() 71 | ); 72 | 73 | assert_eq!( 74 | util::round_upto_digits(FK5_long.to_degrees(), 5), 75 | 313.07686 76 | ); 77 | assert_eq!( 78 | util::round_upto_digits(FK5_lat.to_degrees(), 5), 79 | -2.08487 80 | ); 81 | 82 | } 83 | 84 | #[test] 85 | fn geocent_apprnt_ecl_coords() { 86 | 87 | let (planet_ecl_point, mut R) = planet::geocent_apprnt_ecl_coords ( 88 | &planet::Planet::Venus, 2448976.5 89 | ); 90 | let (mut L, mut B) = (planet_ecl_point.long, planet_ecl_point.lat); 91 | L = util::round_upto_digits(angle::limit_to_360(L.to_degrees()), 2); 92 | B = util::round_upto_digits(B.to_degrees(), 2); 93 | R = util::round_upto_digits(R, 4); 94 | 95 | assert_eq!((L, B, R), (313.08, -2.08, 0.9109)); 96 | 97 | } 98 | -------------------------------------------------------------------------------- /tests/precess.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn annual_precess() { 30 | 31 | let d = time::Date { 32 | year : 1978, 33 | month : time::Month::Jan, 34 | decimal_day : 0.0, 35 | cal_type : time::CalType::Gregorian}; 36 | 37 | let (new_asc, new_dec) = precess::annual_precess( 38 | angle::deg_frm_hms(10, 8, 22.3).to_radians(), 39 | angle::deg_frm_dms(11, 58, 2.0).to_radians(), 40 | time::julian_day(&d) 41 | ); 42 | 43 | let (a, b, c) = angle::hms_frm_deg(new_asc.to_degrees()); 44 | assert_eq!((a, b), (0, 0)); 45 | assert_eq!(util::round_upto_digits(c, 2), util::round_upto_digits(3.208, 2)); 46 | 47 | let (d, e, f) = angle::dms_frm_deg(new_dec.to_degrees()); 48 | assert_eq!((d, e), (0, 0)); 49 | assert_eq!(util::round_upto_digits(f, 2), -17.71); 50 | 51 | } 52 | 53 | #[test] 54 | fn precess_eq_coords() { 55 | 56 | let (new_asc, new_dec) = precess::precess_eq_coords( 57 | 41.054063_f64.to_radians(), 58 | 49.22775_f64.to_radians(), 59 | 2451545.0, 60 | 2462088.69 61 | ); 62 | assert_eq!( 63 | (util::round_upto_digits(new_asc.to_degrees(), 6), 64 | util::round_upto_digits(new_dec.to_degrees(), 6)), 65 | (41.547214, 49.348483) 66 | ); 67 | 68 | } 69 | 70 | #[test] 71 | fn precess_orb_elements() { 72 | 73 | let (new_inc, new_arg_perih, new_long_ascend_node) = 74 | precess::precess_orb_elements ( 75 | 47.122_f64.to_radians(), 76 | 151.4486_f64.to_radians(), 77 | 45.7481_f64.to_radians(), 78 | 2358042.5305, 79 | 2433282.4235 80 | ); 81 | 82 | assert_eq!(util::round_upto_digits(new_inc.to_degrees(), 4), 47.138); 83 | assert_eq!(util::round_upto_digits(new_arg_perih.to_degrees(), 4), 151.4782); 84 | assert_eq!(util::round_upto_digits(new_long_ascend_node.to_degrees(), 4), 48.6037); 85 | 86 | } 87 | 88 | #[test] 89 | fn precess_ecl_coords() { 90 | 91 | let (new_asc, new_dec) = precess::precess_ecl_coords( 92 | 149.48194_f64.to_radians(), 93 | 1.76549_f64.to_radians(), 94 | 2451545.0, 95 | 1643074.5 96 | ); 97 | 98 | assert_eq!((util::round_upto_digits(new_asc.to_degrees(), 3), 99 | util::round_upto_digits(new_dec.to_degrees(), 3)), (118.704, 1.615)); 100 | } 101 | -------------------------------------------------------------------------------- /tests/saturn.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn ring_elements() { 30 | 31 | let mut elements = planet::saturn::ring::elements( 32 | 2448972.50068, 33 | angle::deg_frm_dms(0, 0, 16.86).to_radians(), 34 | 23.43971_f64.to_radians() 35 | ); 36 | 37 | elements.B = util::round_upto_digits(elements.B.to_degrees(), 3); 38 | elements.B1 = util::round_upto_digits(elements.B1.to_degrees(), 3); 39 | elements.P = util::round_upto_digits(angle::limit_to_360(elements.P.to_degrees()), 3); 40 | elements.deltaU = util::round_upto_digits(elements.deltaU.to_degrees(), 3); 41 | 42 | assert_eq!(elements.B, 16.442); 43 | assert_eq!(elements.B1, 14.679); 44 | assert_eq!(elements.P, 6.741); 45 | assert_eq!(elements.deltaU, 4.198); 46 | 47 | let (d_a, m_a, s_a) = angle::dms_frm_deg(elements.a.to_degrees()); 48 | assert_eq!((d_a, m_a), (0, 0)); 49 | assert_eq!(util::round_upto_digits(s_a, 2), 35.87); 50 | 51 | let (d_b, m_b, s_b) = angle::dms_frm_deg(elements.b.to_degrees()); 52 | assert_eq!((d_b, m_b), (0, 0)); 53 | assert_eq!(util::round_upto_digits(s_b, 2), 10.15); 54 | 55 | } 56 | 57 | #[test] 58 | #[allow(unused_variables)] 59 | fn moons() { 60 | 61 | let data = [ 62 | (3.102, -0.204, planet::saturn::moon::Moon::Mimas), 63 | (3.823, 0.318, planet::saturn::moon::Moon::Enceladus), 64 | (4.027, -1.061, planet::saturn::moon::Moon::Tethys), 65 | (-5.365, -1.148, planet::saturn::moon::Moon::Dione), 66 | (-1.122, -3.123, planet::saturn::moon::Moon::Rhea), 67 | (14.568, 4.738, planet::saturn::moon::Moon::Titan), 68 | (-18.001, -5.328, planet::saturn::moon::Moon::Hyperion), 69 | (-48.76/* Meeus gives -48.759 */, 4.137/* Meeus gives 4.136 */, planet::saturn::moon::Moon::Iapetus), 70 | ]; 71 | 72 | for tuple in data.iter() { 73 | let (X, Y, Z) = planet::saturn::moon::apprnt_rect_coords( 74 | 2451439.50074, 75 | &tuple.2 76 | ); 77 | assert_eq!(util::round_upto_digits(X, 3), tuple.0); 78 | assert_eq!(util::round_upto_digits(Y, 3), tuple.1); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /tests/star.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | extern crate astro; 24 | 25 | use astro::*; 26 | 27 | #[test] 28 | fn eq_coords_frm_motion() { 29 | 30 | let (asc, dec) = star::eq_coords_frm_motion( 31 | 101.286962_f64.to_radians(), 32 | -16.716108_f64.to_radians(), 33 | 2.64, 34 | -0.000007773, 35 | (-0.03847 / 3600.0 as f64).to_radians(), 36 | (-1.20530 / 3600.0 as f64).to_radians(), 37 | -1000.0 38 | ); 39 | 40 | let (h1, m1, s1) = angle::hms_frm_deg(asc.to_degrees()); 41 | assert_eq!((h1, m1, util::round_upto_digits(s1, 2)), (6, 45, 47.16)); 42 | 43 | let (d2, m2, s2) = angle::dms_frm_deg(dec.to_degrees()); 44 | assert_eq!((d2, m2, util::round_upto_digits(s2, 1)), (-16, -22, -56.0)); 45 | 46 | } 47 | -------------------------------------------------------------------------------- /tests/sun.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | fn ephemeris() { 30 | 31 | let (mut P, mut B, mut L) = sun::ephemeris( 32 | 2448908.50068, 33 | 199.90234_f64.to_radians(), 34 | 199.906759_f64.to_radians(), 35 | 23.440144_f64.to_radians() 36 | ); 37 | 38 | P = util::round_upto_digits(P.to_degrees(), 2); 39 | B = util::round_upto_digits(B.to_degrees(), 2); 40 | L = util::round_upto_digits(L.to_degrees(), 2); 41 | 42 | assert_eq!((P, B, L), (26.27, 5.99, 238.63)); 43 | 44 | } 45 | 46 | #[test] 47 | fn ecl_coords_to_FK5() { 48 | 49 | let (FK5_long, FK5_lat) = sun::ecl_coords_to_FK5( 50 | 2448908.5, 51 | 199.907372_f64.to_radians(), 52 | angle::deg_frm_dms(0, 0, 0.644).to_radians() 53 | ); 54 | 55 | assert_eq!( 56 | util::round_upto_digits(FK5_long.to_degrees(), 6), 57 | 199.907347 58 | ); 59 | 60 | let (d, m, s) = angle::dms_frm_deg(FK5_lat.to_degrees()); 61 | assert_eq!( 62 | (d, m, util::round_upto_digits(s, 2)), 63 | (0, 0, 0.62) 64 | ); 65 | 66 | } 67 | 68 | #[test] 69 | fn geocent_ecl_coords() { 70 | 71 | let (sun_ecl_point, rad_vec) = sun::geocent_ecl_pos(2448908.5); 72 | 73 | assert_eq!( 74 | util::round_upto_digits(sun_ecl_point.long.to_degrees(), 6), 75 | 199.907297 76 | ); 77 | assert_eq!( 78 | util::round_upto_digits(sun_ecl_point.lat.to_degrees(), 6), 79 | 0.000207 80 | ); 81 | assert_eq!( 82 | util::round_upto_digits(rad_vec, 8), 83 | 0.99760852 84 | ); 85 | 86 | } 87 | 88 | #[test] 89 | fn approx_synd_rot() { 90 | 91 | assert_eq!( 92 | util::round_upto_digits(sun::synodic_rot(1699), 2), 93 | 2444480.72 94 | ); 95 | 96 | } 97 | -------------------------------------------------------------------------------- /tests/time.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | #[macro_use] 26 | extern crate astro; 27 | 28 | use astro::*; 29 | 30 | #[test] 31 | fn sidreal_time() { 32 | 33 | let (h1, m1, s1) = angle::hms_frm_deg(time::mn_sidr(2446895.5).to_degrees()); 34 | assert_eq!((h1, m1, util::round_upto_digits(s1, 4)), (13, 10, 46.3668)); 35 | 36 | let (h2, m2, s2) = angle::hms_frm_deg(apprnt_sidr!(2446895.5).to_degrees()); 37 | assert_eq!((h2, m2, util::round_upto_digits(s2, 4)), (13, 10, 46.1351)); 38 | 39 | } 40 | 41 | #[test] 42 | fn julian_day() { 43 | 44 | // Test taken from Meeus 2nd ed. on pages 61-62 45 | 46 | let mut date = time::Date { 47 | year : 0, 48 | month : time::Month::Jan, 49 | decimal_day : 0.0, 50 | cal_type : time::CalType::Gregorian 51 | }; 52 | 53 | struct TestDate(i16, time::Month, f64, f64, time::CalType); 54 | let gregorian_dates = [ 55 | TestDate( 1957, time::Month::Oct, 4.81, 2436116.31, time::CalType::Gregorian), 56 | TestDate( 2000, time::Month::Jan, 1.5, 2451545.0, time::CalType::Gregorian), 57 | TestDate( 1999, time::Month::Jan, 1.0, 2451179.5, time::CalType::Gregorian), 58 | TestDate( 1987, time::Month::Jan, 27.0, 2446822.5, time::CalType::Gregorian), 59 | TestDate( 1987, time::Month::June, 19.5, 2446966.0, time::CalType::Gregorian), 60 | TestDate( 1988, time::Month::Jan, 27.0, 2447187.5, time::CalType::Gregorian), 61 | TestDate( 1988, time::Month::June, 19.5, 2447332.0, time::CalType::Gregorian), 62 | TestDate( 1900, time::Month::Jan, 1.0, 2415020.5, time::CalType::Gregorian), 63 | TestDate( 1600, time::Month::Jan, 1.0, 2305447.5, time::CalType::Gregorian), 64 | TestDate( 1600, time::Month::Dec, 31.0, 2305812.5, time::CalType::Gregorian), 65 | TestDate( 837, time::Month::Apr, 10.3, 2026871.8, time::CalType::Julian), 66 | TestDate(-123, time::Month::Dec, 31.0, 1676496.5, time::CalType::Julian), 67 | TestDate(-122, time::Month::Jan, 1.0, 1676497.5, time::CalType::Julian), 68 | TestDate(-1000, time::Month::July, 12.5, 1356001.0, time::CalType::Julian), 69 | TestDate(-1000, time::Month::Feb, 29.0, 1355866.5, time::CalType::Julian), 70 | TestDate(-1001, time::Month::Aug, 17.9, 1355671.4, time::CalType::Julian), 71 | TestDate(-4712, time::Month::Jan, 1.5, 0.0, time::CalType::Julian) 72 | ]; 73 | 74 | for date_fields in gregorian_dates.iter() { 75 | date.year = date_fields.0; 76 | date.month = date_fields.1; 77 | date.decimal_day = date_fields.2; 78 | date.cal_type = match date_fields.4 { 79 | time::CalType::Gregorian => time::CalType::Gregorian, 80 | time::CalType::Julian => time::CalType::Julian, 81 | }; 82 | assert_eq!(time::julian_day(&date), date_fields.3); 83 | } 84 | 85 | } 86 | 87 | #[test] 88 | fn weekday_frm_date() 89 | { 90 | let date = time::Date { 91 | year: 1954, 92 | month: time::Month::June, 93 | decimal_day: 30.0, 94 | cal_type: time::CalType::Gregorian 95 | }; 96 | match time::weekday_frm_date(&date) { 97 | time::Weekday::Wednesday => {}, 98 | _ => panic!("time::weekday_frm_date failed") 99 | } 100 | } 101 | 102 | #[test] 103 | fn date_frm_julian_day() { 104 | 105 | // Test taken from Meeus 2nd ed. on page 64 106 | 107 | struct TestData(i16, u8, f64, f64); 108 | let test_data = [ 109 | TestData( 1957, 10, 4.81, 2436116.31), 110 | TestData( 333, 1, 27.5, 1842713.0), 111 | TestData(-584, 5, 28.63, 1507900.13), 112 | ]; 113 | 114 | for data in test_data.iter() { 115 | 116 | let (year, month, day) = time::date_frm_julian_day(data.3).unwrap(); 117 | 118 | assert_eq!(year, data.0); 119 | assert_eq!(month, data.1); 120 | assert_eq!(util::round_upto_digits(day, 2), data.2); 121 | 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /tests/transit.rs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015, 2016 Saurav Sachidanand 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #![allow(non_snake_case)] 24 | 25 | extern crate astro; 26 | use astro::*; 27 | 28 | #[test] 29 | #[allow(unused_variables)] 30 | fn time() { 31 | 32 | let eq_point1 = coords::EqPoint{ 33 | asc: 40.68021_f64.to_radians(), 34 | dec: 18.04761_f64.to_radians() 35 | }; 36 | let eq_point2 = coords::EqPoint{ 37 | asc: 41.73129_f64.to_radians(), 38 | dec: 18.44092_f64.to_radians() 39 | }; 40 | let eq_point3 = coords::EqPoint{ 41 | asc: 42.78204_f64.to_radians(), 42 | dec: 18.82742_f64.to_radians() 43 | }; 44 | 45 | let geograph_point = coords::GeographPoint{ 46 | long: 71.0833_f64.to_radians(), 47 | lat: 42.3333_f64.to_radians(), 48 | }; 49 | 50 | let Theta0 = 177.74208_f64.to_radians(); 51 | 52 | let deltaT = time::delta_t(1988, 3); 53 | 54 | let (h_rise, m_rise, s_rise) = transit::time( 55 | &transit::TransitType::Rise, 56 | &transit::TransitBody::StarOrPlanet, 57 | &geograph_point, 58 | &eq_point1, 59 | &eq_point2, 60 | &eq_point3, 61 | Theta0, 62 | deltaT, 63 | 0.0 64 | ); 65 | 66 | assert_eq!((h_rise, m_rise), (12, 25)); 67 | 68 | let (h_transit, m_transit, s_transit) = transit::time( 69 | &transit::TransitType::Transit, 70 | &transit::TransitBody::StarOrPlanet, 71 | &geograph_point, 72 | &eq_point1, 73 | &eq_point2, 74 | &eq_point3, 75 | Theta0, 76 | deltaT, 77 | 0.0 78 | ); 79 | 80 | assert_eq!((h_transit, m_transit), (19, 40)); 81 | 82 | let (h_set, m_set, s_set) = transit::time( 83 | &transit::TransitType::Set, 84 | &transit::TransitBody::StarOrPlanet, 85 | &geograph_point, 86 | &eq_point1, 87 | &eq_point2, 88 | &eq_point3, 89 | Theta0, 90 | deltaT, 91 | 0.0 92 | ); 93 | 94 | assert_eq!((h_set, m_set), (2, 54)); 95 | 96 | } 97 | --------------------------------------------------------------------------------