// ---------------------------------------------------------------------------- // coordinate.cxx -- Handling of longitude and latitude. // // Copyright (C) 2012 // Remi Chateauneu, F4ECW // // This file is part of fldigi. // // Fldigi 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. // // Fldigi 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 fldigi. If not, see . // ---------------------------------------------------------------------------- #include #include #include #include #include #include #include "config.h" #include "coordinate.h" #include "locator.h" void CoordinateT::Check(void) const { if( m_is_lon ) { if( ( m_angle >= -180.0 ) && ( m_angle <= 180.0 ) ) return ; } else { if( ( m_angle >= -90.0 ) && ( m_angle <= 90.0 ) ) return ; } std::stringstream strm ; strm << "Invalid m_angle=" << m_angle << " m_is_lon=" << m_is_lon ; throw std::runtime_error(strm.str()); } CoordinateT::CoordinateT( double degrees, bool is_lon ) : m_angle( fmod(degrees, 360.0 ) ), m_is_lon(is_lon) { if( m_angle > 180.0 ) m_angle -= 360.0 ; Check(); }; // Longitude East and Latitude North are positive. void CoordinateT::Init( char direction, double angle_degrees ) { m_angle = angle_degrees ; switch( direction ) { case 'W': case 'w': m_angle = -m_angle ; case 'E': case 'e': if( ( angle_degrees < -180 ) || ( angle_degrees > 180 ) ) throw std::runtime_error("Invalid longitude degree"); m_is_lon = true ; break ; case 'S': case 's': m_angle = -m_angle ; case 'N': case 'n': if( ( angle_degrees < -90 ) || ( angle_degrees > 90 ) ) throw std::runtime_error("Invalid latitude degree"); m_is_lon = false ; break ; default: throw std::runtime_error("Invalid direction"); } Check(); } CoordinateT::CoordinateT( char direction, double angle_degrees ) { Init( direction, angle_degrees ); } CoordinateT::CoordinateT( char direction, int degree, int minute, int second ) { // std::cout << "ctor d=" << direction << " " << degree << " " << minute << " " << second << "\n"; if( ( degree < 0 ) || ( degree > 180 ) ) throw std::runtime_error("Invalid degree"); if( ( minute < 0 ) || ( minute >= 60 ) ) throw std::runtime_error("Invalid minute"); if( ( second < 0 ) || ( second >= 60 ) ) throw std::runtime_error("Invalid second"); double angle_degrees = (double)degree + (double)minute / 60.0 + (double)second / 3600.0 ; Init( direction, angle_degrees ); } // Specific for reading from the file of navtex or wmo stations. // Navtex: "57 06 N" // Wmo : "69-36N", "013-27E", "009-25E" ou floating-point degrees: "12.34 E". // Station Latitude or Latitude :DD-MM-SSH where DD is degrees, MM is minutes, SS is seconds // and H is N for northern hemisphere or S for southern hemisphere or // E for eastern hemisphere or W for western hemisphere. // The seconds value is omitted for those stations where the seconds value is unknown. std::istream & operator>>( std::istream & istrm, CoordinateT & ref ) { if( ! istrm ) return istrm ; std::stringstream sstrm ; char direction ; while( true ) { // istrm >> direction ; direction = (char)istrm.get(); if( ! istrm ) return istrm ; switch( direction ) { case 'e': case 'E': case 'w': case 'W': case 's': case 'S': case 'n': case 'N': break; case '0' ... '9' : case '.' : case '-' : case '+' : case ' ' : case '\t' : sstrm << direction ; continue; default: istrm.setstate(std::ios::eofbit); return istrm ; } break; } // TODO: Check that the direction is what we expect. std::string tmpstr = sstrm.str(); // std::cout << "READ:" << tmpstr << ":" << direction << "\n"; const char * tmpPtr = tmpstr.c_str(); int i_degree, i_minute, i_second ; if( ( 3 == sscanf( tmpPtr, "%d-%d-%d", &i_degree, &i_minute, &i_second ) ) || ( 3 == sscanf( tmpPtr, "%d %d %d", &i_degree, &i_minute, &i_second ) ) ) { ref = CoordinateT( direction, i_degree, i_minute, i_second ); return istrm; } if( ( 2 == sscanf( tmpPtr, "%d-%d", &i_degree, &i_minute ) ) || ( 2 == sscanf( tmpPtr, "%d %d", &i_degree, &i_minute ) ) ) { ref = CoordinateT( direction, i_degree, i_minute, 0 ); return istrm; } double d_degree ; if( 1 == sscanf( tmpPtr, "%lf", &d_degree ) ) { ref = CoordinateT( direction, d_degree ); return istrm; } istrm.setstate(std::ios::eofbit); return istrm ; } std::ostream & operator<<( std::ostream & ostrm, const CoordinateT & ref ) { bool sign = ref.m_angle > 0 ; double ang = sign ? ref.m_angle : -ref.m_angle; ostrm << std::setfill('0') << std::setw( ref.m_is_lon ? 3 : 2 ) << (int)ang << "°" << std::setfill('0') << std::setw(2) << ( (int)( 0.5 + ang * 60.0 ) % 60 ) << "'" << std::setfill('0') << std::setw(2) << (int)fmod( ang * 3600.0, 60 ) << "''" << " "; ostrm << ( ref.m_is_lon ? sign ? 'E' : 'W' : sign ? 'N' : 'S' ); return ostrm; } CoordinateT::Pair::Pair( const CoordinateT & coo1, const CoordinateT & coo2 ) : m_lon( coo1.is_lon() ? coo1 : coo2 ) , m_lat( coo2.is_lon() ? coo1 : coo2 ) { if( ! ( coo1.is_lon() ^ coo2.is_lon() ) ) { throw std::runtime_error("Internal inconsistency"); } } CoordinateT::Pair::Pair( double lon, double lat ) : m_lon( CoordinateT( lon, true ) ) , m_lat( CoordinateT( lat, false ) ) {} CoordinateT::Pair::Pair( const std::string & locator ) { double lon, lat ; int res = QRB::locator2longlat( &lon, &lat, locator.c_str() ); if( res != QRB::QRB_OK ) { throw std::runtime_error("Cannot decode Maidenhead locator:" + locator ); }; m_lon = CoordinateT( lon, true ); m_lat = CoordinateT( lat, false ); } double CoordinateT::Pair::distance( const Pair & a ) const { double dist, azimuth ; int res = QRB::qrb( longitude().angle(), latitude().angle(), a.longitude().angle(), a.latitude().angle(), &dist, &azimuth ); if( res != QRB::QRB_OK) { std::stringstream sstrm ; sstrm << "Bad qrb result:" << *this << " <-> " << a ; throw std::runtime_error(sstrm.str()); } return dist ; } std::string CoordinateT::Pair::locator(void) const { char buf[64]; int ret = QRB::longlat2locator( longitude().angle(), latitude().angle(), buf, 3 ); if( ret == QRB::QRB_OK ) { return buf ; } return std::string(); } std::ostream & operator<<( std::ostream & ostrm, const CoordinateT::Pair & ref ) { ostrm << ref.latitude() << "/" << ref.longitude(); return ostrm; } std::istream & operator>>( std::istream & istrm, CoordinateT::Pair & ref ) { istrm >> ref.latitude() >> ref.longitude(); return istrm; }