Advertisement
Guest User

GeoDataCoordinates.cpp

a guest
May 15th, 2012
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 39.41 KB | None | 0 0
  1. //
  2. // This file is part of the Marble Virtual Globe.
  3. //
  4. // This program is free software licensed under the GNU LGPL. You can
  5. // find a copy of this license in LICENSE.txt in the top directory of
  6. // the source code.
  7. //
  8. // Copyright 2004-2007 Torsten Rahn <tackat@kde.org>
  9. // Copyright 2007-2008 Inge Wallin  <ingwa@kde.org>
  10. // Copyright 2008      Patrick Spendrin <ps_ml@gmx.de>
  11. // Copyright 2011      Friedrich W. H. Kossebau <kossebau@kde.org>
  12. // Copyright 2011      Bernhard Beschow <bbeschow@cs.tu-berlin.de>
  13. //
  14.  
  15.  
  16. #include "GeoDataCoordinates.h"
  17. #include "GeoDataCoordinates_p.h"
  18.  
  19. #include <cmath>
  20.  
  21. #include <QtCore/QRegExp>
  22. #include <QtCore/QLocale>
  23. #include <QtCore/QString>
  24. #include <QtCore/QStringList>
  25. #include <QtCore/QCoreApplication>
  26. #include <QtCore/QAtomicInt>
  27.  
  28. #include "global.h"
  29. #include "MarbleDebug.h"
  30.  
  31. #include "Quaternion.h"
  32.  
  33. namespace Marble
  34. {
  35.  
  36. // Helper class for GeoDataCoordinates::fromString(...)
  37. class LonLatParser
  38. {
  39. private:
  40.     enum DirPosition { PrefixDir, PostfixDir };
  41.  
  42.     static QString createDecimalPointExp();
  43.     static QString regExp( const QString& string );
  44.     static void getLocaleList( QStringList& localeList, const QString& localeListString,
  45.                                const QLatin1String& placeholder, const QString& separator );
  46.     static bool isDirection( const QString& input, const QString& direction);
  47.     static bool isDirection( const QString& input, const QStringList& directions);
  48.     static bool isOneOfDirections( const QString& input,
  49.                                    const QString& firstDirection,
  50.                                    const QString& secondDirection,
  51.                                    bool& isFirstDirection);
  52.     static bool isOneOfDirections( const QString& input,
  53.                                    const QStringList& firstDirections,
  54.                                    const QStringList& secondDirections,
  55.                                    bool& isFirstDirection);
  56.  
  57.     /**
  58.      * function template for the function calculating the degree value from
  59.      * the captured texts with the degree, the minutes, the seconds and the signedness
  60.      * (or less, depending on what the function actually expects)
  61.      * @param regex the regexp to take the texts from
  62.      * @param c the index in the list of captured texts of @p regex to start with
  63.      * @param isPosHemisphere if the texts of the degree value are relative to the pos hemisphere
  64.      * @return the calculated degree value
  65.      */
  66.     static qreal degreeValueFromDMS( const QRegExp& regex, int c, bool isPosHemisphere );
  67.     static qreal degreeValueFromDM( const QRegExp& regex, int c, bool isPosHemisphere );
  68.     static qreal degreeValueFromD( const QRegExp& regex, int c, bool isPosHemisphere );
  69.  
  70. public:
  71.     LonLatParser();
  72.     /**
  73.      * @brief parses the complete @p input string and sets the lon and lat properties if successful.
  74.      * @param input the string to parse, must not have other content than the coordinates
  75.      * @return @c true on successful parsing, @c false otherwise.
  76.      */
  77.     bool parse( const QString& input );
  78.     /**
  79.     * @brief return the lon value from the last successful parsing
  80.     */
  81.     qreal lon() const { return m_lon; }
  82.     /**
  83.     * @brief return the lat value from the last successful parsing
  84.     */
  85.     qreal lat() const { return m_lat; }
  86.  
  87. private:
  88.     /**
  89.      * @brief tries to parse the input with the given reg expression and get the lon and lat values
  90.      * @param input the string to parse, must not have other content than the coordinates
  91.      * @param dirPosition position of the dir in the list of captured texts
  92.      * @return @c true on successful parsing, @c false otherwise.
  93.      */
  94.     bool tryMatchFromDms( const QString& input, DirPosition dirPosition );
  95.     bool tryMatchFromDm( const QString& input, DirPosition dirPosition );
  96.     bool tryMatchFromD( const QString& input, DirPosition dirPosition );
  97.  
  98.     /**
  99.     * @brief initializes also all properties which only need to be lazily initialized
  100.     */
  101.     void initAll();
  102.     /**
  103.      * @brief checks if the both passed directions are correct, also returns more data about them
  104.      * @param dir1 first direction string
  105.      * @param dir1 second direction string
  106.      * @param isDir1LonDir is set to @c true if first direction string is a longitude direction,
  107.      *                     @c false otherwise
  108.      * @param isLonDirPosHemisphere is set to @c true if longitude direction is in positive hemisphere,
  109.      *                              @c false otherwise
  110.      * @param isLatDirPosHemisphere is set to @c true if latitude direction is in positive hemisphere,
  111.      *                              @c false otherwise
  112.      * @return @c true if @p dir1 and @p dir2 are correct, @c false otherwise.
  113.      */
  114.     bool isCorrectDirections( const QString& dir1, const QString& dir2,
  115.                               bool& isDir1LonDir,
  116.                               bool& isLonDirPosHemisphere, bool& isLatDirPosHemisphere ) const;
  117.     bool isLocaleLonDirection( const QString& input,
  118.                                bool& isDirPosHemisphere ) const;
  119.     bool isLocaleLatDirection( const QString& input,
  120.                                bool& isDirPosHemisphere ) const;
  121.     bool isLonDirection( const QString& input,
  122.                          bool& isDirPosHemisphere ) const;
  123.     bool isLatDirection( const QString& input,
  124.                          bool& isDirPosHemisphere ) const;
  125.  
  126. private:
  127.     qreal m_lon;
  128.     qreal m_lat;
  129.  
  130. private: // helper values
  131.     const QString m_north;
  132.     const QString m_east;
  133.     const QString m_south;
  134.     const QString m_west;
  135.  
  136.     const QString m_decimalPointExp;
  137.  
  138. private: // helper value, lazily set, in initAll();
  139.     QStringList m_northLocale;
  140.     QStringList m_eastLocale;
  141.     QStringList m_southLocale;
  142.     QStringList m_westLocale;
  143.  
  144.     QStringList m_degreeLocale;
  145.     QStringList m_minutesLocale;
  146.     QStringList m_secondsLocale;
  147.  
  148.     QString m_dirCapExp;
  149.     QString m_degreeExp;
  150.     QString m_minutesExp;
  151.     QString m_secondsExp;
  152. };
  153.  
  154. LonLatParser::LonLatParser()
  155.     : m_lon( 0.0 )
  156.     , m_lat( 0.0 )
  157.     , m_north( QLatin1String("n") )
  158.     , m_east(  QLatin1String("e") )
  159.     , m_south( QLatin1String("s") )
  160.     , m_west(  QLatin1String("w") )
  161.     , m_decimalPointExp( createDecimalPointExp() )
  162. {
  163. }
  164.  
  165.  
  166. void LonLatParser::initAll()
  167. {
  168.     // already all initialized?
  169.     if (! m_dirCapExp.isEmpty() )
  170.         return;
  171.  
  172.     const QLatin1String placeholder = QLatin1String("*");
  173.     const QString separator = QLatin1String("|");
  174.  
  175.     getLocaleList( m_northLocale, GeoDataCoordinates::tr( "*", "North direction terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  176.                    placeholder, separator );
  177.     getLocaleList( m_eastLocale, GeoDataCoordinates::tr( "*", "East direction terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  178.                    placeholder, separator );
  179.     getLocaleList( m_southLocale, GeoDataCoordinates::tr( "*", "South direction terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  180.                    placeholder, separator );
  181.     getLocaleList( m_westLocale, GeoDataCoordinates::tr( "*", "West direction terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  182.                    placeholder, separator );
  183.  
  184.     // use a set to remove duplicates
  185.     QSet<QString> dirs = QSet<QString>()
  186.         << m_north << m_east << m_south << m_west;
  187.     dirs += m_northLocale.toSet();
  188.     dirs += m_eastLocale.toSet();
  189.     dirs += m_southLocale.toSet();
  190.     dirs += m_westLocale.toSet();
  191.  
  192.     QString fullNamesExp;
  193.     QString simpleLetters;
  194.  
  195.     foreach( const QString& dir, dirs ) {
  196.         // collect simple letters
  197.         if ((dir.length() == 1) && (QLatin1Char('a')<=dir.at(0)) && (dir.at(0)<=QLatin1Char('z'))) {
  198.             simpleLetters += dir;
  199.             continue;
  200.         }
  201.  
  202.         // okay to add '|' also for last, separates from firstLetters
  203.         fullNamesExp += regExp(dir) + QLatin1Char('|');
  204.     }
  205.  
  206.     // Sets "(north|east|south|west|[nesw])" in en, as translated names match untranslated ones
  207.     m_dirCapExp =
  208.         QLatin1Char('(') + fullNamesExp + QLatin1Char('[') + simpleLetters + QLatin1String("])");
  209.  
  210.     // expressions for symbols of degree, minutes and seconds
  211.     getLocaleList( m_degreeLocale, GeoDataCoordinates::tr( "*", "Degree symbol terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  212.                    placeholder, separator );
  213.     getLocaleList( m_minutesLocale, GeoDataCoordinates::tr( "*", "Minutes symbol terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  214.                    placeholder, separator );
  215.     getLocaleList( m_secondsLocale, GeoDataCoordinates::tr( "*", "Seconds symbol terms, see http://techbase.kde.org/Projects/Marble/GeoDataCoordinatesTranslation" ),
  216.                    placeholder, separator );
  217.  
  218.     // Used unicode regexp expressions:
  219.     // x00B0: ° DEGREE SIGN
  220.     // x00BA: º MASCULINE ORDINAL INDICATOR (found used as degree sign)
  221.     // x2032: ′ PRIME (minutes)
  222.     // x00B4: ´ ACUTE ACCENT (found as minutes sign)
  223.     // x02CA: ˊ MODIFIER LETTER ACUTE ACCENT
  224.     // x2019: ’ RIGHT SINGLE QUOTATION MARK
  225.     // x2033: ″ DOUBLE PRIME (seconds)
  226.     // x201D: ” RIGHT DOUBLE QUOTATION MARK
  227.  
  228.     m_degreeExp = QLatin1String("\\x00B0|\\x00BA");
  229.     foreach(const QString& symbol, m_degreeLocale) {
  230.         m_degreeExp += QLatin1Char('|') + regExp(symbol);
  231.     }
  232.     m_minutesExp = QLatin1String("'|\\x2032|\\x00B4|\\x20C2|\\x2019");
  233.     foreach(const QString& symbol, m_minutesLocale) {
  234.         m_minutesExp += QLatin1Char('|') + regExp(symbol);
  235.     }
  236.     m_secondsExp = QLatin1String("\"|\\x2033|\\x201D|''|\\x2032\\x2032|\\x00B4\\x00B4|\\x20C2\\x20C2|\\x2019\\x2019");
  237.     foreach(const QString& symbol, m_secondsLocale) {
  238.         m_secondsExp += QLatin1Char('|') + regExp(symbol);
  239.     }
  240. }
  241.  
  242. bool LonLatParser::parse( const QString& string )
  243. {
  244.     QString input = string.toLower().trimmed();
  245.  
  246.     // #1: Just two numbers, no directions, e.g. 74.2245 -32.2434 (assumes lat lon)
  247.     {
  248.         const QString numberCapExp = QString::fromLatin1(
  249.             "([-+]?\\d{1,3}%1?\\d*)(?:,|;|\\s)\\s*"
  250.             "([-+]?\\d{1,3}%1?\\d*)"
  251.             ).arg(m_decimalPointExp);
  252.  
  253.         const QRegExp regex = QRegExp( numberCapExp );
  254.         if( regex.exactMatch(input) ) {
  255.             m_lon = regex.cap(2).toDouble();
  256.             m_lat = regex.cap(1).toDouble();
  257.  
  258.             return true;
  259.         }
  260.     }
  261.  
  262.     initAll();
  263.  
  264.     if ( tryMatchFromD( input, PostfixDir ) ) {
  265.         return true;
  266.     }
  267.  
  268.     if ( tryMatchFromD( input, PrefixDir ) ) {
  269.         return true;
  270.     }
  271.  
  272.     if ( tryMatchFromDms( input, PostfixDir ) ) {
  273.         return true;
  274.     }
  275.  
  276.     if ( tryMatchFromDms( input, PrefixDir ) ) {
  277.         return true;
  278.     }
  279.  
  280.     if ( tryMatchFromDm( input, PostfixDir ) ) {
  281.         return true;
  282.     }
  283.  
  284.     if ( tryMatchFromDm( input, PrefixDir ) ) {
  285.         return true;
  286.     }
  287.  
  288.     return false;
  289. }
  290.  
  291. // #3: Sexagesimal
  292. bool LonLatParser::tryMatchFromDms( const QString& input, DirPosition dirPosition )
  293. {
  294.     // direction as postfix
  295.     const char *postfixCapExp =
  296.         "([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*"
  297.         "(\\d{1,2}%1?\\d*)(?:%5)?\\s*%2[,;]?\\s*"
  298.         "([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*"
  299.         "(\\d{1,2}%1?\\d*)(?:%5)?\\s*%2";
  300.  
  301.     // direction as prefix
  302.     const char *prefixCapExp =
  303.         "%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*"
  304.         "(\\d{1,2}%1?\\d*)(?:%5)?\\s*(?:,|;|\\s)\\s*"
  305.         "%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2})(?:%4|\\s)\\s*"
  306.         "(\\d{1,2}%1?\\d*)(?:%5)?";
  307.  
  308.     const char *expTemplate = ( dirPosition == PostfixDir ) ? postfixCapExp
  309.                                                             : prefixCapExp;
  310.  
  311.     const QString numberCapExp =
  312.         QString::fromLatin1( expTemplate ).arg( m_decimalPointExp, m_dirCapExp,
  313.                                                 m_degreeExp, m_minutesExp, m_secondsExp);
  314.  
  315.     const QRegExp regex = QRegExp( numberCapExp );
  316.     if( !regex.exactMatch( input ) ) {
  317.         return false;
  318.     }
  319.  
  320.     bool isDir1LonDir;
  321.     bool isLonDirPosHemisphere;
  322.     bool isLatDirPosHemisphere;
  323.     const QString dir1 = regex.cap( dirPosition == PostfixDir ? 5 : 1 );
  324.     const QString dir2 = regex.cap( dirPosition == PostfixDir ? 10 : 6 );
  325.     if ( !isCorrectDirections( dir1, dir2, isDir1LonDir,
  326.                                isLonDirPosHemisphere, isLatDirPosHemisphere ) ) {
  327.         return false;
  328.     }
  329.  
  330.     const int valueStartIndex1 = (dirPosition == PostfixDir ? 1 : 2);
  331.     const int valueStartIndex2 = (dirPosition == PostfixDir ? 6 : 7);
  332.     m_lon = degreeValueFromDMS( regex, isDir1LonDir ? valueStartIndex1 : valueStartIndex2,
  333.                                 isLonDirPosHemisphere );
  334.     m_lat = degreeValueFromDMS( regex, isDir1LonDir ? valueStartIndex2 : valueStartIndex1,
  335.                                 isLatDirPosHemisphere );
  336.  
  337.     return true;
  338. }
  339.  
  340. // #4: Sexagesimal with minute precision
  341. bool LonLatParser::tryMatchFromDm( const QString& input, DirPosition dirPosition )
  342. {
  343.     // direction as postfix
  344.     const char *postfixCapExp =
  345.         "([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?\\s*%2[,;]?\\s*"
  346.         "([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?\\s*%2";
  347.  
  348.     // direction as prefix
  349.     const char *prefixCapExp =
  350.         "%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?\\s*(?:,|;|\\s)\\s*"
  351.         "%2\\s*([-+]?)(\\d{1,3})(?:%3|\\s)\\s*(\\d{1,2}%1?\\d*)(?:%4)?";
  352.  
  353.     const char *expTemplate = ( dirPosition == PostfixDir ) ? postfixCapExp
  354.                                                             : prefixCapExp;
  355.  
  356.     const QString numberCapExp =
  357.         QString::fromLatin1( expTemplate ).arg( m_decimalPointExp, m_dirCapExp,
  358.                                                 m_degreeExp, m_minutesExp );
  359.     const QRegExp regex = QRegExp( numberCapExp );
  360.     if( !regex.exactMatch(input) ) {
  361.         return false;
  362.     }
  363.  
  364.     bool isDir1LonDir;
  365.     bool isLonDirPosHemisphere;
  366.     bool isLatDirPosHemisphere;
  367.     const QString dir1 = regex.cap( dirPosition == PostfixDir ? 4 : 1 );
  368.     const QString dir2 = regex.cap( dirPosition == PostfixDir ? 8 : 5 );
  369.     if ( !isCorrectDirections( dir1, dir2, isDir1LonDir,
  370.                                isLonDirPosHemisphere, isLatDirPosHemisphere ) ) {
  371.         return false;
  372.     }
  373.  
  374.     const int valueStartIndex1 = ( dirPosition == PostfixDir ? 1 : 2 );
  375.     const int valueStartIndex2 = ( dirPosition == PostfixDir ? 5 : 6 );
  376.     m_lon = degreeValueFromDM( regex, isDir1LonDir ? valueStartIndex1 : valueStartIndex2,
  377.                                isLonDirPosHemisphere );
  378.     m_lat = degreeValueFromDM( regex, isDir1LonDir ? valueStartIndex2 : valueStartIndex1,
  379.                                isLatDirPosHemisphere );
  380.  
  381.     return true;
  382. }
  383.  
  384. // #2: Two numbers with directions
  385. bool LonLatParser::tryMatchFromD( const QString& input, DirPosition dirPosition )
  386. {
  387.     // direction as postfix, e.g. 74.2245 N 32.2434 W
  388.     const char *postfixCapExp =
  389.         "([-+]?\\d{1,3}%1?\\d*)(?:%3)?(?:\\s*)%2(?:,|;|\\s)\\s*"
  390.         "([-+]?\\d{1,3}%1?\\d*)(?:%3)?(?:\\s*)%2";
  391.  
  392.     // direction as prefix, e.g. N 74.2245 W 32.2434
  393.     const char *prefixCapExp =
  394.         "%2\\s*([-+]?\\d{1,3}%1?\\d*)(?:%3)?\\s*(?:,|;|\\s)\\s*"
  395.         "%2\\s*([-+]?\\d{1,3}%1?\\d*)(?:%3)?";
  396.  
  397.     const char *expTemplate = ( dirPosition == PostfixDir ) ? postfixCapExp
  398.                                                             : prefixCapExp;
  399.  
  400.     const QString numberCapExp =
  401.         QString::fromLatin1( expTemplate ).arg( m_decimalPointExp, m_dirCapExp, m_degreeExp );
  402.     const QRegExp regex = QRegExp( numberCapExp );
  403.     if( !regex.exactMatch( input ) ) {
  404.         return false;
  405.     }
  406.  
  407.     bool isDir1LonDir;
  408.     bool isLonDirPosHemisphere;
  409.     bool isLatDirPosHemisphere;
  410.     const QString dir1 = regex.cap( dirPosition == PostfixDir ? 2 : 1 );
  411.     const QString dir2 = regex.cap( dirPosition == PostfixDir ? 4 : 3 );
  412.     if ( !isCorrectDirections( dir1, dir2, isDir1LonDir,
  413.                                isLonDirPosHemisphere, isLatDirPosHemisphere ) ) {
  414.         return false;
  415.     }
  416.  
  417.     const int valueStartIndex1 = ( dirPosition == PostfixDir ? 1 : 2 );
  418.     const int valueStartIndex2 = ( dirPosition == PostfixDir ? 3 : 4 );
  419.     m_lon = degreeValueFromD( regex, isDir1LonDir ? valueStartIndex1 : valueStartIndex2,
  420.                               isLonDirPosHemisphere );
  421.     m_lat = degreeValueFromD( regex, isDir1LonDir ? valueStartIndex2 : valueStartIndex1,
  422.                               isLatDirPosHemisphere );
  423.  
  424.     return true;
  425. }
  426.  
  427. QString LonLatParser::createDecimalPointExp()
  428. {
  429.     const QChar decimalPoint = QLocale::system().decimalPoint();
  430.  
  431.     return (decimalPoint == QLatin1Char('.')) ? QString::fromLatin1("\\.") :
  432.         QLatin1String("[.") + decimalPoint + QLatin1Char(']');
  433. }
  434.  
  435. QString LonLatParser::regExp(const QString& string)
  436. {
  437.     QString result;
  438.     for (int i = 0; i < string.length(); ++i) {
  439.         const QChar c = string.at(i);
  440.         if ((QLatin1Char('a') <= c) && (c <= QLatin1Char('z'))) {
  441.             result += c;
  442.         } else if (c.isSpace()) {
  443.             result += QLatin1String("\\s");
  444.         } else if (c == QLatin1Char('.')) {
  445.             result += QLatin1String("\\.");
  446.         } else {
  447.             result += QString::fromLatin1("\\x%1").arg(c.unicode(), 4, 16, QLatin1Char('0'));
  448.         }
  449.     }
  450.     return result;
  451. }
  452.  
  453. void LonLatParser::getLocaleList( QStringList& localeList, const QString& localeListString,
  454.                                   const QLatin1String& placeholder, const QString& separator )
  455. {
  456.     const QString lowerLocaleListString = localeListString.toLower();
  457.     if (lowerLocaleListString != placeholder) {
  458.         localeList = lowerLocaleListString.split(separator, QString::SkipEmptyParts);
  459.     }
  460. }
  461.  
  462. bool LonLatParser::isDirection( const QString& input, const QStringList& directions )
  463. {
  464.     return ( directions.contains(input) );
  465. }
  466.  
  467. bool LonLatParser::isDirection( const QString& input, const QString& direction )
  468. {
  469.     return ( input == direction );
  470. }
  471.  
  472. bool LonLatParser::isOneOfDirections( const QString& input,
  473.                                       const QString& firstDirection,
  474.                                       const QString& secondDirection,
  475.                                       bool& isFirstDirection )
  476. {
  477.     isFirstDirection = isDirection(input, firstDirection);
  478.     return isFirstDirection || isDirection(input, secondDirection);
  479. }
  480.  
  481. bool LonLatParser::isOneOfDirections( const QString& input,
  482.                                       const QStringList& firstDirections,
  483.                                       const QStringList& secondDirections,
  484.                                       bool& isFirstDirection )
  485. {
  486.     isFirstDirection = isDirection(input, firstDirections);
  487.     return isFirstDirection || isDirection(input, secondDirections);
  488. }
  489.  
  490.  
  491. bool LonLatParser::isLocaleLonDirection( const QString& input,
  492.                                          bool& isDirPosHemisphere ) const
  493. {
  494.     return isOneOfDirections(input, m_eastLocale, m_westLocale, isDirPosHemisphere);
  495. }
  496.  
  497. bool LonLatParser::isLocaleLatDirection( const QString& input,
  498.                                          bool& isDirPosHemisphere ) const
  499. {
  500.     return isOneOfDirections(input, m_northLocale, m_southLocale, isDirPosHemisphere);
  501. }
  502.  
  503. bool LonLatParser::isLonDirection( const QString& input,
  504.                                    bool& isDirPosHemisphere ) const
  505. {
  506.     return isOneOfDirections(input, m_east, m_west, isDirPosHemisphere);
  507. }
  508.  
  509. bool LonLatParser::isLatDirection( const QString& input,
  510.                                    bool& isDirPosHemisphere ) const
  511. {
  512.     return isOneOfDirections(input, m_north, m_south, isDirPosHemisphere);
  513. }
  514.  
  515.  
  516. qreal LonLatParser::degreeValueFromDMS( const QRegExp& regex, int c, bool isPosHemisphere )
  517. {
  518.     const bool isNegativeValue = (regex.cap( c++ ) == QLatin1String("-"));
  519.     const uint degree = regex.cap( c++ ).toUInt();
  520.     const uint minutes = regex.cap( c++ ).toUInt();
  521.     const qreal seconds = regex.cap( c ).toDouble();
  522.  
  523.     qreal result = degree + (minutes*MIN2HOUR) + (seconds*SEC2HOUR);
  524.  
  525.     if (isNegativeValue)
  526.         result *= -1;
  527.     if (! isPosHemisphere)
  528.         result *= -1;
  529.  
  530.     return result;
  531. }
  532.  
  533. qreal LonLatParser::degreeValueFromDM( const QRegExp& regex, int c, bool isPosHemisphere )
  534. {
  535.     const bool isNegativeValue = (regex.cap( c++ ) == QLatin1String("-"));
  536.     const uint degree = regex.cap( c++ ).toUInt();
  537.     const qreal minutes = regex.cap( c ).toDouble();
  538.  
  539.     qreal result = degree + (minutes*MIN2HOUR);
  540.  
  541.     if (isNegativeValue)
  542.         result *= -1;
  543.     if (! isPosHemisphere)
  544.         result *= -1;
  545.  
  546.     return result;
  547. }
  548.  
  549. qreal LonLatParser::degreeValueFromD( const QRegExp& regex, int c, bool isPosHemisphere )
  550. {
  551.     qreal result = regex.cap( c ).toDouble();
  552.  
  553.     if (! isPosHemisphere)
  554.         result *= -1;
  555.  
  556.     return result;
  557. }
  558.  
  559. bool LonLatParser::isCorrectDirections(const QString& dir1, const QString& dir2,
  560.                                        bool& isDir1LonDir,
  561.                                        bool& isLonDirPosHemisphere,
  562.                                        bool& isLatDirPosHemisphere) const
  563. {
  564.     // first try localized names
  565.     isDir1LonDir = isLocaleLonDirection(dir1, isLonDirPosHemisphere);
  566.     const bool resultLocale = isDir1LonDir ?
  567.         isLocaleLatDirection(dir2, isLatDirPosHemisphere) :
  568.         (isLocaleLatDirection(dir1, isLatDirPosHemisphere) &&
  569.          isLocaleLonDirection(dir2, isLonDirPosHemisphere));
  570.  
  571.     if (resultLocale)
  572.         return resultLocale;
  573.  
  574.     // fallback to try english names as lingua franca
  575.     isDir1LonDir = isLonDirection(dir1, isLonDirPosHemisphere);
  576.     return isDir1LonDir ?
  577.         isLatDirection(dir2, isLatDirPosHemisphere) :
  578.         (isLatDirection(dir1, isLatDirPosHemisphere) &&
  579.          isLonDirection(dir2, isLonDirPosHemisphere));
  580. }
  581.  
  582.  
  583.  
  584. GeoDataCoordinates::Notation GeoDataCoordinates::s_notation = GeoDataCoordinates::DMS;
  585.  
  586. GeoDataCoordinates::GeoDataCoordinates( qreal _lon, qreal _lat, qreal _alt, GeoDataCoordinates::Unit unit, int _detail )
  587.   : d( new GeoDataCoordinatesPrivate( _lon, _lat, _alt, unit, _detail ) )
  588. {
  589.     d->ref.ref();
  590. }
  591.  
  592. /* simply copy the d pointer
  593. * it will be replaced in the detach function instead
  594. */
  595. GeoDataCoordinates::GeoDataCoordinates( const GeoDataCoordinates& other )
  596.   : d( other.d )
  597. {
  598.     d->ref.ref();
  599. }
  600.  
  601. /*
  602.  * standard ctor;
  603.  * create a new private pointer which initializes the atomic reference counter
  604.  */
  605. GeoDataCoordinates::GeoDataCoordinates()
  606.   : d( new GeoDataCoordinatesPrivate() )
  607. {
  608.     d->ref.ref();
  609. }
  610.  
  611. /*
  612.  * only delete the private d pointer if the number of references is 0
  613.  * remember that all copies share the same d pointer!
  614.  */
  615. GeoDataCoordinates::~GeoDataCoordinates()
  616. {
  617.     if (!d->ref.deref())
  618.         delete d;
  619. #ifdef DEBUG_GEODATA
  620. //    mDebug() << "delete coordinates";
  621. #endif
  622. }
  623.  
  624. /*
  625.  * if only one copy exists, return
  626.  * else make a new private d pointer object and assign the values of the current
  627.  * one to it
  628.  * at the end, if the number of references thus reaches 0 delete it
  629.  * this state shouldn't happen, but if it does, we have to clean up behind us.
  630.  */
  631. void GeoDataCoordinates::detach()
  632. {
  633.     if(d->ref == 1)
  634.         return;
  635.  
  636.     GeoDataCoordinatesPrivate *new_d = new GeoDataCoordinatesPrivate( *d );
  637.  
  638.     if (!d->ref.deref())
  639.         delete d;
  640.  
  641.     d = new_d;
  642.     d->ref.ref();
  643. }
  644.  
  645. /*
  646.  * call detach() at the start of all non-static, non-const functions
  647.  */
  648. void GeoDataCoordinates::set( qreal _lon, qreal _lat, qreal _alt, GeoDataCoordinates::Unit unit )
  649. {
  650.     detach();
  651.     d->m_altitude = _alt;
  652.     switch( unit ){
  653.     default:
  654.     case Radian:
  655.         d->m_q = Quaternion::fromSpherical( _lon, _lat );
  656.         d->m_lon = _lon;
  657.         d->m_lat = _lat;
  658.         break;
  659.     case Degree:
  660.         d->m_q = Quaternion::fromSpherical( _lon * DEG2RAD , _lat * DEG2RAD  );
  661.         d->m_lon = _lon * DEG2RAD;
  662.         d->m_lat = _lat * DEG2RAD;
  663.         break;
  664.     }
  665. }
  666.  
  667. /*
  668.  * call detach() at the start of all non-static, non-const functions
  669.  */
  670. void GeoDataCoordinates::setLongitude( qreal _lon, GeoDataCoordinates::Unit unit )
  671. {
  672.     detach();
  673.     switch( unit ){
  674.     default:
  675.     case Radian:
  676.         d->m_q = Quaternion::fromSpherical( _lon, d->m_lat );
  677.         d->m_lon = _lon;
  678.         break;
  679.     case Degree:
  680.         d->m_q = Quaternion::fromSpherical( _lon * DEG2RAD , d->m_lat  );
  681.         d->m_lon = _lon * DEG2RAD;
  682.         break;
  683.     }
  684. }
  685.  
  686.  
  687. /*
  688.  * call detach() at the start of all non-static, non-const functions
  689.  */
  690. void GeoDataCoordinates::setLatitude( qreal _lat, GeoDataCoordinates::Unit unit )
  691. {
  692.     detach();
  693.     switch( unit ){
  694.     case Radian:
  695.         d->m_q = Quaternion::fromSpherical( d->m_lon, _lat );
  696.         d->m_lat = _lat;
  697.         break;
  698.     case Degree:
  699.         d->m_q = Quaternion::fromSpherical( d->m_lon, _lat * DEG2RAD   );
  700.         d->m_lat = _lat * DEG2RAD;
  701.         break;
  702.     }
  703. }
  704.  
  705.  
  706. void GeoDataCoordinates::geoCoordinates( qreal& lon, qreal& lat,
  707.                                GeoDataCoordinates::Unit unit ) const
  708. {
  709.     switch ( unit )
  710.     {
  711.     default:
  712.     case Radian:
  713.             lon = d->m_lon;
  714.             lat = d->m_lat;
  715.         break;
  716.     case Degree:
  717.             lon = d->m_lon * RAD2DEG;
  718.             lat = d->m_lat * RAD2DEG;
  719.         break;
  720.     }
  721. }
  722.  
  723. void GeoDataCoordinates::geoCoordinates( qreal& lon, qreal& lat, qreal& alt,
  724.                                          GeoDataCoordinates::Unit unit ) const
  725. {
  726.     geoCoordinates( lon, lat, unit );
  727.     alt = d->m_altitude;
  728. }
  729.  
  730. qreal GeoDataCoordinates::longitude( GeoDataCoordinates::Unit unit ) const
  731. {
  732.     switch ( unit )
  733.     {
  734.     default:
  735.     case Radian:
  736.         return d->m_lon;
  737.     case Degree:
  738.         return d->m_lon * RAD2DEG;
  739.     }
  740. }
  741.  
  742. qreal GeoDataCoordinates::latitude( GeoDataCoordinates::Unit unit ) const
  743. {
  744.     switch ( unit )
  745.     {
  746.     default:
  747.     case Radian:
  748.         return d->m_lat;
  749.     case Degree:
  750.         return d->m_lat * RAD2DEG;
  751.     }
  752. }
  753.  
  754. //static
  755. GeoDataCoordinates::Notation GeoDataCoordinates::defaultNotation()
  756. {
  757.     return s_notation;
  758. }
  759.  
  760. //static
  761. void GeoDataCoordinates::setDefaultNotation( GeoDataCoordinates::Notation notation )
  762. {
  763.     s_notation = notation;
  764. }
  765.  
  766. //static
  767. qreal GeoDataCoordinates::normalizeLon( qreal lon, GeoDataCoordinates::Unit unit )
  768. {
  769.     qreal halfCircle;
  770.     if ( unit == GeoDataCoordinates::Radian ) {
  771.         halfCircle = M_PI;
  772.     }
  773.     else {
  774.         halfCircle = 180;
  775.     }
  776.  
  777.     if ( lon > halfCircle ) {
  778.         int cycles = (int)( ( lon + halfCircle ) / ( 2 * halfCircle ) );
  779.         return lon - ( cycles * 2 * halfCircle );
  780.     }
  781.     if ( lon < -halfCircle ) {
  782.         int cycles = (int)( ( lon - halfCircle ) / ( 2 * halfCircle ) );
  783.         return lon - ( cycles * 2 * halfCircle );
  784.     }
  785.  
  786.     return lon;
  787. }
  788.  
  789. //static
  790. qreal GeoDataCoordinates::normalizeLat( qreal lat, GeoDataCoordinates::Unit unit )
  791. {
  792.     qreal halfCircle;
  793.     if ( unit == GeoDataCoordinates::Radian ) {
  794.         halfCircle = M_PI;
  795.     }
  796.     else {
  797.         halfCircle = 180;
  798.     }
  799.  
  800.     if ( lat > ( halfCircle / 2.0 ) ) {
  801.         int cycles = (int)( ( lat + halfCircle ) / ( 2 * halfCircle ) );
  802.         qreal temp;
  803.         if( cycles == 0 ) { // pi/2 < lat < pi
  804.             temp = halfCircle - lat;
  805.         } else {
  806.             temp = lat - ( cycles * 2 * halfCircle );
  807.         }
  808.         if ( temp > ( halfCircle / 2.0 ) ) {
  809.             return ( halfCircle - temp );
  810.         }
  811.         if ( temp < ( -halfCircle / 2.0 ) ) {
  812.             return ( -halfCircle - temp );
  813.         }
  814.         return temp;
  815.     }
  816.     if ( lat < ( -halfCircle / 2.0 ) ) {
  817.         int cycles = (int)( ( lat - halfCircle ) / ( 2 * halfCircle ) );
  818.         qreal temp;
  819.         if( cycles == 0 ) {
  820.             temp = -halfCircle - lat;
  821.         } else {
  822.             temp = lat - ( cycles * 2 * halfCircle );
  823.         }
  824.         if ( temp > ( +halfCircle / 2.0 ) ) {
  825.             return ( +halfCircle - temp );
  826.         }
  827.         if ( temp < ( -halfCircle / 2.0 ) ) {
  828.             return ( -halfCircle - temp );
  829.         }
  830.         return temp;
  831.     }
  832.     return lat;
  833. }
  834.  
  835. //static
  836. void GeoDataCoordinates::normalizeLonLat( qreal &lon, qreal &lat, GeoDataCoordinates::Unit unit )
  837. {
  838.     qreal halfCircle;
  839.     if ( unit == GeoDataCoordinates::Radian ) {
  840.         halfCircle = M_PI;
  841.     }
  842.     else {
  843.         halfCircle = 180;
  844.     }
  845.  
  846.     if ( lon > +halfCircle ) {
  847.         int cycles = (int)( ( lon + halfCircle ) / ( 2 * halfCircle ) );
  848.         lon = lon - ( cycles * 2 * halfCircle );
  849.     }
  850.     if ( lon < -halfCircle ) {
  851.         int cycles = (int)( ( lon - halfCircle ) / ( 2 * halfCircle ) );
  852.         lon = lon - ( cycles * 2 * halfCircle );
  853.     }
  854.  
  855.     if ( lat > ( +halfCircle / 2.0 ) ) {
  856.         int cycles = (int)( ( lat + halfCircle ) / ( 2 * halfCircle ) );
  857.         qreal temp;
  858.         if( cycles == 0 ) { // pi/2 < lat < pi
  859.             temp = halfCircle - lat;
  860.         } else {
  861.             temp = lat - ( cycles * 2 * halfCircle );
  862.         }
  863.         if ( temp > ( +halfCircle / 2.0 ) ) {
  864.             lat =  +halfCircle - temp;
  865.         }
  866.         if ( temp < ( -halfCircle / 2.0 ) ) {
  867.             lat =  -halfCircle - temp;
  868.         }
  869.         lat = temp;
  870.         if( lon > 0 ) {
  871.             lon = -halfCircle + lon;
  872.         } else {
  873.             lon = halfCircle + lon;
  874.         }
  875.     }
  876.     if ( lat < ( -halfCircle / 2.0 ) ) {
  877.         int cycles = (int)( ( lat - halfCircle ) / ( 2 * halfCircle ) );
  878.         qreal temp;
  879.         if( cycles == 0 ) {
  880.             temp = -halfCircle - lat;
  881.         } else {
  882.             temp = lat - ( cycles * 2 * halfCircle );
  883.         }
  884.         if ( temp > ( +halfCircle / 2.0 ) ) {
  885.             lat =  +halfCircle - temp;
  886.         }
  887.         if ( temp < ( -halfCircle / 2.0 ) ) {
  888.             lat =  -halfCircle - temp;
  889.         }
  890.         lat = temp;
  891.         if( lon > 0 ) {
  892.             lon = -halfCircle + lon;
  893.         } else {
  894.             lon = halfCircle + lon;
  895.         }
  896.     }
  897.     return;
  898. }
  899.  
  900. GeoDataCoordinates GeoDataCoordinates::fromString( const QString& string, bool& successful )
  901. {
  902.     LonLatParser parser;
  903.     successful = parser.parse(string);
  904.     if (successful) {
  905.         return GeoDataCoordinates( parser.lon(), parser.lat(), 0, GeoDataCoordinates::Degree );
  906.     } else {
  907.         return GeoDataCoordinates();
  908.     }
  909. }
  910.  
  911.  
  912. QString GeoDataCoordinates::toString() const
  913. {
  914.     return GeoDataCoordinates::toString( s_notation );
  915. }
  916.  
  917. QString GeoDataCoordinates::toString( GeoDataCoordinates::Notation notation, int precision ) const
  918. {
  919.         return  lonToString( d->m_lon, notation, Radian, precision )
  920.                 + QString(", ")
  921.                 + latToString( d->m_lat, notation, Radian, precision );
  922. }
  923.  
  924. QString GeoDataCoordinates::lonToString( qreal lon, GeoDataCoordinates::Notation notation,  
  925.                                                     GeoDataCoordinates::Unit unit,
  926.                                                     int precision,
  927.                                                     char format )
  928. {
  929.     QString weString = ( lon < 0 ) ? tr("W") : tr("E");
  930.  
  931.     QString lonString;
  932.  
  933.     qreal lonDegF = ( unit == Degree ) ? fabs( lon ) : fabs( (qreal)(lon) * RAD2DEG );
  934.  
  935.     // Take care of -1 case
  936.     precision = ( precision < 0 ) ? 5 : precision;
  937.    
  938.     if ( notation == GeoDataCoordinates::DMS )
  939.     {
  940.         int lonDeg = (int) lonDegF;
  941.         qreal lonMinF = 60 * (lonDegF - lonDeg);
  942.         int lonMin = (int) lonMinF;
  943.         qreal lonSecF = 60 * (lonMinF - lonMin);
  944.         int lonSec = (int) lonSecF;
  945.  
  946.         // Adjustment for fuzziness (like 49.999999999999999999999)
  947.         if ( precision > 2 ) {
  948.             lonSec = qRound( lonSecF );
  949.         }
  950.         if (lonSec > 59) {
  951.             lonSecF = 0;
  952.             lonSec = lonSecF;
  953.             lonMin = lonMin + 1;
  954.         }
  955.         if ( precision == 0 ) {
  956.             lonMin = qRound( lonMinF );
  957.         }
  958.         if (lonMin > 59) {
  959.             lonMinF = 0;
  960.             lonMin = lonMinF;
  961.             lonDeg = lonDeg + 1;
  962.         }
  963.  
  964.         // Evaluate the string
  965.         lonString = QString::fromUtf8("%1\xc2\xb0").arg(lonDeg, 3, 10, QChar(' ') );
  966.  
  967.         if ( precision == 0 || lonDeg == lonDegF ) {
  968.             return lonString + weString;
  969.         }
  970.  
  971.         lonString += QString(" %2\'").arg(lonMin, 2, 10, QChar('0') );
  972.  
  973.         if ( precision < 3 || lonMin == lonMinF || lonSec == 0 ) {
  974.             return lonString + weString;
  975.         }
  976.  
  977.         // Includes -1 case!
  978.         if ( precision < 5 || lonSec == lonSecF ) {        
  979.             lonString += QString(" %3\"").arg(lonSec, 2, 'f', 0, QChar('0') );
  980.             return lonString + weString;
  981.         }
  982.  
  983.         lonString += QString(" %L3\"").arg(lonSecF, precision - 1, 'f', precision - 4, QChar('0') );
  984.     }
  985.     else // notation = GeoDataCoordinates::Decimal
  986.     {
  987.         lonString = QString::fromUtf8("%L1\xc2\xb0").arg(lonDegF, 4 + precision, format, precision, QChar(' ') );
  988.     }
  989.  
  990.     return lonString + weString;
  991. }
  992.  
  993. QString GeoDataCoordinates::lonToString() const
  994. {
  995.     return GeoDataCoordinates::lonToString( d->m_lon , s_notation );
  996. }
  997.  
  998. QString GeoDataCoordinates::latToString( qreal lat, GeoDataCoordinates::Notation notation,
  999.                                                     GeoDataCoordinates::Unit unit,
  1000.                                                     int precision,
  1001.                                                     char format )
  1002. {
  1003.     QString nsString = ( lat > 0 ) ? tr("N") : tr("S");
  1004.  
  1005.     QString latString;
  1006.  
  1007.     qreal latDegF = ( unit == Degree ) ? fabs( lat ) : fabs( (qreal)(lat) * RAD2DEG );
  1008.  
  1009.     // Take care of -1 case
  1010.     precision = ( precision < 0 ) ? 5 : precision;
  1011.    
  1012.     if ( notation == GeoDataCoordinates::DMS )
  1013.     {
  1014.         int latDeg = (int) latDegF;
  1015.         qreal latMinF = 60 * (latDegF - latDeg);
  1016.         int latMin = (int) latMinF;
  1017.         qreal latSecF = 60 * (latMinF - latMin);
  1018.         int latSec = (int) latSecF;
  1019.  
  1020.         // Adjustment for fuzziness (like 49.999999999999999999999)
  1021.         if ( precision > 2 ) {
  1022.             latSec = qRound( latSecF );
  1023.         }
  1024.         if (latSec > 59) {
  1025.             latSecF = 0;
  1026.             latSec = latSecF;
  1027.             latMin = latMin + 1;
  1028.         }
  1029.         if ( precision == 0 ) {
  1030.             latMin = qRound( latMinF );
  1031.         }
  1032.         if (latMin > 59) {
  1033.             latMinF = 0;
  1034.             latMin = latMinF;
  1035.             latDeg = latDeg + 1;
  1036.         }
  1037.  
  1038.         // Evaluate the string
  1039.         latString = QString::fromUtf8("%1\xc2\xb0").arg(latDeg, 3, 10, QChar(' ') );
  1040.  
  1041.         if ( precision == 0 || latDeg == latDegF ) {
  1042.             return latString + nsString;
  1043.         }
  1044.  
  1045.         latString += QString(" %2\'").arg(latMin, 2, 10, QChar('0') );
  1046.  
  1047.         if ( precision < 3 || latMin == latMinF || latSec == 0 ) {
  1048.             return latString + nsString;
  1049.         }
  1050.  
  1051.         // Includes -1 case!
  1052.         if ( precision < 5 || latSec == latSecF ) {        
  1053.             latString += QString(" %3\"").arg(latSec, 2, 'f', 0, QChar('0') );
  1054.             return latString + nsString;
  1055.         }
  1056.  
  1057.         latString += QString(" %L3\"").arg(latSecF, precision - 1, 'f', precision - 4, QChar('0') );
  1058.     }
  1059.     else // notation = GeoDataCoordinates::Decimal
  1060.     {
  1061.         latString = QString::fromUtf8("%L1\xc2\xb0").arg(latDegF, 4 + precision, format, precision, QChar(' ') );
  1062.     }
  1063.     return latString + nsString;
  1064. }
  1065.  
  1066. QString GeoDataCoordinates::latToString() const
  1067. {
  1068.     return GeoDataCoordinates::latToString( d->m_lat, s_notation );
  1069. }
  1070.  
  1071. bool GeoDataCoordinates::operator==( const GeoDataCoordinates &rhs ) const
  1072. {
  1073.     return *d == *rhs.d;
  1074. }
  1075.  
  1076. bool GeoDataCoordinates::operator!=( const GeoDataCoordinates &rhs ) const
  1077. {
  1078.     return *d != *rhs.d;
  1079. }
  1080.  
  1081. void GeoDataCoordinates::setAltitude( const qreal altitude )
  1082. {
  1083.     detach();
  1084.     d->m_altitude = altitude;
  1085. }
  1086.  
  1087. qreal GeoDataCoordinates::altitude() const
  1088. {
  1089.     return d->m_altitude;
  1090. }
  1091.  
  1092. int GeoDataCoordinates::detail() const
  1093. {
  1094.     return d->m_detail;
  1095. }
  1096.  
  1097. void GeoDataCoordinates::setDetail( const int det )
  1098. {
  1099.     detach();
  1100.     d->m_detail = det;
  1101. }
  1102.  
  1103. const Quaternion& GeoDataCoordinates::quaternion() const
  1104. {
  1105.     return d->m_q;
  1106. }
  1107.  
  1108. bool GeoDataCoordinates::isPole( Pole pole ) const
  1109. {
  1110.     // Evaluate the most likely case first:
  1111.     // The case where we haven't hit the pole and where our latitude is normalized
  1112.     // to the range of 90 deg S ... 90 deg N
  1113.     if ( fabs( (qreal) 2.0 * d->m_lat ) < M_PI ) {
  1114.         return false;
  1115.     }
  1116.     else {
  1117.         if ( fabs( (qreal) 2.0 * d->m_lat ) == M_PI ) {
  1118.             // Ok, we have hit a pole. Now let's check whether it's the one we've asked for:
  1119.             if ( pole == AnyPole ){
  1120.                 return true;
  1121.             }
  1122.             else {
  1123.                 if ( pole == NorthPole && 2.0 * d->m_lat == +M_PI ) {
  1124.                     return true;
  1125.                 }
  1126.                 if ( pole == SouthPole && 2.0 * d->m_lat == -M_PI ) {
  1127.                     return true;
  1128.                 }
  1129.                 return false;
  1130.             }
  1131.         }
  1132.         //
  1133.         else {
  1134.             // FIXME: Should we just normalize latitude and longitude and be done?
  1135.             //        While this might work well for persistent data it would create some
  1136.             //        possible overhead for temporary data, so this needs careful thinking.
  1137.             mDebug() << "GeoDataCoordinates not normalized!";
  1138.  
  1139.             // Only as a last resort we cover the unlikely case where
  1140.             // the latitude is not normalized to the range of
  1141.             // 90 deg S ... 90 deg N
  1142.             if ( fabs( (qreal) 2.0 * normalizeLat( d->m_lat ) ) < M_PI  ) {
  1143.                 return false;
  1144.             }
  1145.             else {
  1146.                 // Ok, we have hit a pole. Now let's check whether it's the one we've asked for:
  1147.                 if ( pole == AnyPole ){
  1148.                     return true;
  1149.                 }
  1150.                 else {
  1151.                     if ( pole == NorthPole && 2.0 * d->m_lat == +M_PI ) {
  1152.                         return true;
  1153.                     }
  1154.                     if ( pole == SouthPole && 2.0 * d->m_lat == -M_PI ) {
  1155.                         return true;
  1156.                     }
  1157.                     return false;
  1158.                 }
  1159.             }            
  1160.         }
  1161.     }
  1162. }
  1163.  
  1164. GeoDataCoordinates& GeoDataCoordinates::operator=( const GeoDataCoordinates &other )
  1165. {
  1166.     qAtomicAssign(d, other.d);
  1167.     return *this;
  1168. }
  1169.  
  1170. void GeoDataCoordinates::pack( QDataStream& stream ) const
  1171. {
  1172.     stream << d->m_lon;
  1173.     stream << d->m_lat;
  1174.     stream << d->m_altitude;
  1175. }
  1176.  
  1177. void GeoDataCoordinates::unpack( QDataStream& stream )
  1178. {
  1179.     // call detach even though it shouldn't be needed - one never knows
  1180.     detach();
  1181.     stream >> d->m_lon;
  1182.     stream >> d->m_lat;
  1183.     stream >> d->m_altitude;
  1184.  
  1185.     d->m_q = Quaternion::fromSpherical( d->m_lon, d->m_lat );
  1186. }
  1187.  
  1188. void GeoDataCoordinates::setType( int type )
  1189. {
  1190.     d->type = type;
  1191. }
  1192.  
  1193. int GeoDataCoordinates::getType() const
  1194. {
  1195.     return d->type;
  1196. }
  1197.  
  1198. void GeoDataCoordinates::setClock( MarbleClock* clock )
  1199. {
  1200.     d->m_clock = clock;
  1201. }
  1202.  
  1203. MarbleClock* GeoDataCoordinates::getClock() const
  1204. {
  1205.     return d->m_clock;
  1206. }
  1207.  
  1208. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement