1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 07:13:21 +02:00
GPXSee/src/map/imgmap.cpp

223 lines
5.5 KiB
C++
Raw Normal View History

2019-05-10 18:56:19 +02:00
#include <QFile>
#include <QPainter>
#include <QPixmapCache>
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include <QtCore>
#else // QT_VERSION < 5
#include <QtConcurrent>
#endif // QT_VERSION < 5
#include "common/rectc.h"
2020-01-19 17:05:26 +01:00
#include "common/range.h"
2020-04-26 01:17:54 +02:00
#include "common/wgs84.h"
2020-02-09 23:24:48 +01:00
#include "IMG/img.h"
#include "IMG/gmap.h"
2020-04-26 01:17:54 +02:00
#include "IMG/rastertile.h"
#include "osm.h"
2019-05-10 18:56:19 +02:00
#include "pcs.h"
#include "rectd.h"
#include "imgmap.h"
2019-10-05 12:41:42 +02:00
#define TILE_SIZE 384
#define TEXT_EXTENT 160
2019-05-10 18:56:19 +02:00
2020-04-26 15:46:42 +02:00
static QList<MapData*> overlays(const QString &fileName)
{
QList<MapData*> list;
for (int i = 1; i < 32; i++) {
2020-04-26 15:46:42 +02:00
QString ol(fileName + "." + QString::number(i));
if (QFileInfo(ol).isFile()) {
MapData *data = new IMG(ol);
if (data->isValid())
list.append(data);
else {
qWarning("%s: %s", qPrintable(data->fileName()),
qPrintable(data->errorString()));
delete data;
}
} else
break;
}
return list;
}
2019-05-10 18:56:19 +02:00
IMGMap::IMGMap(const QString &fileName, QObject *parent)
2020-12-02 23:58:11 +01:00
: Map(fileName, parent), _projection(PCS::pcs(3857)), _valid(false)
2019-05-10 18:56:19 +02:00
{
2020-02-09 23:24:48 +01:00
if (GMAP::isGMAP(fileName))
2020-04-26 15:46:42 +02:00
_data.append(new GMAP(fileName));
else {
_data.append(new IMG(fileName));
_data.append(overlays(fileName));
}
2020-02-09 23:24:48 +01:00
2020-04-26 15:46:42 +02:00
if (!_data.first()->isValid()) {
_errorString = _data.first()->errorString();
2019-05-10 18:56:19 +02:00
return;
}
2020-04-26 15:46:42 +02:00
_dataBounds = _data.first()->bounds() & OSM::BOUNDS;
_zoom = _data.first()->zooms().min();
2019-05-10 18:56:19 +02:00
updateTransform();
_valid = true;
}
2019-07-04 18:18:03 +02:00
void IMGMap::load()
{
2020-04-26 15:46:42 +02:00
for (int i = 0; i < _data.size(); i++)
_data.at(i)->load();
2019-07-04 18:18:03 +02:00
}
void IMGMap::unload()
{
2020-04-26 15:46:42 +02:00
for (int i = 0; i < _data.size(); i++)
_data.at(i)->clear();
2019-07-04 18:18:03 +02:00
}
2019-05-10 18:56:19 +02:00
int IMGMap::zoomFit(const QSize &size, const RectC &rect)
{
2020-04-26 15:46:42 +02:00
const Range &zooms = _data.first()->zooms();
2019-05-10 18:56:19 +02:00
if (rect.isValid()) {
2019-05-29 18:27:11 +02:00
RectD pr(rect, _projection, 10);
2019-05-10 18:56:19 +02:00
2020-04-26 15:46:42 +02:00
_zoom = zooms.min();
for (int i = zooms.min() + 1; i <= zooms.max(); i++) {
2019-05-29 18:27:11 +02:00
Transform t(transform(i));
QRectF r(t.proj2img(pr.topLeft()), t.proj2img(pr.bottomRight()));
if (size.width() < r.width() || size.height() < r.height())
2019-05-10 18:56:19 +02:00
break;
_zoom = i;
}
} else
2020-04-26 15:46:42 +02:00
_zoom = zooms.max();
2019-05-10 18:56:19 +02:00
updateTransform();
return _zoom;
}
int IMGMap::zoomIn()
{
2020-04-26 15:46:42 +02:00
_zoom = qMin(_zoom + 1, _data.first()->zooms().max());
2019-05-10 18:56:19 +02:00
updateTransform();
return _zoom;
}
int IMGMap::zoomOut()
{
2020-04-26 15:46:42 +02:00
_zoom = qMax(_zoom - 1, _data.first()->zooms().min());
2019-05-10 18:56:19 +02:00
updateTransform();
return _zoom;
}
void IMGMap::setZoom(int zoom)
{
_zoom = zoom;
updateTransform();
}
2019-05-29 18:27:11 +02:00
Transform IMGMap::transform(int zoom) const
2019-05-10 18:56:19 +02:00
{
double scale = _projection.isGeographic()
? 360.0 / (1<<zoom) : (2.0 * M_PI * WGS84_RADIUS) / (1<<zoom);
PointD topLeft(_projection.ll2xy(_dataBounds.topLeft()));
2019-05-29 18:27:11 +02:00
return Transform(ReferencePoint(PointD(0, 0), topLeft),
2019-05-10 18:56:19 +02:00
PointD(scale, scale));
}
2019-05-29 18:27:11 +02:00
void IMGMap::updateTransform()
{
_transform = transform(_zoom);
2020-03-07 19:24:39 +01:00
RectD prect(_dataBounds, _projection);
2020-03-07 19:24:39 +01:00
_bounds = QRectF(_transform.proj2img(prect.topLeft()),
_transform.proj2img(prect.bottomRight()));
2020-10-27 16:46:09 +01:00
// Adjust the bounds of world maps to avoid problems with wrapping
if (_dataBounds.left() == -180.0 || _dataBounds.right() == 180.0)
_bounds.adjust(0.5, 0, -0.5, 0);
2019-05-29 18:27:11 +02:00
}
2019-05-10 18:56:19 +02:00
void IMGMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{
Q_UNUSED(flags);
QPointF tl(floor(rect.left() / TILE_SIZE)
* TILE_SIZE, floor(rect.top() / TILE_SIZE) * TILE_SIZE);
QSizeF s(rect.right() - tl.x(), rect.bottom() - tl.y());
int width = ceil(s.width() / TILE_SIZE);
int height = ceil(s.height() / TILE_SIZE);
QList<RasterTile> tiles;
2020-04-26 15:46:42 +02:00
for (int n = 0; n < _data.size(); n++) {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
QPixmap pm;
QPoint ttl(tl.x() + i * TILE_SIZE, tl.y() + j * TILE_SIZE);
QString key = _data.at(n)->fileName() + "-" + QString::number(_zoom)
+ "_" + QString::number(ttl.x()) + "_" + QString::number(ttl.y());
if (QPixmapCache::find(key, pm))
painter->drawPixmap(ttl, pm);
else {
QList<MapData::Poly> polygons, lines;
QList<MapData::Point> points;
QRectF polyRect(ttl, QPointF(ttl.x() + TILE_SIZE,
ttl.y() + TILE_SIZE));
2020-10-27 16:46:09 +01:00
polyRect &= bounds();
2020-04-26 15:46:42 +02:00
RectD polyRectD(_transform.img2proj(polyRect.topLeft()),
_transform.img2proj(polyRect.bottomRight()));
_data.at(n)->polys(polyRectD.toRectC(_projection, 4), _zoom,
&polygons, &lines);
QRectF pointRect(QPointF(ttl.x() - TEXT_EXTENT,
ttl.y() - TEXT_EXTENT), QPointF(ttl.x() + TILE_SIZE
+ TEXT_EXTENT, ttl.y() + TILE_SIZE + TEXT_EXTENT));
2020-10-27 16:46:09 +01:00
pointRect &= bounds();
2020-04-26 15:46:42 +02:00
RectD pointRectD(_transform.img2proj(pointRect.topLeft()),
_transform.img2proj(pointRect.bottomRight()));
_data.at(n)->points(pointRectD.toRectC(_projection, 4),
_zoom, &points);
tiles.append(RasterTile(this, _data.at(n)->style(), _zoom,
2020-04-26 15:46:42 +02:00
QRect(ttl, QSize(TILE_SIZE, TILE_SIZE)), key, polygons,
lines, points));
}
2019-05-10 18:56:19 +02:00
}
}
}
QFuture<void> future = QtConcurrent::map(tiles, &RasterTile::render);
2019-05-10 18:56:19 +02:00
future.waitForFinished();
for (int i = 0; i < tiles.size(); i++) {
RasterTile &mt = tiles[i];
QPixmap pm(QPixmap::fromImage(mt.img()));
if (pm.isNull())
continue;
QPixmapCache::insert(mt.key(), pm);
painter->drawPixmap(mt.xy(), pm);
}
}
void IMGMap::setProjection(const Projection &projection)
{
if (projection == _projection)
return;
_projection = projection;
// Limit the bounds for some well known Mercator projections
2020-10-27 16:46:09 +01:00
// (world maps have N/S bounds up to 90/-90!)
2020-04-26 15:46:42 +02:00
_dataBounds = (_projection == PCS::pcs(3857) || _projection == PCS::pcs(3395))
? _data.first()->bounds() & OSM::BOUNDS : _data.first()->bounds();
updateTransform();
QPixmapCache::clear();
}