diff --git a/src/Wima/Geometry/WimaMeasurementArea.cc b/src/Wima/Geometry/WimaMeasurementArea.cc index da0727f6ff3e1819c18b8224e0fbdf38732ec7b2..3e367ba7ab082d558cf5eff36f508a1227b756a1 100644 --- a/src/Wima/Geometry/WimaMeasurementArea.cc +++ b/src/Wima/Geometry/WimaMeasurementArea.cc @@ -57,12 +57,10 @@ size_t TileData::size() const { const char *WimaMeasurementArea::settingsGroup = "MeasurementArea"; const char *WimaMeasurementArea::tileHeightName = "TileHeight"; const char *WimaMeasurementArea::tileWidthName = "TileWidth"; -const char *WimaMeasurementArea::minTileAreaName = "MinTileArea"; +const char *WimaMeasurementArea::minTileAreaName = "MinTileAreaPercent"; 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( @@ -72,8 +70,9 @@ WimaMeasurementArea::WimaMeasurementArea(QObject *parent) this /* QObject parent */)), _tileWidth(SettingsFact(settingsGroup, _metaDataMap[tileWidthName], this /* QObject parent */)), - _minTileArea(SettingsFact(settingsGroup, _metaDataMap[minTileAreaName], - this /* QObject parent */)), + _minTileAreaPercent(SettingsFact(settingsGroup, + _metaDataMap[minTileAreaName], + this /* QObject parent */)), _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], this /* QObject parent */)), _state(STATE::IDLE) { @@ -90,8 +89,9 @@ WimaMeasurementArea::WimaMeasurementArea(const WimaMeasurementArea &other, this /* QObject parent */)), _tileWidth(SettingsFact(settingsGroup, _metaDataMap[tileWidthName], this /* QObject parent */)), - _minTileArea(SettingsFact(settingsGroup, _metaDataMap[minTileAreaName], - this /* QObject parent */)), + _minTileAreaPercent(SettingsFact(settingsGroup, + _metaDataMap[minTileAreaName], + this /* QObject parent */)), _showTiles(SettingsFact(settingsGroup, _metaDataMap[showTilesName], this /* QObject parent */)), _state(STATE::IDLE) { @@ -123,7 +123,7 @@ Fact *WimaMeasurementArea::tileHeight() { return &_tileHeight; } Fact *WimaMeasurementArea::tileWidth() { return &_tileWidth; } -Fact *WimaMeasurementArea::minTileArea() { return &_minTileArea; } +Fact *WimaMeasurementArea::minTileArea() { return &_minTileAreaPercent; } Fact *WimaMeasurementArea::showTiles() { return &_showTiles; } @@ -156,46 +156,56 @@ int WimaMeasurementArea::maxTiles() const { return SNAKE_MAX_TILES; } bool WimaMeasurementArea::ready() const { return this->_state == STATE::IDLE; } void WimaMeasurementArea::saveToJson(QJsonObject &json) { - this->WimaArea::saveToJson(json); - json[tileHeightName] = _tileHeight.rawValue().toDouble(); - json[tileWidthName] = _tileWidth.rawValue().toDouble(); - json[minTileAreaName] = _minTileArea.rawValue().toDouble(); - json[showTilesName] = _showTiles.rawValue().toBool(); - json[areaTypeName] = WimaMeasurementAreaName; + if (ready()) { + this->WimaArea::saveToJson(json); + json[tileHeightName] = _tileHeight.rawValue().toDouble(); + json[tileWidthName] = _tileWidth.rawValue().toDouble(); + json[minTileAreaName] = _minTileAreaPercent.rawValue().toDouble(); + json[showTilesName] = _showTiles.rawValue().toBool(); + json[areaTypeName] = WimaMeasurementAreaName; + } else { + qCDebug(WimaMeasurementAreaLog) << "saveToJson(): not ready for saveing."; + } } bool WimaMeasurementArea::loadFromJson(const QJsonObject &json, QString &errorString) { if (this->WimaArea::loadFromJson(json, errorString)) { + disableUpdates(); bool retVal = true; - if (json.contains(tileHeightName) && json[tileHeightName].isDouble()) { - _tileHeight.setRawValue(json[tileHeightName].toDouble()); - } else { + if (!json.contains(tileHeightName) || !json[tileHeightName].isDouble()) { errorString.append(tr("Could not load tile height!\n")); retVal = false; } - if (json.contains(tileWidthName) && json[tileWidthName].isDouble()) { - _tileWidth.setRawValue(json[tileWidthName].toDouble()); - } else { + if (!json.contains(tileWidthName) || !json[tileWidthName].isDouble()) { errorString.append(tr("Could not load tile width!\n")); retVal = false; } - if (json.contains(minTileAreaName) && json[minTileAreaName].isDouble()) { - _minTileArea.setRawValue(json[minTileAreaName].toDouble()); - } else { + if (!json.contains(minTileAreaName) || !json[minTileAreaName].isDouble()) { errorString.append(tr("Could not load minimal tile area!\n")); retVal = false; } - if (json.contains(showTilesName) && json[showTilesName].isBool()) { - _showTiles.setRawValue(json[showTilesName].toBool()); - } else { + if (!json.contains(showTilesName) || !json[showTilesName].isBool()) { errorString.append(tr("Could not load show tiles !\n")); retVal = false; } + + if (retVal) { + _tileHeight.setRawValue(json[tileHeightName].toDouble()); + _tileWidth.setRawValue(json[tileWidthName].toDouble()); + _minTileAreaPercent.setRawValue(json[minTileAreaName].toDouble()); + _showTiles.setRawValue(json[showTilesName].toBool()); + + enableUpdates(); + doUpdate(); + } else { + enableUpdates(); + } + return retVal; } else { return false; @@ -222,69 +232,71 @@ void WimaMeasurementArea::doUpdate() { using namespace boost::units; auto start = std::chrono::high_resolution_clock::now(); - - 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->_state != STATE::UPDATE && - long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES && - this->count() >= 3 && this->isSimplePolygon()) { - setState(STATE::UPDATE); - auto polygon = this->coordinateList(); - for (auto &v : polygon) { - v.setAltitude(0); - } - const auto minArea = - this->_minTileArea.rawValue().toDouble() * si::meter * si::meter; - 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()); - // Convert to ENU system. - QGeoCoordinate origin = polygon.first(); - FPolygon polygonENU; - areaToEnu(origin, polygon, polygonENU); - std::vector tilesENU; - BoundingBox bbox; - std::string errorString; - // Generate tiles. - if (snake::tiles(polygonENU, height, width, minArea, tilesENU, bbox, - errorString)) { - // Convert to geo system. - for (const auto &t : tilesENU) { - auto geoTile = new SnakeTile(pData.get()); - for (const auto &v : t.outer()) { - QGeoCoordinate geoVertex; - fromENU(origin, v, geoVertex); - geoTile->push_back(geoVertex); + // Check state. + if (this->_state != STATE::UPDATEING && !this->_state == STATE::STOP) { + 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; + // Check some conditions. + if (long(std::ceil(estNumTiles.value())) <= SNAKE_MAX_TILES && + this->count() >= 3 && this->isSimplePolygon()) { + setState(STATE::UPDATEING); + + auto polygon = this->coordinateList(); + for (auto &v : polygon) { + v.setAltitude(0); + } + 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()); + // Convert to ENU system. + QGeoCoordinate origin = polygon.first(); + FPolygon polygonENU; + areaToEnu(origin, polygon, polygonENU); + std::vector tilesENU; + BoundingBox bbox; + std::string errorString; + // Generate tiles. + if (snake::tiles(polygonENU, height, width, minArea, tilesENU, bbox, + errorString)) { + // Convert to geo system. + for (const auto &t : tilesENU) { + auto geoTile = new SnakeTile(pData.get()); + for (const auto &v : t.outer()) { + QGeoCoordinate geoVertex; + fromENU(origin, v, geoVertex); + geoTile->push_back(geoVertex); + } + pData->tiles.append(geoTile); + // Calculate center. + snake::FPoint center; + snake::polygonCenter(t, center); + QGeoCoordinate geoCenter; + fromENU(origin, center, geoCenter); + pData->tileCenterPoints.append(QVariant::fromValue(geoCenter)); } - pData->tiles.append(geoTile); - // Calculate center. - snake::FPoint center; - snake::polygonCenter(t, center); - QGeoCoordinate geoCenter; - fromENU(origin, center, geoCenter); - pData->tileCenterPoints.append(QVariant::fromValue(geoCenter)); } - } - pData->moveToThread(th); + pData->moveToThread(th); - qCDebug(WimaMeasurementAreaLog) - << "doUpdate(): update time: " - << std::chrono::duration_cast( - std::chrono::high_resolution_clock::now() - start) - .count() - << " ms"; + qCDebug(WimaMeasurementAreaLog) + << "doUpdate(): update time: " + << std::chrono::duration_cast( + std::chrono::high_resolution_clock::now() - start) + .count() + << " ms"; - return pData; - }); // QtConcurrent::run() + return pData; + }); // QtConcurrent::run() - this->_watcher.setFuture(future); + this->_watcher.setFuture(future); + } } - qCDebug(WimaMeasurementAreaLog) << "doUpdate(): execution time: " << std::chrono::duration_cast( @@ -295,6 +307,7 @@ void WimaMeasurementArea::doUpdate() { void WimaMeasurementArea::deferUpdate() { if (this->_state == STATE::IDLE || this->_state == STATE::DEFERED) { + qCDebug(WimaMeasurementAreaLog) << "defereUpdate(): defer update."; if (this->_state == STATE::IDLE) { this->_progress.clear(); this->_tileData.clear(); @@ -303,16 +316,16 @@ void WimaMeasurementArea::deferUpdate() { } this->setState(STATE::DEFERED); this->_timer.start(100); - } else if (this->_state == STATE::UPDATE) { - setState(STATE::RESTART); + } else if (this->_state == STATE::UPDATEING) { + qCDebug(WimaMeasurementAreaLog) << "defereUpdate(): restart."; + setState(STATE::RESTARTING); } } void WimaMeasurementArea::storeTiles() { auto start = std::chrono::high_resolution_clock::now(); - if (this->_state == STATE::UPDATE) { - + if (this->_state == STATE::UPDATEING) { qCDebug(WimaMeasurementAreaLog) << "storeTiles(): update."; this->_tileData = *this->_watcher.result(); @@ -321,10 +334,11 @@ void WimaMeasurementArea::storeTiles() { this->progressChanged(); emit this->tilesChanged(); setState(STATE::IDLE); - } else if (this->_state == STATE::RESTART) { + } else if (this->_state == STATE::RESTARTING) { qCDebug(WimaMeasurementAreaLog) << "storeTiles(): restart."; - doUpdate(); + } else if (this->_state == STATE::STOP) { + qCDebug(WimaMeasurementAreaLog) << "storeTiles(): stop."; } qCDebug(WimaMeasurementAreaLog) << "storeTiles() execution time: " @@ -334,13 +348,24 @@ void WimaMeasurementArea::storeTiles() { << " ms"; } +void WimaMeasurementArea::disableUpdates() { + setState(STATE::IDLE); + this->_timer.stop(); +} + +void WimaMeasurementArea::enableUpdates() { + if (this->_state == STATE::STOP) { + setState(STATE::IDLE); + } +} + void WimaMeasurementArea::init() { this->setObjectName(WimaMeasurementAreaName); connect(&this->_tileHeight, &Fact::rawValueChanged, this, &WimaMeasurementArea::deferUpdate); connect(&this->_tileWidth, &Fact::rawValueChanged, this, &WimaMeasurementArea::deferUpdate); - connect(&this->_minTileArea, &Fact::rawValueChanged, this, + connect(&this->_minTileAreaPercent, &Fact::rawValueChanged, this, &WimaMeasurementArea::deferUpdate); connect(this, &WimaArea::pathChanged, this, &WimaMeasurementArea::deferUpdate); diff --git a/src/Wima/Geometry/WimaMeasurementArea.h b/src/Wima/Geometry/WimaMeasurementArea.h index 374269aa77d8aadd537e7cbd23351c210730e5d1..72df1afb95c9912c4ff17e86e670dc0c924180e3 100644 --- a/src/Wima/Geometry/WimaMeasurementArea.h +++ b/src/Wima/Geometry/WimaMeasurementArea.h @@ -27,12 +27,7 @@ public: class WimaMeasurementArea : public WimaArea { Q_OBJECT - enum class STATE { - IDLE, - DEFERED, - UPDATE, - RESTART, - }; + enum class STATE { IDLE, DEFERED, UPDATEING, RESTARTING, STOP }; public: WimaMeasurementArea(QObject *parent = nullptr); @@ -71,10 +66,6 @@ public: void saveToJson(QJsonObject &json); bool loadFromJson(const QJsonObject &json, QString &errorString); - // Friends - friend void print(const WimaMeasurementArea &area, QString outputStr); - friend void print(const WimaMeasurementArea &area); - // Static Variables static const char *settingsGroup; static const char *tileHeightName; @@ -98,6 +89,8 @@ private slots: void doUpdate(); void deferUpdate(); void storeTiles(); + void disableUpdates(); + void enableUpdates(); private: // Member Methodes @@ -109,15 +102,15 @@ private: SettingsFact _tileHeight; SettingsFact _tileWidth; - SettingsFact _minTileArea; + SettingsFact _minTileAreaPercent; // 0..100 SettingsFact _showTiles; + QVector _progress; + // Tile stuff. mutable QTimer _timer; using DataPtr = std::shared_ptr; + mutable STATE _state; mutable TileData _tileData; mutable QFutureWatcher _watcher; - mutable STATE _state; - - QVector _progress; }; diff --git a/src/Wima/Geometry/json/WimaMeasurementArea.SettingsGroup.json b/src/Wima/Geometry/json/WimaMeasurementArea.SettingsGroup.json index cd838205eb09393df6b216b49b4ffc4a1f3d572d..c4fda54e2296fc8eaf992feaac5054d0aa969c90 100644 --- a/src/Wima/Geometry/json/WimaMeasurementArea.SettingsGroup.json +++ b/src/Wima/Geometry/json/WimaMeasurementArea.SettingsGroup.json @@ -18,31 +18,14 @@ "defaultValue": 5 }, { - "name": "MinTileArea", - "shortDescription": "The minimal allowed area of a tile", + "name": "MinTileAreaPercent", + "shortDescription": "The minimal allowed area in percent (of width*height).", "type": "double", - "units": "m^2", + "units": "%", "min": 0, + "max": 100, "decimalPlaces": 2, - "defaultValue": 5 -}, -{ - "name": "TransectDistance", - "shortDescription": "The transect distance", - "type": "double", - "units": "m", - "min": 0.3, - "decimalPlaces": 2, - "defaultValue": 2 -}, -{ - "name": "MinTransectLength", - "shortDescription": "The minimal transect length", - "type": "double", - "units": "m", - "min": 0, - "decimalPlaces": 2, - "defaultValue": 1 + "defaultValue": 20 }, { "name": "ShowTiles",