/**************************************************************************** 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_stepaffiliatepointalignementsandfieldinventory.h" #include "tools/onf_alignementpointclusterdrawmanager.h" #include "documentinterface.h" #include ONF_StepAffiliatePointAlignementsAndFieldInventory::ONF_StepAffiliatePointAlignementsAndFieldInventory() : SuperClass() { _distThrehold = 3.0; _interactiveCorrection = true; _dataContainer = nullptr; setManual(true); _m_status = 0; _m_doc = nullptr; } ONF_StepAffiliatePointAlignementsAndFieldInventory::~ONF_StepAffiliatePointAlignementsAndFieldInventory() { } QString ONF_StepAffiliatePointAlignementsAndFieldInventory::description() const { return tr("Apparier alignements et positions terrain"); } QString ONF_StepAffiliatePointAlignementsAndFieldInventory::detailledDescription() const { return tr(""); } QString ONF_StepAffiliatePointAlignementsAndFieldInventory::inputDescription() const { return SuperClass::inputDescription() + tr("

"); } QString ONF_StepAffiliatePointAlignementsAndFieldInventory::outputDescription() const { return SuperClass::outputDescription() + tr("

"); } QString ONF_StepAffiliatePointAlignementsAndFieldInventory::detailsDescription() const { return tr(""); } CT_VirtualAbstractStep* ONF_StepAffiliatePointAlignementsAndFieldInventory::createNewInstance() const { return new ONF_StepAffiliatePointAlignementsAndFieldInventory(); } //////////////////// PROTECTED METHODS ////////////////// void ONF_StepAffiliatePointAlignementsAndFieldInventory::declareInputModels(CT_StepInModelStructureManager& manager) { manager.addResult(_inResPlot, tr("Placette"), "", true); manager.setZeroOrMoreRootGroup(_inResPlot, _inZeroOrMoreRootGroupPlot); manager.addGroup(_inZeroOrMoreRootGroupPlot, _inGrp, tr("Groupe")); manager.addItem(_inGrp, _inRef, tr("Arbre")); manager.addItemAttribute(_inRef, _inRefDbh, CT_AbstractCategory::DATA_VALUE, tr("DBH")); manager.addItemAttribute(_inRef, _inRefHeight, CT_AbstractCategory::DATA_VALUE, tr("Height")); manager.addItemAttribute(_inRef, _inRefID, CT_AbstractCategory::DATA_ID, tr("IDtree")); manager.addItemAttribute(_inRef, _inRefIDplot, CT_AbstractCategory::DATA_ID, tr("IDplot")); manager.addItemAttribute(_inRef, _inSpecies, CT_AbstractCategory::DATA_VALUE, tr("Species")); manager.addResult(_inResAlignements, tr("Alignements"), "", true); manager.setZeroOrMoreRootGroup(_inResAlignements, _inZeroOrMoreRootGroupAlignements); manager.addGroup(_inZeroOrMoreRootGroupAlignements, _inGrpAlignements, tr("Groupe")); manager.addItem(_inGrpAlignements, _inAlignements, tr("Alignement")); manager.addResult(_inResSc, tr("Scène"), "", true); manager.setZeroOrMoreRootGroup(_inResSc, _inZeroOrMoreRootGroupSc); manager.addGroup(_inZeroOrMoreRootGroupSc, _inScGrp, tr("Groupe")); manager.addItem(_inScGrp, _inSc, tr("Scène")); manager.addResult(_inResSc2, tr("Scène 2"), "", true); manager.setZeroOrMoreRootGroup(_inResSc2, _inZeroOrMoreRootGroupSc2); manager.addGroup(_inZeroOrMoreRootGroupSc2, _inScGrp2, tr("Groupe")); manager.addItem(_inScGrp2, _inSc2, tr("Scène 2")); manager.addResult(_inResDTM, tr("MNT"), "", true); manager.setZeroOrMoreRootGroup(_inResDTM, _inZeroOrMoreRootGroupDTM); manager.addGroup(_inZeroOrMoreRootGroupDTM, _inDTMGrp, tr("Groupe")); manager.addItem(_inDTMGrp, _inDTM, tr("MNT")); } void ONF_StepAffiliatePointAlignementsAndFieldInventory::declareOutputModels(CT_StepOutModelStructureManager& manager) { manager.addResultCopy(_inResPlot); manager.addItem(_inGrp, _outSceneModel, tr("Cluster arbre")); manager.addItemAttribute(_outSceneModel, _outSceneIDClusterAttModel, CT_AbstractCategory::DATA_ID, tr("IDCluster")); manager.addItemAttribute(_outSceneModel, _outSceneCommentAttModel, CT_AbstractCategory::DATA_VALUE, tr("Comment")); } void ONF_StepAffiliatePointAlignementsAndFieldInventory::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog) { postInputConfigDialog->addDouble(tr("Distance d'appariement maximale :"), "m", 0, std::numeric_limits::max(), 2, _distThrehold); postInputConfigDialog->addBool(tr("Correction interactive"), "", "", _interactiveCorrection); } void ONF_StepAffiliatePointAlignementsAndFieldInventory::compute() { setManual(_interactiveCorrection); _dataContainer = new ONF_ActionAffiliatePointAlignementsAndFieldInventory_dataContainer(); for(const CT_AbstractItemDrawableWithPointCloud* scene : _inSc.iterateInputs(_inResSc)) { _dataContainer->_scenes.append(const_cast(scene)); } for(const CT_AbstractItemDrawableWithPointCloud* scene : _inSc2.iterateInputs(_inResSc2)) { _dataContainer->_scenes2.append(const_cast(scene)); } const CT_Image2D* dtm = _inDTM.firstInput(_inResDTM); _m_status = 0; _dataContainer->_drawManager = new ONF_AlignementPointClusterDrawManager(); _dataContainer->_newClusterDrawManager = new ONF_AlignementPointClusterDrawManager("Added Points"); for(const CT_PointCluster* alignement : _inAlignements.iterateInputs(_inResAlignements)) { CT_PointCluster* al = const_cast(alignement); _dataContainer->_alignements.append(al); al->setAlternativeDrawManager(_dataContainer->_drawManager); } for(CT_StandardItemGroup* grp : _inGrp.iterateOutputs(_inResPlot)) { const CT_Circle2D* circle = grp->singularItem(_inRef); if(circle != nullptr) { ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition* treePos = new ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition(); treePos->_base(0) = circle->centerX(); treePos->_base(1) = circle->centerY(); treePos->_base(2) = 0; if (dtm != nullptr) { treePos->_base(2) = double(dtm->valueAtCoords(treePos->_base(0), treePos->_base(1))); if (qFuzzyCompare(treePos->_base(2), double(dtm->NA()))) {treePos->_base(2) = 0;} } const CT_AbstractItemAttribute* att = circle->itemAttribute(_inRefDbh); if (att != nullptr) {treePos->_dbh = att->toFloat(circle, nullptr);} if (treePos->_dbh <= 0) {treePos->_dbh = 7.5;} att = circle->itemAttribute(_inRefHeight); if (att != nullptr) {treePos->_height = att->toFloat(circle, nullptr);} if (treePos->_height <= 0) {treePos->_height = -1;} att = circle->itemAttribute(_inRefID); if (att != nullptr) {treePos->_idTree = att->toString(circle, nullptr);} att = circle->itemAttribute(_inRefIDplot); if (att != nullptr) {treePos->_idPlot = att->toString(circle, nullptr);} att = circle->itemAttribute(_inSpecies); if (att != nullptr) {treePos->_species = att->toString(circle, nullptr);} _dataContainer->_positions.append(treePos); treePos->_grp = grp; } } // Tri par ordre décroissant de diamètre std::sort(_dataContainer->_positions.begin(), _dataContainer->_positions.end(), ONF_StepAffiliatePointAlignementsAndFieldInventory::lessThan); positionMatching(_dataContainer); if (_interactiveCorrection) { requestManualMode(); _m_status = 1; } for (int i = 0 ; i < _dataContainer->_positions.size() ; i++) { ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition* treePos = _dataContainer->_positions.at(i); if (treePos->_grp != nullptr) { // Création du cluster CT_PointCluster *outCluster = new CT_PointCluster(); // Fusion des scènes associées for (int i = 0 ; i < treePos->_alignementsIds.size() ; i++) { int id = treePos->_alignementsIds.at(i); CT_PointCluster* alignement = static_cast(_dataContainer->_alignements.at(id)); if (alignement != nullptr) { const CT_AbstractPointCloudIndex *pointCloudIndex = alignement->pointCloudIndex(); CT_PointIterator itP(pointCloudIndex); while(itP.hasNext()) { size_t index = itP.next().currentGlobalIndex(); if (_dataContainer->_newCluster[id] || !_dataContainer->_droppedPointsIds.contains(index)) { outCluster->addPoint(index); } } } } if (outCluster->pointCloudIndexSize() > 0) { // ajout du cluster QString sceneName = QString("%1_%2").arg(treePos->_idPlot).arg(treePos->_idTree); outCluster->addItemAttribute(_outSceneIDClusterAttModel, _outSceneIDClusterAttModel.createInstance(CT_AbstractCategory::DATA_ID, sceneName)); outCluster->addItemAttribute(_outSceneCommentAttModel, _outSceneCommentAttModel.createInstance(CT_AbstractCategory::DATA_VALUE, treePos->_rmq)); treePos->_grp->addSingularItem(_outSceneModel, outCluster); } else { delete outCluster; } } delete treePos; } for (int i = 0 ; i < _dataContainer->_alignements.size() ; i++) { _dataContainer->_alignements[i]->setAlternativeDrawManager(nullptr); } if (_interactiveCorrection) { requestManualMode(); } qDeleteAll(_dataContainer->_addedAlignements.values()); delete _dataContainer->_drawManager; delete _dataContainer->_newClusterDrawManager; delete _dataContainer; } void ONF_StepAffiliatePointAlignementsAndFieldInventory::positionMatching(ONF_ActionAffiliatePointAlignementsAndFieldInventory_dataContainer* dataContainer) { dataContainer->_matched.resize(dataContainer->_alignements.size()); dataContainer->_matched.fill(false); dataContainer->_newCluster.resize(dataContainer->_alignements.size()); dataContainer->_newCluster.fill(false); for (int ap = 0 ; ap < dataContainer->_alignements.size() ; ap++) { CT_PointCluster* alignement = static_cast(dataContainer->_alignements.at(ap)); const CT_PointClusterBarycenter& bary = alignement->getBarycenter(); ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition* bestPos = nullptr; double bestPosDist = std::numeric_limits::max(); for (int pos = 0 ; pos < dataContainer->_positions.size() ; pos++) { ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition* treePos = dataContainer->_positions.at(pos); double dist = sqrt(pow(treePos->_base(0) - bary.x(), 2) + pow(treePos->_base(1) - bary.y(), 2)); if (dist < _distThrehold && dist < bestPosDist) { bestPosDist = dist; bestPos = treePos; } } if (bestPos != nullptr) { bestPos->addAlignement(ap); dataContainer->_matched[ap] = true; } } } void ONF_StepAffiliatePointAlignementsAndFieldInventory::initManualMode() { if(_m_doc == nullptr) { // create a new 3D document QColor col = Qt::black; _m_doc = guiContext()->documentManager()->new3DDocument(2.0, false, &col); ONF_ActionAffiliatePointAlignementsAndFieldInventory* action = new ONF_ActionAffiliatePointAlignementsAndFieldInventory(_dataContainer); // set the action (a copy of the action is added at all graphics view, and the action passed in parameter is deleted) _m_doc->setCurrentAction(action, false); } // QMessageBox::information(nullptr, // tr("Mode manuel"), // tr("Bienvenue dans le mode manuel de cette étape.\n"), // QMessageBox::Ok); } void ONF_StepAffiliatePointAlignementsAndFieldInventory::useManualMode(bool quit) { if(_m_status == 0) { if(quit) { } } else if(_m_status == 1) { if(!quit) { _m_doc = nullptr; quitManualMode(); } } }