1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2025-01-18 19:52:09 +01:00
GPXSee/src/common/rectc.cpp
Martin Tůma 547d7a5f23 Fix the POI search algorithm
(At least so, that it does not trigger the rtree assert. The whole RectC logic
has to be fixed to properly handle poles/dateline "overflows")
2020-12-03 21:12:41 +01:00

179 lines
3.5 KiB
C++

#include <cmath>
#include "wgs84.h"
#include "rectc.h"
#define MIN_LAT deg2rad(-90.0)
#define MAX_LAT deg2rad(90.0)
#define MIN_LON deg2rad(-180.0)
#define MAX_LON deg2rad(180.0)
static inline double WLON(double lon)
{
return remainder(lon, 360.0);
}
static inline double LLAT(double lat)
{
return (lat < 0.0) ? qMax(lat, -90.0) : qMin(lat, 90.0);
}
RectC::RectC(const Coordinates &center, double radius)
{
double radDist = radius / WGS84_RADIUS;
double radLon = deg2rad(center.lon());
double radlat = deg2rad(center.lat());
double minLat = radlat - radDist;
double maxLat = radlat + radDist;
double minLon, maxLon;
if (minLat > MIN_LAT && maxLat < MAX_LAT) {
double deltaLon = asin(sin(radDist) / cos(radlat));
minLon = radLon - deltaLon;
if (minLon < MIN_LON)
minLon += 2 * M_PI;
maxLon = radLon + deltaLon;
if (maxLon > MAX_LON)
maxLon -= 2 * M_PI;
} else {
// a pole is within the distance
minLat = qMax(minLat, MIN_LAT);
maxLat = qMin(maxLat, MAX_LAT);
minLon = MIN_LON;
maxLon = MAX_LON;
}
_tl = Coordinates(rad2deg(minLon), rad2deg(maxLat));
_br = Coordinates(rad2deg(maxLon), rad2deg(minLat));
}
RectC RectC::operator|(const RectC &r) const
{
if (isNull())
return r;
if (r.isNull())
return *this;
double l1 = _tl.lon();
double r1 = _tl.lon();
if (_br.lon() < _tl.lon())
l1 = _br.lon();
else
r1 = _br.lon();
double l2 = r._tl.lon();
double r2 = r._tl.lon();
if (r._br.lon() < r._tl.lon())
l2 = r._br.lon();
else
r2 = r._br.lon();
double t1 = _tl.lat();
double b1 = _tl.lat();
if (_br.lat() > _tl.lat())
t1 = _br.lat();
else
b1 = _br.lat();
double t2 = r._tl.lat();
double b2 = r._tl.lat();
if (r._br.lat() > r._tl.lat())
t2 = r._br.lat();
else
b2 = r._br.lat();
return RectC(Coordinates(qMin(l1, l2), qMax(t1, t2)),
Coordinates(qMax(r1, r2), qMin(b1, b2)));
}
RectC RectC::operator&(const RectC &r) const
{
if (isNull() || r.isNull())
return RectC();
double l1 = _tl.lon();
double r1 = _tl.lon();
if (_br.lon() < _tl.lon())
l1 = _br.lon();
else
r1 = _br.lon();
double l2 = r._tl.lon();
double r2 = r._tl.lon();
if (r._br.lon() < r._tl.lon())
l2 = r._br.lon();
else
r2 = r._br.lon();
if (l1 > r2 || l2 > r1)
return RectC();
double t1 = _tl.lat();
double b1 = _tl.lat();
if (_br.lat() > _tl.lat())
t1 = _br.lat();
else
b1 = _br.lat();
double t2 = r._tl.lat();
double b2 = r._tl.lat();
if (r._br.lat() > r._tl.lat())
t2 = r._br.lat();
else
b2 = r._br.lat();
if (b1 > t2 || b2 > t1)
return RectC();
return RectC(Coordinates(qMax(l1, l2), qMin(t1, t2)),
Coordinates(qMin(r1, r2), qMax(b1, b2)));
}
RectC RectC::united(const Coordinates &c) const
{
if (c.isNull())
return *this;
if (isNull())
return RectC(c, c);
double l = _tl.lon();
double r = _tl.lon();
if (_br.lon() < _tl.lon())
l = _br.lon();
else
r = _br.lon();
double t = _tl.lat();
double b = _tl.lat();
if (_br.lat() > _tl.lat())
t = _br.lat();
else
b = _br.lat();
if (c.lon() < l)
l = c.lon();
if (c.lon() > r)
r = c.lon();
if (c.lat() < b)
b = c.lat();
if (c.lat() > t)
t = c.lat();
return RectC(Coordinates(l, t), Coordinates(r, b));
}
RectC RectC::adjusted(double lon1, double lat1, double lon2, double lat2) const
{
return RectC(Coordinates(WLON(_tl.lon() + lon1), LLAT(_tl.lat() + lat1)),
Coordinates(WLON(_br.lon() + lon2), LLAT(_br.lat() + lat2)));
}
#ifndef QT_NO_DEBUG
QDebug operator<<(QDebug dbg, const RectC &rect)
{
dbg.nospace() << "RectC(" << rect.topLeft() << ", " << rect.bottomRight()
<< ")";
return dbg.space();
}
#endif // QT_NO_DEBUG