/**************************************************************************** Copyright (C) 2010-2012 the Office National des Forêts (ONF), France All rights reserved. Contact : alexandre.piboule@onf.fr Developers : Alexandre PIBOULE (ONF) This file is part of PluginONF library. PluginONF is free library: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PluginONF is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PluginONF. If not, see . *****************************************************************************/ #include "onf_stepmanualinventory.h" #include "actions/onf_actionmanualinventory.h" #include #include #include #include ONF_StepManualInventory::ONF_StepManualInventory() : SuperClass() { m_doc = nullptr; setManual(true); _paramFileName.append("../ComputreeHowTo/param_inv.txt"); _deltaH = 0.15; _maxCircleDist = 2; } QString ONF_StepManualInventory::description() const { return tr("Séléctionner un DBH par arbre"); } CT_VirtualAbstractStep* ONF_StepManualInventory::createNewInstance() const { return new ONF_StepManualInventory(); } //////////////////// PROTECTED METHODS ////////////////// void ONF_StepManualInventory::declareInputModels(CT_StepInModelStructureManager& manager) { CT_HandleInResultGroupCopy<> _inResult; CT_HandleInStdZeroOrMoreGroup _inZeroOrMoreRootGroup; CT_HandleInStdGroup<> _inGroup; CT_HandleInSingularItem _inScene; CT_HandleInItemAttribute _inAtt; CT_HandleOutStdGroup _outGroup; CT_HandleOutSingularItem _outScene; CT_HandleOutStdItemAttribute _outAtt; manager.addResult(_inResult, tr("Scene(s)")); manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup); manager.addGroup(_inZeroOrMoreRootGroup, _inGroup); manager.addItem(_inGroup, _inScene, tr("Scene(s)")); manager.addItemAttribute(_inScene, _inAtt, CT_AbstractCategory::DATA_VALUE, tr("value")); manager.addResultCopy(_inResult); manager.addGroup(_inGroup, _outGroup, tr("Groupe")); manager.addItem(_outGroup, _outScene, tr("Scene")); manager.addItemAttribute(_outScene, _outAtt, PS_CATEGORY_MANAGER->findByUniqueName(CT_AbstractCategory::DATA_VALUE), tr("value")); CT_InResultModelGroup *res_inMntres = createNewInResultModel(_inMntres, tr("MNT"), "", true); res_inMntres->setRootGroup(_inMntgrp, CT_AbstractItemGroup::staticGetType(), tr("MNT")); res_inMntres->addItemModel(_inMntgrp, _inMnt, CT_Image2D::staticGetType(), tr("MNT")); CT_InResultModelGroupToCopy *res_inScres = createNewInResultModelForCopy(_inScres, tr("Scènes")); res_inScres->setZeroOrMoreRootGroup(); res_inScres->addGroupModel("", _inScBase, CT_AbstractItemGroup::staticGetType(), tr("Groupe de base")); res_inScres->addGroupModel(_inScBase, _inLayer, CT_AbstractItemGroup::staticGetType(), tr("Niveau Z")); res_inScres->addGroupModel(_inLayer, _inCluster, CT_AbstractItemGroup::staticGetType(), tr("Cluster")); res_inScres->addItemModel(_inCluster, _inCircle, CT_Circle::staticGetType(), tr("Cercle")); res_inScres->addItemModel(_inScBase, _inScene, CT_Scene::staticGetType(), tr("Scene")); res_inScres->addItemModel(_inScBase, _inPositions, CT_Point2D::staticGetType(), tr("Position2D")); } void ONF_StepManualInventory::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog) { postInputConfigDialog->addFileChoice("Fichier de paramétrage", CT_FileChoiceButton::OneExistingFile, "Fichier ascii (*.txt)", _paramFileName); postInputConfigDialog->addDouble(tr("Ne pas accepter de cercle plus loin que :"), "m", 0, 99999, 2, _maxCircleDist); postInputConfigDialog->addDouble(tr("Choisir préférenciellement le diamètre à + ou - :"), "cm", 0, 10000, 0, _deltaH, 100); } void ONF_StepManualInventory::declareOutputModels(CT_StepOutModelStructureManager& manager) { // Création de la liste des attributs supplémentaires if (_paramFileName.size() > 0) { QFile f(_paramFileName.first()); if (f.exists() && f.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&f); QString paramString = stream.readAll(); QStringList paramList = paramString.split("\n", QString::SkipEmptyParts); for (int i = 0 ; i < paramList.size() ; i++) { QStringList values = paramList.at(i).split(";"); if (values.size() > 0) { QStringList modalities = values.mid(1); _paramData.insert(values.at(0), modalities); _paramAutoRename.insert(values.at(0), } } } } CT_OutResultModelGroupToCopyPossibilities *resCpy_scres = createNewOutResultModelToCopy(_inScres); if(resCpy_scres != nullptr) { resCpy_scres->addItemModel(_inScBase, _dbhcircle, new CT_Circle(), tr("Cercle du DHP")); resCpy_scres->addItemModel(_inScBase, _attributes, new CT_ItemAttributeList(), tr("Attributs")); resCpy_scres->addItemAttributeModel(_attributes,_attribute_dbh, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_NUMBER), tr("DHP (cm)")); resCpy_scres->addItemAttributeModel(_attributes,_attribute_x, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_X), tr("X")); resCpy_scres->addItemAttributeModel(_attributes,_attribute_y, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_Y), tr("Y")); resCpy_scres->addItemAttributeModel(_attributes,_attribute_z, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_Z), tr("Z")); resCpy_scres->addItemAttributeModel(_attributes,_attribute_h130, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_HEIGHT), tr("H130")); resCpy_scres->addItemAttributeModel(_attributes,_attribute_h, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_HEIGHT), tr("Hauteur")); // Ajout des modèles pour les attributs supplémentaires QMutableMapIteratoraddItemAttributeModel(_attributes, autoRenameModel, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_VALUE), name); } } } void ONF_StepManualInventory::compute() { m_doc = nullptr; m_status = 0; double hminLightGray = 1.3 - _deltaH; double hmaxLightGray = 1.3 + _deltaH; QList outResultList = getOutResultList(); CT_ResultGroup* resCpy_scres = outResultList.at(0); // Récupération du MNT QList inResultList = getInputResults(); CT_ResultGroup* res_inMntres = inResultList.at(0); //CT_ResultGroup* resCpy_scres = inResultList.at(1); CT_ResultItemIterator it_inMntgrp(res_inMntres, this, _inMnt); if (it_inMntgrp.hasNext()) { _item_inMnt = (CT_Image2D*)it_inMntgrp.next(); } if (_item_inMnt != nullptr) { _selectedDbh = new QMap(); _availableDbh = new QMap >(); _suppAttributes = new QMap >(); _preferredDbh = new QList(); _sceneDTMValues = new QMap(); _trashedScenes = new QList(); // Boucle sur les groupes contenant ls scènes CT_ResultGroupIterator itCpy_scBase(resCpy_scres, this, _inScBase); while (itCpy_scBase.hasNext() && !isStopped()) { CT_StandardItemGroup* grpCpy_scBase = (CT_StandardItemGroup*) itCpy_scBase.next(); const CT_Scene* itemCpy_scene = (const CT_Scene*)grpCpy_scBase->firstItemByINModelName(this, _inScene); const CT_Point2D* itemCpy_position = (const CT_Point2D*)grpCpy_scBase->firstItemByINModelName(this, _inPositions); if (itemCpy_scene != nullptr && itemCpy_position != nullptr) { _positions.insert(itemCpy_scene, itemCpy_position); // Initialisation des attributs supplémentaires QMap &map = _suppAttributes->insert(itemCpy_scene, QMap()).value(); QMapIterator itPar(_paramData); while (itPar.hasNext()) { itPar.next(); map.insert(itPar.key(), QString()); } double x = itemCpy_position->centerX(); // Use Position coordinates for Height reference double y = itemCpy_position->centerY(); double mntZ = _item_inMnt->valueAtCoords(x, y); _sceneDTMValues->insert(itemCpy_scene, mntZ); QMultiMap &circleList = _availableDbh->insert(itemCpy_scene, QMultiMap()).value(); CT_GroupIterator itCpy_layer(grpCpy_scBase, this, _inLayer); while (itCpy_layer.hasNext() && !isStopped()) { CT_StandardItemGroup* grpCpy_layer = (CT_StandardItemGroup*) itCpy_layer.next(); CT_GroupIterator itCpy_cluster(grpCpy_layer, this, _inCluster); while (itCpy_cluster.hasNext() && !isStopped()) { CT_StandardItemGroup* grpCpy_cluster = (CT_StandardItemGroup*) itCpy_cluster.next(); const CT_Circle* itemCpy_circle = (CT_Circle*)grpCpy_cluster->firstItemByINModelName(this, _inCircle); if (itemCpy_circle != nullptr) { double dist = sqrt(pow(x - itemCpy_circle->centerX(), 2) + pow(y - itemCpy_circle->centerY(), 2)); if (dist <= _maxCircleDist) { circleList.insertMulti(itemCpy_circle->centerZ() - mntZ, itemCpy_circle); // Liste des cercles préférrés double height = itemCpy_circle->centerZ() - mntZ; if (height >= hminLightGray && height <= hmaxLightGray) { _preferredDbh->append(itemCpy_circle); } } } } } } } // remplit _selectedDbh findBestCircleForEachScene(); // request the manual mode requestManualMode(); CT_ResultGroupIterator itCpy_scBaseOut(resCpy_scres, this, _inScBase); while (itCpy_scBaseOut.hasNext() && !isStopped()) { CT_StandardItemGroup* grpCpy_scBase = (CT_StandardItemGroup*) itCpy_scBaseOut.next(); const CT_Scene* itemCpy_scene = (const CT_Scene*)grpCpy_scBase->firstItemByINModelName(this, _inScene); const CT_Point2D* itemCpy_position = (const CT_Point2D*)grpCpy_scBase->firstItemByINModelName(this, _inPositions); if (itemCpy_scene != nullptr && itemCpy_position != nullptr && !_trashedScenes->contains(itemCpy_scene)) { CT_Circle* bestCircle = (CT_Circle*) _selectedDbh->value(itemCpy_scene, nullptr); if (bestCircle != nullptr) { CT_Circle* itemCpy_dbhcircle = (CT_Circle*) bestCircle->copy(_dbhcircle.completeName(), resCpy_scres, CT_ResultCopyModeList() << CT_ResultCopyModeList::CopyItemDrawableReference); grpCpy_scBase->addSingularItem(itemCpy_dbhcircle); double dbh = bestCircle->getRadius() * 200.0; double x = itemCpy_position->centerX(); // Use Position coordinates for Height reference double y = itemCpy_position->centerY(); double mntZ = _item_inMnt->valueAtCoords(x, y); double height = computeMaxZ(itemCpy_scene) - mntZ; if ((height < 0) || (mntZ == _item_inMnt->NA())) {height = 0;} CT_ItemAttributeList* itemCpy_attributes = new CT_ItemAttributeList(_attributes.completeName(), resCpy_scres); grpCpy_scBase->addSingularItem(itemCpy_attributes); itemCpy_attributes->addItemAttribute(new CT_StdItemAttributeT(_attribute_dbh.completeName(), CT_AbstractCategory::DATA_NUMBER, resCpy_scres, dbh)); itemCpy_attributes->addItemAttribute(new CT_StdItemAttributeT(_attribute_x.completeName(), CT_AbstractCategory::DATA_X, resCpy_scres, bestCircle->centerX())); itemCpy_attributes->addItemAttribute(new CT_StdItemAttributeT(_attribute_y.completeName(), CT_AbstractCategory::DATA_Y, resCpy_scres, bestCircle->centerY())); itemCpy_attributes->addItemAttribute(new CT_StdItemAttributeT(_attribute_z.completeName(), CT_AbstractCategory::DATA_Z, resCpy_scres, bestCircle->centerZ())); itemCpy_attributes->addItemAttribute(new CT_StdItemAttributeT(_attribute_h130.completeName(), CT_AbstractCategory::DATA_HEIGHT, resCpy_scres, bestCircle->centerZ() - mntZ)); itemCpy_attributes->addItemAttribute(new CT_StdItemAttributeT(_attribute_h.completeName(), CT_AbstractCategory::DATA_HEIGHT, resCpy_scres, height)); // Initialisation des attributs supplémentaires const QMap &map = _suppAttributes->value(itemCpy_scene, QMap()); QMutableMapIteratoraddItemAttribute(new CT_StdItemAttributeT(autoRename.completeName(), CT_AbstractCategory::DATA_VALUE, resCpy_scres, value)); } } } } m_status = 1; requestManualMode(); delete _selectedDbh; delete _availableDbh; delete _suppAttributes; delete _preferredDbh; delete _sceneDTMValues; delete _trashedScenes; qDeleteAll(_temporaryCircles); } } void ONF_StepManualInventory::initManualMode() { // create a new 3D document if(m_doc == nullptr) m_doc = getGuiContext()->documentManager()->new3DDocument(); // change camera type to orthographic if(m_doc != nullptr && !m_doc->views().isEmpty()) dynamic_cast(m_doc->views().at(0))->camera()->setType(CameraInterface::ORTHOGRAPHIC); m_doc->removeAllItemDrawable(); m_doc->setCurrentAction(new ONF_ActionManualInventory(_selectedDbh, _availableDbh, _preferredDbh, _trashedScenes, _sceneDTMValues, &_paramData, _suppAttributes)); QMessageBox::information(nullptr, tr("Mode manuel"), tr("Bienvenue dans le mode manuel de cette étape !"), QMessageBox::Ok); } void ONF_StepManualInventory::useManualMode(bool quit) { if(m_status == 0) { if(quit) { } } else if(m_status == 1) { if(!quit) { m_doc = nullptr; quitManualMode(); } } } void ONF_StepManualInventory::findBestCircleForEachScene() { QMapIterator itScenes(_positions); while (itScenes.hasNext()) { itScenes.next(); const CT_Scene* scene = itScenes.key(); const CT_Point2D* pos = itScenes.value(); double x = pos->centerX(); double y = pos->centerY(); double z = _item_inMnt->valueAtCoords(x, y) + 1.3; QList circles = (_availableDbh->value(scene)).values(); double mindelta = std::numeric_limits::max(); const CT_Circle* bestCircle = nullptr; QListIterator itCircles(circles); while (itCircles.hasNext()) { const CT_Circle* currentCircle = itCircles.next(); double dist = std::fabs(currentCircle->centerZ() - z); if (dist < mindelta) { mindelta = dist; bestCircle = currentCircle; } } if (bestCircle == nullptr) { CT_Circle* tmpCircle = new CT_Circle(nullptr, nullptr, new CT_CircleData(Eigen::Vector3d(x, y, z), Eigen::Vector3d(0, 0, 1), 0.05, -9999)); _selectedDbh->insert(scene, tmpCircle); _temporaryCircles.append(tmpCircle); } else { _selectedDbh->insert(scene, bestCircle); } } } double ONF_StepManualInventory::computeMaxZ(const CT_Scene* scene) { CT_PointIterator it(scene->pointCloudIndex()); double zmax = -std::numeric_limits::max(); while(it.hasNext()) { const CT_Point &point = it.next().currentPoint(); if (point(2) > zmax) zmax = point(2); } return zmax; }