1 /* 2 * This library is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU Lesser General Public 4 * License as published by the Free Software Foundation; either 5 * version 2 of the License, or (at your option) any later version. 6 * 7 * This library is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 * Lesser General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 15 * 16 * Copyright (C) 2000 - 2005 Liam Girdwood <lgirdwood@gmail.com> 17 */ 18 19 module nova.transform; 20 21 import std.math; 22 23 import nova.utility; 24 import nova.sidereal_time; 25 import nova.nutation; 26 import nova.precession; 27 import nova.ln_types; 28 29 extern (C) { 30 31 /*! \fn void ln_get_rect_from_helio(struct ln_helio_posn *object, struct ln_rect_posn *position); 32 * \param object Object heliocentric coordinates 33 * \param position Pointer to store new position 34 * 35 * Transform an objects heliocentric ecliptical coordinates 36 * into heliocentric rectangular coordinates. 37 */ 38 /* Equ 37.1 Pg 264 39 */ 40 @nogc void ln_get_rect_from_helio(const ref ln_helio_posn object, 41 ref ln_rect_posn position) nothrow 42 { 43 double sin_e, cos_e; 44 double cos_B, sin_B, sin_L, cos_L; 45 46 /* ecliptic J2000 */ 47 sin_e = 0.397777156; 48 cos_e = 0.917482062; 49 50 /* calc common values */ 51 cos_B = cos(ln_deg_to_rad(object.B)); 52 cos_L = cos(ln_deg_to_rad(object.L)); 53 sin_B = sin(ln_deg_to_rad(object.B)); 54 sin_L = sin(ln_deg_to_rad(object.L)); 55 56 /* equ 37.1 */ 57 position.X = object.R * cos_L * cos_B; 58 position.Y = object.R * (sin_L * cos_B * cos_e - sin_B * sin_e); 59 position.Z = object.R * (sin_L * cos_B * sin_e + sin_B * cos_e); 60 } 61 62 /*! \fn void ln_get_hrz_from_equ(struct ln_equ_posn *object, struct ln_lnlat_posn *observer, double JD, struct ln_hrz_posn *position) 63 * \param object Object coordinates. 64 * \param observer Observer cordinates. 65 * \param JD Julian day 66 * \param position Pointer to store new position. 67 * 68 * Transform an objects equatorial coordinates into horizontal coordinates 69 * for the given julian day and observers position. 70 * 71 * 0 deg azimuth = south, 90 deg = west. 72 */ 73 /* Equ 12.1,12.2 pg 88 74 * 75 * TODO: 76 * Transform horizontal coordinates to galactic coordinates. 77 */ 78 79 @nogc void ln_get_hrz_from_equ(const ref ln_equ_posn object, 80 const ref ln_lnlat_posn observer, double JD, ref ln_hrz_posn position) nothrow 81 { 82 double sidereal; 83 84 /* get mean sidereal time in hours*/ 85 sidereal = ln_get_mean_sidereal_time(JD); 86 ln_get_hrz_from_equ_sidereal_time (object, observer, sidereal, position); 87 } 88 89 90 @nogc void ln_get_hrz_from_equ_sidereal_time(const ref ln_equ_posn object, 91 const ref ln_lnlat_posn observer, double sidereal, 92 ref ln_hrz_posn position) nothrow 93 { 94 real H, ra, latitude, declination, A, Ac, As, h, Z, Zs; 95 96 /* change sidereal_time from hours to radians*/ 97 sidereal *= 2.0 * PI / 24.0; 98 99 /* calculate hour angle of object at observers position */ 100 ra = ln_deg_to_rad(object.ra); 101 H = sidereal + ln_deg_to_rad(observer.lng) - ra; 102 103 /* hence formula 12.5 and 12.6 give */ 104 /* convert to radians - hour angle, observers latitude, object declination */ 105 latitude = ln_deg_to_rad(observer.lat); 106 declination = ln_deg_to_rad(object.dec); 107 108 /* formula 12.6 *; missuse of A (you have been warned) */ 109 A = sin(latitude) * sin(declination) + cos(latitude) * 110 cos(declination) * cos(H); 111 h = asin(A); 112 113 /* convert back to degrees */ 114 position.alt = ln_rad_to_deg(h); 115 116 /* zenith distance, Telescope Control 6.8a */ 117 Z = acos(A); 118 119 /* is'n there better way to compute that? */ 120 Zs = sin(Z); 121 122 /* sane check for zenith distance; don't try to divide by 0 */ 123 if (fabs(Zs) < 1e-5) { 124 if (object.dec > 0.0) 125 position.az = 180.0; 126 else 127 position.az = 0.0; 128 if ((object.dec > 0.0 && observer.lat > 0.0) 129 || (object.dec < 0.0 && observer.lat < 0.0)) 130 position.alt = 90.0; 131 else 132 position.alt = -90.0; 133 return; 134 } 135 136 /* formulas TC 6.8d Taff 1991, pp. 2 and 13 - vector transformations */ 137 As = (cos(declination) * sin(H)) / Zs; 138 Ac = (sin(latitude) * cos(declination) * cos(H) - cos(latitude) * 139 sin(declination)) / Zs; 140 141 // don't blom at atan2 142 if (Ac == 0.0 && As == 0.0) { 143 if (object.dec > 0) 144 position.az = 180.0; 145 else 146 position.az = 0.0; 147 return; 148 } 149 A = atan2(As, Ac); 150 151 /* convert back to degrees */ 152 position.az = ln_range_degrees(ln_rad_to_deg(A)); 153 } 154 155 /*! \fn void ln_get_equ_from_hrz(struct ln_hrz_posn *object, struct ln_lnlat_posn *observer, double JD, struct ln_equ_posn *position) 156 * \param object Object coordinates. 157 * \param observer Observer cordinates. 158 * \param JD Julian day 159 * \param position Pointer to store new position. 160 * 161 * Transform an objects horizontal coordinates into equatorial coordinates 162 * for the given julian day and observers position. 163 */ 164 @nogc void ln_get_equ_from_hrz(const ref ln_hrz_posn object, 165 const ref ln_lnlat_posn observer, double JD, ref ln_equ_posn position) nothrow 166 { 167 real H, longitude, declination, latitude, A, h, sidereal; 168 169 /* change observer/object position into radians */ 170 171 /* object alt/az */ 172 A = ln_deg_to_rad(object.az); 173 h = ln_deg_to_rad(object.alt); 174 175 /* observer long / lat */ 176 longitude = ln_deg_to_rad(observer.lng); 177 latitude = ln_deg_to_rad(observer.lat); 178 179 /* equ on pg89 */ 180 H = atan2(sin(A), (cos(A) * sin(latitude) + tan(h) * cos(latitude))); 181 declination = sin(latitude) * sin(h) - cos(latitude) * cos(h) * cos(A); 182 declination = asin(declination); 183 184 /* get ra = sidereal - longitude + H and change sidereal to radians*/ 185 sidereal = ln_get_apparent_sidereal_time(JD); 186 sidereal *= 2.0 * PI / 24.0; 187 188 position.ra = ln_range_degrees(ln_rad_to_deg(sidereal - H + longitude)); 189 position.dec = ln_rad_to_deg(declination); 190 } 191 192 /*! \fn void ln_get_equ_from_ecl(struct ln_lnlat_posn *object, double JD, struct ln_equ_posn *position) 193 * \param object Object coordinates. 194 * \param JD Julian day 195 * \param position Pointer to store new position. 196 * 197 * Transform an objects ecliptical coordinates into equatorial coordinates 198 * for the given julian day. 199 */ 200 /* Equ 12.3, 12.4 pg 89 201 */ 202 @nogc void ln_get_equ_from_ecl(const ref ln_lnlat_posn object, double JD, 203 ref ln_equ_posn position) nothrow 204 { 205 double ra, declination, longitude, latitude; 206 ln_nutation nutation; 207 208 /* get obliquity of ecliptic and change it to rads */ 209 ln_get_nutation(JD, nutation); 210 nutation.ecliptic = ln_deg_to_rad(nutation.ecliptic); 211 212 /* change object's position into radians */ 213 214 /* object */ 215 longitude = ln_deg_to_rad(object.lng); 216 latitude = ln_deg_to_rad(object.lat); 217 218 /* Equ 12.3, 12.4 */ 219 ra = atan2((sin(longitude) * cos(nutation.ecliptic) - 220 tan(latitude) * sin(nutation.ecliptic)), cos(longitude)); 221 declination = sin(latitude) * cos(nutation.ecliptic) + cos(latitude) * 222 sin(nutation.ecliptic) * sin(longitude); 223 declination = asin(declination); 224 225 /* store in position */ 226 position.ra = ln_range_degrees(ln_rad_to_deg(ra)); 227 position.dec = ln_rad_to_deg(declination); 228 } 229 230 /*! \fn void ln_get_ecl_from_equ(struct ln_equ_posn *object, double JD, struct ln_lnlat_posn *position) 231 * \param object Object coordinates in B1950. Use ln_get_equ_prec2 to transform from J2000. 232 * \param JD Julian day 233 * \param position Pointer to store new position. 234 * 235 * Transform an objects equatorial cordinates into ecliptical coordinates 236 * for the given julian day. 237 */ 238 /* Equ 12.1, 12.2 Pg 88 239 */ 240 @nogc void ln_get_ecl_from_equ(const ref ln_equ_posn object, double JD, 241 ref ln_lnlat_posn position) nothrow 242 { 243 double ra, declination, latitude, longitude; 244 ln_nutation nutation; 245 246 /* object position */ 247 ra = ln_deg_to_rad(object.ra); 248 declination = ln_deg_to_rad(object.dec); 249 ln_get_nutation(JD, nutation); 250 nutation.ecliptic = ln_deg_to_rad(nutation.ecliptic); 251 252 /* Equ 12.1, 12.2 */ 253 longitude = atan2((sin(ra) * cos(nutation.ecliptic) + tan(declination) * 254 sin(nutation.ecliptic)), cos(ra)); 255 latitude = sin(declination) * cos(nutation.ecliptic) - cos(declination) * 256 sin(nutation.ecliptic) * sin(ra); 257 latitude = asin(latitude); 258 259 /* store in position */ 260 position.lat = ln_rad_to_deg(latitude); 261 position.lng = ln_range_degrees(ln_rad_to_deg(longitude)); 262 } 263 264 /*! \fn void ln_get_ecl_from_rect(struct ln_rect_posn *rect, struct ln_lnlat_posn *posn) 265 * \param rect Rectangular coordinates. 266 * \param posn Pointer to store new position. 267 * 268 * Transform an objects rectangular coordinates into ecliptical coordinates. 269 */ 270 /* Equ 33.2 271 */ 272 @nogc void ln_get_ecl_from_rect(const ref ln_rect_posn rect, ref ln_lnlat_posn posn) nothrow 273 { 274 double t; 275 276 t = sqrt(rect.X * rect.X + rect.Y * rect.Y); 277 posn.lng = ln_range_degrees(ln_rad_to_deg(atan2(rect.X, rect.Y))); 278 posn.lat = ln_rad_to_deg(atan2(t, rect.Z)); 279 } 280 281 /*! \fn void ln_get_equ_from_gal(struct ln_gal_posn *gal, struct ln_equ_posn *equ) 282 * \param gal Galactic coordinates. 283 * \param equ B1950 equatorial coordinates. Use ln_get_equ_prec2 to transform to J2000. 284 * 285 * Transform an object galactic coordinates into B1950 equatorial coordinate. 286 */ 287 /* Pg 94 */ 288 @nogc void ln_get_equ_from_gal(const ref ln_gal_posn gal, ref ln_equ_posn equ) nothrow 289 { 290 double RAD_27_4, SIN_27_4, COS_27_4; 291 double l_123, cos_l_123; 292 double sin_b, cos_b, rad_gal_b; 293 double y; 294 295 RAD_27_4 = ln_deg_to_rad(27.4); 296 SIN_27_4 = sin(RAD_27_4); 297 COS_27_4 = cos(RAD_27_4); 298 299 l_123 = ln_deg_to_rad(gal.l - 123); 300 cos_l_123 = cos(l_123); 301 302 rad_gal_b = ln_deg_to_rad(gal.b); 303 304 sin_b = sin(rad_gal_b); 305 cos_b = cos(rad_gal_b); 306 307 y = atan2(sin(l_123), cos_l_123 * SIN_27_4 - (sin_b / cos_b) * COS_27_4); 308 equ.ra = ln_range_degrees(ln_rad_to_deg(y) + 12.25); 309 equ.dec = 310 ln_rad_to_deg(asin(sin_b * SIN_27_4 + cos_b * COS_27_4 * cos_l_123)); 311 } 312 313 /*! \fn void ln_get_equ2000_from_gal(struct ln_gal_posn *gal, struct ln_equ_posn *equ) 314 * \param gal Galactic coordinates. 315 * \param equ J2000 equatorial coordinates. 316 * 317 * Transform an object galactic coordinates into equatorial coordinate. 318 */ 319 @nogc void ln_get_equ2000_from_gal(const ref ln_gal_posn gal, ref ln_equ_posn equ) nothrow 320 { 321 ln_get_equ_from_gal(gal, equ); 322 ln_get_equ_prec2(equ, B1950, JD2000, equ); 323 } 324 325 /*! \fn ln_get_gal_from_equ(struct ln_equ_posn *equ, struct ln_gal_posn *gal) 326 * \param equ B1950 equatorial coordinates. 327 * \param gal Galactic coordinates. 328 * 329 * Transform an object B1950 equatorial coordinate into galactic coordinates. 330 */ 331 /* Pg 94 */ 332 @nogc void ln_get_gal_from_equ(const ref ln_equ_posn equ, ref ln_gal_posn gal) nothrow 333 { 334 double RAD_27_4, SIN_27_4, COS_27_4; 335 double ra_192_25, cos_ra_192_25; 336 double rad_equ_dec; 337 double cos_dec, sin_dec; 338 double x; 339 340 RAD_27_4 = ln_deg_to_rad(27.4); 341 SIN_27_4 = sin(RAD_27_4); 342 COS_27_4 = cos(RAD_27_4); 343 344 ra_192_25 = ln_deg_to_rad(192.25 - equ.ra); 345 cos_ra_192_25 = cos(ra_192_25); 346 347 rad_equ_dec = ln_deg_to_rad(equ.dec); 348 349 sin_dec = sin(rad_equ_dec); 350 cos_dec = cos(rad_equ_dec); 351 352 x = atan2(sin(ra_192_25), 353 cos_ra_192_25 * SIN_27_4 - (sin_dec / cos_dec) * COS_27_4); 354 gal.l = ln_range_degrees(303 - ln_rad_to_deg(x)); 355 gal.b = ln_rad_to_deg(asin(sin_dec * SIN_27_4 + cos_dec * 356 COS_27_4 * cos_ra_192_25)); 357 } 358 359 /*! \fn void ln_get_gal_from_equ2000(struct ln_equ_posn *equ, struct ln_gal_posn *gal) 360 * \param equ J2000 equatorial coordinates. 361 * \param gal Galactic coordinates. 362 * 363 * Transform an object J2000 equatorial coordinate into galactic coordinates. 364 */ 365 @nogc void ln_get_gal_from_equ2000(const ref ln_equ_posn equ, ref ln_gal_posn gal) nothrow 366 { 367 ln_equ_posn equ_1950; 368 ln_get_equ_prec2(equ, JD2000, B1950, equ_1950); 369 ln_get_gal_from_equ(equ_1950, gal); 370 } 371 372 /*! \example transforms.c 373 * 374 * Examples of how to use transformation functions. 375 */ 376 377 }