Details
Description
The bug is that QGeoTiledMapData::coordinateToScreenPosition uses wrong map projection algorithm.
It should use the customizable algorithm function:
QPoint QGeoTiledMapData::coordinateToWorldReferencePosition(const QGeoCoordinate &coordinate) const
Instead it uses always the default Mercator Spherical algorithm provided in:
QPoint QGeoTiledMapDataPrivate::coordinateToWorldReferencePosition(double lng, double lat) const
Here's the default implementation of:
QPointF QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordwgs) const
180 QPointF QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordwgs) const 181 { 182 Q_D(const QGeoTiledMapData); 183 return d->coordinateToScreenPosition(coordwgs.longitude(), coordwgs.latitude()); 184 }
As can be seen this directly just calls the private implementation in QGeoTiledMapDataPrivate::coordinateToScreenPosition():
159 QPointF QGeoTiledMapDataPrivate::coordinateToScreenPosition(double lon, double lat) const 160 { 161 QPointF offset = windowOffset(); 162 163 QPoint pos(coordinateToWorldReferencePosition(lon, lat)); 164 165 const int x = pos.x() - worldReferenceViewportRect.left(); 166 // if (x < 0) 167 // x += worldReferenceSize.width(); 168 169 const int y = pos.y() - worldReferenceViewportRect.top(); 170 171 QPointF posF(offset.x() + qreal(x) / zoomFactor, offset.y() + qreal(y) / zoomFactor); 172 173 return posF; 174 }
The map projection is implemented in QGeoTiledMapDataPrivate::coordinateToWorldReferencePosition(), which is a private implementation that can not be customized:
220 QPoint QGeoTiledMapDataPrivate::coordinateToWorldReferencePosition(double lng, double lat) const 221 { 222 lng = lng / 360.0 + 0.5; 223 224 lat = 0.5 - (log(tan((PI / 4.0) + (PI / 2.0) * lat / 180.0)) / PI) / 2.0; 225 lat = qMax(0.0, lat); 226 lat = qMin(1.0, lat); 227 228 const double x = lng * worldReferenceSize.width(); 229 const double y = lat * worldReferenceSize.height(); 230 231 const QPoint r(int(x > 0 ? x + 0.5 : x - 0.5), 232 int(y > 0 ? y + 0.5 : y - 0.5)); 233 return r; 234 }
As you can see, the implementation never calls the customizable function:
QPoint QGeoTiledMapData::coordinateToWorldReferencePosition(const QGeoCoordinate &coordinate) const
Easy workaround candidate is to override the function coordinateToScreenPosition() in custom tile map plugin:
QPointF QGeoTiledMapData::coordinateToScreenPosition(const QGeoCoordinate &coordwgs) const
However this does not help since the default tile map plugin implementation uses the wrong coordinateToScreenPosition() function that can not be overridden by custom map plugin implementers (since it is in the private implementation):
QPointF QGeoMapDataPrivate::coordinateToScreenPosition(double lon, double lat) const
This private function is directly used e.g. from the QGeoMapObjectEngine class so fixing of this bug into Qt Mobility is very important.
Otherwise no 3rd party developer can utilize different map projections by customizing the tiled map base implementation!