Commit a22db7f4 authored by Valentin Platzgummer's avatar Valentin Platzgummer

Tiles added to WimaMeasurementArea

parent a0c951cb
#include "WimaMeasurementArea.h" #include "WimaMeasurementArea.h"
#include "QtConcurrentRun"
#include "SnakeTile.h" #include "SnakeTile.h"
#include "snake.h" #include "snake.h"
#include <boost/units/systems/si.hpp> #include <boost/units/systems/si.hpp>
#ifndef SNAKE_MAX_TILES
#define SNAKE_MAX_TILES 1000
#endif
const char *WimaMeasurementArea::settingsGroup = "MeasurementArea"; const char *WimaMeasurementArea::settingsGroup = "MeasurementArea";
const char *WimaMeasurementArea::tileHeightName = "TileHeight"; const char *WimaMeasurementArea::tileHeightName = "TileHeight";
const char *WimaMeasurementArea::tileWidthName = "TileWidth"; const char *WimaMeasurementArea::tileWidthName = "TileWidth";
...@@ -13,6 +18,8 @@ const char *WimaMeasurementArea::minTransectLengthName = "MinTransectLength"; ...@@ -13,6 +18,8 @@ const char *WimaMeasurementArea::minTransectLengthName = "MinTransectLength";
const char *WimaMeasurementArea::showTilesName = "ShowTiles"; const char *WimaMeasurementArea::showTilesName = "ShowTiles";
const char *WimaMeasurementArea::WimaMeasurementAreaName = "Measurement Area"; const char *WimaMeasurementArea::WimaMeasurementAreaName = "Measurement Area";
void tileDeleter(QmlObjectListModel *tiles) { tiles->clearAndDeleteContents(); }
WimaMeasurementArea::WimaMeasurementArea(QObject *parent) WimaMeasurementArea::WimaMeasurementArea(QObject *parent)
: WimaArea(parent), : WimaArea(parent),
_metaDataMap(FactMetaData::createMapFromJsonFile( _metaDataMap(FactMetaData::createMapFromJsonFile(
...@@ -32,7 +39,8 @@ WimaMeasurementArea::WimaMeasurementArea(QObject *parent) ...@@ -32,7 +39,8 @@ WimaMeasurementArea::WimaMeasurementArea(QObject *parent)
this /* QObject parent */)), this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)), this /* QObject parent */)),
_calculating(false) { _pTiles(new QmlObjectListModel(), &tileDeleter), _calculating(false),
_polygonValid(false) {
init(); init();
} }
...@@ -56,7 +64,8 @@ WimaMeasurementArea::WimaMeasurementArea(const WimaMeasurementArea &other, ...@@ -56,7 +64,8 @@ WimaMeasurementArea::WimaMeasurementArea(const WimaMeasurementArea &other,
this /* QObject parent */)), this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName],
this /* QObject parent */)), this /* QObject parent */)),
_calculating(false) { _pTiles(new QmlObjectListModel(), &tileDeleter), _calculating(false),
_polygonValid(false) {
init(); init();
} }
...@@ -73,7 +82,7 @@ operator=(const WimaMeasurementArea &other) { ...@@ -73,7 +82,7 @@ operator=(const WimaMeasurementArea &other) {
} }
WimaMeasurementArea::~WimaMeasurementArea() { WimaMeasurementArea::~WimaMeasurementArea() {
this->_tiles.clearAndDeleteContents(); this->_pTiles->clearAndDeleteContents();
} }
QString WimaMeasurementArea::mapVisualQML() const { QString WimaMeasurementArea::mapVisualQML() const {
...@@ -96,6 +105,12 @@ Fact *WimaMeasurementArea::minTransectLength() { return &_minTransectLength; } ...@@ -96,6 +105,12 @@ Fact *WimaMeasurementArea::minTransectLength() { return &_minTransectLength; }
Fact *WimaMeasurementArea::showTiles() { return &_showTiles; } Fact *WimaMeasurementArea::showTiles() { return &_showTiles; }
QmlObjectListModel *WimaMeasurementArea::tiles() { return this->_pTiles.get(); }
int WimaMeasurementArea::maxTiles() { return SNAKE_MAX_TILES; }
bool WimaMeasurementArea::ready() { return !_calculating; }
void WimaMeasurementArea::saveToJson(QJsonObject &json) { void WimaMeasurementArea::saveToJson(QJsonObject &json) {
this->WimaArea::saveToJson(json); this->WimaArea::saveToJson(json);
json[tileHeightName] = _tileHeight.rawValue().toDouble(); json[tileHeightName] = _tileHeight.rawValue().toDouble();
...@@ -160,41 +175,72 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json, ...@@ -160,41 +175,72 @@ bool WimaMeasurementArea::loadFromJson(const QJsonObject &json,
return false; return false;
} }
} }
//!
//! \brief WimaMeasurementArea::doUpdate
//! \pre WimaMeasurementArea::deferUpdate must be called first, don't call this
//! function directly!
void WimaMeasurementArea::doUpdate() { void WimaMeasurementArea::doUpdate() {
using namespace snake; using namespace snake;
using namespace boost::units; using namespace boost::units;
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
#endif #endif
auto polygon = this->coordinateList(); const auto height = this->_tileHeight.rawValue().toDouble() * si::meter;
for (auto &v : polygon) { const auto width = this->_tileWidth.rawValue().toDouble() * si::meter;
v.setAltitude(0); const auto tileArea = width * height;
} const auto totalArea = this->area() * si::meter * si::meter;
if (polygon.size() > 3) { const auto estNumTiles = totalArea / tileArea;
QGeoCoordinate origin = polygon.first(); if (!this->_calculating &&
BoostPolygon polygonENU; long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES &&
areaToEnu(origin, polygon, polygonENU); this->count() >= 3 && this->isSimplePolygon()) {
Length height = this->_tileHeight.rawValue().toDouble() * si::meter; this->_calculating = true;
Length width = this->_tileWidth.rawValue().toDouble() * si::meter; if (!this->_polygonValid) {
Area minArea = this->_polygon = this->coordinateList();
for (auto &v : this->_polygon) {
v.setAltitude(0);
}
this->_polygonValid = true;
}
const auto &polygon = this->_polygon;
const auto minArea =
this->_minTileArea.rawValue().toDouble() * si::meter * si::meter; this->_minTileArea.rawValue().toDouble() * si::meter * si::meter;
std::vector<BoostPolygon> tilesENU; auto *th = this->thread();
BoundingBox bbox; auto future = QtConcurrent::run([polygon, th, height, width, minArea] {
std::string errorString; #ifdef SNAKE_SHOW_TIME
if (snake::tiles(polygonENU, height, width, minArea, tilesENU, bbox, auto start = std::chrono::high_resolution_clock::now();
errorString)) { #endif
this->_tiles.clearAndDeleteContents(); TilesPtr pTiles(new QmlObjectListModel(), &tileDeleter);
for (const auto &t : tilesENU) { QGeoCoordinate origin = polygon.first();
auto geoTile = new SnakeTile(&this->_tiles); BoostPolygon polygonENU;
for (const auto &v : t.outer()) { areaToEnu(origin, polygon, polygonENU);
QGeoCoordinate geoVertex; std::vector<BoostPolygon> tilesENU;
fromENU(origin, v, geoVertex); BoundingBox bbox;
geoTile->push_back(geoVertex); std::string errorString;
if (snake::tiles(polygonENU, height, width, minArea, tilesENU, bbox,
errorString)) {
for (const auto &t : tilesENU) {
auto geoTile = new SnakeTile(pTiles.get());
for (const auto &v : t.outer()) {
QGeoCoordinate geoVertex;
fromENU(origin, v, geoVertex);
geoTile->push_back(geoVertex);
}
pTiles->append(geoTile);
} }
this->_tiles.append(geoTile);
} }
} pTiles->moveToThread(th);
#ifdef SNAKE_SHOW_TIME
qDebug()
<< "WimaMeasurementArea::doUpdate concurrent update execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
#endif
return pTiles;
}); // QtConcurrent::run()
this->_watcher.setFuture(future);
} }
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
qDebug() << "WimaMeasurementArea::doUpdate execution time: " qDebug() << "WimaMeasurementArea::doUpdate execution time: "
...@@ -209,9 +255,30 @@ void WimaMeasurementArea::deferUpdate() { ...@@ -209,9 +255,30 @@ void WimaMeasurementArea::deferUpdate() {
if (this->_timer.isActive()) { if (this->_timer.isActive()) {
this->_timer.stop(); this->_timer.stop();
} }
if (this->_pTiles->count() > 0) {
this->_pTiles->clearAndDeleteContents();
emit this->tilesChanged();
}
this->_timer.start(100); this->_timer.start(100);
} }
void WimaMeasurementArea::storeTiles() {
#ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now();
#endif
this->_pTiles = this->_watcher.result();
this->_calculating = false;
emit this
->tilesChanged(); // This is expensive. Drawing tiles is expensive too.
#ifdef SNAKE_SHOW_TIME
qDebug() << "WimaMeasurementArea::storeTiles() execution time: "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start)
.count()
<< " ms";
#endif
}
void WimaMeasurementArea::init() { void WimaMeasurementArea::init() {
this->setObjectName(WimaMeasurementAreaName); this->setObjectName(WimaMeasurementAreaName);
connect(&this->_tileHeight, &Fact::rawValueChanged, this, connect(&this->_tileHeight, &Fact::rawValueChanged, this,
...@@ -222,15 +289,20 @@ void WimaMeasurementArea::init() { ...@@ -222,15 +289,20 @@ void WimaMeasurementArea::init() {
&WimaMeasurementArea::deferUpdate); &WimaMeasurementArea::deferUpdate);
connect(this, &WimaArea::pathChanged, this, connect(this, &WimaArea::pathChanged, this,
&WimaMeasurementArea::deferUpdate); &WimaMeasurementArea::deferUpdate);
connect(this, &WimaArea::pathChanged,
[this] { this->_polygonValid = false; });
this->_timer.setSingleShot(true); this->_timer.setSingleShot(true);
connect(&this->_timer, &QTimer::timeout, this, connect(&this->_timer, &QTimer::timeout, this,
&WimaMeasurementArea::doUpdate); &WimaMeasurementArea::doUpdate);
connect(&this->_watcher,
&QFutureWatcher<std::unique_ptr<QmlObjectListModel>>::finished, this,
&WimaMeasurementArea::storeTiles);
} }
/*! /*!
* \class WimaMeasurementArea * \class WimaMeasurementArea
* \brief Class defining the area inside which the actual drone measurements are * \brief Class defining the area inside which the actual drone measurements
* performed. * are performed.
* *
* \sa WimaArea, WimaController, WimaPlaner * \sa WimaArea, WimaController, WimaPlaner
*/ */
#pragma once #pragma once
#include <QFutureWatcher>
#include <QObject> #include <QObject>
#include <QTimer> #include <QTimer>
...@@ -22,6 +23,8 @@ public: ...@@ -22,6 +23,8 @@ public:
Q_PROPERTY(Fact *transectDistance READ transectDistance CONSTANT) Q_PROPERTY(Fact *transectDistance READ transectDistance CONSTANT)
Q_PROPERTY(Fact *minTransectLength READ minTransectLength CONSTANT) Q_PROPERTY(Fact *minTransectLength READ minTransectLength CONSTANT)
Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT) Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT)
Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged)
Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged)
// Overrides from WimaPolygon // Overrides from WimaPolygon
QString mapVisualQML(void) const; QString mapVisualQML(void) const;
...@@ -33,6 +36,9 @@ public: ...@@ -33,6 +36,9 @@ public:
Fact *transectDistance(); Fact *transectDistance();
Fact *minTransectLength(); Fact *minTransectLength();
Fact *showTiles(); Fact *showTiles();
QmlObjectListModel *tiles();
int maxTiles();
bool ready();
// Member Methodes // Member Methodes
void saveToJson(QJsonObject &json); void saveToJson(QJsonObject &json);
...@@ -53,12 +59,15 @@ public: ...@@ -53,12 +59,15 @@ public:
static const char *WimaMeasurementAreaName; static const char *WimaMeasurementAreaName;
signals: signals:
void tilesChanged();
void maxTilesChanged();
public slots: public slots:
private slots: private slots:
void doUpdate(); void doUpdate();
void deferUpdate(); void deferUpdate();
void storeTiles();
private: private:
// Member Methodes // Member Methodes
...@@ -76,6 +85,10 @@ private: ...@@ -76,6 +85,10 @@ private:
// Tile stuff. // Tile stuff.
QTimer _timer; QTimer _timer;
std::atomic_bool _calculating; using TilesPtr = std::shared_ptr<QmlObjectListModel>;
QmlObjectListModel _tiles; TilesPtr _pTiles;
QList<QGeoCoordinate> _polygon;
QFutureWatcher<TilesPtr> _watcher;
bool _calculating;
bool _polygonValid;
}; };
...@@ -178,6 +178,12 @@ Rectangle { ...@@ -178,6 +178,12 @@ Rectangle {
QGCLabel { text: qsTr("Nodes") } QGCLabel { text: qsTr("Nodes") }
QGCLabel { text: areaItem.count } QGCLabel { text: areaItem.count }
QGCLabel { text: qsTr("Tiles") }
QGCLabel { text: areaItem.tiles.count }
QGCLabel { text: qsTr("Max. Tiles") }
QGCLabel { text: areaItem.maxTiles }
} }
} // Column } // Column
} // Rectangle } // Rectangle
...@@ -85,7 +85,7 @@ Item { ...@@ -85,7 +85,7 @@ Item {
Component.onDestruction: { Component.onDestruction: {
} }
// Polygon
WimaMapPolygonVisuals { WimaMapPolygonVisuals {
qgcView: _root.qgcView qgcView: _root.qgcView
mapControl: map mapControl: map
...@@ -96,6 +96,7 @@ Item { ...@@ -96,6 +96,7 @@ Item {
interiorOpacity: 0.25 interiorOpacity: 0.25
} }
// Border Polygon
WimaMapPolygonVisuals { WimaMapPolygonVisuals {
qgcView: _root.qgcView qgcView: _root.qgcView
mapControl: map mapControl: map
...@@ -106,4 +107,40 @@ Item { ...@@ -106,4 +107,40 @@ Item {
interiorOpacity: 1 interiorOpacity: 1
} }
// Add Snake tiles to the map
Component {
id: tileComponent
MapPolygon {
color: "transparent"
opacity: 1
border.color: "black"
border.width: 1
path: []
}
}
Repeater {
property bool enable: areaItem.showTiles.value
model: enable ? areaItem.tiles : 0
Item{
property var _tileComponent
function addVisuals() {
_tileComponent = tileComponent.createObject(map)
map.addMapItem(_tileComponent)
_tileComponent.path = object.path
}
function removeVisuals() {
_tileComponent.destroy()
}
Component.onCompleted: {
addVisuals()
}
Component.onDestruction: {
removeVisuals()
}
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment