Jump to content

KDE Core/Platform 11/Geolocation

From KDE Community Wiki

Warning

This page contains rough working notes from discussion sessions at Platform 11, the contents of which may not accurately reflect any decisions made. Please do not infer anything from these notes, official summaries of the conclusions reached will be made available for discussion as soon as possible.


Geolocation

Qt5 Proposal: Move QGeoCoordinate and maybe QGeoAddress from QtLocation to QtCore as fundamental data types in the Qt Meta Type system. This will enable common data containers to be used by all low-level libraries for api and storage without needing a Geolocation library at compile or runtime. It should also allow interoperability of Geolocation libraries and online services and provide some independence when making a choice.

Discussed with Torsten / Marble guys and they are in favour. Torsten may be at QCS so can add input there.

GeoCoordinate

Key differences:

  • Marble always in 3d defaults altitude to 0m, Qt allows 2d or 3d
  • Marble returns coords in choice of Decimal Degrees or Radians, Qt only in Decimal Degrees
  • Marble is shared (has ref counter), Qt is not
  • Marble is able to be subclassed (has virtuals), Qt is not
  • Marble is a Qt Meta Type, Qt is not
  • Marble can set/get lat/lon/alt in a single call, Qt can not
  • Marble provides normalize methods, Qt does not
  • Marble provides precision parm for toString(), Qt does not
  • Marble provides fromString() method, Qt does not
  • Qt provides some Great Circle calculations which use the earth radius, Marble does these elsewhere and provides the radius as a parameter (to make it work on a certain altitude level or for other planets).
  • Marble caches position vector for performance
  • Marble stores int Detail level (this is possibly deprecated though)

Minor differences:

  • Marble defines Earth radius as 6378.000, Qt as 6371.0072
  • Marble stores internally in qreal Radians, Qt in double Decimal Degrees
  • Qt provides isValid(), Marble does not (since it doesn't distinguish Coordinate Types)

Other comments:

  • atDistanceAndAzimuth() method doesn't look right, especially distanceUp paramater

Suggested changes:

  • Move to QtCore
  • Make Q Meta Type
  • Possibly make shared
  • Possibly make able to subclass (i.e. allow Marble to derive and store cached position vector if not accepted)
  • Add convenience set/get methods for lat/lon/alt in a single call
  • Add api to return as degrees or radians
  • Add precision to toString()
  • Add separate lat/lon/alt to toString()
  • Add fromString()

Nice to have, but can be in wrapper?:

  • position vector
  • Detail level
  • Normalize
  • isPole()

Qt 5 Code (simplified):

class Q_LOCATION_EXPORT QGeoCoordinate { public:

   enum CoordinateType {
       InvalidCoordinate,
       Coordinate2D,
       Coordinate3D
   };
   enum CoordinateFormat {
       Degrees,
       DegreesWithHemisphere,
       DegreesMinutes,
       DegreesMinutesWithHemisphere,
       DegreesMinutesSeconds,
       DegreesMinutesSecondsWithHemisphere
   };
   QGeoCoordinate();
   QGeoCoordinate(double latitude, double longitude);
   QGeoCoordinate(double latitude, double longitude, double altitude);
   QGeoCoordinate(const QGeoCoordinate &other);
   ~QGeoCoordinate();
   QGeoCoordinate &operator=(const QGeoCoordinate &other);
   bool operator==(const QGeoCoordinate &other) const;
   inline bool operator!=(const QGeoCoordinate &other) const {
       return !operator==(other);
   }
   bool isValid() const;
   CoordinateType type() const;
   void setLatitude(double latitude);
   double latitude() const;
   void setLongitude(double longitude);
   double longitude() const;
   void setAltitude(double altitude);
   double altitude() const;
   qreal distanceTo(const QGeoCoordinate &other) const;
   qreal azimuthTo(const QGeoCoordinate &other) const;
   QGeoCoordinate atDistanceAndAzimuth(qreal distance, qreal azimuth, qreal distanceUp = 0.0) const;
   QString toString(CoordinateFormat format = DegreesMinutesSecondsWithHemisphere) const;

};

Marble API (simplified):

class GEODATA_EXPORT GeoDataCoordinates {

public:
   enum Unit{
       Radian,
       Degree
   };
   enum Notation{
       Decimal,
       DMS
   };
   GeoDataCoordinates();
   GeoDataCoordinates( qreal lon, qreal lat, qreal alt = 0,
                       GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian,
                       int detail = 0 );
   GeoDataCoordinates( const GeoDataCoordinates& other );
   virtual ~GeoDataCoordinates();
   GeoDataCoordinates& operator=( const GeoDataCoordinates &other );
   bool operator==( const GeoDataCoordinates& ) const;
   void set( qreal lon, qreal lat, qreal alt = 0,
             GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian );
   void geoCoordinates( qreal& lon, qreal& lat,
                        GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ) const;
   void setLongitude( qreal lon,
             GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian );
   qreal longitude( GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian )
                                                               const;
   void setLatitude( qreal lat,
             GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian );
   qreal latitude( GeoDataCoordinates::Unit unit = GeoDataCoordinates::Radian ) const;
   void setAltitude( const qreal altitude );
   qreal altitude() const;
   void setDetail( const int det );
   int detail() const;
   const Quaternion &quaternion() const;
   bool isPole( Pole = AnyPole ) const;
   static void setDefaultNotation( GeoDataCoordinates::Notation notation );
   static GeoDataCoordinates::Notation defaultNotation();
   static qreal normalizeLon( qreal lon,
                              GeoDataCoordinates::Unit = GeoDataCoordinates::Radian );
   static qreal normalizeLat( qreal lat,
                              GeoDataCoordinates::Unit = GeoDataCoordinates::Radian );
   static void normalizeLonLat( qreal &lon, qreal &lat,
                                GeoDataCoordinates::Unit = GeoDataCoordinates::Radian );
   static GeoDataCoordinates fromString( const QString &string, bool& successful );
   QString toString() const;
   QString toString( GeoDataCoordinates::Notation notation, int precision = -1 ) const;
   static QString lonToString( qreal lon, GeoDataCoordinates::Notation notation,
                                          GeoDataCoordinates::Unit unit = Radian,
                                          int precision = -1,
                                          char format = 'f' );
   QString lonToString() const;
   static QString latToString( qreal lat, GeoDataCoordinates::Notation notation,
                                          GeoDataCoordinates::Unit unit = Radian,
                                          int precision = -1,
   QString latToString() const;


   virtual void pack( QDataStream& stream ) const;
   virtual void unpack( QDataStream& stream );
   virtual void detach();

};

GeoAddress

TODO: Do some more research on other common address containers for comparison, e.g. online geocoding services, OSM, OSX, etc.

A very simple implementation lacking sophistication, no validation or intelligence, simply a container. No equivalent in Marble, but may be useful as is other fundamental type in Geocoding services, is a clean stand-alone implementation if not very sophisticated.

  • https://qt.gitorious.org/qt/qtlocation/blobs/master/src/location/qgeoaddress.h
  • Uses US names for division levels (States, etc) instead of more generic names.
  • Street name field is combination of many things, would be better if house number was separate. Perhaps do as extra fields?
  • Country Code is ISO Alpha3 rather than more common ISO Alpha2 as used in QLocale
  • No validation/cross-check between Country Code and Country Name, QLocale could provide the name for the code instead but would limit to only valid ISO countries.
  • Could hold ISO Subdivision Code?
  • Is shared
  • Is not Qt Meta Type

Overall could live with it as is, but any enhancements would be nice.

Address structure is normally:

  • Admin 0 - Country - ISO 3166-1
  • Admin 1 - State / Province / UK County - ISO 3166-2
  • Admin 2 - County / District
  • Admin 3 - Extra if needed
  • Locality / City / Town
  • Suburb / Neighbourhood
  • Street Name
  • House Number

Standards:

class Q_LOCATION_EXPORT QGeoAddress { public:

   QGeoAddress();
   QGeoAddress(const QGeoAddress &other);
   ~QGeoAddress();
   QGeoAddress &operator=(const QGeoAddress &other);
   bool operator==(const QGeoAddress &other) const;
   bool operator!=(const QGeoAddress &other) const {
       return !(other == *this);
   }
   QString country() const;
   void setCountry(const QString &country);
   QString countryCode() const;
   void setCountryCode(const QString &countryCode);
   QString state() const;
   void setState(const QString &state);
   QString county() const;
   void setCounty(const QString &county);
   QString city() const;
   void setCity(const QString &city);
   QString district() const;
   void setDistrict(const QString &district);
   QString street() const;
   void setStreet(const QString &street);
   QString postcode() const;
   void setPostcode(const QString &postcode);
   bool isEmpty() const;
   void clear();

private:

   QSharedDataPointer<QGeoAddressPrivate> d;

};

Google Geocoding format: <GeocodeResponse>

<status>OK</status> 
<result> 
 <type>street_address</type> 
 <formatted_address>1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA</formatted_address> 
 <address_component> 
  <long_name>1600</long_name> 
  <short_name>1600</short_name> 
  <type>street_number</type> 
 </address_component> 
 <address_component> 
  <long_name>Amphitheatre Pkwy</long_name> 
  <short_name>Amphitheatre Pkwy</short_name> 
  <type>route</type> 
 </address_component> 
 <address_component> 
  <long_name>Mountain View</long_name> 
  <short_name>Mountain View</short_name> 
  <type>locality</type> 
  <type>political</type> 
 </address_component> 
 <address_component> 
  <long_name>San Jose</long_name> 
  <short_name>San Jose</short_name> 
  <type>administrative_area_level_3</type> 
  <type>political</type> 
 </address_component> 
 <address_component> 
  <long_name>Santa Clara</long_name> 
  <short_name>Santa Clara</short_name> 
  <type>administrative_area_level_2</type> 
  <type>political</type> 
 </address_component> 
 <address_component> 
  <long_name>California</long_name> 
  <short_name>CA</short_name> 
  <type>administrative_area_level_1</type> 
  <type>political</type> 
 </address_component> 
 <address_component> 
  <long_name>United States</long_name> 
  <short_name>US</short_name> 
  <type>country</type> 
  <type>political</type> 
 </address_component> 
 <address_component> 
  <long_name>94043</long_name> 
  <short_name>94043</short_name> 
  <type>postal_code</type> 
 </address_component> 
 <geometry> 
  <location> 
   <lat>37.4217550</lat> 
   <lng>-122.0846330</lng> 
  </location> 
  <location_type>ROOFTOP</location_type> 
  <viewport> 
   <southwest> 
    <lat>37.4188514</lat> 
    <lng>-122.0874526</lng> 
   </southwest> 
   <northeast> 
    <lat>37.4251466</lat> 
    <lng>-122.0811574</lng> 
   </northeast> 
  </viewport> 
 </geometry> 
</result> 

</GeocodeResponse>