1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-06 14:53:21 +02:00

Provide propper map bounds for overviews

This commit is contained in:
Martin Tůma 2020-12-13 19:40:09 +01:00
parent 4cef089c81
commit 239e571358
13 changed files with 228 additions and 75 deletions

View File

@ -1,3 +1,4 @@
#include <cmath>
#include <QCursor> #include <QCursor>
#include <QPainter> #include <QPainter>
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
@ -8,6 +9,66 @@
#include "mapitem.h" #include "mapitem.h"
static void growLeft(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.x() < rect.left())
rect.setLeft(p.x());
}
static void growRight(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.x() > rect.right())
rect.setRight(p.x());
}
static void growTop(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.y() > rect.top())
rect.setTop(p.y());
}
static void growBottom(Map *map, const Coordinates &c, QRectF &rect)
{
QPointF p(map->ll2xy(c));
if (p.y() < rect.bottom())
rect.setBottom(p.y());
}
static QRectF bbox(const RectC &rect, Map *map, int samples = 100)
{
if (!rect.isValid())
return QRectF();
double dx = rect.width() / samples;
double dy = rect.height() / samples;
QPointF tl(map->ll2xy(rect.topLeft()));
QPointF br(map->ll2xy(rect.bottomRight()));
QRectF prect(tl, br);
for (int i = 0; i <= samples; i++) {
double x = remainder(rect.left() + i * dx, 360.0);
growTop(map, Coordinates(x, rect.bottom()), prect);
growBottom(map, Coordinates(x, rect.top()), prect);
}
for (int i = 0; i <= samples; i++) {
double y = rect.bottom() + i * dy;
growLeft(map, Coordinates(rect.left(), y), prect);
growRight(map, Coordinates(rect.right(), y), prect);
}
return prect;
}
QString MapItem::info() const QString MapItem::info() const
{ {
ToolTip tt; ToolTip tt;
@ -28,8 +89,9 @@ MapItem::MapItem(MapAction *action, Map *map, GraphicsItem *parent)
_name = src->name(); _name = src->name();
_fileName = src->path(); _fileName = src->path();
_bounds = RectC(src->xy2ll(src->bounds().topLeft()), // Zoom to the maximal zoom level to get the most accurate bounds
src->xy2ll(src->bounds().bottomRight())); src->zoomFit(QSize(), RectC());
_bounds = src->llBounds();
connect(this, SIGNAL(triggered()), action, SLOT(trigger())); connect(this, SIGNAL(triggered()), action, SLOT(trigger()));
@ -51,23 +113,18 @@ void MapItem::updatePainterPath()
{ {
_painterPath = QPainterPath(); _painterPath = QPainterPath();
if (_bounds.left() > _bounds.right()) { QRectF r(bbox(_bounds, _map));
QRectF r1(_map->ll2xy(_bounds.topLeft()), _map->ll2xy(Coordinates(180,
_bounds.bottomRight().lat())));
QRectF r2(_map->ll2xy(Coordinates(-180, _bounds.topLeft().lat())),
_map->ll2xy(_bounds.bottomRight()));
QRectF r(_map->ll2xy(_bounds.topLeft()),
_map->ll2xy(_bounds.bottomRight()));
if (r1.united(r2) == r) if (r.left() > r.right()) {
_painterPath.addRect(r); QRectF r1(bbox(RectC(_bounds.topLeft(),
else { Coordinates(180, _bounds.bottomRight().lat())), _map));
_painterPath.addRect(r1); QRectF r2(bbox(RectC(Coordinates(-180, _bounds.topLeft().lat()),
_painterPath.addRect(r2); _bounds.bottomRight()), _map));
}
_painterPath.addRect(r1);
_painterPath.addRect(r2);
} else } else
_painterPath.addRect(QRectF(_map->ll2xy(_bounds.topLeft()), _painterPath.addRect(r);
_map->ll2xy(_bounds.bottomRight())));
} }
void MapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, void MapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,

View File

@ -294,8 +294,7 @@ int MapView::fitMapZoom() const
RectC br = _tr | _rr | _wr | _ar; RectC br = _tr | _rr | _wr | _ar;
return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN), return _map->zoomFit(viewport()->size() - QSize(2*MARGIN, 2*MARGIN),
br.isNull() ? RectC(_map->xy2ll(_map->bounds().topLeft()), br.isNull() ? _map->llBounds() : br);
_map->xy2ll(_map->bounds().bottomRight())) : br);
} }
QPointF MapView::contentCenter() const QPointF MapView::contentCenter() const

View File

@ -1,7 +1,6 @@
#include <QtGlobal> #include <QtGlobal>
#include <QPainter> #include <QPainter>
#include "common/rectc.h" #include "common/rectc.h"
#include "osm.h"
#include "emptymap.h" #include "emptymap.h"

View File

@ -1,6 +1,7 @@
#ifndef EMPTYMAP_H #ifndef EMPTYMAP_H
#define EMPTYMAP_H #define EMPTYMAP_H
#include "osm.h"
#include "map.h" #include "map.h"
class EmptyMap : public Map class EmptyMap : public Map
@ -13,6 +14,7 @@ public:
QString name() const {return QString();} QString name() const {return QString();}
QRectF bounds(); QRectF bounds();
RectC llBounds() {return OSM::BOUNDS;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}

View File

@ -18,6 +18,7 @@ public:
QString name() const {return _data.first()->name();} QString name() const {return _data.first()->name();}
QRectF bounds() {return _bounds;} QRectF bounds() {return _bounds;}
RectC llBounds() {return _dataBounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);

View File

@ -20,6 +20,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds() {return _bounds;}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom) {_zoom = zoom;} void setZoom(int zoom) {_zoom = zoom;}

View File

@ -1,6 +1,67 @@
#include <cmath>
#include <QLineF> #include <QLineF>
#include "map.h" #include "map.h"
#define SAMPLES 100
void Map::growLeft(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lon() < rect.left())
rect.setLeft(c.lon());
}
void Map::growRight(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lon() > rect.right())
rect.setRight(c.lon());
}
void Map::growTop(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lat() > rect.top())
rect.setTop(c.lat());
}
void Map::growBottom(const QPointF &p, RectC &rect)
{
Coordinates c(xy2ll(p));
if (c.lat() < rect.bottom())
rect.setBottom(c.lat());
}
RectC Map::llBounds()
{
QRectF b(bounds());
double dx = b.width() / SAMPLES;
double dy = b.height() / SAMPLES;
Coordinates tl(xy2ll(b.topLeft()));
Coordinates br(xy2ll(b.bottomRight()));
RectC rect(tl, br);
for (int i = 0; i <= SAMPLES; i++) {
double x = b.left() + i * dx;
growBottom(QPointF(x, b.bottom()), rect);
growTop(QPointF(x, b.top()), rect);
}
for (int i = 0; i <= SAMPLES; i++) {
double y = b.top() + i * dy;
growLeft(QPointF(b.left(), y), rect);
growRight(QPointF(b.right(), y), rect);
}
return rect;
}
qreal Map::resolution(const QRectF &rect) qreal Map::resolution(const QRectF &rect)
{ {
qreal cy = rect.center().y(); qreal cy = rect.center().y();

View File

@ -5,11 +5,10 @@
#include <QString> #include <QString>
#include <QRectF> #include <QRectF>
#include <QFlags> #include <QFlags>
#include "common/coordinates.h" #include "common/rectc.h"
class QPainter; class QPainter;
class RectC;
class Projection; class Projection;
class Map : public QObject class Map : public QObject
@ -31,6 +30,7 @@ public:
const QString &path() const {return _path;} const QString &path() const {return _path;}
virtual QString name() const = 0; virtual QString name() const = 0;
virtual RectC llBounds();
virtual QRectF bounds() = 0; virtual QRectF bounds() = 0;
virtual qreal resolution(const QRectF &rect); virtual qreal resolution(const QRectF &rect);
@ -60,6 +60,11 @@ signals:
void mapLoaded(); void mapLoaded();
private: private:
void growLeft(const QPointF &p, RectC &rect);
void growRight(const QPointF &p, RectC &rect);
void growTop(const QPointF &p, RectC &rect);
void growBottom(const QPointF &p, RectC &rect);
QString _path; QString _path;
}; };

View File

@ -14,6 +14,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}

View File

@ -19,6 +19,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds() {return _bounds;}
qreal resolution(const QRectF &rect); qreal resolution(const QRectF &rect);
int zoom() const {return _zoom;} int zoom() const {return _zoom;}

View File

@ -4,69 +4,92 @@
#include "rectd.h" #include "rectd.h"
static void growRect(const Projection &proj, const Coordinates &c, RectD &rect) static void growLeft(const Projection &proj, const Coordinates &c, RectD &rect)
{ {
if (c.isNull())
return;
PointD p(proj.ll2xy(c)); PointD p(proj.ll2xy(c));
if (rect.isNull()) if (p.x() < rect.left())
rect = RectD(p, p); rect.setLeft(p.x());
else {
if (p.x() < rect.left())
rect.setLeft(p.x());
if (p.x() > rect.right())
rect.setRight(p.x());
if (p.y() < rect.bottom())
rect.setBottom(p.y());
if (p.y() > rect.top())
rect.setTop(p.y());
}
} }
static void growRect(const Projection &proj, const PointD &p, RectC &rect) static void growRight(const Projection &proj, const Coordinates &c, RectD &rect)
{ {
if (p.isNull()) PointD p(proj.ll2xy(c));
return;
if (p.x() > rect.right())
rect.setRight(p.x());
}
static void growTop(const Projection &proj, const Coordinates &c, RectD &rect)
{
PointD p(proj.ll2xy(c));
if (p.y() > rect.top())
rect.setTop(p.y());
}
static void growBottom(const Projection &proj, const Coordinates &c, RectD &rect)
{
PointD p(proj.ll2xy(c));
if (p.y() < rect.bottom())
rect.setBottom(p.y());
}
static void growLeft(const Projection &proj, const PointD &p, RectC &rect)
{
Coordinates c(proj.xy2ll(p)); Coordinates c(proj.xy2ll(p));
if (rect.isNull()) if (c.lon() < rect.left())
rect = RectC(c, c); rect.setLeft(c.lon());
else { }
if (c.lon() < rect.left())
rect.setLeft(c.lon()); static void growRight(const Projection &proj, const PointD &p, RectC &rect)
if (c.lon() > rect.right()) {
rect.setRight(c.lon()); Coordinates c(proj.xy2ll(p));
if (c.lat() < rect.bottom())
rect.setBottom(c.lat()); if (c.lon() > rect.right())
if (c.lat() > rect.top()) rect.setRight(c.lon());
rect.setTop(c.lat()); }
}
static void growTop(const Projection &proj, const PointD &p, RectC &rect)
{
Coordinates c(proj.xy2ll(p));
if (c.lat() > rect.top())
rect.setTop(c.lat());
}
static void growBottom(const Projection &proj, const PointD &p, RectC &rect)
{
Coordinates c(proj.xy2ll(p));
if (c.lat() < rect.bottom())
rect.setBottom(c.lat());
} }
RectD::RectD(const RectC &rect, const Projection &proj, int samples) RectD::RectD(const RectC &rect, const Projection &proj, int samples)
{ {
RectD prect; if (!rect.isValid())
return;
if (rect.isValid()) { double dx = rect.width() / samples;
double dx = rect.width() / samples; double dy = rect.height() / samples;
double dy = rect.height() / samples;
growRect(proj, rect.topLeft(), prect); PointD tl(proj.ll2xy(rect.topLeft()));
PointD br(proj.ll2xy(rect.bottomRight()));
RectD prect(tl, br);
for (int i = 0; i <= samples; i++) { for (int i = 0; i <= samples; i++) {
double x = remainder(rect.left() + i * dx, 360.0); double x = remainder(rect.left() + i * dx, 360.0);
growRect(proj, Coordinates(x, rect.bottom()), prect); growBottom(proj, Coordinates(x, rect.bottom()), prect);
growRect(proj, Coordinates(x, rect.top()), prect); growTop(proj, Coordinates(x, rect.top()), prect);
} }
for (int i = 0; i <= samples; i++ ) { for (int i = 0; i <= samples; i++) {
double y = rect.bottom() + i * dy; double y = rect.bottom() + i * dy;
growRect(proj, Coordinates(rect.left(), y), prect); growLeft(proj, Coordinates(rect.left(), y), prect);
growRect(proj, Coordinates(rect.right(), y), prect); growRight(proj, Coordinates(rect.right(), y), prect);
}
} }
*this = prect; *this = prect;
@ -77,22 +100,23 @@ RectC RectD::toRectC(const Projection &proj, int samples) const
if (!isValid()) if (!isValid())
return RectC(); return RectC();
RectC rect;
double dx = width() / samples; double dx = width() / samples;
double dy = height() / samples; double dy = height() / samples;
growRect(proj, topLeft(), rect); Coordinates tl(proj.xy2ll(topLeft()));
Coordinates br(proj.xy2ll(bottomRight()));
RectC rect(tl, br);
for (int i = 0; i <= samples; i++) { for (int i = 0; i <= samples; i++) {
double x = left() + i * dx; double x = left() + i * dx;
growRect(proj, PointD(x, bottom()), rect); growBottom(proj, PointD(x, bottom()), rect);
growRect(proj, PointD(x, top()), rect); growTop(proj, PointD(x, top()), rect);
} }
for (int i = 0; i <= samples; i++ ) { for (int i = 0; i <= samples; i++) {
double y = bottom() + i * dy; double y = bottom() + i * dy;
growRect(proj, PointD(left(), y), rect); growLeft(proj, PointD(left(), y), rect);
growRect(proj, PointD(right(), y), rect); growRight(proj, PointD(right(), y), rect);
} }
return rect; return rect;

View File

@ -20,6 +20,7 @@ public:
QString name() const {return _name;} QString name() const {return _name;}
QRectF bounds(); QRectF bounds();
RectC llBounds() {return _wms->bbox();}
int zoom() const {return _zoom;} int zoom() const {return _zoom;}
void setZoom(int zoom); void setZoom(int zoom);

View File

@ -85,6 +85,7 @@ QRectF WMTSMap::bounds()
bounds = QRectF(_transform.proj2img(_bounds.topLeft()) bounds = QRectF(_transform.proj2img(_bounds.topLeft())
/ coordinatesRatio(), _transform.proj2img( / coordinatesRatio(), _transform.proj2img(
_bounds.bottomRight()) / coordinatesRatio()); _bounds.bottomRight()) / coordinatesRatio());
return bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds; return bounds.isValid() ? tileBounds.intersected(bounds) : tileBounds;
} }