Commit 4948045b authored by Valentin Platzgummer's avatar Valentin Platzgummer

MeasurementArea prepared for new NemoInterface

parent 0e658bb3
......@@ -226,11 +226,6 @@ contains (DEFINES, DISABLE_AIRMAP) {
}
}
# GeograpicLib (TODO: add Windows support!)
LinuxBuild {
LIBS += -L$$PWD/libs/libGeographic -lGeographic # libGeograpic.so.17
}
# google or-tools (TODO: add Windows support!)
LinuxBuild {
OR_TOOLS_PATH = $$PWD/libs/or-tools-src-ubuntu
......
......@@ -445,7 +445,11 @@ contains (DEFINES, QGC_ENABLE_PAIRING) {
#
HEADERS += \
src/MeasurementComplexItem/geometry/ProgressArray.h \
src/MeasurementComplexItem/geometry/TileDiff.h \
src/MeasurementComplexItem/geometry/geometry.h \
src/MeasurementComplexItem/HashFunctions.h \
src/MeasurementComplexItem/nemo_interface/MeasurementTile.h \
src/QmlControls/QmlUnitsConversion.h \
src/MeasurementComplexItem/geometry/GeoArea.h \
src/MeasurementComplexItem/geometry/MeasurementArea.h \
......@@ -487,7 +491,6 @@ HEADERS += \
src/MeasurementComplexItem/nemo_interface/QNemoHeartbeat.h \
src/MeasurementComplexItem/nemo_interface/QNemoProgress.h \
src/MeasurementComplexItem/nemo_interface/QNemoProgress.h \
src/MeasurementComplexItem/nemo_interface/SnakeTile.h \
src/MeasurementComplexItem/nemo_interface/SnakeTileLocal.h \
src/MeasurementComplexItem/nemo_interface/SnakeTiles.h \
src/MeasurementComplexItem/nemo_interface/SnakeTilesLocal.h \
......@@ -498,6 +501,7 @@ HEADERS += \
src/api/QmlComponentInfo.h \
src/GPS/Drivers/src/base_station.h \
src/Settings/WimaSettings.h \
src/comm/QmlObjectListHelper.h \
src/comm/ros_bridge/include/RosBridgeClient.h \
src/comm/ros_bridge/include/com_private.h \
src/comm/ros_bridge/include/message_traits.h \
......@@ -525,6 +529,8 @@ SOURCES += \
src/MeasurementComplexItem/geometry/MeasurementArea.cc \
src/MeasurementComplexItem/geometry/SafeArea.cc \
src/MeasurementComplexItem/geometry/geometry.cpp \
src/MeasurementComplexItem/HashFunctions.cpp \
src/MeasurementComplexItem/nemo_interface/MeasurementTile.cpp \
src/Vehicle/VehicleEscStatusFactGroup.cc \
src/MeasurementComplexItem/AreaData.cc \
src/api/QGCCorePlugin.cc \
......@@ -541,7 +547,7 @@ SOURCES += \
src/MeasurementComplexItem/geometry/GeoPoint3D.cpp \
src/MeasurementComplexItem/NemoInterface.cpp \
src/MeasurementComplexItem/nemo_interface/QNemoProgress.cc \
src/MeasurementComplexItem/nemo_interface/SnakeTile.cpp \
src/comm/QmlObjectListHelper.cpp \
src/comm/ros_bridge/include/RosBridgeClient.cpp \
src/comm/ros_bridge/include/com_private.cpp \
src/comm/ros_bridge/include/messages/geographic_msgs/geopoint.cpp \
......
......@@ -10,7 +10,7 @@
#include "geometry/MeasurementArea.h"
#include "geometry/SafeArea.h"
#include "geometry/clipper/clipper.hpp"
#include "nemo_interface/SnakeTile.h"
#include "nemo_interface/MeasurementTile.h"
QGC_LOGGING_CATEGORY(CircularGeneratorLog, "CircularGeneratorLog")
......@@ -118,31 +118,22 @@ bool CircularGenerator::get(Work &work) {
auto pPolygon = std::make_shared<geometry::FPolygon>();
geometry::areaToEnu(origin, geoPolygon, *pPolygon);
// Progress and tiles.
const auto &progress = measurementArea->progress();
// Collect tiles with progress == 100 %.
const auto *tiles = measurementArea->tiles();
auto pTiles = std::make_shared<std::vector<geometry::FPolygon>>();
if (progress.size() == tiles->count()) {
for (int i = 0; i < tiles->count(); ++i) {
if (progress[i] == 100) {
const auto *obj = (*tiles)[int(i)];
const auto *tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
geometry::FPolygon tileENU;
geometry::areaToEnu(origin, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
} else {
qCDebug(CircularGeneratorLog)
<< "get(): progress.size() != tiles->count().";
return false;
}
for (int i = 0; i < tiles->count(); ++i) {
const auto tile =
qobject_cast<const MeasurementTile *>(tiles->operator[](i));
if (tile != nullptr) {
if (qFuzzyCompare(tile->progress(), 100)) {
geometry::FPolygon tileENU;
geometry::areaToEnu(origin, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
}
} else {
qCDebug(CircularGeneratorLog) << "get(): tile == nullptr.";
return false;
}
} else {
qCDebug(CircularGeneratorLog)
<< "get(): progress.size() != tiles->count().";
return false;
}
auto serviceArea = getGeoArea<const SafeArea *>(*this->_d->areaList());
......
#ifndef HASHFUNCTIONS_H
#define HASHFUNCTIONS_H
#include <QGeoCoordinate>
#include <functional>
#include <QmlObjectListModel.h>
namespace std {
template <> struct hash<QGeoCoordinate> {
std::size_t operator()(const QGeoCoordinate &c) {
hash<double> h;
return h(c.latitude()) ^ h(c.longitude()) ^ h(c.altitude());
}
};
template <template <class> class Container, class EntryType>
struct hash<Container<EntryType>> {
std::size_t operator()(const Container<EntryType> &list) {
std::size_t value = 0;
hash<EntryType> h;
for (const auto it = std::begin(list); it != std::end(list); ++it) {
value ^= h(*it);
}
return value;
}
};
} // namespace std
#endif // HASHFUNCTIONS_H
......@@ -9,7 +9,7 @@
#include "geometry/clipper/clipper.hpp"
#include "RoutingThread.h"
#include "nemo_interface/SnakeTile.h"
#include "nemo_interface/MeasurementTile.h"
namespace routing {
......@@ -100,29 +100,21 @@ bool LinearGenerator::get(Work &generator) {
geometry::areaToEnu(origin, geoPolygon, *pPolygon);
// Progress and tiles.
const auto &progress = measurementArea->progress();
const auto *tiles = measurementArea->tiles();
auto pTiles = std::make_shared<std::vector<geometry::FPolygon>>();
if (progress.size() == tiles->count()) {
for (int i = 0; i < tiles->count(); ++i) {
if (progress[i] == 100) {
const QObject *obj = (*tiles)[int(i)];
const auto *tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
geometry::FPolygon tileENU;
geometry::areaToEnu(origin, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
} else {
qCDebug(LinearGeneratorLog) << "get(): tile == nullptr";
return false;
}
for (int i = 0; i < tiles->count(); ++i) {
const auto tile =
qobject_cast<const MeasurementTile *>(tiles->operator[](i));
if (qFuzzyCompare(tile->progress(), 100)) {
if (tile != nullptr) {
geometry::FPolygon tileENU;
geometry::areaToEnu(origin, tile->coordinateList(), tileENU);
pTiles->push_back(std::move(tileENU));
} else {
qCDebug(LinearGeneratorLog) << "get(): tile == nullptr";
return false;
}
}
} else {
qCDebug(LinearGeneratorLog)
<< "get(): progress.size() != tiles->count().";
return false;
}
auto serviceArea = getGeoArea<const SafeArea *>(*this->_d->areaList());
......
......@@ -8,7 +8,7 @@
#include "geometry/SafeArea.h"
#include "geometry/clipper/clipper.hpp"
#include "geometry/geometry.h"
#include "nemo_interface/SnakeTile.h"
#include "nemo_interface/MeasurementTile.h"
// QGC
#include "JsonHelper.h"
......
......@@ -17,7 +17,7 @@
#include "geometry/geometry.h"
#include "nemo_interface/QNemoHeartbeat.h"
#include "nemo_interface/QNemoProgress.h"
#include "nemo_interface/SnakeTile.h"
#include "nemo_interface/MeasurementTile.h"
#include "ros_bridge/include/messages/geographic_msgs/geopoint.h"
#include "ros_bridge/include/messages/jsk_recognition_msgs/polygon_array.h"
......@@ -158,7 +158,7 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
UniqueLock lk2(this->tilesENUMutex, std::adopt_lock);
const auto *obj = tileData.tiles[0];
const auto *tile = qobject_cast<const SnakeTile *>(obj);
const auto *tile = qobject_cast<const MeasurementTile *>(obj);
if (tile != nullptr) {
if (tile->coordinateList().size() > 0) {
if (tile->coordinateList().first().isValid()) {
......@@ -167,7 +167,7 @@ void NemoInterface::Impl::setTileData(const TileData &tileData) {
this->tilesENU.polygons().clear();
for (int i = 0; i < tileData.tiles.count(); ++i) {
obj = tileData.tiles[i];
tile = qobject_cast<const SnakeTile *>(obj);
tile = qobject_cast<const MeasurementTile *>(obj);
if (tile != nullptr) {
SnakeTileLocal tileENU;
geometry::areaToEnu(origin, tile->coordinateList(), tileENU.path());
......
#include "MeasurementArea.h"
#include "QtConcurrentRun"
#include "HashFunctions.h"
#include "geometry.h"
#include "nemo_interface/SnakeTile.h"
#include "nemo_interface/MeasurementTile.h"
#include <ctime>
#include "QtConcurrentRun"
#include <QJsonArray>
#include <QQmlEngine>
#include <boost/units/systems/si.hpp>
#include "JsonHelper.h"
#include "QGCLoggingCategory.h"
#include "QmlObjectListHelper.h"
#include <QJsonArray>
#ifndef SNAKE_MAX_TILES
#define SNAKE_MAX_TILES 1000
#ifndef MAX_TILES
#define MAX_TILES 1000
#endif
using namespace geometry;
......@@ -26,142 +30,31 @@ bool getTiles(const FPolygon &area, Length tileHeight, Length tileWidth,
QGC_LOGGING_CATEGORY(MeasurementAreaLog, "MeasurementAreaLog")
namespace {
const char *tileCenterPointsKey = "TileCenterPoints";
const char *tileArrayKey = "TileArray";
} // namespace
TileData::TileData() : tiles(this) {}
TileData::~TileData() { tiles.clearAndDeleteContents(); }
TileData &TileData::operator=(const TileData &other) {
this->tiles.clearAndDeleteContents();
for (std::size_t i = 0; i < std::size_t(other.tiles.count()); ++i) {
const auto *obj = other.tiles[i];
const auto *tile = qobject_cast<const SnakeTile *>(obj);
if (tile != nullptr) {
this->tiles.append(tile->clone(this));
} else {
qCWarning(MeasurementAreaLog) << "TileData::operator=: nullptr";
}
}
this->tileCenterPoints = other.tileCenterPoints;
return *this;
}
bool TileData::operator==(const TileData &other) const {
if (this->tileCenterPoints == other.tileCenterPoints &&
this->tiles.count() == other.tiles.count()) {
for (int i = 0; i < other.tiles.count(); ++i) {
if (this->tiles[i] != other.tiles[i]) {
return false;
}
}
return true;
} else {
return false;
}
}
TileData::TileData() {}
TileData::~TileData() {}
TileData &TileData::operator=(const TileData &other) { return *this; }
bool TileData::operator==(const TileData &other) const { return false; }
bool TileData::operator!=(const TileData &other) const {
return !this->operator==(other);
}
void TileData::saveToJson(QJsonObject &json) {
// save center points
QJsonValue jsonCenterPoints;
JsonHelper::saveGeoCoordinateArray(tileCenterPoints, false, jsonCenterPoints);
json[tileCenterPointsKey] = std::move(jsonCenterPoints);
// save tiles
QJsonArray jsonTiles;
for (int i = 0; i < tiles.count(); ++i) {
auto tile = tiles.value<SnakeTile *>(i);
if (tile != nullptr) {
QJsonObject jsonTile;
tile->saveToJson(jsonTile);
jsonTiles.append(jsonTile);
} else {
qCritical() << "TileData::saveToJson(): Object other than SnakeTile "
"inside tiles (QmlObjectListModel))";
Q_ASSERT(tile != nullptr);
}
}
json[tileArrayKey] = std::move(jsonTiles);
return operator==(other);
}
void TileData::saveToJson(QJsonObject &json) {}
bool TileData::loadFromJson(const QJsonObject &json, QString &errorString) {
clear();
// load tiles
if (json.contains(tileArrayKey) && json[tileArrayKey].isArray()) {
QString e;
for (const auto &jsonTile : json[tileArrayKey].toArray()) {
auto tile = new SnakeTile(this);
if (tile->loadFromJson(jsonTile.toObject(), e)) {
tiles.append(tile);
} else {
tile->deleteLater();
errorString.append(e);
return false;
}
}
} else {
errorString.append(tr("Not able to load tiles.\n"));
qCWarning(MeasurementAreaLog)
<< "Not able to load tiles. tileArrayKey missing or wrong type.";
if (json.contains(tileArrayKey)) {
qCWarning(MeasurementAreaLog)
<< "tile array type: " << json[tileArrayKey].type();
}
return false;
}
// load center points
if (json.contains(tileCenterPointsKey) &&
json[tileCenterPointsKey].isArray()) {
QString e;
if (!JsonHelper::loadGeoCoordinateArray(json[tileCenterPointsKey], false,
tileCenterPoints, e)) {
errorString.append(e);
errorString.append("\n");
return false;
}
} else {
errorString.append(tr("Not able to load center points.\n"));
qCWarning(MeasurementAreaLog)
<< "Not able to load center points. tileCenterPointsKey missing or "
"wrong type.";
if (json.contains(tileCenterPointsKey)) {
qCWarning(MeasurementAreaLog)
<< "center points type: " << json[tileCenterPointsKey].type();
}
return false;
}
return true;
}
void TileData::clear() {
this->tiles.clearAndDeleteContents();
this->tileCenterPoints.clear();
return false;
}
size_t TileData::size() const {
if (tiles.count() == tileCenterPoints.size()) {
return tiles.count();
} else {
return 0;
}
}
void TileData::clear() {}
std::size_t TileData::size() const { return 0; }
const char *MeasurementArea::settingsGroup = "MeasurementArea";
const char *tileHeightKey = "TileHeight";
const char *tileWidthName = "TileWidth";
const char *minTileAreaKey = "MinTileAreaPercent";
const char *showTilesKey = "ShowTiles";
const char *progressKey = "Progress";
const char *tileKey = "Tiles";
const char *MeasurementArea::nameString = "Measurement Area";
......@@ -179,7 +72,8 @@ MeasurementArea::MeasurementArea(QObject *parent)
this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesKey],
this /* QObject parent */)),
_holdProgress(false), _state(STATE::IDLE) {
_tiles(new QmlObjectListModel()), _holdProgress(false),
_state(STATE::IDLE) {
init();
}
......@@ -197,7 +91,8 @@ MeasurementArea::MeasurementArea(const MeasurementArea &other, QObject *parent)
this /* QObject parent */)),
_showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesKey],
this /* QObject parent */)),
_holdProgress(false), _state(STATE::IDLE) {
_tiles(new QmlObjectListModel()), _holdProgress(false),
_state(STATE::IDLE) {
init();
disableUpdate();
......@@ -207,8 +102,12 @@ MeasurementArea::MeasurementArea(const MeasurementArea &other, QObject *parent)
_showTiles = other._showTiles;
if (other.ready()) {
_progress = other._progress;
_tileData = other._tileData;
for (int i = 0; i < other._tiles->count(); ++i) {
_tiles->append(
qobject_cast<const MeasurementTile *>(other._tiles->operator[](i))
->clone(_tiles.get()));
}
_tileMap = other._tileMap;
enableUpdate();
} else {
enableUpdate();
......@@ -226,8 +125,13 @@ MeasurementArea &MeasurementArea::operator=(const MeasurementArea &other) {
_showTiles = other._showTiles;
if (other.ready()) {
_progress = other._progress;
_tileData = other._tileData;
_tiles->clearAndDeleteContents();
for (int i = 0; i < other._tiles->count(); ++i) {
_tiles->append(
qobject_cast<const MeasurementTile *>(other._tiles->operator[](i))
->clone(_tiles.get()));
}
_tileMap = other._tileMap;
enableUpdate();
} else {
enableUpdate();
......@@ -236,7 +140,7 @@ MeasurementArea &MeasurementArea::operator=(const MeasurementArea &other) {
return *this;
}
MeasurementArea::~MeasurementArea() {}
MeasurementArea::~MeasurementArea() { _tiles->clearAndDeleteContents(); }
QString MeasurementArea::mapVisualQML() const {
return QStringLiteral("MeasurementAreaMapVisual.qml");
......@@ -259,32 +163,21 @@ Fact *MeasurementArea::minTileArea() { return &_minTileAreaPercent; }
Fact *MeasurementArea::showTiles() { return &_showTiles; }
QmlObjectListModel *MeasurementArea::tiles() { return &this->_tileData.tiles; }
const QVector<int> &MeasurementArea::progress() const {
return this->_progress;
}
QVector<int> MeasurementArea::progressQml() const { return this->_progress; }
QmlObjectListModel *MeasurementArea::tiles() { return _tiles.get(); }
const QmlObjectListModel *MeasurementArea::tiles() const {
return &this->_tileData.tiles;
return _tiles.get();
}
const QVariantList &MeasurementArea::tileCenterPoints() const {
return this->_tileData.tileCenterPoints;
}
const TileData &MeasurementArea::tileData() const { return this->_tileData; }
int MeasurementArea::maxTiles() const { return SNAKE_MAX_TILES; }
int MeasurementArea::maxTiles() const { return MAX_TILES; }
bool MeasurementArea::ready() const { return this->_state == STATE::IDLE; }
bool MeasurementArea::measurementCompleted() const {
if (ready()) {
for (const auto &p : _progress) {
if (p != 100) {
for (int i = 0; i < _tiles->count(); ++i) {
const auto tile = qobject_cast<const MeasurementTile *>(_tiles->get(i));
if (!qFuzzyCompare(tile->progress(), 100)) {
return false;
}
}
......@@ -303,17 +196,15 @@ bool MeasurementArea::saveToJson(QJsonObject &json) {
json[showTilesKey] = _showTiles.rawValue().toBool();
json[areaTypeKey] = nameString;
// save progess
QJsonArray jsonProgess;
for (const auto &p : _progress) {
jsonProgess.append(p);
}
json[progressKey] = std::move(jsonProgess);
// save tiles
QJsonObject jsonTiles;
_tileData.saveToJson(jsonTiles);
json[tileKey] = std::move(jsonTiles);
QJsonArray jsonTileArray;
for (int i = 0; i < _tiles->count(); ++i) {
auto tile = qobject_cast<MeasurementTile *>(_tiles->get(i));
QJsonObject jsonTile;
tile->saveToJson(jsonTile);
jsonTileArray.append(jsonTile);
}
json[tileArrayKey] = std::move(jsonTileArray);
return true;
} else {
......@@ -359,52 +250,39 @@ bool MeasurementArea::loadFromJson(const QJsonObject &json,
_showTiles.setRawValue(json[showTilesKey].toBool());
}
// load tiles and progress
// load tiles
bool tileError = false;
if (json.contains(tileKey) && json[tileKey].isObject()) {
if (json.contains(tileArrayKey) && json[tileArrayKey].isArray()) {
QString e;
if (!_tileData.loadFromJson(json[tileKey].toObject(), e)) {
qCWarning(MeasurementAreaLog) << "TileData::loadFromJson(): " << e;
tileError = true;
} else {
progressChanged();
}
} else {
tileError = true;
}
_tiles->clearAndDeleteContents();
for (auto &&jsonTile : json[tileArrayKey].toArray()) {
bool progressError = false;
QVector<int> prog;
if (json.contains(progressKey) && json[progressKey].isArray()) {
for (const auto &p : json[progressKey].toArray()) {
if (p.isDouble()) {
prog.append(p.toDouble());
auto tile = new MeasurementTile(this);
if (tile->loadFromJson(jsonTile.toObject(), e)) {
_tiles->append(tile);
} else {
progressError = true;
tile->deleteLater();
qCWarning(MeasurementAreaLog) << e;
tileError = true;
break;
}
}
// check if entries are in range
if (!progressError) {
for (const auto &p : prog) {
if (p < 0 || p > 100) {
progressError = true;
break;
}
}
}
} else {
progressError = true;
}
if (!progressError) {
_progress.swap(prog);
emit progressChanged();
qCWarning(MeasurementAreaLog)
<< "Not able to load tiles. tileArrayKey missing or wrong type.";
if (json.contains(tileArrayKey)) {
qCWarning(MeasurementAreaLog)
<< "tile array type: " << json[tileArrayKey].type();
}
tileError = true;
}
// do update if error occurred.
enableUpdate();
if (progressError || tileError) {
if (tileError) {
doUpdate();
}
......@@ -426,28 +304,44 @@ bool MeasurementArea::isCorrect() {
return false;
}
bool MeasurementArea::setProgress(const QVector<int> &p) {
if (ready()) {
if (!_holdProgress && p.size() == this->tiles()->count() &&
this->_progress != p) {
this->_progress = p;
void MeasurementArea::updateProgress(const ProgressArray &array) {
if (ready() && !_holdProgress && array.size() > 0) {
bool anyChanges = false;
for (const auto &pair : array) {
const auto &id = pair.first;
const auto &progress = pair.second;
auto it = _tileMap.find(id);
if (it != _tileMap.end()) {
if (!qFuzzyCompare(progress, it->second->progress())) {
it->second->setProgress(progress);
anyChanges = true;
}
}
}
if (anyChanges) {
emit progressChanged();
emit progressAccepted();
return true;
}
}
emit progressNotAccepted();
return false;
}
void MeasurementArea::randomProgress() {
if (ready()) {
std::srand(std::time(nullptr));
for (auto &p : _progress) {
for (int i = 0; i < _tiles->count(); ++i) {
auto tile = _tiles->value<MeasurementTile *>(i);
Q_ASSERT(tile != nullptr);
auto p = tile->progress();
p += std::rand() % 125;
if (p > 100) {
p = 100;
}
tile->setProgress(p);
}
emit progressChanged();
......@@ -456,13 +350,25 @@ void MeasurementArea::randomProgress() {
void MeasurementArea::resetProgress() {
if (ready()) {
for (auto &p : _progress) {
p = 0;
bool anyChanges = false;
for (int i = 0; i < _tiles->count(); ++i) {
auto tile = _tiles->value<MeasurementTile *>(i);
Q_ASSERT(tile != nullptr);
if (!qFuzzyCompare(tile->progress(), 0)) {
tile->setProgress(0);
anyChanges = true;
}
}
emit progressChanged();
if (anyChanges) {
emit progressChanged();
}
}
}
//!
//! \brief MeasurementArea::doUpdate
//! \pre MeasurementArea::deferUpdate must be called first, don't call
......@@ -480,7 +386,7 @@ void MeasurementArea::doUpdate() {
const auto totalArea = this->area() * si::meter * si::meter;
const auto estNumTiles = totalArea / tileArea;
// Check some conditions.
if (long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES &&
if (long(std::ceil(estNumTiles.value())) <= MAX_TILES &&
this->GeoArea::isCorrect()) {
setState(STATE::UPDATEING);
......@@ -491,10 +397,11 @@ void MeasurementArea::doUpdate() {
const auto minArea =
this->_minTileAreaPercent.rawValue().toDouble() / 100 * tileArea;
auto *th = this->thread();
auto future = QtConcurrent::run([polygon, th, height, width, minArea] {
auto start = std::chrono::high_resolution_clock::now();
DataPtr pData(new TileData());
TilePtr pData(new QmlObjectListModel());
// Convert to ENU system.
QGeoCoordinate origin = polygon.first();
FPolygon polygonENU;
......@@ -505,19 +412,17 @@ void MeasurementArea::doUpdate() {
if (getTiles(polygonENU, height, width, minArea, tilesENU, bbox)) {
// Convert to geo system.
for (const auto &t : tilesENU) {
auto geoTile = new SnakeTile(pData.get());
auto geoTile = new MeasurementTile(pData.get());
std::size_t hashValue = 0;
std::hash<QGeoCoordinate> hashFun;
for (const auto &v : t.outer()) {
QGeoCoordinate geoVertex;
fromENU(origin, v, geoVertex);
geoTile->push_back(geoVertex);
hashValue ^= hashFun(geoVertex);
}
pData->tiles.append(geoTile);
// Calculate center.
geometry::FPoint center;
geometry::polygonCenter(t, center);
QGeoCoordinate geoCenter;
fromENU(origin, center, geoCenter);
pData->tileCenterPoints.append(QVariant::fromValue(geoCenter));
geoTile->setId(long(hashValue));
pData->append(geoTile);
}
}
pData->moveToThread(th);
......@@ -547,10 +452,10 @@ void MeasurementArea::deferUpdate() {
if (this->_state == STATE::IDLE || this->_state == STATE::DEFERED) {
qCDebug(MeasurementAreaLog) << "defereUpdate(): defer update.";
if (this->_state == STATE::IDLE) {
this->_progress.clear();
this->_tileData.clear();
emit this->progressChanged();
emit this->tilesChanged();
this->_tileMap.clear();
this->_tiles->clearAndDeleteContents();
emit tilesChanged();
emit progressChanged();
}
this->setState(STATE::DEFERED);
this->_timer.start(100);
......@@ -566,11 +471,49 @@ void MeasurementArea::storeTiles() {
if (this->_state == STATE::UPDATEING) {
qCDebug(MeasurementAreaLog) << "storeTiles(): update.";
this->_tileData = *this->_watcher.result();
_tiles->clearAndDeleteContents();
this->_tiles = this->_watcher.result();
this->_watcher.result().reset();
QQmlEngine::setObjectOwnership(this->_tiles.get(),
QQmlEngine::CppOwnership);
// update tileMap
this->_tileMap.clear();
for (int i = 0; i < _tiles->count(); ++i) {
auto tile = qobject_cast<MeasurementTile *>(_tiles->get(i));
auto it = _tileMap.find(tile->id());
// find unique id
if (it != _tileMap.end()) {
long newId = tile->id() + 1;
constexpr long counterMax = 1e6;
unsigned long counter = 0;
for (; counter <= counterMax; ++counter) {
it = _tileMap.find(newId);
if (it == _tileMap.end()) {
break;
} else {
++newId;
}
}
if (counter != counterMax) {
tile->setId(newId);
tile->setProgress(0.0);
} else {
qCritical()
<< "MeasurementArea::storeTiles(): not able to find unique id!";
continue;
}
}
_tileMap.insert(std::make_pair(tile->id(), tile));
}
// This is expensive. Drawing tiles is expensive too.
this->_progress = QVector<int>(this->_tileData.tiles.count(), 0);
this->progressChanged();
emit this->tilesChanged();
emit progressChanged();
setState(STATE::IDLE);
} else if (this->_state == STATE::RESTARTING) {
qCDebug(MeasurementAreaLog) << "storeTiles(): restart.";
......@@ -587,7 +530,7 @@ void MeasurementArea::storeTiles() {
}
void MeasurementArea::disableUpdate() {
setState(STATE::IDLE);
setState(STATE::STOP);
this->_timer.stop();
}
......@@ -599,6 +542,9 @@ void MeasurementArea::enableUpdate() {
void MeasurementArea::init() {
this->setObjectName(nameString);
QQmlEngine::setObjectOwnership(this->_tiles.get(), QQmlEngine::CppOwnership);
connect(&this->_tileHeight, &Fact::rawValueChanged, this,
&MeasurementArea::deferUpdate);
connect(&this->_tileWidth, &Fact::rawValueChanged, this,
......@@ -632,6 +578,25 @@ void MeasurementArea::setHoldProgress(bool holdProgress) {
}
}
void MeasurementArea::updateIds(const QList<TileDiff> &array) {
for (const auto &diff : array) {
auto it = _tileMap.find(diff.oldTile.id());
if (it != _tileMap.end() &&
diff.oldTile.coordinateList() == it->second->coordinateList()) {
// Change id and update _tileMap.
const auto newId = diff.newTile.id();
auto tile = it->second;
tile->setId(newId);
_tileMap.erase(it);
auto ret = _tileMap.insert(std::make_pair(newId, tile));
Q_ASSERT(ret.second == true /*insert success?*/);
Q_UNUSED(ret);
}
}
}
bool getTiles(const FPolygon &area, Length tileHeight, Length tileWidth,
Area minTileArea, std::vector<FPolygon> &tiles,
BoundingBox &bbox) {
......
......@@ -6,14 +6,14 @@
#include <QTimer>
#include "GeoArea.h"
#include "MeasurementComplexItem/nemo_interface/MeasurementTile.h"
#include "ProgressArray.h"
#include "TileDiff.h"
#include "SettingsFact.h"
class TileData : public QObject {
public:
QmlObjectListModel tiles;
QVariantList tileCenterPoints;
TileData();
~TileData();
......@@ -26,12 +26,15 @@ public:
void clear();
std::size_t size() const;
QmlObjectListModel tiles;
QVariantList tileCenterPoints;
};
class MeasurementArea : public GeoArea {
Q_OBJECT
enum class STATE { IDLE, DEFERED, UPDATEING, RESTARTING, STOP };
using DataPtr = QSharedPointer<TileData>;
using TilePtr = QSharedPointer<QmlObjectListModel>;
public:
MeasurementArea(QObject *parent = nullptr);
......@@ -45,7 +48,6 @@ public:
Q_PROPERTY(Fact *showTiles READ showTiles CONSTANT)
Q_PROPERTY(QmlObjectListModel *tiles READ tiles NOTIFY tilesChanged)
Q_PROPERTY(int maxTiles READ maxTiles NOTIFY maxTilesChanged)
Q_PROPERTY(QVector<int> progress READ progressQml NOTIFY progressChanged)
Q_PROPERTY(bool holdProgress READ holdProgress WRITE setHoldProgress NOTIFY
holdProgressChanged)
......@@ -63,11 +65,7 @@ public:
Fact *minTileArea();
Fact *showTiles();
QmlObjectListModel *tiles();
const QVector<int> &progress() const;
QVector<int> progressQml() const;
const QmlObjectListModel *tiles() const;
const QVariantList &tileCenterPoints() const; // List of QGeoCoordinate
const TileData &tileData() const;
int maxTiles() const;
bool ready() const;
......@@ -92,14 +90,13 @@ public:
signals:
void tilesChanged();
void maxTilesChanged();
void progressChanged();
void progressAccepted();
void progressNotAccepted();
void readyChanged();
void holdProgressChanged();
void progressChanged();
public slots:
bool setProgress(const QVector<int> &p);
void updateIds(const QList<TileDiff> &array);
void updateProgress(const ProgressArray &array);
Q_INVOKABLE void randomProgress();
Q_INVOKABLE void resetProgress();
......@@ -123,12 +120,11 @@ private:
SettingsFact _minTileAreaPercent; // 0..100
SettingsFact _showTiles;
QVector<int> _progress;
bool _holdProgress;
// Tile stuff.
// Tile stuff.
mutable QTimer _timer;
mutable STATE _state;
mutable TileData _tileData;
mutable QFutureWatcher<DataPtr> _watcher;
TilePtr _tiles;
std::map<long /*id*/, MeasurementTile *> _tileMap;
bool _holdProgress;
QTimer _timer;
STATE _state;
QFutureWatcher<TilePtr> _watcher;
};
#ifndef PROGRESSARRAY_H
#define PROGRESSARRAY_H
#include <QVector>
#include <tuple>
typedef std::pair<long /*id*/, double /*progress*/> TaggedProgress;
typedef QVector<TaggedProgress> ProgressArray;
#endif // PROGRESSARRAY_H
#ifndef TILEDIFF_H
#define TILEDIFF_H
#include "nemo_interface/MeasurementTile.h"
struct TileDiff {
MeasurementTile oldTile;
MeasurementTile newTile;
};
#endif // TILEDIFF_H
......@@ -105,8 +105,9 @@ struct BoundingBox {
FPolygon corners;
};
constexpr int earth_radius = 6371000; // meters (m)
constexpr double epsilon = std::numeric_limits<double>::epsilon(); // meters (m)
static constexpr int earth_radius = 6371000; // meters (m)
static constexpr double epsilon =
std::numeric_limits<double>::epsilon(); // meters (m)
template <class GeoPoint1, class GeoPoint2>
void toENU(const GeoPoint1 &origin, const GeoPoint2 &in, FPoint &out) {
......
#include "MeasurementTile.h"
MeasurementTile::MeasurementTile(QObject *parent)
: GeoArea(parent), _progress(0), _id(0) {
init();
}
MeasurementTile::MeasurementTile(const MeasurementTile &other, QObject *parent)
: GeoArea(other, parent), _progress(other._progress), _id(other._id) {
init();
}
MeasurementTile::~MeasurementTile() {}
MeasurementTile &MeasurementTile::operator=(const MeasurementTile &other) {
GeoArea::operator=(other);
setProgress(other._progress);
setId(other._id);
return *this;
}
QString MeasurementTile::mapVisualQML() const { return QStringLiteral(""); }
QString MeasurementTile::editorQML() const { return QStringLiteral(""); }
MeasurementTile *MeasurementTile::clone(QObject *parent) const {
return new MeasurementTile(*this, parent);
}
void MeasurementTile::push_back(const QGeoCoordinate &c) {
this->appendVertex(c);
}
void MeasurementTile::init() { this->setObjectName("Tile"); }
uint64_t MeasurementTile::id() const { return _id; }
void MeasurementTile::setId(const uint64_t &id) {
if (_id != id) {
_id = id;
emit idChanged();
}
}
double MeasurementTile::progress() const { return _progress; }
void MeasurementTile::setProgress(double progress) {
if (_progress != progress) {
_progress = progress;
emit progressChanged();
}
}
#pragma once
#include "geometry/GeoArea.h"
#include <QGeoCoordinate>
class MeasurementTile : public GeoArea {
Q_OBJECT
public:
MeasurementTile(QObject *parent = nullptr);
MeasurementTile(const MeasurementTile &other, QObject *parent = nullptr);
~MeasurementTile();
MeasurementTile &operator=(const MeasurementTile &other);
Q_PROPERTY(double progress READ progress NOTIFY progressChanged)
Q_PROPERTY(long id READ id NOTIFY idChanged)
virtual QString mapVisualQML() const override;
virtual QString editorQML() const override;
virtual MeasurementTile *clone(QObject *parent) const;
void push_back(const QGeoCoordinate &c);
double progress() const;
void setProgress(double progress);
uint64_t id() const;
void setId(const uint64_t &id);
signals:
void progressChanged();
void idChanged();
private:
void init();
double _progress;
long _id;
};
#include "SnakeTile.h"
SnakeTile::SnakeTile(QObject *parent) : GeoArea(parent) { init(); }
SnakeTile::SnakeTile(const SnakeTile &other, QObject *parent)
: GeoArea(other, parent) {
init();
}
SnakeTile::~SnakeTile() {}
QString SnakeTile::mapVisualQML() const { return QStringLiteral(""); }
QString SnakeTile::editorQML() const { return QStringLiteral(""); }
SnakeTile *SnakeTile::clone(QObject *parent) const {
return new SnakeTile(*this, parent);
}
void SnakeTile::push_back(const QGeoCoordinate &c) { this->appendVertex(c); }
void SnakeTile::init() { this->setObjectName("Tile"); }
#pragma once
#include "geometry/GeoArea.h"
#include <QGeoCoordinate>
class SnakeTile : public GeoArea {
Q_OBJECT
public:
SnakeTile(QObject *parent = nullptr);
SnakeTile(const SnakeTile &other, QObject *parent = nullptr);
~SnakeTile();
virtual QString mapVisualQML() const override;
virtual QString editorQML() const override;
virtual SnakeTile *clone(QObject *parent) const;
void push_back(const QGeoCoordinate &c);
private:
void init();
};
#pragma once
#include "SnakeTile.h"
#include "MeasurementTile.h"
#include "Wima/Geometry/GenericPolygonArray.h"
using SnakeTiles = GenericPolygonArray<SnakeTile, QVector>;
using SnakeTiles = GenericPolygonArray<MeasurementTile, QVector>;
......@@ -48,7 +48,34 @@ Item {
interiorOpacity: _root.opacity
}
// Add Snake tiles to the map
Repeater {
id: progressRepeater
property bool enable: geoArea.showTiles.value
model: enable ? geoArea.tiles : []
Item {
property var _tileComponent
Component.onCompleted: {
_tileComponent = tileComponent.createObject(map)
_tileComponent.polygon.path = Qt.binding(function () {
return object.path
})
_tileComponent.polygon.opacity = 0.6
_tileComponent.polygon.border.color = "black"
_tileComponent.polygon.border.width = 1
_tileComponent.polygon.color = Qt.binding(function () {
return getColor(object.progress)
})
}
Component.onDestruction: {
_tileComponent.destroy()
}
}
}
Component {
id: tileComponent
......@@ -86,32 +113,4 @@ Item {
return "limegreen"
}
Repeater {
id: progressRepeater
property bool enable: geoArea.showTiles.value
model: enable ? geoArea.tiles : []
Item {
property var _tileComponent
property int _progress: _root.geoArea.progress[index] ? _root.geoArea.progress[index] : 0
Component.onCompleted: {
_tileComponent = tileComponent.createObject(map)
_tileComponent.polygon.path = Qt.binding(function () {
return object.path
})
_tileComponent.polygon.opacity = 0.6
_tileComponent.polygon.border.color = "black"
_tileComponent.polygon.border.width = 1
_tileComponent.polygon.color = Qt.binding(function () {
return getColor(_progress)
})
}
Component.onDestruction: {
_tileComponent.destroy()
}
}
}
}
#include "QmlObjectListHelper.h"
#ifndef QMLOBJECTLISTHELPER_H
#define QMLOBJECTLISTHELPER_H
#include "QmlObjectListModel.h"
#include <type_traits>
template <class PtrType>
inline bool contains(const QmlObjectListModel &in, const PtrType toFind) {
static_assert(std::is_pointer<PtrType>::value, "PtrType must be a pointer.");
typedef typename std::remove_pointer<PtrType>::type Type;
for (int i = 0; i < in.count(); ++i) {
const auto obj = qobject_cast<const Type *>(in[i]);
Q_ASSERT(obj != nullptr);
Q_ASSERT(toFind != nullptr);
if (*obj == *toFind) {
return true;
}
}
return false;
}
template <class PtrType>
inline bool equals(const QmlObjectListModel &list,
const QmlObjectListModel &otherList) {
static_assert(std::is_pointer<PtrType>::value, "PtrType must be a pointer.");
typedef typename std::remove_pointer<PtrType>::type Type;
if (list.count() == otherList.count()) {
for (int i = 0; i < list.count(); ++i) {
const auto obj = qobject_cast<const Type *>(list[i]);
const auto otherObj = qobject_cast<const Type *>(otherList[i]);
Q_ASSERT(obj != nullptr);
Q_ASSERT(otherObj != nullptr);
if (*obj != *otherObj) {
return false;
}
}
return true;
} else {
return false;
}
}
#endif // QMLOBJECTLISTHELPER_H
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