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