1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-11-24 11:45:53 +01:00

Various KMZ map fixes

This commit is contained in:
Martin Tůma 2020-12-23 23:05:12 +01:00
parent 86dd6ed772
commit 07894f3a55
2 changed files with 86 additions and 64 deletions

View File

@ -1,12 +1,12 @@
/* /*
WARNING: This code uses internal Qt API - the QZipReader class for reading WARNING: This code uses internal Qt API - the QZipReader class for reading
ZIP files - and things may break if Qt changes the API. For Qt5 this is not ZIP files - and things may break if Qt changes the API. For Qt5 this is not
a problem as we can "see the feature" now and there are no changes in all a problem as we can "see the future" now and there are no changes in all
the supported Qt5 versions up to the last one (5.15). In Qt6 the class the supported Qt5 versions up to the last one (5.15). In Qt6 the class
might change or even disappear in the future, but this is very unlikely might change or even disappear in the future, but this is very unlikely
as there were no changes for several years and The Qt Company's politics as there were no changes for several years and The Qt Company's politics
is: "do not invest any resources into any desktop platform stuff unless is: "do not invest any resources into any desktop related stuff unless
absolutely necessary". There is an issue (QTBUG-3897) since year 2009 to absolutely necessary". There is an issue (QTBUG-3897) since the year 2009 to
include the ZIP reader into the public API, which aptly illustrates the include the ZIP reader into the public API, which aptly illustrates the
effort The Qt Company is willing to make about anything desktop related... effort The Qt Company is willing to make about anything desktop related...
*/ */
@ -25,24 +25,24 @@
#define ZOOM_THRESHOLD 0.9 #define ZOOM_THRESHOLD 0.9
#define TL(m) ((m).bbox.topLeft()) #define TL(m) ((m).bbox().topLeft())
#define BR(m) ((m).bbox.bottomRight()) #define BR(m) ((m).bbox().bottomRight())
const Projection &KMZMap::Overlay::projection()
{
static Projection p = Projection(PCS::pcs(3857));
return p;
}
KMZMap::Overlay::Overlay(const QString &path, const QSize &size, KMZMap::Overlay::Overlay(const QString &path, const QSize &size,
const RectC &bbox, double rotation) : path(path), size(size), bbox(bbox), const RectC &bbox, double rotation) : _path(path), _bbox(bbox),
rotation(rotation), img(0) _rotation(rotation), _img(0)
{ {
ReferencePoint tl(PointD(0, 0), projection().ll2xy(bbox.topLeft())); ReferencePoint tl(PointD(0, 0), PointD(bbox.left(), bbox.top()));
ReferencePoint br(PointD(size.width(), size.height()), ReferencePoint br(PointD(size.width(), size.height()),
projection().ll2xy(bbox.bottomRight())); PointD(bbox.right(), bbox.bottom()));
transform = Transform(tl, br); QTransform t;
t.rotate(-rotation);
QRectF b(0, 0, size.width(), size.height());
QPolygonF ma = t.map(b);
_bounds = ma.boundingRect();
_transform = Transform(tl, br);
} }
qreal KMZMap::Overlay::resolution(const QRectF &rect) const qreal KMZMap::Overlay::resolution(const QRectF &rect) const
@ -59,32 +59,34 @@ qreal KMZMap::Overlay::resolution(const QRectF &rect) const
void KMZMap::Overlay::draw(QPainter *painter, const QRectF &rect, Flags flags) void KMZMap::Overlay::draw(QPainter *painter, const QRectF &rect, Flags flags)
{ {
if (img) { if (_img) {
if (rotation) { if (_rotation) {
painter->save(); painter->save();
painter->rotate(-rotation); painter->rotate(-_rotation);
img->draw(painter, rect.adjusted(-10, -10, 10, 10), flags); _img->draw(painter, rect, flags);
painter->restore(); painter->restore();
} else } else
img->draw(painter, rect, flags); _img->draw(painter, rect, flags);
} }
//painter->setPen(Qt::red);
//painter->drawRect(_bounds);
} }
void KMZMap::Overlay::load(QZipReader *zip) void KMZMap::Overlay::load(QZipReader *zip)
{ {
if (!img) { if (!_img) {
QByteArray ba(zip->fileData(path)); QByteArray ba(zip->fileData(_path));
img = new Image(QImage::fromData(ba)); _img = new Image(QImage::fromData(ba));
} }
} }
void KMZMap::Overlay::unload() void KMZMap::Overlay::unload()
{ {
delete img; delete _img;
img = 0; _img = 0;
} }
bool KMZMap::resCmp(const Overlay &m1, const Overlay &m2) bool KMZMap::resCmp(const Overlay &m1, const Overlay &m2)
{ {
qreal r1, r2; qreal r1, r2;
@ -130,24 +132,30 @@ void KMZMap::computeBounds()
m.append(_maps.at(i)); m.append(_maps.at(i));
std::sort(m.begin(), m.end(), xCmp); std::sort(m.begin(), m.end(), xCmp);
offsets[_maps.indexOf(m.first())].setX(0); offsets[_maps.indexOf(m.first())].setX(m.first().bounds().left());
for (int i = 1; i < m.size(); i++) { for (int i = 1; i < m.size(); i++) {
qreal w = m.first().ll2xy(TL(m.at(i))).x(); qreal w = m.first().ll2xy(TL(m.at(i))).x();
offsets[_maps.indexOf(m.at(i))].setX(w); offsets[_maps.indexOf(m.at(i))].setX(w + m.at(i).bounds().left());
} }
std::sort(m.begin(), m.end(), yCmp); std::sort(m.begin(), m.end(), yCmp);
offsets[_maps.indexOf(m.first())].setY(0); offsets[_maps.indexOf(m.first())].setY(m.first().bounds().top());
for (int i = 1; i < m.size(); i++) { for (int i = 1; i < m.size(); i++) {
qreal h = m.first().ll2xy(TL(m.at(i))).y(); qreal h = m.first().ll2xy(TL(m.at(i))).y();
offsets[_maps.indexOf(m.at(i))].setY(h); offsets[_maps.indexOf(m.at(i))].setY(h + m.at(i).bounds().top());
} }
} }
_adjust = 0;
_bounds = QVector<Bounds>(_maps.count()); _bounds = QVector<Bounds>(_maps.count());
for (int i = 0; i < _maps.count(); i++) for (int i = 0; i < _maps.count(); i++) {
_bounds[i] = Bounds(_maps.at(i).bbox, QRectF xy(offsets.at(i), _maps.at(i).bounds().size());
QRectF(offsets.at(i), _maps.at(i).size));
_bounds[i] = Bounds(_maps.at(i).bbox(), xy);
_adjust = qMin(qMin(_maps.at(i).bounds().left(),
_maps.at(i).bounds().top()), _adjust);
}
_adjust = -_adjust;
} }
@ -243,7 +251,7 @@ void KMZMap::document(QXmlStreamReader &reader, QZipReader &zip)
void KMZMap::folder(QXmlStreamReader &reader, QZipReader &zip) void KMZMap::folder(QXmlStreamReader &reader, QZipReader &zip)
{ {
while (reader.readNextStartElement()) { while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String("Placemark")) if (reader.name() == QLatin1String("GroundOverlay"))
groundOverlay(reader, zip); groundOverlay(reader, zip);
else if (reader.name() == QLatin1String("Folder")) else if (reader.name() == QLatin1String("Folder"))
folder(reader, zip); folder(reader, zip);
@ -268,7 +276,7 @@ void KMZMap::kml(QXmlStreamReader &reader, QZipReader &zip)
KMZMap::KMZMap(const QString &fileName, QObject *parent) KMZMap::KMZMap(const QString &fileName, QObject *parent)
: Map(fileName, parent), _zip(0) : Map(fileName, parent), _zoom(0), _mapIndex(-1), _zip(0)
{ {
QZipReader zip(fileName, QIODevice::ReadOnly); QZipReader zip(fileName, QIODevice::ReadOnly);
QByteArray xml(zip.fileData("doc.kml")); QByteArray xml(zip.fileData("doc.kml"));
@ -305,16 +313,13 @@ QString KMZMap::name() const
QRectF KMZMap::bounds() QRectF KMZMap::bounds()
{ {
QSizeF s(0, 0); QRectF rect;
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) { for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++)
if (_bounds.at(i).xy.right() > s.width()) rect |= _bounds.at(i).xy;
s.setWidth(_bounds.at(i).xy.right());
if (_bounds.at(i).xy.bottom() > s.height())
s.setHeight(_bounds.at(i).xy.bottom());
}
return QRectF(QPointF(0, 0), s); rect.moveTopLeft(rect.topLeft() * 2);
return rect;
} }
int KMZMap::zoomFit(const QSize &size, const RectC &br) int KMZMap::zoomFit(const QSize &size, const RectC &br)
@ -382,6 +387,11 @@ QPointF KMZMap::ll2xy(const Coordinates &c)
} }
QPointF p = _maps.at(_mapIndex).ll2xy(c); QPointF p = _maps.at(_mapIndex).ll2xy(c);
if (_maps.at(_mapIndex).rotation()) {
QTransform matrix;
matrix.rotate(-_maps.at(_mapIndex).rotation());
return matrix.map(p) + _bounds.at(_mapIndex).xy.topLeft();
} else
return p + _bounds.at(_mapIndex).xy.topLeft(); return p + _bounds.at(_mapIndex).xy.topLeft();
} }
@ -397,22 +407,29 @@ Coordinates KMZMap::xy2ll(const QPointF &p)
} }
QPointF p2 = p - _bounds.at(idx).xy.topLeft(); QPointF p2 = p - _bounds.at(idx).xy.topLeft();
if (_maps.at(idx).rotation()) {
QTransform matrix;
matrix.rotate(_maps.at(idx).rotation());
return _maps.at(idx).xy2ll(matrix.map(p2));
} else
return _maps.at(idx).xy2ll(p2); return _maps.at(idx).xy2ll(p2);
} }
void KMZMap::draw(QPainter *painter, const QRectF &rect, Flags flags) void KMZMap::draw(QPainter *painter, const QRectF &rect, Flags flags)
{ {
QRectF er = rect.adjusted(-_adjust, -_adjust, _adjust, _adjust);
// All in one map // All in one map
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) { for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
if (_bounds.at(i).xy.contains(rect)) { if (_bounds.at(i).xy.contains(er)) {
draw(painter, rect, i, flags); draw(painter, er, i, flags);
return; return;
} }
} }
// Multiple maps // Multiple maps
for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) { for (int i = _zooms.at(_zoom).first; i <= _zooms.at(_zoom).last; i++) {
QRectF ir = rect.intersected(_bounds.at(i).xy); QRectF ir = er.intersected(_bounds.at(i).xy);
if (!ir.isNull()) if (!ir.isNull())
draw(painter, ir, i, flags); draw(painter, ir, i, flags);
} }

View File

@ -1,7 +1,6 @@
#ifndef KMZMAP_H #ifndef KMZMAP_H
#define KMZMAP_H #define KMZMAP_H
#include "projection.h"
#include "transform.h" #include "transform.h"
#include "rectd.h" #include "rectd.h"
#include "map.h" #include "map.h"
@ -39,34 +38,39 @@ public:
QString errorString() const {return _errorString;} QString errorString() const {return _errorString;}
private: private:
struct Overlay { class Overlay {
QString path; public:
QSize size;
RectC bbox;
double rotation;
Image *img;
Transform transform;
Overlay(const QString &path, const QSize &size, const RectC &bbox, Overlay(const QString &path, const QSize &size, const RectC &bbox,
double rotation); double rotation);
bool operator==(const Overlay &other) const bool operator==(const Overlay &other) const
{return path == other.path;} {return _path == other._path;}
QPointF ll2xy(const Coordinates &c) const QPointF ll2xy(const Coordinates &c) const
{return QPointF(transform.proj2img(projection().ll2xy(c)));} {return QPointF(_transform.proj2img(QPointF(c.lon(), c.lat())));}
Coordinates xy2ll(const QPointF &p) const Coordinates xy2ll(const QPointF &p) const
{return projection().xy2ll(transform.img2proj(p));} {
PointD pp(_transform.img2proj(p));
return Coordinates(pp.x(), pp.y());
}
QRectF bounds() const {return QRectF(QPointF(0, 0), size);} const RectC &bbox() const {return _bbox;}
const QRectF &bounds() const {return _bounds;}
qreal resolution(const QRectF &rect) const; qreal resolution(const QRectF &rect) const;
qreal rotation() const {return _rotation;}
void draw(QPainter *painter, const QRectF &rect, Flags flags); void draw(QPainter *painter, const QRectF &rect, Flags flags);
void load(QZipReader *zip); void load(QZipReader *zip);
void unload(); void unload();
static const Projection &projection(); private:
QString _path;
QRectF _bounds;
RectC _bbox;
qreal _rotation;
Image *_img;
Transform _transform;
}; };
struct Zoom { struct Zoom {
@ -107,6 +111,7 @@ private:
int _zoom; int _zoom;
int _mapIndex; int _mapIndex;
QZipReader *_zip; QZipReader *_zip;
qreal _adjust;
bool _valid; bool _valid;
QString _errorString; QString _errorString;