/*************************************************************************** * GSkyDir.cpp - Sky direction class * * ----------------------------------------------------------------------- * * copyright (C) 2008-2013 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ /** * @file GSkyDir.cpp * @brief Sky direction class implementation * @author Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include #include "GException.hpp" #include "GTools.hpp" #include "GMath.hpp" #include "GSkyDir.hpp" #include "GMatrix.hpp" #include "GVector.hpp" /* __ Method name definitions ____________________________________________ */ /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /* __ Prototypes _________________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Constructor ***************************************************************************/ GSkyDir::GSkyDir(void) { // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] dir Sky direction. ***************************************************************************/ GSkyDir::GSkyDir(const GSkyDir& dir) { // Initialise members init_members(); // Copy members copy_members(dir); // Return return; } /***********************************************************************//** * @brief Destructor ***************************************************************************/ GSkyDir::~GSkyDir(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] dir Sky direction. * @return Sky direction. ***************************************************************************/ GSkyDir& GSkyDir::operator= (const GSkyDir& dir) { // Execute only if object is not identical if (this != &dir) { // Free members free_members(); // Initialise members init_members(); // Copy members copy_members(dir); } // endif: object was not identical // Return this object return *this; } /*========================================================================== = = = Public methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Clear sky direction ***************************************************************************/ void GSkyDir::clear(void) { // Free members free_members(); // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Clone sky direction * * @return Pointer to deep copy of sky direction. ***************************************************************************/ GSkyDir* GSkyDir::clone(void) const { // Clone sky direction return new GSkyDir(*this); } /***********************************************************************//** * @brief Set equatorial sky direction (radians) * * @param[in] ra Right Ascension in radians. * @param[in] dec Declination in radians. * * Sets Right Ascension and Declination in radians. ***************************************************************************/ void GSkyDir::radec(const double& ra, const double& dec) { // Set attributes m_has_lb = false; m_has_radec = true; #if defined(G_SINCOS_CACHE) m_has_lb_cache = false; m_has_radec_cache = false; #endif // Set direction m_ra = ra; m_dec = dec; // Return return; } /***********************************************************************//** * @brief Set equatorial sky direction (degrees) * * @param[in] ra Right Ascension in degrees. * @param[in] dec Declination in degrees. * * Sets Right Ascension and Declination in degrees. ***************************************************************************/ void GSkyDir::radec_deg(const double& ra, const double& dec) { // Set attributes m_has_lb = false; m_has_radec = true; #if defined(G_SINCOS_CACHE) m_has_lb_cache = false; m_has_radec_cache = false; #endif // Set direction m_ra = ra * gammalib::deg2rad; m_dec = dec * gammalib::deg2rad; // Return return; } /***********************************************************************//** * @brief Set galactic sky direction (radians) * * @param[in] l Galactic longitude in radians. * @param[in] b Galactic latitude in radians. * * Sets Galactic longitude and latitude in radians. ***************************************************************************/ void GSkyDir::lb(const double& l, const double& b) { // Set attributes m_has_lb = true; m_has_radec = false; #if defined(G_SINCOS_CACHE) m_has_lb_cache = false; m_has_radec_cache = false; #endif // Set direction m_l = l; m_b = b; // Return return; } /***********************************************************************//** * @brief Set galactic sky direction (degrees) * * @param[in] l Galactic longitude in degrees. * @param[in] b Galactic latitude in degrees. * * Sets Galactic longitude and latitude in degrees. ***************************************************************************/ void GSkyDir::lb_deg(const double& l, const double& b) { // Set attributes m_has_lb = true; m_has_radec = false; #if defined(G_SINCOS_CACHE) m_has_lb_cache = false; m_has_radec_cache = false; #endif // Set direction m_l = l * gammalib::deg2rad; m_b = b * gammalib::deg2rad; // Return return; } /***********************************************************************//** * @brief Set sky direction from 3D vector in celestial coordinates * * @param[in] vector 3D vector. * * Convert a 3-dimensional vector in celestial coordinates into a sky * direction. The transformation is given by * * \f[ * \alpha = \arctan \left( \frac{x_1}{x_0} \right) * \f] * * \f[ * \delta = \arcsin x_2 * \f] ***************************************************************************/ void GSkyDir::celvector(const GVector& vector) { // Set attributes m_has_lb = false; m_has_radec = true; #if defined(G_SINCOS_CACHE) m_has_lb_cache = false; m_has_radec_cache = false; #endif // Convert vector into sky position m_dec = std::asin(vector[2]); m_ra = std::atan2(vector[1], vector[0]); // Return return; } /***********************************************************************//** * @brief Rotate sky direction by zenith and azimuth angle * * @param[in] phi Azimuth angle (deg). * @param[in] theta Zenith angle (deg). * * Rotate sky direction by a zenith and azimuth angle given in the system * of the sky direction and aligned in celestial coordinates. * The azimuth angle is counted counter clockwise from celestial north * (this is identical to the astronomical definition of a position angle). ***************************************************************************/ void GSkyDir::rotate_deg(const double& phi, const double& theta) { // If we have no equatorial coordinates then get them now if (!m_has_radec && m_has_lb) { gal2equ(); } // Allocate Euler and rotation matrices GMatrix ry; GMatrix rz; // Set up rotation matrix to rotate from native coordinates to // celestial coordinates ry.eulery(m_dec * gammalib::rad2deg - 90.0); rz.eulerz(-m_ra * gammalib::rad2deg); GMatrix rot = (ry * rz).transpose(); // Set up native coordinate vector double phi_rad = phi * gammalib::deg2rad; double theta_rad = theta * gammalib::deg2rad; double cos_phi = std::cos(phi_rad); double sin_phi = std::sin(phi_rad); double cos_theta = std::cos(theta_rad); double sin_theta = std::sin(theta_rad); GVector native(-cos_phi*sin_theta, sin_phi*sin_theta, cos_theta); // Rotate vector into celestial coordinates GVector dir = rot * native; // Convert vector into sky position celvector(dir); // Return return; } /***********************************************************************//** * @brief Return galactic longitude in degrees * * @return Galactic longitude in degrees. ***************************************************************************/ double GSkyDir::l_deg(void) const { // If we have no galactic coordinates then get them now if (!m_has_lb && m_has_radec) { equ2gal(); } // Return galactic longitude return m_l * gammalib::rad2deg; } /***********************************************************************//** * @brief Returns galactic latitude in degrees * * @return Galactic latitude in degrees. ***************************************************************************/ double GSkyDir::b_deg(void) const { // If we have no galactic coordinates then get them now if (!m_has_lb && m_has_radec) { equ2gal(); } // Return galactic latitude return m_b * gammalib::rad2deg; } /***********************************************************************//** * @brief Returns Right Ascension in degrees * * @return Right Ascension in degrees. ***************************************************************************/ double GSkyDir::ra_deg(void) const { // If we have no equatorial coordinates then get them now if (!m_has_radec && m_has_lb) { gal2equ(); } // Return Right Ascension return m_ra * gammalib::rad2deg; } /***********************************************************************//** * @brief Returns Declination in degrees * * @return Declination in degrees. ***************************************************************************/ double GSkyDir::dec_deg(void) const { // If we have no equatorial coordinates then get them now if (!m_has_radec && m_has_lb) { gal2equ(); } // Return Declination return m_dec * gammalib::rad2deg; } /***********************************************************************//** * @brief Return sky direction as 3D vector in celestial coordinates * * @return Sky direction as 3D vector in celestial coordinates. ***************************************************************************/ GVector GSkyDir::celvector(void) const { // If we have no equatorial coordinates then get them now if (!m_has_radec && m_has_lb) { gal2equ(); } // Compute 3D vector double cosra = std::cos(m_ra); double sinra = std::sin(m_ra); #if defined(G_SINCOS_CACHE) if (!m_has_radec_cache) { m_has_radec_cache = true; m_sin_dec = std::sin(m_dec); m_cos_dec = std::cos(m_dec); } GVector vector(m_cos_dec*cosra, m_cos_dec*sinra, m_sin_dec); #else double cosdec = std::cos(m_dec); double sindec = std::sin(m_dec); GVector vector(cosdec*cosra, cosdec*sinra, sindec); #endif // Return vector return vector; } /***********************************************************************//** * @brief Compute angular distance between sky directions in radians * * @param[in] dir Sky direction to which distance is to be computed. * @return Angular distance in radians. * * Computes the angular distance between two sky directions in radians. ***************************************************************************/ double GSkyDir::dist(const GSkyDir& dir) const { // Initialise cosine of distance double cosdis; // Compute dependent on coordinate system availability. This speeds // up things by avoiding unnecessary coordinate transformations. if (m_has_lb) { #if defined(G_SINCOS_CACHE) if (!m_has_lb_cache) { m_has_lb_cache = true; m_sin_b = std::sin(m_b); m_cos_b = std::cos(m_b); } #endif if (dir.m_has_lb) { #if defined(G_SINCOS_CACHE) if (!dir.m_has_lb_cache) { dir.m_has_lb_cache = true; dir.m_sin_b = std::sin(dir.m_b); dir.m_cos_b = std::cos(dir.m_b); } cosdis = m_sin_b * dir.m_sin_b + m_cos_b * dir.m_cos_b * std::cos(dir.m_l - m_l); #else cosdis = std::sin(m_b) * std::sin(dir.m_b) + std::cos(m_b) * std::cos(dir.m_b) * std::cos(dir.m_l - m_l); #endif } else { #if defined(G_SINCOS_CACHE) cosdis = m_sin_b * std::sin(dir.b()) + m_cos_b * std::cos(dir.b()) * std::cos(dir.l() - m_l); #else cosdis = std::sin(m_b) * std::sin(dir.b()) + std::cos(m_b) * std::cos(dir.b()) * std::cos(dir.l() - m_l); #endif } } else if (m_has_radec) { #if defined(G_SINCOS_CACHE) if (!m_has_radec_cache) { m_has_radec_cache = true; m_sin_dec = std::sin(m_dec); m_cos_dec = std::cos(m_dec); } #endif if (dir.m_has_radec) { #if defined(G_SINCOS_CACHE) if (!dir.m_has_radec_cache) { dir.m_has_radec_cache = true; dir.m_sin_dec = std::sin(dir.m_dec); dir.m_cos_dec = std::cos(dir.m_dec); } cosdis = m_sin_dec * dir.m_sin_dec + m_cos_dec * dir.m_cos_dec * std::cos(dir.m_ra - m_ra); #else cosdis = std::sin(m_dec) * std::sin(dir.m_dec) + std::cos(m_dec) * std::cos(dir.m_dec) * std::cos(dir.m_ra - m_ra); #endif } else { #if defined(G_SINCOS_CACHE) cosdis = m_sin_dec * sin(dir.dec()) + m_cos_dec * cos(dir.dec()) * std::cos(dir.ra() - m_ra); #else cosdis = sin(m_dec) * sin(dir.dec()) + cos(m_dec) * cos(dir.dec()) * std::cos(dir.ra() - m_ra); #endif } } else { cosdis = std::sin(dec()) * std::sin(dir.dec()) + std::cos(dec()) * std::cos(dir.dec()) * std::cos(dir.ra() - ra()); } // Compute distance (use argument save GTools function) double dist = gammalib::acos(cosdis); // Return distance return dist; } /***********************************************************************//** * @brief Compute angular distance between sky directions in degrees * * @param[in] dir Sky direction to which distance is to be computed. * @return Angular distance in degrees. * * Computes the angular distance between two sky directions in degrees. ***************************************************************************/ double GSkyDir::dist_deg(const GSkyDir& dir) const { // Return distance in degrees return (dist(dir) * gammalib::rad2deg); } /***********************************************************************//** * @brief Compute position angle between sky directions in radians * * @param[in] dir Sky direction. * @return Position angle in radians. * * Computes the position angle using * \f[PA = \arctan \left( * \frac{\sin( \alpha_1 - \alpha_0 )} * {\cos \delta_0 \tan \delta_1 - * \sin \delta_0 \cos(\alpha_1 - \alpha_0)} \right)\f] * where * \f$(\alpha_0,\delta_0)\f$ are the coordinates of the reference point, and * \f$(\alpha_1,\delta_1)\f$ are the coordinates of sky direction for which * the position angle is to be computed. * * The position angle is counted counterclockwise from north. ***************************************************************************/ double GSkyDir::posang(const GSkyDir& dir) const { // Initialise arguments of arctan double arg_1; double arg_2; // Compute dependent on coordinate system availability. This speeds // up things by avoiding unnecessary coordinate transformations. if (m_has_lb) { #if defined(G_SINCOS_CACHE) if (!m_has_lb_cache) { m_has_lb_cache = true; m_sin_b = std::sin(m_b); m_cos_b = std::cos(m_b); } #endif if (dir.m_has_lb) { arg_1 = std::sin(dir.m_l - m_l); #if defined(G_SINCOS_CACHE) arg_2 = m_cos_b * std::tan(dir.m_b) - m_sin_b * std::cos(dir.m_l - m_l); #else arg_2 = std::cos(m_b) * std::tan(dir.m_b) - std::sin(m_b) * std::cos(dir.m_l - m_l); #endif } else { arg_1 = std::sin(dir.l() - m_l); #if defined(G_SINCOS_CACHE) arg_2 = m_cos_b * std::tan(dir.b()) - m_sin_b * std::cos(dir.l() - m_l); #else arg_2 = std::cos(m_b) * std::tan(dir.b()) - std::sin(m_b) * std::cos(dir.l() - m_l); #endif } } else if (m_has_radec) { #if defined(G_SINCOS_CACHE) if (!m_has_radec_cache) { m_has_radec_cache = true; m_sin_dec = std::sin(m_dec); m_cos_dec = std::cos(m_dec); } #endif if (dir.m_has_radec) { arg_1 = std::sin(dir.m_ra - m_ra); #if defined(G_SINCOS_CACHE) arg_2 = m_cos_dec * std::tan(dir.m_dec) - m_sin_dec * std::cos(dir.m_ra - m_ra); #else arg_2 = std::cos(m_dec) * std::tan(dir.m_dec) - std::sin(m_dec) * std::cos(dir.m_ra - m_ra); #endif } else { arg_1 = std::sin(dir.ra() - m_ra); #if defined(G_SINCOS_CACHE) arg_2 = m_cos_dec * std::tan(dir.dec()) - m_sin_dec * std::cos(dir.ra() - m_ra); #else arg_2 = std::cos(m_dec) * std::tan(dir.dec()) - std::sin(m_dec) * std::cos(dir.ra() - m_ra); #endif } } else { arg_1 = std::sin(dir.ra() - ra()); arg_2 = std::cos(dec())*std::tan(dir.dec()) - std::sin(dec())*std::cos(dir.ra() - ra()); } // Compute position angle double pa = std::atan2(arg_1, arg_2); // Return position angle return pa; } /***********************************************************************//** * @brief Compute position angle between sky directions in degrees * * @param[in] dir Sky direction. * @return Position angle in degrees. * * Returns the position angle of a sky direction in degrees. * * See the posang() method for more information about the computation of the * position angle. ***************************************************************************/ double GSkyDir::posang_deg(const GSkyDir& dir) const { // Return position angle in degrees return (posang(dir) * gammalib::rad2deg); } /***********************************************************************//** * @brief Print sky direction information * * @param[in] chatter Chattiness (defaults to NORMAL). * @return String containing sky direction information. ***************************************************************************/ std::string GSkyDir::print(const GChatter& chatter) const { // Initialise result string std::string result; // Continue only if chatter is not silent if (chatter != SILENT) { // Put coordinates in string if (m_has_lb) { result = "(l,b)=("+gammalib::str(m_l*gammalib::rad2deg) + "," + gammalib::str(m_b*gammalib::rad2deg)+")"; } else if (m_has_radec) { result = "(RA,Dec)=("+gammalib::str(m_ra*gammalib::rad2deg) + "," + gammalib::str(m_dec*gammalib::rad2deg)+")"; } else { result = "(RA,Dec)=(not initialised)"; } } // endif: chatter was not silent // Return result return result; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GSkyDir::init_members(void) { // Initialise members m_has_lb = false; m_has_radec = false; m_l = 0.0; m_b = 0.0; m_ra = 0.0; m_dec = 0.0; // Initialise sincos cache #if defined(G_SINCOS_CACHE) m_has_lb_cache = false; m_has_radec_cache = false; m_sin_b = 0.0; m_cos_b = 0.0; m_sin_dec = 0.0; m_cos_dec = 0.0; #endif // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] dir Sky direction. ***************************************************************************/ void GSkyDir::copy_members(const GSkyDir& dir) { // Copy members m_has_lb = dir.m_has_lb; m_has_radec = dir.m_has_radec; m_l = dir.m_l; m_b = dir.m_b; m_ra = dir.m_ra; m_dec = dir.m_dec; // Copy sincos cache #if defined(G_SINCOS_CACHE) m_has_lb_cache = dir.m_has_lb_cache; m_has_radec_cache = dir.m_has_radec_cache; m_sin_b = dir.m_sin_b; m_cos_b = dir.m_cos_b; m_sin_dec = dir.m_sin_dec; m_cos_dec = dir.m_cos_dec; #endif // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void GSkyDir::free_members(void) { // Return return; } /***********************************************************************//** * @brief Convert equatorial to galactic coordinates ***************************************************************************/ void GSkyDir::equ2gal(void) const { // Get non-const pointers to data members. This allows to circumvent // the const correctness and allows treating GSkyDir access methods // as const double* l = (double*)&m_l; double* b = (double*)&m_b; // Convert from equatorial to galactic euler(0, m_ra, m_dec, l, b); // Return return; } /***********************************************************************//** * @brief Convert galactic to equatorial coordinates ***************************************************************************/ void GSkyDir::gal2equ(void) const { // Get non-const pointers to data members. This allows to circumvent // the const correctness and allows treating GSkyDir access methods // as const double* ra = (double*)&m_ra; double* dec = (double*)&m_dec; // Convert from galactic to equatorial euler(1, m_l, m_b, ra, dec); // Return return; } /***********************************************************************//** * @brief General coordinate transformation routine for J2000 * * @param[in] type Conversion type (0=equ2gal, 1=gal2equ) * @param[in] xin Input longitude (RA or GLON) in radians. * @param[in] yin Input latitude (Dec or GLAT) in radians. * @param[out] xout Output longitude in radians. * @param[out] yout Output latitude in radians. ***************************************************************************/ void GSkyDir::euler(const int& type, const double& xin, const double &yin, double* xout, double *yout) const { // Set transformation constants const double psi[] = {0.57477043300, 4.9368292465}; const double stheta[] = {0.88998808748, -0.88998808748}; const double ctheta[] = {0.45598377618, 0.45598377618}; const double phi[] = {4.9368292465, 0.57477043300}; // Perform transformation double a = xin - phi[type]; double b = yin; double sb = std::sin(b); double cb = std::cos(b); double cbsa = cb * std::sin(a); // a = std::atan2(ctheta[type] * cbsa + stheta[type] * sb, cb * std::cos(a)); b = -stheta[type] * cbsa + ctheta[type] * sb; if (b > 1.0) b = 1.0; // *yout = std::asin(b); *xout = gammalib::modulo((a+psi[type] + gammalib::fourpi), gammalib::twopi); // Return return; } /*========================================================================== = = = Friends = = = ==========================================================================*/ /***********************************************************************//** * @brief Equality operator * * @param[in] a First sky direction. * @param[in] b Second sky direction. * * Compare two sky directions. If the coordinate is at the pole, the Right * Ascension or Longitude value is irrelevant. * * Comparisons are done dependent on the available coordinate system. This * speeds up things and avoids unnecessary coordinate transformations. ***************************************************************************/ bool operator==(const GSkyDir &a, const GSkyDir &b) { // Initialise result bool equal = false; // Compute dependent on coordinate system availability. This speeds // up things by avoiding unnecessary coordinate transformations. if (a.m_has_lb) { if (b.m_has_lb) { if (std::abs(a.m_b) == 90.0) { equal = (a.m_b == b.m_b); } else { equal = (a.m_b == b.m_b && a.m_l == b.m_l); } } else { if (std::abs(a.m_b) == 90.0) { equal = (a.m_b == b.b()); } else { equal = (a.m_b == b.b() && a.m_l == b.l()); } } } else if (a.m_has_radec) { if (b.m_has_radec) { if (std::abs(a.m_dec) == 90.0) { equal = (a.m_dec == b.m_dec); } else { equal = (a.m_dec == b.m_dec && a.m_ra == b.m_ra); } } else { if (std::abs(a.m_dec) == 90.0) { equal = (a.m_dec == b.dec()); } else { equal = (a.m_dec == b.dec() && a.m_ra == b.ra()); } } } else { if (std::abs(b.dec()) == 90.0) { equal = (b.dec() == a.dec()); } else { equal = (b.dec() == a.dec() && b.ra() == a.ra()); } } // Return equality return equal; } /***********************************************************************//** * @brief Non equality operator * * @param[in] a First sky direction. * @param[in] b Second sky direction. ***************************************************************************/ bool operator!=(const GSkyDir &a, const GSkyDir &b) { // Return non equality return (!(a==b)); }