Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
smarttowel committed Sep 3, 2019
1 parent 88d0a52 commit 9a96611
Show file tree
Hide file tree
Showing 10 changed files with 267 additions and 22 deletions.
144 changes: 144 additions & 0 deletions src/Plugins/kmloverlay/kmlgeopolygon.cpp
@@ -0,0 +1,144 @@
#include "kmlgeopolygon.h"

#include <QPainter>
#include <QGeoRectangle>
#include <math.h>

KmlGeoPolygon::KmlGeoPolygon(QQuickItem *parent):
QQuickPaintedItem(parent),
m_map(nullptr)
{
setRenderTarget(QQuickPaintedItem::FramebufferObject);
setAntialiasing(false);
setMipmap(true);
}

void KmlGeoPolygon::registerQmlType()
{
qmlRegisterType<KmlGeoPolygon>("KmlGeoPolygon", 1, 0, "KmlGeoPolygon");
}

void KmlGeoPolygon::clearPolygon()
{
m_polygon.clear();
m_holes.clear();
}

void KmlGeoPolygon::prepareForDrawing()
{
QRegion clip(m_polygon);

for(int i = 0; i < m_holes.size(); i++)
clip -= QRegion(m_holes[i]);

QRegion window(QRect(x(), y(), width(), height()));
m_clip = clip;//.intersected(window);
}

void KmlGeoPolygon::setGeoPolygon(const QGeoPolygon &geoPolygon)
{
m_geoPolygon = geoPolygon;
recalcCoordinates();
prepareForDrawing();
}

QGeoPolygon KmlGeoPolygon::getGeoPolygon() const
{
return m_geoPolygon;
}

void KmlGeoPolygon::setMap(QObject *map)
{
m_map = map;
recalcCoordinates();
prepareForDrawing();
}

QObject *KmlGeoPolygon::getMap() const
{
return m_map;
}

QGeoShape KmlGeoPolygon::getArea() const
{
return m_area;
}

void KmlGeoPolygon::setArea(const QGeoShape &area)
{
m_area = area;
if(m_map)
{
recalcCoordinates();
prepareForDrawing();
update();
}
}

void KmlGeoPolygon::setColor(const QColor &color)
{
if(m_color != color)
{
m_color = color;
emit colorChanged();
update();
}
}

QColor KmlGeoPolygon::getColor() const
{
return m_color;
}

void KmlGeoPolygon::paint(QPainter *painter)
{
painter->setPen(m_color);

painter->setClipRegion(m_clip);
QPainterPath p;
p.addPolygon(m_polygon);
painter->fillPath(p, QBrush(m_color, Qt::SolidPattern));
}

QPoint KmlGeoPolygon::fromCoordinate(const QGeoCoordinate &c)
{
QPointF point;
QMetaObject::invokeMethod(m_map, "fromCoordinate",
Q_RETURN_ARG(QPointF, point),
Q_ARG(QGeoCoordinate, c),
Q_ARG(bool, false));
return point.toPoint();
}

void KmlGeoPolygon::recalcCoordinates()
{
clearPolygon();
auto visibleRegion = m_map->property("visibleRegion").value<QGeoShape>().boundingGeoRectangle();
QRect vr(fromCoordinate(visibleRegion.topLeft()),
fromCoordinate(visibleRegion.bottomRight()));
for(int i = 0; i < m_geoPolygon.size(); i++)
{
QPoint point = fromCoordinate(m_geoPolygon.coordinateAt(i));
if(std::isnan(point.x()) || std::isnan(point.y()))
continue;

m_polygon.append(point);
}
for(int j = 0; j < m_geoPolygon.holesCount(); j++)
{
QPolygon polyHole;
for(int k = 0; k < m_geoPolygon.hole(j).size(); k++)
{
QPoint point = fromCoordinate(m_geoPolygon.hole(j)[k].value<QGeoCoordinate>());
if(std::isnan(point.x()) || std::isnan(point.y()))
continue;
polyHole.append(point);
}
m_holes.append(polyHole);
}

setX(vr.x());
setY(vr.y());
setWidth(vr.width());
setHeight(vr.height());
}
54 changes: 54 additions & 0 deletions src/Plugins/kmloverlay/kmlgeopolygon.h
@@ -0,0 +1,54 @@
#ifndef KMLGEOPOLYGON_H
#define KMLGEOPOLYGON_H

#include <QGeoPolygon>
#include <QPolygon>
#include <QQuickPaintedItem>

class KmlGeoPolygon: public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QGeoPolygon geoPolygon READ getGeoPolygon WRITE setGeoPolygon)
Q_PROPERTY(QObject *map READ getMap WRITE setMap);
Q_PROPERTY(QGeoShape area READ getArea WRITE setArea);
Q_PROPERTY(QColor color READ getColor WRITE setColor NOTIFY colorChanged);
public:

explicit KmlGeoPolygon(QQuickItem *parent = 0);

static void registerQmlType();

void setGeoPolygon(const QGeoPolygon &geoPolygon);
QGeoPolygon getGeoPolygon() const;

void setMap(QObject *map);
QObject* getMap() const;

QGeoShape getArea() const;
void setArea(const QGeoShape &area);

void setColor(const QColor &color);
QColor getColor() const;

void paint(QPainter *painter);

private:
QObject *m_map;
QGeoShape m_area;
QGeoPolygon m_geoPolygon;
QPolygon m_polygon;
QVector<QPolygon> m_holes;
QColor m_color;
QRegion m_clip;

QPoint fromCoordinate(const QGeoCoordinate &c);

void clearPolygon();
void prepareForDrawing();
void recalcCoordinates();

signals:
void colorChanged();
};

#endif // KMLGEOPOLYGON_H
3 changes: 3 additions & 0 deletions src/Plugins/kmloverlay/kmloverlay.cpp
Expand Up @@ -3,11 +3,14 @@
#include "ApxApp.h"
#include "kmlparser.h"
#include <QFileDialog>
#include "kmlgeopolygon.h"

KmlOverlay::KmlOverlay(Fact *parent)
: Fact(parent, "kmloverlay", tr("KML Overlay"), tr("KML objects overlay"), Group)
, m_kmlPolygons(new KmlPolygonsModel())
{
KmlGeoPolygon::registerQmlType();

setIcon("google-earth");

f_open = new Fact(this, "open", tr("Open..."), tr("Open KML file"));
Expand Down
2 changes: 2 additions & 0 deletions src/Plugins/kmloverlay/kmloverlay.qbs
Expand Up @@ -17,6 +17,8 @@ ApxApp.ApxPlugin {
Depends { name: "qmlqrc" }

files: [
"kmlgeopolygon.cpp",
"kmlgeopolygon.h",
"kmloverlayplugin.h",
"kmloverlay.cpp",
"kmloverlay.h",
Expand Down
2 changes: 2 additions & 0 deletions src/Plugins/kmloverlay/kmlparser.cpp
Expand Up @@ -9,6 +9,7 @@ KmlParser::KmlParser() {}

void KmlParser::parse(const QByteArray &data)
{
m_polygonId = 0;
m_polygons.clear();

QString errorMessage;
Expand Down Expand Up @@ -57,6 +58,7 @@ void KmlParser::polygonCallback(const QDomElement &el, const QColor &color)
{
KmlPolygon polygon;
polygon.color = color;
polygon.id = m_polygonId++;
auto cbouter = std::bind(&KmlParser::polygonOuterCallback, this, _1, std::ref(polygon));
auto cbinner = std::bind(&KmlParser::polygonInnerCallback, this, _1, std::ref(polygon));
iterateOverChildrenElements(el, "outerBoundaryIs", cbouter);
Expand Down
2 changes: 2 additions & 0 deletions src/Plugins/kmloverlay/kmlparser.h
Expand Up @@ -8,6 +8,7 @@

struct KmlPolygon
{
uint64_t id;
QColor color;
QGeoPolygon data;
};
Expand All @@ -24,6 +25,7 @@ class KmlParser

QList<KmlPolygon> m_polygons;
QDomDocument m_dom;
uint64_t m_polygonId;

void iterateOverChildrenElements(const QDomElement &parent,
const QString &tagname,
Expand Down
43 changes: 32 additions & 11 deletions src/Plugins/kmloverlay/kmlpolygonsmodel.cpp
Expand Up @@ -7,24 +7,36 @@

KmlPolygonsModel::KmlPolygonsModel() {}

QPointF KmlPolygonsModel::setPolygons(const QList<KmlPolygon> &polygons)
QPointF KmlPolygonsModel::setPolygons(const QList<KmlPolygon> &kmlPolygons)
{
m_allPolygons.clear();

QPolygonF allPoints;
for (auto &p : polygons)
allPoints.append(toPolygon(p.data));
for (auto &p : kmlPolygons)
{
QPolygonF polygon = toPolygon(p.data);
allPoints.append(polygon);

KmlPolygonExtended kmlPolygonExtended;
kmlPolygonExtended.kmlPolygon = p;
kmlPolygonExtended.polygon = polygon;
m_allPolygons.append(kmlPolygonExtended);
}

auto center = std::accumulate(allPoints.begin(), allPoints.end(), QPointF(0, 0))
/ allPoints.size();

m_allPolygons = polygons;
beginResetModel();
m_viewPolygons.clear();
endResetModel();
updateViewPolygons();

return center;
}

void KmlPolygonsModel::setBoundingBox(const QRectF &bb)
{
m_bb = QRectF(bb.x() - bb.width(), bb.y() - bb.height(), bb.width() * 3, bb.height() * 3);
m_bb = QRectF(bb.x(), bb.y(), bb.width(), bb.height());
updateViewPolygons();
}

Expand All @@ -46,9 +58,9 @@ QVariant KmlPolygonsModel::data(const QModelIndex &index, int role) const
int row = index.row();
if (row >= 0 && row < m_viewPolygons.size()) {
if (role == Polygon) {
result = QVariant::fromValue(m_viewPolygons[row].data);
result = QVariant::fromValue(m_viewPolygons[row].kmlPolygon.data);
} else if (role == Color) {
result = m_viewPolygons[row].color;
result = m_viewPolygons[row].kmlPolygon.color;
}
}
return result;
Expand All @@ -62,13 +74,22 @@ QHash<int, QByteArray> KmlPolygonsModel::roleNames() const

void KmlPolygonsModel::updateViewPolygons()
{
beginResetModel();
m_viewPolygons.clear();
for (int i = 0; i < m_viewPolygons.size(); i++) {
if(!m_viewPolygons[i].polygon.intersects(m_bb)) {
beginRemoveRows(QModelIndex(), i, i);
m_viewPolygons.removeAt(i);
endRemoveRows();
}
}

for (auto &p : m_allPolygons) {
if (toPolygon(p.data).intersects(m_bb))
if (!m_viewPolygons.contains(p) && p.polygon.intersects(m_bb)) {
int row = m_viewPolygons.size();
beginInsertRows(QModelIndex(), row, row);
m_viewPolygons.append(p);
endInsertRows();
}
}
endResetModel();
}

QPolygonF KmlPolygonsModel::toPolygon(const QGeoPolygon &geoPolygon)
Expand Down
15 changes: 12 additions & 3 deletions src/Plugins/kmloverlay/kmlpolygonsmodel.h
Expand Up @@ -12,7 +12,7 @@ class KmlPolygonsModel : public QAbstractListModel
enum Roles { Polygon = Qt::UserRole + 1, Color };
KmlPolygonsModel();

QPointF setPolygons(const QList<KmlPolygon> &polygons);
QPointF setPolygons(const QList<KmlPolygon> &kmlPolygons);
void setBoundingBox(const QRectF &bb);

int rowCount(const QModelIndex &index) const override;
Expand All @@ -21,9 +21,18 @@ class KmlPolygonsModel : public QAbstractListModel
QHash<int, QByteArray> roleNames() const override;

private:
struct KmlPolygonExtended
{
KmlPolygon kmlPolygon;
QPolygonF polygon;
bool operator==(const KmlPolygonExtended &other) {
return kmlPolygon.id == other.kmlPolygon.id;
}
};

QPolygonF m_bb;
QList<KmlPolygon> m_allPolygons;
QList<KmlPolygon> m_viewPolygons;
QList<KmlPolygonExtended> m_allPolygons;
QList<KmlPolygonExtended> m_viewPolygons;

void updateViewPolygons();

Expand Down

0 comments on commit 9a96611

Please sign in to comment.