diff --git a/CMakeLists.txt b/CMakeLists.txt
index b5571ac..563b6df 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake
cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default
project(QAD)
set(QAD_MAJOR 2)
-set(QAD_MINOR 12)
+set(QAD_MINOR 13)
set(QAD_REVISION 0)
set(QAD_SUFFIX )
set(QAD_COMPANY SHS)
diff --git a/icons/maps.png b/icons/maps.png
new file mode 100644
index 0000000..ae68d54
Binary files /dev/null and b/icons/maps.png differ
diff --git a/libs/map/CMakeLists.txt b/libs/map/CMakeLists.txt
new file mode 100644
index 0000000..ff89440
--- /dev/null
+++ b/libs/map/CMakeLists.txt
@@ -0,0 +1 @@
+qad_library(map "Gui;Widgets;Network" "qad_widgets")
diff --git a/libs/map/lang/qad_application_en.ts b/libs/map/lang/qad_application_en.ts
new file mode 100644
index 0000000..cc85e91
--- /dev/null
+++ b/libs/map/lang/qad_application_en.ts
@@ -0,0 +1,144 @@
+
+
+
+
+ AboutWindow
+
+
+ - About
+
+
+
+
+ Versions
+
+
+
+
+ Build
+
+
+
+
+ Authors
+
+
+
+
+ About Qt...
+
+
+
+
+ OK
+
+
+
+
+
+ About
+
+
+
+
+ EMainWindow
+
+
+
+ Clear recent list
+
+
+
+
+
+
+
+ Show all
+
+
+
+
+
+
+
+ Hide all
+
+
+
+
+ Toolbars
+
+
+
+
+ Docks
+
+
+
+
+ Select file to open
+
+
+
+
+ Select files to open
+
+
+
+
+ Save changes%1?
+
+
+
+
+ in
+
+
+
+
+ Select file to save
+
+
+
+
+ HistoryView
+
+
+
+ History cleared
+
+
+
+
+ LogView
+
+
+ Category:
+
+
+
+
+
+
+ Clear
+
+
+
+
+
+ Select All
+
+
+
+
+
+ Copy
+
+
+
+
+ All
+
+
+
+
diff --git a/libs/map/lang/qad_application_ru.ts b/libs/map/lang/qad_application_ru.ts
new file mode 100644
index 0000000..bb4ba21
--- /dev/null
+++ b/libs/map/lang/qad_application_ru.ts
@@ -0,0 +1,144 @@
+
+
+
+
+ AboutWindow
+
+
+ - About
+ - О программе
+
+
+
+ Versions
+ Версии
+
+
+
+ Build
+ Сборка
+
+
+
+ Authors
+ Авторы
+
+
+
+ About Qt...
+ О Qt ...
+
+
+
+ OK
+
+
+
+
+
+ About
+ О программе
+
+
+
+ EMainWindow
+
+
+
+ Clear recent list
+ Очистить список недавних
+
+
+
+
+
+
+ Show all
+ Показать все
+
+
+
+
+
+
+ Hide all
+ Скрыть все
+
+
+
+ Toolbars
+ Панели инструментов
+
+
+
+ Docks
+ Окна
+
+
+
+ Select file to open
+ Выбрать файл для открытия
+
+
+
+ Select files to open
+ Выберите файлы для открытия
+
+
+
+ Save changes%1?
+ Сохранить изменения%1?
+
+
+
+ in
+ в
+
+
+
+ Select file to save
+ Выберите файл для сохранения
+
+
+
+ HistoryView
+
+
+
+ History cleared
+ История очищена
+
+
+
+ LogView
+
+
+ Category:
+ Категория:
+
+
+
+
+
+ Clear
+ Очистить
+
+
+
+
+ Select All
+ Выделить всё
+
+
+
+
+ Copy
+ Копировать
+
+
+
+ All
+ Все
+
+
+
diff --git a/libs/map/lang/update.bat b/libs/map/lang/update.bat
new file mode 100644
index 0000000..34f3eee
--- /dev/null
+++ b/libs/map/lang/update.bat
@@ -0,0 +1,2 @@
+lupdate ../ -ts qad_application_ru.ts
+lupdate ../ -ts qad_application_en.ts
diff --git a/libs/map/mapitembase.cpp b/libs/map/mapitembase.cpp
new file mode 100644
index 0000000..b9089d0
--- /dev/null
+++ b/libs/map/mapitembase.cpp
@@ -0,0 +1,95 @@
+#include "mapitembase.h"
+
+#include "mapview.h"
+#include "osm_math_p.h"
+
+
+MapItemBase::MapItemBase() {}
+
+
+MapItemBase::~MapItemBase() {
+ if (!parent) return;
+ parent->removeItem(this);
+}
+
+
+void MapItemBase::setInteracive(bool newInteracive) {
+ m_interacive = newInteracive;
+ updateParent();
+}
+
+
+void MapItemBase::setVisible(bool newVisible) {
+ m_visible = newVisible;
+ updateParent();
+}
+
+
+void MapItemBase::setRotation(double deg) {
+ m_rotation = deg;
+ updateParent();
+}
+
+
+void MapItemBase::rotate(double deg) {
+ m_rotation += deg;
+ while (deg < 0)
+ deg += 360.;
+ while (deg > 360.)
+ deg -= 360.;
+ updateParent();
+}
+
+
+void MapItemBase::scale(QPointF s) {
+ m_scale = {m_scale.x() * s.x(), m_scale.y() * s.y()};
+ updateParent();
+}
+
+
+void MapItemBase::setScale(QPointF s) {
+ m_scale = s;
+ updateParent();
+}
+
+
+void MapItemBase::setPosition(QPointF geo) {
+ m_position = geo;
+ updatePosition();
+ updateParent();
+}
+
+
+void MapItemBase::setCursor(const QCursor & newCursor) {
+ m_cursor = newCursor;
+ updateParent();
+}
+
+
+QPointF MapItemBase::mapToView(QPointF norm) const {
+ if (!parent) return norm;
+ return parent->mapFromNorm(norm);
+}
+
+
+double MapItemBase::scalePx2M(QPointF norm) const {
+ if (!parent) return 1.;
+ return parent->scalePx2M(norm);
+}
+
+
+void MapItemBase::updatePosition() {
+ norm_pos = OSM::geo2xy(m_position);
+ potitionChanged();
+ zoomChanged();
+}
+
+
+void MapItemBase::updateParent() {
+ if (parent) parent->update();
+}
+
+
+void MapItemBase::setBoundingRect(QRectF b) {
+ m_bounding = b;
+}
diff --git a/libs/map/mapitembase.h b/libs/map/mapitembase.h
new file mode 100644
index 0000000..55ba0ba
--- /dev/null
+++ b/libs/map/mapitembase.h
@@ -0,0 +1,94 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitembase_h
+#define mapitembase_h
+
+#include "qad_map_export.h"
+
+#include
+#include
+#include
+#include
+#include
+
+class MapView;
+
+class QAD_MAP_EXPORT MapItemBase {
+ friend class MapView;
+
+public:
+ explicit MapItemBase();
+ virtual ~MapItemBase();
+
+
+ bool isInteracive() const { return m_interacive; }
+ void setInteracive(bool newInteracive);
+
+ bool isVisible() const { return m_visible; }
+ void setVisible(bool newVisible);
+
+ double getRotation() const { return m_rotation; }
+ void setRotation(double deg);
+ void rotate(double deg);
+
+ QPointF getScale() const { return m_scale; }
+ void scale(double s) { scale({s, s}); }
+ void scale(double sx, double sy) { scale({sx, sy}); }
+ void scale(QPointF s);
+ void setScale(double s) { setScale({s, s}); }
+ void setScale(double sx, double sy) { scale({sx, sy}); }
+ void setScale(QPointF s);
+
+ QPointF position() const { return m_position; }
+ void setPosition(QPointF geo);
+ void setPosition(double lat, double lng) { setPosition({lat, lng}); }
+
+ const QCursor & cursor() const { return m_cursor; }
+ void setCursor(const QCursor & newCursor);
+
+ QVariant data(int id) const { return data_.value(id); }
+ void setData(int id, const QVariant & d) { data_[id] = d; }
+
+protected:
+ QPointF mapToView(QPointF norm) const;
+ double scalePx2M(QPointF norm) const;
+ virtual void draw(QPainter * p) = 0;
+ void updateParent();
+ void setBoundingRect(QRectF b);
+
+ QPointF norm_pos;
+ bool ignore_scale = false;
+
+private:
+ void updatePosition();
+ virtual void potitionChanged() {}
+ virtual void zoomChanged() {}
+
+ MapView * parent = nullptr;
+ bool m_visible = true, m_interacive = false;
+ double m_rotation = 0.;
+ QPointF m_position, m_scale = {1., 1.};
+ QRectF m_bounding;
+ QCursor m_cursor;
+ QMap data_;
+};
+
+
+#endif
diff --git a/libs/map/mapitemellipse.cpp b/libs/map/mapitemellipse.cpp
new file mode 100644
index 0000000..be7ad8b
--- /dev/null
+++ b/libs/map/mapitemellipse.cpp
@@ -0,0 +1,77 @@
+#include "mapitemellipse.h"
+
+#include
+
+
+MapItemEllipse::MapItemEllipse(const QRectF & r) {
+ setEllipse(r);
+}
+
+
+MapItemEllipse::MapItemEllipse(const QPointF & p, double rx, double ry) {
+ setEllipse(p, rx, ry);
+}
+
+
+void MapItemEllipse::setStartAngle(double a) {
+ sa = a;
+ rebuild();
+ updateParent();
+}
+
+
+void MapItemEllipse::setEndAngle(double a) {
+ ea = a;
+ rebuild();
+ updateParent();
+}
+
+
+void MapItemEllipse::setEllipse(const QRectF & r) {
+ rct = r;
+ rebuild();
+ updateParent();
+}
+
+
+void MapItemEllipse::setEllipse(const QPointF & p, double rx, double ry) {
+ rct.setWidth(rx * 2.);
+ rct.setHeight(ry * 2.);
+ rct.moveCenter(p);
+ rebuild();
+ updateParent();
+}
+
+
+void MapItemEllipse::draw(QPainter * p) {
+ p->setPen(pen());
+ p->setBrush(brush());
+ QPolygonF dp(pol);
+ double us = unitScale();
+ for (auto & i: dp)
+ i = QPointF(i.x(), -i.y()) / us;
+ p->drawPolygon(dp);
+ setBoundingRect(dp.boundingRect());
+}
+
+
+void MapItemEllipse::rebuild() {
+ pol.clear();
+ QPointF c = rct.center();
+ bool full = sa == ea;
+ if (!full) pol << c;
+ double w = rct.width() / 2., h = rct.height() / 2.;
+ static double deg2rad = M_PI / 180.;
+ if (full) {
+ sa = 0.;
+ ea = 360.;
+ } else {
+ if (ea < sa) qSwap(sa, ea);
+ }
+ for (double a = sa; a <= ea; a += 3.) {
+ if (a > ea) a = ea;
+ QPointF p(sin(a * deg2rad) * w, cos(a * deg2rad) * h);
+ pol << (c + p);
+ }
+ if (!full) pol << c;
+}
diff --git a/libs/map/mapitemellipse.h b/libs/map/mapitemellipse.h
new file mode 100644
index 0000000..6dbd132
--- /dev/null
+++ b/libs/map/mapitemellipse.h
@@ -0,0 +1,53 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemellipse_h
+#define mapitemellipse_h
+
+#include "mapitemnongeogeometrybase.h"
+
+
+/// ellipse in meters, based on map scale at "position", or pixels
+/// north = 0 deg, positive is clockwise
+class QAD_MAP_EXPORT MapItemEllipse: public MapItemNonGeoGeometryBase {
+public:
+ MapItemEllipse(const QRectF & r = QRectF());
+ MapItemEllipse(const QPointF & p, double rx, double ry);
+
+
+ QRectF rect() const { return rct; }
+ double startAngle() const { return sa; }
+ double endAngle() const { return ea; }
+ void setStartAngle(double a);
+ void setEndAngle(double a);
+ void setEllipse(const QRectF & r);
+ void setEllipse(const QPointF & p, double rx, double ry);
+
+protected:
+ void draw(QPainter * p) override;
+ void rebuild();
+
+private:
+ QRectF rct;
+ QPolygonF pol;
+ double sa = 0., ea = 0.;
+};
+
+
+#endif
diff --git a/libs/map/mapitemgeometrybase.cpp b/libs/map/mapitemgeometrybase.cpp
new file mode 100644
index 0000000..53dcfba
--- /dev/null
+++ b/libs/map/mapitemgeometrybase.cpp
@@ -0,0 +1,16 @@
+#include "mapitemgeometrybase.h"
+
+
+MapItemGeometryBase::MapItemGeometryBase() {}
+
+
+void MapItemGeometryBase::setPen(QPen newPen) {
+ m_pen = newPen;
+ updateParent();
+}
+
+
+void MapItemGeometryBase::setBrush(QBrush newBrush) {
+ m_brush = newBrush;
+ updateParent();
+}
diff --git a/libs/map/mapitemgeometrybase.h b/libs/map/mapitemgeometrybase.h
new file mode 100644
index 0000000..d87b92c
--- /dev/null
+++ b/libs/map/mapitemgeometrybase.h
@@ -0,0 +1,53 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemgeometrybase_h
+#define mapitemgeometrybase_h
+
+#include "mapitembase.h"
+
+#include
+#include
+#include
+
+class QAD_MAP_EXPORT MapItemGeometryBase: public MapItemBase {
+ friend class MapView;
+
+public:
+ explicit MapItemGeometryBase();
+
+
+ QPen pen() const { return m_pen; }
+ void setPen(QPen newPen);
+
+ QBrush brush() const { return m_brush; }
+ void setBrush(QBrush newBrush);
+
+protected:
+ virtual void updatePolygon() {}
+
+ QPolygonF norm_polygon;
+
+private:
+ QPen m_pen = QPen(Qt::black, 1);
+ QBrush m_brush = QBrush(Qt::white);
+};
+
+
+#endif
diff --git a/libs/map/mapitemgeopolygon.cpp b/libs/map/mapitemgeopolygon.cpp
new file mode 100644
index 0000000..0d886ed
--- /dev/null
+++ b/libs/map/mapitemgeopolygon.cpp
@@ -0,0 +1,35 @@
+#include "mapitemgeopolygon.h"
+
+#include "osm_math_p.h"
+
+
+MapItemGeoPolygon::MapItemGeoPolygon(const QPolygonF & p) {
+ ignore_scale = true;
+ setPolygon(p);
+}
+
+
+void MapItemGeoPolygon::setPolygon(const QPolygonF & p) {
+ pol = p;
+ updatePolygon();
+}
+
+
+void MapItemGeoPolygon::draw(QPainter * p) {
+ p->setPen(pen());
+ p->setBrush(brush());
+ QPolygonF dp(norm_polygon);
+ QPointF pos_offset = mapToView(norm_pos);
+ for (auto & i: dp)
+ i = mapToView(i) - pos_offset;
+ p->drawPolygon(dp);
+ setBoundingRect(dp.boundingRect());
+}
+
+
+void MapItemGeoPolygon::updatePolygon() {
+ norm_polygon.resize(pol.size());
+ for (int i = 0; i < pol.size(); ++i)
+ norm_polygon[i] = OSM::geo2xy(pol[i]);
+ updateParent();
+}
diff --git a/libs/map/mapitemgeopolygon.h b/libs/map/mapitemgeopolygon.h
new file mode 100644
index 0000000..5af0487
--- /dev/null
+++ b/libs/map/mapitemgeopolygon.h
@@ -0,0 +1,44 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemgeopolygon_h
+#define mapitemgeopolygon_h
+
+#include "mapitemgeometrybase.h"
+
+
+/// polygon in geo-coordinates
+class QAD_MAP_EXPORT MapItemGeoPolygon: public MapItemGeometryBase {
+public:
+ explicit MapItemGeoPolygon(const QPolygonF & p = QPolygonF());
+
+
+ QPolygonF polygon() const { return pol; }
+ void setPolygon(const QPolygonF & p);
+
+protected:
+ void draw(QPainter * p) override;
+ void updatePolygon() override;
+
+private:
+ QPolygonF pol;
+};
+
+
+#endif
diff --git a/libs/map/mapitemgeopolyline.cpp b/libs/map/mapitemgeopolyline.cpp
new file mode 100644
index 0000000..19b6bc7
--- /dev/null
+++ b/libs/map/mapitemgeopolyline.cpp
@@ -0,0 +1,34 @@
+#include "mapitemgeopolyline.h"
+
+#include "osm_math_p.h"
+
+
+MapItemGeoPolyline::MapItemGeoPolyline(const QPolygonF & p) {
+ ignore_scale = true;
+ setPolyline(p);
+}
+
+
+void MapItemGeoPolyline::setPolyline(const QPolygonF & p) {
+ pol = p;
+ updatePolygon();
+}
+
+
+void MapItemGeoPolyline::draw(QPainter * p) {
+ p->setPen(pen());
+ QPolygonF dp(norm_polygon);
+ QPointF pos_offset = mapToView(norm_pos);
+ for (auto & i: dp)
+ i = mapToView(i) - pos_offset;
+ p->drawPolyline(dp);
+ setBoundingRect(dp.boundingRect());
+}
+
+
+void MapItemGeoPolyline::updatePolygon() {
+ norm_polygon.resize(pol.size());
+ for (int i = 0; i < pol.size(); ++i)
+ norm_polygon[i] = OSM::geo2xy(pol[i]);
+ updateParent();
+}
diff --git a/libs/map/mapitemgeopolyline.h b/libs/map/mapitemgeopolyline.h
new file mode 100644
index 0000000..6b87e87
--- /dev/null
+++ b/libs/map/mapitemgeopolyline.h
@@ -0,0 +1,44 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemgeopolyline_h
+#define mapitemgeopolyline_h
+
+#include "mapitemgeometrybase.h"
+
+
+/// polyline in geo-coordinates
+class QAD_MAP_EXPORT MapItemGeoPolyline: public MapItemGeometryBase {
+public:
+ explicit MapItemGeoPolyline(const QPolygonF & p = QPolygonF());
+
+
+ QPolygonF polyline() const { return pol; }
+ void setPolyline(const QPolygonF & p);
+
+protected:
+ void draw(QPainter * p) override;
+ void updatePolygon() override;
+
+private:
+ QPolygonF pol;
+};
+
+
+#endif
diff --git a/libs/map/mapitemimage.cpp b/libs/map/mapitemimage.cpp
new file mode 100644
index 0000000..8e2f3e1
--- /dev/null
+++ b/libs/map/mapitemimage.cpp
@@ -0,0 +1,38 @@
+#include "mapitemimage.h"
+
+
+MapItemImage::MapItemImage(const QPixmap & p) {
+ setPixmap(p);
+}
+
+
+void MapItemImage::setPixmap(const QPixmap & p) {
+ m_pixmap = p;
+ updateParent();
+}
+
+
+void MapItemImage::setAlignment(Qt::Alignment a) {
+ m_alignment = a;
+ updateParent();
+}
+
+
+void MapItemImage::draw(QPainter * p) {
+ if (m_pixmap.isNull()) return;
+ QRectF pr(QPointF(0, 0), QSizeF(m_pixmap.size()));
+ if (m_alignment.testFlag(Qt::AlignHCenter)) {
+ pr.translate(-pr.center().x(), 0.);
+ }
+ if (m_alignment.testFlag(Qt::AlignRight)) {
+ pr.translate(-pr.width(), 0.);
+ }
+ if (m_alignment.testFlag(Qt::AlignVCenter)) {
+ pr.translate(0., -pr.center().y());
+ }
+ if (m_alignment.testFlag(Qt::AlignBottom)) {
+ pr.translate(0., -pr.height());
+ }
+ p->drawPixmap(pr, m_pixmap, m_pixmap.rect());
+ setBoundingRect(pr);
+}
diff --git a/libs/map/mapitemimage.h b/libs/map/mapitemimage.h
new file mode 100644
index 0000000..9c3a36b
--- /dev/null
+++ b/libs/map/mapitemimage.h
@@ -0,0 +1,46 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemimage_h
+#define mapitemimage_h
+
+#include "mapitembase.h"
+
+#include
+
+class QAD_MAP_EXPORT MapItemImage: public MapItemBase {
+public:
+ explicit MapItemImage(const QPixmap & p = QPixmap());
+
+ QPixmap pixmap() const { return m_pixmap; }
+ void setPixmap(const QPixmap & p);
+
+ Qt::Alignment alignment() const { return m_alignment; }
+ void setAlignment(Qt::Alignment a);
+
+protected:
+ void draw(QPainter * p) override;
+
+private:
+ QPixmap m_pixmap;
+ Qt::Alignment m_alignment = Qt::AlignCenter;
+};
+
+
+#endif
diff --git a/libs/map/mapitemnongeogeometrybase.cpp b/libs/map/mapitemnongeogeometrybase.cpp
new file mode 100644
index 0000000..59d58c2
--- /dev/null
+++ b/libs/map/mapitemnongeogeometrybase.cpp
@@ -0,0 +1,21 @@
+#include "mapitemnongeogeometrybase.h"
+
+
+void MapItemNonGeoGeometryBase::setUnits(Units u) {
+ m_units = u;
+ updateParent();
+}
+
+
+void MapItemNonGeoGeometryBase::zoomChanged() {
+ px2m = scalePx2M(norm_pos);
+}
+
+
+double MapItemNonGeoGeometryBase::unitScale() const {
+ switch (m_units) {
+ case Meters: return px2m;
+ default: break;
+ }
+ return 1.;
+}
diff --git a/libs/map/mapitemnongeogeometrybase.h b/libs/map/mapitemnongeogeometrybase.h
new file mode 100644
index 0000000..ee34e92
--- /dev/null
+++ b/libs/map/mapitemnongeogeometrybase.h
@@ -0,0 +1,49 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemnongeogeometrybase_h
+#define mapitemnongeogeometrybase_h
+
+#include "mapitemgeometrybase.h"
+
+
+/// ellipse in meters, based on map scale at "position"
+/// north = 0 deg, positive is clockwise
+class QAD_MAP_EXPORT MapItemNonGeoGeometryBase: public MapItemGeometryBase {
+public:
+ enum Units {
+ Meters,
+ Pixels
+ };
+
+ Units units() const { return m_units; }
+ void setUnits(Units u);
+
+protected:
+ void zoomChanged() override;
+ double unitScale() const;
+
+
+private:
+ Units m_units = Meters;
+ double px2m = 1.;
+};
+
+
+#endif
diff --git a/libs/map/mapitempolygon.cpp b/libs/map/mapitempolygon.cpp
new file mode 100644
index 0000000..1a97ada
--- /dev/null
+++ b/libs/map/mapitempolygon.cpp
@@ -0,0 +1,24 @@
+#include "mapitempolygon.h"
+
+
+MapItemPolygon::MapItemPolygon(const QPolygonF & p) {
+ setPolygon(p);
+}
+
+
+void MapItemPolygon::setPolygon(const QPolygonF & p) {
+ pol = p;
+ updateParent();
+}
+
+
+void MapItemPolygon::draw(QPainter * p) {
+ p->setPen(pen());
+ p->setBrush(brush());
+ QPolygonF dp(pol);
+ double us = unitScale();
+ for (auto & i: dp)
+ i = QPointF(i.x(), -i.y()) / us;
+ p->drawPolygon(dp);
+ setBoundingRect(dp.boundingRect());
+}
diff --git a/libs/map/mapitempolygon.h b/libs/map/mapitempolygon.h
new file mode 100644
index 0000000..77e140d
--- /dev/null
+++ b/libs/map/mapitempolygon.h
@@ -0,0 +1,43 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitempolygon_h
+#define mapitempolygon_h
+
+#include "mapitemnongeogeometrybase.h"
+
+
+/// polygon in meters, based on map scale at "position", or pixels
+class QAD_MAP_EXPORT MapItemPolygon: public MapItemNonGeoGeometryBase {
+public:
+ explicit MapItemPolygon(const QPolygonF & p = QPolygonF());
+
+
+ QPolygonF polygon() const { return pol; }
+ void setPolygon(const QPolygonF & p);
+
+protected:
+ void draw(QPainter * p) override;
+
+private:
+ QPolygonF pol;
+};
+
+
+#endif
diff --git a/libs/map/mapitempolyline.cpp b/libs/map/mapitempolyline.cpp
new file mode 100644
index 0000000..de9611a
--- /dev/null
+++ b/libs/map/mapitempolyline.cpp
@@ -0,0 +1,23 @@
+#include "mapitempolyline.h"
+
+
+MapItemPolyline::MapItemPolyline(const QPolygonF & p) {
+ setPolyline(p);
+}
+
+
+void MapItemPolyline::setPolyline(const QPolygonF & p) {
+ pol = p;
+ updateParent();
+}
+
+
+void MapItemPolyline::draw(QPainter * p) {
+ p->setPen(pen());
+ QPolygonF dp(pol);
+ double us = unitScale();
+ for (auto & i: dp)
+ i = QPointF(i.x(), -i.y()) / us;
+ p->drawPolyline(dp);
+ setBoundingRect(dp.boundingRect());
+}
diff --git a/libs/map/mapitempolyline.h b/libs/map/mapitempolyline.h
new file mode 100644
index 0000000..1f4dcac
--- /dev/null
+++ b/libs/map/mapitempolyline.h
@@ -0,0 +1,43 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitempolyline_h
+#define mapitempolyline_h
+
+#include "mapitemnongeogeometrybase.h"
+
+
+/// polyline in meters, based on map scale at "position", or pixels
+class QAD_MAP_EXPORT MapItemPolyline: public MapItemNonGeoGeometryBase {
+public:
+ explicit MapItemPolyline(const QPolygonF & p = QPolygonF());
+
+
+ QPolygonF polyline() const { return pol; }
+ void setPolyline(const QPolygonF & p);
+
+protected:
+ void draw(QPainter * p) override;
+
+private:
+ QPolygonF pol;
+};
+
+
+#endif
diff --git a/libs/map/mapitemtext.cpp b/libs/map/mapitemtext.cpp
new file mode 100644
index 0000000..401a2a8
--- /dev/null
+++ b/libs/map/mapitemtext.cpp
@@ -0,0 +1,50 @@
+#include "mapitemtext.h"
+
+
+MapItemText::MapItemText(const QString & t) {
+ setBrush(Qt::NoBrush);
+ setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
+ setText(t);
+}
+
+
+void MapItemText::setAlignment(Qt::Alignment a) {
+ m_alignment = a;
+ updateParent();
+}
+
+
+void MapItemText::setText(const QString & s) {
+ str = s;
+ updateParent();
+}
+
+
+void MapItemText::setFont(const QFont & f) {
+ m_font = f;
+ updateParent();
+}
+
+
+void MapItemText::draw(QPainter * p) {
+ if (str.isEmpty()) return;
+ p->setPen(pen());
+ p->setFont(font());
+ auto br = p->fontMetrics().boundingRect(str);
+ br.translate(-br.topLeft());
+ if (m_alignment.testFlag(Qt::AlignHCenter)) {
+ br.translate(-br.center().x(), 0.);
+ }
+ if (m_alignment.testFlag(Qt::AlignRight)) {
+ br.translate(-br.width(), 0.);
+ }
+ if (m_alignment.testFlag(Qt::AlignVCenter)) {
+ br.translate(0., -br.center().y());
+ }
+ if (m_alignment.testFlag(Qt::AlignBottom)) {
+ br.translate(0., -br.height());
+ }
+ p->fillRect(br.adjusted(-2, 0, 2, 0), brush());
+ p->drawText(br, Qt::TextSingleLine, str);
+ setBoundingRect(br);
+}
diff --git a/libs/map/mapitemtext.h b/libs/map/mapitemtext.h
new file mode 100644
index 0000000..4763379
--- /dev/null
+++ b/libs/map/mapitemtext.h
@@ -0,0 +1,51 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapitemtext_h
+#define mapitemtext_h
+
+#include "mapitemgeometrybase.h"
+
+#include
+
+
+class QAD_MAP_EXPORT MapItemText: public MapItemGeometryBase {
+public:
+ explicit MapItemText(const QString & t = QString());
+
+ Qt::Alignment alignment() const { return m_alignment; }
+ void setAlignment(Qt::Alignment a);
+
+ QString text() const { return str; }
+ void setText(const QString & s);
+
+ QFont font() const { return m_font; }
+ void setFont(const QFont & f);
+
+protected:
+ void draw(QPainter * p) override;
+
+private:
+ Qt::Alignment m_alignment = Qt::AlignCenter;
+ QString str;
+ QFont m_font;
+};
+
+
+#endif
diff --git a/libs/map/mapview.cpp b/libs/map/mapview.cpp
new file mode 100644
index 0000000..dc2d9e2
--- /dev/null
+++ b/libs/map/mapview.cpp
@@ -0,0 +1,317 @@
+#include "mapview.h"
+
+#include "osm_downloader_p.h"
+#include "osm_math_p.h"
+#include "osm_tile_cache_p.h"
+#include "qad_types.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+const int tileSize = 256;
+
+
+MapView::MapView(QWidget * parent): QWidget(parent) {
+ downloader = new OSMDownloader(this);
+ cache = new OSMTileCache(this);
+ setMouseTracking(true);
+ connect(cache, &OSMTileCache::tileReady, this, [this]() { drawBackground(); });
+ int size = 16;
+ QPixmap px(QSize(size, size) * 2);
+ QPainter p(&px);
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ p.fillRect(i * size, j * size, size, size, (((i + j) % 2) == 0) ? Qt::white : Qt::lightGray);
+ }
+ }
+ p.end();
+ brush_tr.setTexture(px);
+ zoomTo(0);
+}
+
+
+MapView::~MapView() {
+ for (auto * i: items_)
+ i->parent = nullptr;
+ qDeleteAll(items_);
+ delete cache;
+ delete downloader;
+}
+
+
+void MapView::addItem(MapItemBase * item) {
+ if (items_.contains(item)) return;
+ items_ << item;
+ item->parent = this;
+ item->updatePosition();
+ update();
+}
+
+
+void MapView::removeItem(MapItemBase * item) {
+ if (!items_.contains(item)) return;
+ items_.removeOne(item);
+ if (hover == item) hover = nullptr;
+}
+
+
+QPointF MapView::center() const {
+ return OSM::xy2geo(center_);
+}
+
+
+void MapView::setCenter(QPointF c) {
+ center_ = OSM::geo2xy(c);
+ updateViewRect();
+ drawBackground();
+}
+
+
+void MapView::setZoom(double z) {
+ zoomTo(z);
+}
+
+
+void MapView::mousePressEvent(QMouseEvent * e) {
+ is_pan = false;
+ press_point = e->pos();
+}
+
+
+void MapView::mouseReleaseEvent(QMouseEvent * e) {
+ if (!is_pan) {
+ if (hover) emit itemClicked(hover);
+ }
+ is_pan = false;
+}
+
+
+void MapView::mouseDoubleClickEvent(QMouseEvent * e) {}
+
+
+void MapView::mouseMoveEvent(QMouseEvent * e) {
+ // QPointF geo = OSM::xy2geo(mapToNorm(e->pos()));
+ // qDebug() << QString("%1 , %2").arg(geo.x(), 0, 'f', 5).arg(geo.y(), 0, 'f', 5);
+ if (e->buttons() == Qt::LeftButton) {
+ if (is_pan) {
+ double mins = qMin(width(), height());
+ center_ -= QPointF(e->pos() - press_point) / scale_ / mins;
+ press_point = e->pos();
+ updateViewRect();
+ drawBackground();
+ } else {
+ if ((e->pos() - press_point).manhattanLength() >= QApplication::startDragDistance()) is_pan = true;
+ }
+ }
+ updateMouse(e->pos());
+}
+
+
+void MapView::wheelEvent(QWheelEvent * e) {
+ double scl = e->angleDelta().x() == 0 ? e->angleDelta().y() : e->angleDelta().x();
+ scl = 1. + (scl / 400.);
+ QPoint mp;
+#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
+ mp = e->pos();
+#else
+ mp = e->position().toPoint();
+#endif
+ zoom(scl, mp);
+}
+
+
+void MapView::paintEvent(QPaintEvent *) {
+ QPainter p(this);
+ p.drawPixmap(0, 0, background);
+ drawItems(p);
+ updateMouse(mapFromGlobal(QCursor::pos()));
+}
+
+
+void MapView::resizeEvent(QResizeEvent *) {
+ cache->setMinimumCacheSize((width() + tileSize) * (height() + tileSize) * 4);
+ checkZoom();
+ updateZoomLevel();
+ updateViewRect();
+ drawBackground();
+}
+
+
+void MapView::drawBackground() {
+ if (size() != background.size()) background = QPixmap(size());
+ background.fill(palette().window().color());
+ QPainter p(&background);
+ double mins = qMin(width(), height());
+ int sx = qMax(0, (int)floor(view_rect.left() * tiles_side));
+ int sy = qMax(0, (int)floor(view_rect.top() * tiles_side));
+ int ex = qMin(tiles_side, (int)ceil(view_rect.right() * tiles_side));
+ int ey = qMin(tiles_side, (int)ceil(view_rect.bottom() * tiles_side));
+ double ts = 1. / tiles_side / qMax(view_rect.width(), view_rect.height()) * qMax(width(), height());
+ QPointF offset = view_rect.topLeft() * mins * scale_;
+ p.setRenderHint(QPainter::SmoothPixmapTransform);
+ p.setPen(Qt::white);
+ for (int ix = sx; ix < ex; ++ix) {
+ for (int iy = sy; iy < ey; ++iy) {
+ QRectF r((ix)*ts, (iy)*ts, ts, ts);
+ r.translate(-offset);
+ auto tile = cache->getTile((OSM::TileIndex){zoom_level, ix, iy});
+ if (!tile.isEmpty()) {
+ p.drawPixmap(r, tile.pixmap, QRectF(tile.pixmap.rect()));
+ } else {
+ p.fillRect(r, brush_tr);
+ }
+ // p.setPen(Qt::white);
+ // p.drawText(r, Qt::AlignCenter, QString("%1x%2").arg(ix).arg(iy));
+ }
+ }
+ // qDebug() << sx << sy << ex << ey << ts;
+ update();
+}
+
+
+void MapView::drawItems(QPainter & p) {
+ auto src_tr = p.transform();
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setRenderHint(QPainter::SmoothPixmapTransform);
+ QPoint mouse = mapFromGlobal(QCursor::pos());
+ MapItemBase * hover = nullptr;
+ for (auto * i: items_) {
+ if (!i->isVisible()) continue;
+ QPointF ipos = mapFromNorm(i->norm_pos);
+ p.setTransform(src_tr);
+ p.translate(ipos);
+ p.rotate(i->getRotation());
+ if (!i->ignore_scale) p.scale(i->getScale().x(), i->getScale().y());
+ i->draw(&p);
+ QTransform mtr;
+ mtr.rotate(-i->getRotation());
+ mtr.translate(-ipos.x(), -ipos.y());
+ QPoint m = mtr.map(mouse);
+ if (i->m_bounding.contains(m)) {
+ hover = i;
+ }
+ }
+ if (hover)
+ setCursor(hover->cursor());
+ else
+ unsetCursor();
+}
+
+
+void MapView::checkZoom() {
+ static const double max = 20;
+ if (zoom_ < 0.) zoom_ = 0.;
+ if (zoom_ > max) zoom_ = max;
+ double mins = qMin(width(), height()) / appScale(this);
+ scale_ = std::pow(2., zoom_) * tileSize / mins;
+ updateViewRect();
+}
+
+
+void MapView::zoomLevelChanged(int new_level) {
+ zoom_level = qBound(0, new_level, max_level);
+ // qDebug() << "level changed" << new_level << zoom_level;
+ tiles_side = 1 << zoom_level;
+ // for (int x = 0; x < tiles_side; ++x)
+ // for (int y = 0; y < tiles_side; ++y)
+ // downloader->queueTile(OSM::TileIndex{zoom_level, x, y});
+}
+
+
+void MapView::updateZoomLevel() {
+ int zl = qRound(zoom_);
+ if (zl != zoom_level) zoomLevelChanged(zl);
+}
+
+
+void MapView::updateViewRect() {
+ double mins = qMin(width(), height());
+ if (mins <= 0) return;
+ view_rect.setRect(0, 0, (width() / mins) / scale_, (height() / mins) / scale_);
+ view_rect.moveCenter(center_);
+ for (auto * i: items_)
+ i->zoomChanged();
+}
+
+
+void MapView::updateMouse(QPoint mouse) {
+ MapItemBase * new_hover = nullptr;
+ for (auto * i: items_) {
+ if (!i->isVisible() || !i->isInteracive()) continue;
+ QPointF ipos = mapFromNorm(i->norm_pos);
+ QTransform mtr;
+ if (!i->ignore_scale) mtr.scale(1. / i->getScale().x(), 1. / i->getScale().y());
+ mtr.rotate(-i->getRotation());
+ mtr.translate(-ipos.x(), -ipos.y());
+ QPoint m = mtr.map(mouse);
+ if (i->m_bounding.contains(m)) {
+ new_hover = i;
+ }
+ }
+ if (new_hover)
+ setCursor(new_hover->cursor());
+ else
+ unsetCursor();
+ if (new_hover != hover) {
+ if (hover) emit itemLeaved(hover);
+ if (new_hover) emit itemEntered(new_hover);
+ }
+ hover = new_hover;
+}
+
+
+double MapView::scalePx2M(QPointF norm) {
+ double lat = OSM::y2lat(norm.y()) * M_PI / 180.;
+ px2m = qMax(view_rect.width(), view_rect.height()) / qMax(width(), height()) * tileSize;
+ px2m *= 156543.03 * cos(lat);
+ // qDebug() << px2m << lat;
+ return px2m;
+}
+
+
+QPointF MapView::mapToNorm(QPoint screen) const {
+ QPointF s(screen.x() / (double)width(), screen.y() / (double)height());
+ return view_rect.topLeft() + QPointF(view_rect.width() * s.x(), view_rect.height() * s.y());
+}
+
+
+QPoint MapView::mapFromNorm(QPointF norm) const {
+ QPointF s = norm - view_rect.topLeft();
+ return QPoint(qRound((s.x() / view_rect.width()) * width()), qRound((s.y() / view_rect.height()) * height()));
+}
+
+
+void MapView::zoom(double factor) {
+ zoom(factor, rect().center());
+}
+
+
+void MapView::zoom(double factor, QPoint anchor) {
+ QPointF prev_center = mapToNorm(anchor);
+ zoom_ += (factor - 1.);
+ checkZoom();
+ QPointF new_center = mapToNorm(anchor);
+ center_ += prev_center - new_center;
+ view_rect.translate(prev_center - new_center);
+ updateZoomLevel();
+ drawBackground();
+}
+
+
+void MapView::zoomTo(double level) {
+ zoom_ = level;
+ checkZoom();
+ updateZoomLevel();
+ drawBackground();
+}
+
+
+void MapView::centerTo(QPointF coord) {
+ center_ = OSM::geo2xy(coord);
+ updateViewRect();
+ drawBackground();
+}
diff --git a/libs/map/mapview.h b/libs/map/mapview.h
new file mode 100644
index 0000000..b3e68e8
--- /dev/null
+++ b/libs/map/mapview.h
@@ -0,0 +1,104 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef mapview_h
+#define mapview_h
+
+#include "mapitembase.h"
+#include "qad_map_export.h"
+
+#include
+#include
+
+
+class OSMDownloader;
+class OSMTileCache;
+
+class QAD_MAP_EXPORT MapView: public QWidget {
+ Q_OBJECT
+ Q_PROPERTY(QPointF center READ center WRITE setCenter)
+ Q_PROPERTY(double zoom READ getZoom WRITE setZoom)
+
+ friend class OSMDownloader;
+ friend class OSMTileCache;
+ friend class MapItemBase;
+
+public:
+ explicit MapView(QWidget * parent = 0);
+ ~MapView();
+
+ void addItem(MapItemBase * item);
+ void removeItem(MapItemBase * item);
+
+ QPointF center() const;
+ void setCenter(QPointF c);
+
+ double getZoom() const { return zoom_; }
+ void setZoom(double z);
+
+private:
+ QSize sizeHint() const override { return QSize(200, 200); }
+ void mousePressEvent(QMouseEvent * e) override;
+ void mouseReleaseEvent(QMouseEvent * e) override;
+ void mouseDoubleClickEvent(QMouseEvent * e) override;
+ void mouseMoveEvent(QMouseEvent * e) override;
+ void wheelEvent(QWheelEvent * e) override;
+ void paintEvent(QPaintEvent *) override;
+ void resizeEvent(QResizeEvent *) override;
+ void drawBackground();
+ void drawItems(QPainter & p);
+ void checkZoom();
+ void zoomLevelChanged(int new_level);
+ void updateZoomLevel();
+ void updateViewRect();
+ void updateMouse(QPoint mouse);
+ double scalePx2M(QPointF norm);
+
+ QPointF mapToNorm(QPoint screen) const;
+ QPoint mapFromNorm(QPointF norm) const;
+
+ OSMDownloader * downloader = nullptr;
+ OSMTileCache * cache = nullptr;
+ MapItemBase * hover = nullptr;
+ QPointF center_ = QPointF(0.5, 0.5);
+ QPoint press_point;
+ QPixmap background;
+ QRectF view_rect;
+ QVector items_;
+ QBrush brush_tr;
+ bool is_pan = false;
+ double zoom_ = 1., scale_ = 1., px2m = 1.;
+ int zoom_level = 0, tiles_side = 1, max_level = 19;
+
+public slots:
+ void zoom(double factor);
+ void zoom(double factor, QPoint anchor);
+ void zoomTo(double level);
+ void centerTo(QPointF coord);
+
+private slots:
+
+signals:
+ void itemClicked(MapItemBase * item);
+ void itemEntered(MapItemBase * item);
+ void itemLeaved(MapItemBase * item);
+};
+
+
+#endif
diff --git a/libs/map/osm_downloader.cpp b/libs/map/osm_downloader.cpp
new file mode 100644
index 0000000..5229ed6
--- /dev/null
+++ b/libs/map/osm_downloader.cpp
@@ -0,0 +1,73 @@
+#include "mapview.h"
+#include "osm_downloader_p.h"
+#include "osm_tile_cache_p.h"
+
+
+OSMDownloader::OSMDownloader(MapView * p): QThread() {
+ qRegisterMetaType();
+ nam = new QNetworkAccessManager();
+ parent = p;
+ provider = "http://tile.openstreetmap.org";
+ start();
+}
+
+
+OSMDownloader::~OSMDownloader() {
+ requestInterruption();
+ cond.wakeAll();
+ wait();
+ delete nam;
+}
+
+
+void OSMDownloader::queueTile(OSM::TileIndex index) {
+ // auto hash = tile.hash();
+ cond_mutex.lock();
+ if (!queue.contains(index) && !in_progress.contains(index.hash())) {
+ queue.enqueue(index);
+ cond.wakeOne();
+ }
+ cond_mutex.unlock();
+}
+
+
+void OSMDownloader::requestTile(OSM::TileIndex index) {
+ QNetworkRequest req(provider + QString("/%1/%2/%3.png").arg(index.z).arg(index.x).arg(index.y));
+ req.setHeader(QNetworkRequest::UserAgentHeader, "Qt/5");
+ auto * r = nam->get(req);
+ if (!r) return;
+ connect(r, &QNetworkReply::finished, this, [this, r, index]() {
+ r->deleteLater();
+ if (r->error() != QNetworkReply::NoError) {
+ qDebug() << "Error:" << r->error();
+ } else {
+ QByteArray data = r->readAll();
+ if (!data.isEmpty()) {
+ QPixmap tim;
+ tim.loadFromData(data, "png");
+ if (!tim.isNull()) parent->cache->tileDownloaded(index, tim);
+ }
+ }
+ cond_mutex.lock();
+ in_progress.remove(index.hash());
+ cond_mutex.unlock();
+ });
+}
+
+
+void OSMDownloader::run() {
+ while (!isInterruptionRequested()) {
+ cond_mutex.lock();
+ if (queue.isEmpty())
+ cond.wait(&cond_mutex);
+ else {
+ auto t = queue.dequeue();
+ in_progress.insert(t.hash());
+ QMetaObject::invokeMethod(
+ parent,
+ [this, t]() { requestTile(t); },
+ Qt::QueuedConnection);
+ }
+ cond_mutex.unlock();
+ }
+}
diff --git a/libs/map/osm_downloader_p.h b/libs/map/osm_downloader_p.h
new file mode 100644
index 0000000..18fd9cd
--- /dev/null
+++ b/libs/map/osm_downloader_p.h
@@ -0,0 +1,66 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef osm_downloader_h
+#define osm_downloader_h
+
+#include "osm_types_p.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class MapView;
+
+class OSMDownloader: public QThread {
+ Q_OBJECT
+
+public:
+ explicit OSMDownloader(MapView * p);
+ ~OSMDownloader();
+
+ void queueTile(OSM::TileIndex index);
+
+
+private:
+ void run() override;
+ void requestTile(OSM::TileIndex index);
+
+ MapView * parent;
+ QNetworkAccessManager * nam = nullptr;
+ QString provider;
+ QWaitCondition cond;
+ QMutex cond_mutex;
+ QQueue queue;
+ QSet in_progress;
+
+public slots:
+
+private slots:
+
+signals:
+};
+
+
+#endif
diff --git a/libs/map/osm_math_p.h b/libs/map/osm_math_p.h
new file mode 100644
index 0000000..df52275
--- /dev/null
+++ b/libs/map/osm_math_p.h
@@ -0,0 +1,66 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef osm_math_p_h
+#define osm_math_p_h
+
+#include
+#include
+
+// lon -> -180..+180
+// lat -> -85.0511..+85.0511
+
+namespace OSM {
+
+
+inline double lng2x(double lon) {
+ return (lon + 180.0) / 360.0;
+}
+
+
+inline double lat2y(double lat) {
+ double latrad = lat * M_PI / 180.0;
+ return (1.0 - asinh(tan(latrad)) / M_PI) / 2.0;
+}
+
+
+inline double x2lng(double x) {
+ return x * 360.0 - 180;
+}
+
+
+inline double y2lat(double y) {
+ double n = M_PI - 2.0 * M_PI * y;
+ return 180.0 / M_PI * atan(0.5 * (exp(n) - exp(-n)));
+}
+
+
+inline QPointF xy2geo(QPointF p) {
+ return QPointF(y2lat(p.y()), x2lng(p.x()));
+}
+
+
+inline QPointF geo2xy(QPointF p) {
+ return QPointF(lng2x(p.y()), lat2y(p.x()));
+}
+
+
+} // namespace OSM
+
+#endif
diff --git a/libs/map/osm_tile_cache.cpp b/libs/map/osm_tile_cache.cpp
new file mode 100644
index 0000000..0f63253
--- /dev/null
+++ b/libs/map/osm_tile_cache.cpp
@@ -0,0 +1,100 @@
+#include "mapview.h"
+#include "osm_downloader_p.h"
+#include "osm_tile_cache_p.h"
+#include "qad_locations.h"
+
+
+OSMTileCache::OSMTileCache(MapView * p): QThread() {
+ qRegisterMetaType();
+ qRegisterMetaType();
+ parent = p;
+ cache_root = QAD::userPath(QAD::ltCache, "map_osm") + "/";
+ cache_dir.setPath(cache_root);
+ qDebug() << "[OSMTileCache] save cache to" << cache_root;
+ if (!cache_dir.exists()) cache_dir.mkpath(".");
+ setAdditionalCacheSize(64);
+ start();
+}
+
+
+OSMTileCache::~OSMTileCache() {
+ requestInterruption();
+ cond.wakeAll();
+ wait();
+}
+
+
+void OSMTileCache::tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap) {
+ auto * tile = new OSM::TilePixmap();
+ tile->index = index;
+ tile->pixmap = pixmap;
+ saveTile(tile);
+}
+
+
+OSM::TilePixmap OSMTileCache::getTile(OSM::TileIndex index) {
+ OSM::TilePixmap ret;
+ ret.index = index;
+ auto * tile = tile_cache[index.hash()];
+ if (tile) {
+ ret.pixmap = tile->pixmap;
+ } else {
+ QString hashdir = index.cacheDir();
+ if (cache_dir.exists(hashdir)) {
+ QString hashname = hashdir + "/" + index.hashName();
+ if (cache_dir.exists(hashname)) {
+ ret.pixmap.load(cache_dir.absoluteFilePath(hashname), "png");
+ tile = new OSM::TilePixmap();
+ tile->index = index;
+ tile->pixmap = ret.pixmap;
+ tile_cache.insert(tile->index.hash(), tile, tile->pixmapBytes());
+ return ret;
+ }
+ }
+ parent->downloader->queueTile(index);
+ }
+ return ret;
+}
+
+
+void OSMTileCache::updateCacheSize() {
+ tile_cache.setMaxCost(fixed_size_b + add_size_b);
+}
+
+
+void OSMTileCache::saveTile(OSM::TilePixmap * tile) {
+ tile_cache.insert(tile->index.hash(), tile, tile->pixmapBytes());
+ emit tileReady(*tile);
+ cond_mutex.lock();
+ if (!queue.contains(*tile)) {
+ queue.enqueue(*tile);
+ cond.wakeOne();
+ }
+ cond_mutex.unlock();
+}
+
+
+void OSMTileCache::writeToDisk(const OSM::TilePixmap & tile) {
+ QString hashdir = tile.index.cacheDir();
+ if (!cache_dir.exists(hashdir)) cache_dir.mkdir(hashdir);
+ QFile f(cache_dir.absoluteFilePath(hashdir + "/" + tile.index.hashName()));
+ if (!f.open(QIODevice::ReadWrite)) return;
+ f.resize(0);
+ tile.pixmap.save(&f, "png");
+}
+
+
+void OSMTileCache::run() {
+ while (!isInterruptionRequested()) {
+ OSM::TilePixmap tile;
+ cond_mutex.lock();
+ if (queue.isEmpty()) {
+ cond.wait(&cond_mutex);
+ cond_mutex.unlock();
+ } else {
+ tile = queue.dequeue();
+ cond_mutex.unlock();
+ writeToDisk(tile);
+ }
+ }
+}
diff --git a/libs/map/osm_tile_cache_p.h b/libs/map/osm_tile_cache_p.h
new file mode 100644
index 0000000..b3bcfe1
--- /dev/null
+++ b/libs/map/osm_tile_cache_p.h
@@ -0,0 +1,77 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef osm_tile_cache_h
+#define osm_tile_cache_h
+
+#include "osm_types_p.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+class MapView;
+
+class OSMTileCache: public QThread {
+ Q_OBJECT
+
+public:
+ explicit OSMTileCache(MapView * p);
+ ~OSMTileCache();
+
+ void setMinimumCacheSize(int bytes) {
+ fixed_size_b = bytes;
+ updateCacheSize();
+ }
+ void setAdditionalCacheSize(int mb) {
+ add_size_b = mb * 1024 * 1024;
+ updateCacheSize();
+ }
+
+ void tileDownloaded(OSM::TileIndex index, const QPixmap & pixmap);
+ OSM::TilePixmap getTile(OSM::TileIndex index);
+
+private:
+ void updateCacheSize();
+ void saveTile(OSM::TilePixmap * tile);
+ void writeToDisk(const OSM::TilePixmap & tile);
+ void run() override;
+
+ MapView * parent;
+ QString cache_root;
+ QDir cache_dir;
+ QWaitCondition cond;
+ QMutex cond_mutex;
+ int fixed_size_b = 0, add_size_b = 0;
+ QQueue queue;
+ QCache tile_cache;
+
+public slots:
+
+private slots:
+
+signals:
+ void tileReady(OSM::TilePixmap);
+};
+
+
+#endif
diff --git a/libs/map/osm_types.cpp b/libs/map/osm_types.cpp
new file mode 100644
index 0000000..e9ea923
--- /dev/null
+++ b/libs/map/osm_types.cpp
@@ -0,0 +1,62 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#include "osm_types_p.h"
+
+#include
+
+using namespace OSM;
+
+
+QString TileIndex ::hashName() const {
+ return QString("%1.%2.%3").arg(z).arg(x).arg(y);
+}
+
+
+quint64 TileIndex::hash() const {
+ union _Hash {
+ quint64 ret;
+ struct {
+ quint64 z: 8;
+ quint64 x: 24;
+ quint64 y: 24;
+ };
+ };
+ _Hash h;
+ h.ret = 0;
+ h.z = z;
+ h.x = x;
+ h.y = y;
+ return h.ret;
+}
+
+
+QString TileIndex::cacheDir() const {
+ return QString::number(qHash(hash()) % 256);
+};
+
+
+bool TilePixmap::isEmpty() const {
+ return pixmap.isNull();
+}
+
+
+int TilePixmap::pixmapBytes() const {
+ return pixmap.width() * pixmap.height() * pixmap.depth() / 8;
+}
diff --git a/libs/map/osm_types_p.h b/libs/map/osm_types_p.h
new file mode 100644
index 0000000..4203b26
--- /dev/null
+++ b/libs/map/osm_types_p.h
@@ -0,0 +1,56 @@
+/*
+ QAD - Qt ADvanced
+
+ Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef osm_types_h
+#define osm_types_h
+
+#include
+
+namespace OSM {
+
+struct TileIndex {
+ int z;
+ int x;
+ int y;
+ QString hashName() const;
+ quint64 hash() const;
+ QString cacheDir() const;
+};
+
+struct TilePixmap {
+ TileIndex index;
+ QPixmap pixmap;
+ bool isEmpty() const;
+ int pixmapBytes() const;
+};
+
+} // namespace OSM
+
+inline bool operator==(const OSM::TileIndex & v0, const OSM::TileIndex & v1) {
+ return (v0.z == v1.z) && (v0.x == v1.x) && (v0.y == v1.y);
+}
+
+inline bool operator==(const OSM::TilePixmap & v0, const OSM::TilePixmap & v1) {
+ return v0.index == v1.index;
+}
+
+Q_DECLARE_METATYPE(OSM::TileIndex);
+Q_DECLARE_METATYPE(OSM::TilePixmap);
+
+#endif
diff --git a/libs/map/plugin/CMakeLists.txt b/libs/map/plugin/CMakeLists.txt
new file mode 100644
index 0000000..ff0f90e
--- /dev/null
+++ b/libs/map/plugin/CMakeLists.txt
@@ -0,0 +1 @@
+qad_plugin(map "Gui;Widgets" "")
diff --git a/libs/map/plugin/mapplugin.cpp b/libs/map/plugin/mapplugin.cpp
new file mode 100644
index 0000000..6da93f5
--- /dev/null
+++ b/libs/map/plugin/mapplugin.cpp
@@ -0,0 +1,70 @@
+#include "mapplugin.h"
+
+#include "mapview.h"
+
+#include
+
+
+MapPlugin::MapPlugin(QObject * parent): QObject(parent) {
+ m_initialized = false;
+}
+
+
+void MapPlugin::initialize(QDesignerFormEditorInterface * /* core */) {
+ if (m_initialized) return;
+
+ // Add extension registrations, etc. here
+
+ m_initialized = true;
+}
+
+
+bool MapPlugin::isInitialized() const {
+ return m_initialized;
+}
+
+
+QWidget * MapPlugin::createWidget(QWidget * parent) {
+ MapView * w = new MapView(parent);
+ return w;
+}
+
+
+QString MapPlugin::name() const {
+ return QLatin1String("MapView");
+}
+
+
+QString MapPlugin::group() const {
+ return QLatin1String("Display Widgets");
+}
+
+
+QIcon MapPlugin::icon() const {
+ return QIcon("://icons/maps.png");
+}
+
+
+QString MapPlugin::toolTip() const {
+ return QLatin1String("");
+}
+
+
+QString MapPlugin::whatsThis() const {
+ return QLatin1String("");
+}
+
+
+bool MapPlugin::isContainer() const {
+ return false;
+}
+
+
+QString MapPlugin::domXml() const {
+ return QLatin1String("\n\n");
+}
+
+
+QString MapPlugin::includeFile() const {
+ return QLatin1String("mapview.h");
+}
diff --git a/libs/map/plugin/mapplugin.h b/libs/map/plugin/mapplugin.h
new file mode 100644
index 0000000..ecfddb6
--- /dev/null
+++ b/libs/map/plugin/mapplugin.h
@@ -0,0 +1,33 @@
+#ifndef MAPPLUGIN_H
+#define MAPPLUGIN_H
+
+#include
+#include
+
+
+class MapPlugin
+ : public QObject
+ , public QDesignerCustomWidgetInterface {
+ Q_OBJECT
+ Q_INTERFACES(QDesignerCustomWidgetInterface)
+
+public:
+ explicit MapPlugin(QObject * parent = 0);
+
+ bool isContainer() const;
+ bool isInitialized() const;
+ QIcon icon() const;
+ QString domXml() const;
+ QString group() const;
+ QString includeFile() const;
+ QString name() const;
+ QString toolTip() const;
+ QString whatsThis() const;
+ QWidget * createWidget(QWidget * parent);
+ void initialize(QDesignerFormEditorInterface * core);
+
+private:
+ bool m_initialized;
+};
+
+#endif
diff --git a/libs/map/plugin/mapview_designerplugin.cpp b/libs/map/plugin/mapview_designerplugin.cpp
new file mode 100644
index 0000000..0523614
--- /dev/null
+++ b/libs/map/plugin/mapview_designerplugin.cpp
@@ -0,0 +1,13 @@
+#include "mapview_designerplugin.h"
+
+#include "mapplugin.h"
+
+
+MapDesignerPlugin::MapDesignerPlugin(QObject * parent): QObject(parent) {
+ m_widgets.append(new MapPlugin(this));
+}
+
+
+QList MapDesignerPlugin::customWidgets() const {
+ return m_widgets;
+}
diff --git a/libs/map/plugin/mapview_designerplugin.h b/libs/map/plugin/mapview_designerplugin.h
new file mode 100644
index 0000000..b7ab702
--- /dev/null
+++ b/libs/map/plugin/mapview_designerplugin.h
@@ -0,0 +1,23 @@
+#ifndef MAP_DESIGNERPLUGIN_H
+#define MAP_DESIGNERPLUGIN_H
+
+#include
+#include
+
+
+class MapDesignerPlugin
+ : public QObject
+ , public QDesignerCustomWidgetCollectionInterface {
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "qad.map")
+ Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
+
+public:
+ MapDesignerPlugin(QObject * parent = 0);
+ virtual QList customWidgets() const;
+
+private:
+ QList m_widgets;
+};
+
+#endif
diff --git a/libs/map/qad_map.qrc b/libs/map/qad_map.qrc
new file mode 100644
index 0000000..6546225
--- /dev/null
+++ b/libs/map/qad_map.qrc
@@ -0,0 +1,5 @@
+
+
+ ../../icons/maps.png
+
+
diff --git a/utils/mapviewer/CMakeLists.txt b/utils/mapviewer/CMakeLists.txt
new file mode 100644
index 0000000..6d5a248
--- /dev/null
+++ b/utils/mapviewer/CMakeLists.txt
@@ -0,0 +1,15 @@
+find_package(PIP)
+if (PIP_FOUND)
+
+ project(mapviewer)
+ if(APPLE)
+ set(APP_ICON "")
+ elseif(WIN32)
+ set(APP_ICON "icons/maps.ico")
+ else()
+ set(APP_ICON "icons/maps.png")
+ endif()
+ set(APP_INFO "Map viewer")
+ qad_application(${PROJECT_NAME} "Gui;Widgets" "qad_map")
+
+endif()
diff --git a/utils/mapviewer/icons/maps.ico b/utils/mapviewer/icons/maps.ico
new file mode 100644
index 0000000..6853c7e
Binary files /dev/null and b/utils/mapviewer/icons/maps.ico differ
diff --git a/utils/mapviewer/icons/maps.png b/utils/mapviewer/icons/maps.png
new file mode 100644
index 0000000..ae68d54
Binary files /dev/null and b/utils/mapviewer/icons/maps.png differ
diff --git a/utils/mapviewer/main.cpp b/utils/mapviewer/main.cpp
new file mode 100644
index 0000000..054a865
--- /dev/null
+++ b/utils/mapviewer/main.cpp
@@ -0,0 +1,72 @@
+#include "mapitemellipse.h"
+#include "mapitemgeopolygon.h"
+#include "mapitemgeopolyline.h"
+#include "mapitemimage.h"
+#include "mapitempolygon.h"
+#include "mapitemtext.h"
+#include "mapview.h"
+#include "qad_types.h"
+
+#include
+#include
+#include
+#include
+#include
+
+int main(int argc, char * argv[]) {
+ QApplication a(argc, argv);
+ enableHighDPI();
+ MapView w;
+ w.resize(800, 600);
+ w.show();
+ /*QVector g = {QPointF(55.583055, 37.580008), QPointF(55.583055, 37.590008), QPointF(55.593055, 37.580008)};
+ QVector p = {QPointF(0, 0), QPointF(200, 0), QPointF(0, 100)};
+ MapItemPolygon * pol = new MapItemPolygon(QPolygonF(p));
+ MapItemGeoPolyline * gpol = new MapItemGeoPolyline(QPolygonF(g));
+ MapItemEllipse * ell = new MapItemEllipse(QPointF(), 50, 50);
+ MapItemImage * im = new MapItemImage(QPixmap(":/icons/maps.png"));
+ MapItemText * it = new MapItemText(QString::fromUtf8("Это Ваня!"));
+ im->setPosition({55.583055, 37.580008});
+ im->setScale(0.2, 0.5);
+ im->setAlignment(Qt::AlignRight | Qt::AlignTop);
+ im->setCursor(Qt::PointingHandCursor);
+ im->setInteracive(true);
+ it->setPosition({55.583055, 37.580008});
+ it->setBrush(QColor(127, 0, 0, 127));
+ it->setPen(QColor(64, 255, 64));
+ it->setFont(QFont("times", 18));
+ it->setCursor(Qt::OpenHandCursor);
+ it->setInteracive(true);
+ pol->setPosition({55.583055, 37.580008});
+ pol->setUnits(MapItemNonGeoGeometryBase::Pixels);
+ gpol->setBrush(QColor(0, 0, 255, 64));
+ gpol->setPen(QPen(QColor(64, 64, 255), 3));
+ ell->setPosition({55.583055, 37.580008});
+ ell->setStartAngle(-20);
+ ell->setEndAngle(20);
+ ell->setEllipse(QPointF(100, 0), 50, 50);
+ ell->setInteracive(true);
+ QTimer t;
+ QObject::connect(&w, &MapView::itemClicked, [](MapItemBase * item) { qDebug() << "click" << item; });
+ QObject::connect(&w, &MapView::itemEntered, [](MapItemBase * item) { qDebug() << "enter" << item; });
+ QObject::connect(&w, &MapView::itemLeaved, [](MapItemBase * item) { qDebug() << "leave" << item; });
+
+ QObject::connect(&t, &QTimer::timeout, [im, it, pol, ell]() {
+ im->rotate(1);
+ it->rotate(-0.1);
+ // pol->rotate(0.2);
+ ell->rotate(-0.2);
+ static double t = 0.;
+ t += 0.025;
+ ell->setScale((sin(t) / 2. + 1.));
+ });
+ t.start(100);
+ w.addItem(im);
+ w.addItem(gpol);
+ w.addItem(pol);
+ w.addItem(it);
+ w.addItem(ell);*/
+ w.centerTo({55.583055, 37.580008});
+ w.zoomTo(17);
+ return a.exec();
+}
diff --git a/utils/mapviewer/mapviewer.qrc b/utils/mapviewer/mapviewer.qrc
new file mode 100644
index 0000000..f49b0df
--- /dev/null
+++ b/utils/mapviewer/mapviewer.qrc
@@ -0,0 +1,5 @@
+
+
+ icons/maps.png
+
+