diff --git a/gpxsee.pro b/gpxsee.pro index 02ac5358..1e920604 100644 --- a/gpxsee.pro +++ b/gpxsee.pro @@ -141,7 +141,8 @@ HEADERS += src/config.h \ src/data/locparser.h \ src/data/slfparser.h \ src/map/geotiffmap.h \ - src/map/image.h + src/map/image.h \ + src/common/greatcircle.h SOURCES += src/main.cpp \ src/common/coordinates.cpp \ src/common/rectc.cpp \ @@ -246,7 +247,8 @@ SOURCES += src/main.cpp \ src/data/locparser.cpp \ src/data/slfparser.cpp \ src/map/geotiffmap.cpp \ - src/map/image.cpp + src/map/image.cpp \ + src/common/greatcircle.cpp RESOURCES += gpxsee.qrc TRANSLATIONS = lang/gpxsee_cs.ts \ diff --git a/src/GUI/pathitem.cpp b/src/GUI/pathitem.cpp index a527791d..39dee9f2 100644 --- a/src/GUI/pathitem.cpp +++ b/src/GUI/pathitem.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "common/greatcircle.h" #include "map/map.h" #include "tooltip.h" #include "nicenum.h" @@ -44,8 +45,27 @@ void PathItem::updatePainterPath(Map *map) _painterPath = QPainterPath(); _painterPath.moveTo(map->ll2xy(_path.first().coordinates())); - for (int i = 1; i < _path.size(); i++) - _painterPath.lineTo(map->ll2xy(_path.at(i).coordinates())); + for (int i = 1; i < _path.size(); i++) { + Coordinates c1(_path.at(i-1).coordinates()); + Coordinates c2(_path.at(i).coordinates()); + unsigned n = qAbs(c1.lon() - c2.lon()); + + if (n) { + if (n > 180) + n = n - 180; + double prev = c1.lon(); + for (unsigned j = 1; j <= n * 60; j++) { + Coordinates c(GreatCircle::pointAt(c1, c2, j/(n * 60.0))); + double current = c.lon(); + if (fabs(current - prev) > 180.0) + _painterPath.moveTo(map->ll2xy(c)); + else + _painterPath.lineTo(map->ll2xy(c)); + prev = current; + } + } else + _painterPath.lineTo(map->ll2xy(c2)); + } } void PathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, @@ -141,19 +161,23 @@ QPointF PathItem::position(qreal x) const return _map->ll2xy(_path.at(mid).coordinates()); } - QLineF l; + Coordinates c1, c2; qreal p1, p2; + if (_path.at(mid).distance() < x) { - l = QLineF(_map->ll2xy(_path.at(mid).coordinates()), - _map->ll2xy(_path.at(mid+1).coordinates())); + c1 = _path.at(mid).coordinates(); c2 = _path.at(mid+1).coordinates(); p1 = _path.at(mid).distance(); p2 = _path.at(mid+1).distance(); } else { - l = QLineF(_map->ll2xy(_path.at(mid-1).coordinates()), - _map->ll2xy(_path.at(mid).coordinates())); + c1 = _path.at(mid-1).coordinates(); c2 = _path.at(mid).coordinates(); p1 = _path.at(mid-1).distance(); p2 = _path.at(mid).distance(); } - return l.pointAt((x - p1) / (p2 - p1)); + if ((unsigned)qAbs(c1.lon() - c2.lon())) + return _map->ll2xy(GreatCircle::pointAt(c1, c2, (x - p1) / (p2 - p1))); + else { + QLineF l(_map->ll2xy(c1), _map->ll2xy(c2)); + return l.pointAt((x - p1) / (p2 - p1)); + } } void PathItem::moveMarker(qreal distance) diff --git a/src/common/greatcircle.cpp b/src/common/greatcircle.cpp new file mode 100644 index 00000000..dda5a6e2 --- /dev/null +++ b/src/common/greatcircle.cpp @@ -0,0 +1,23 @@ +#include "greatcircle.h" + +Coordinates GreatCircle::pointAt(const Coordinates &c1, const Coordinates &c2, + double f) +{ + double lat1 = deg2rad(c1.lat()); + double lon1 = deg2rad(c1.lon()); + double lat2 = deg2rad(c2.lat()); + double lon2 = deg2rad(c2.lon()); + + double cosLat1 = cos(lat1); + double cosLat2 = cos(lat2); + double d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cosLat1 + * cosLat2 * pow(sin((lon1 - lon2) / 2), 2))); + double sinD = sin(d); + double A = sin((1.0-f)*d) / sinD; + double B = sin(f*d) / sinD; + double x = A * cosLat1 * cos(lon1) + B * cosLat2 * cos(lon2); + double y = A * cosLat1 * sin(lon1) + B * cosLat2 * sin(lon2); + double z = A * sin(lat1) + B * sin(lat2); + + return Coordinates(rad2deg(atan2(y, x)), rad2deg(atan2(z, sqrt(x*x + y*y)))); +} diff --git a/src/common/greatcircle.h b/src/common/greatcircle.h new file mode 100644 index 00000000..e71b3fa1 --- /dev/null +++ b/src/common/greatcircle.h @@ -0,0 +1,11 @@ +#ifndef GREATCIRCLE_H +#define GREATCIRCLE_H + +#include "coordinates.h" + +namespace GreatCircle +{ + Coordinates pointAt(const Coordinates &c1, const Coordinates &c2, double f); +} + +#endif // GREATCIRCLE_H diff --git a/src/data/poi.cpp b/src/data/poi.cpp index 5ccb7c88..2896bc29 100644 --- a/src/data/poi.cpp +++ b/src/data/poi.cpp @@ -1,6 +1,7 @@ #include #include #include "common/rectc.h" +#include "common/greatcircle.h" #include "data.h" #include "poi.h" @@ -94,28 +95,6 @@ static bool cb(size_t data, void* context) return true; } -static Coordinates intermediate(const Coordinates &c1, const Coordinates &c2, - double f) -{ - double lat1 = deg2rad(c1.lat()); - double lon1 = deg2rad(c1.lon()); - double lat2 = deg2rad(c2.lat()); - double lon2 = deg2rad(c2.lon()); - - double cosLat1 = cos(lat1); - double cosLat2 = cos(lat2); - double d = 2 * asin(sqrt(pow((sin((lat1 - lat2) / 2)), 2) + cosLat1 - * cosLat2 * pow(sin((lon1 - lon2) / 2), 2))); - double sinD = sin(d); - double A = sin((1.0-f)*d) / sinD; - double B = sin(f*d) / sinD; - double x = A * cosLat1 * cos(lon1) + B * cosLat2 * cos(lon2); - double y = A * cosLat1 * sin(lon1) + B * cosLat2 * sin(lon2); - double z = A * sin(lat1) + B * sin(lat2); - - return Coordinates(rad2deg(atan2(y, x)), rad2deg(atan2(z, sqrt(x*x + y*y)))); -} - QList POI::points(const Path &path) const { QList ret; @@ -128,8 +107,8 @@ QList POI::points(const Path &path) const double ds = path.at(i).distance() - path.at(i-1).distance(); unsigned n = (unsigned)ceil(ds / _radius); for (unsigned j = 0; j < n; j++) { - RectC br(n > 1 ? intermediate(path.at(i-1).coordinates(), - path.at(i).coordinates(), (double)j/(double)n) + RectC br(n > 1 ? GreatCircle::pointAt(path.at(i-1).coordinates(), + path.at(i).coordinates(), (double)j/n) : path.at(i-1).coordinates(), _radius); min[0] = br.topLeft().lon();