Commit a22db7f4 authored by Valentin Platzgummer's avatar Valentin Platzgummer

Tiles added to WimaMeasurementArea

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