/**************************************************************************** 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 "ct_itemdrawable/ct_scene.h" #include "ct_itemdrawable/ct_pointcluster.h" #include "ct_itemdrawable/ct_circle2d.h" #include "ctliblas/itemdrawable/las/ct_stdlaspointsattributescontainer.h" #include "ct_itemdrawable/ct_pointsattributesscalartemplated.h" #include "ct_result/ct_resultgroup.h" #include "ct_result/model/inModel/ct_inresultmodelgroup.h" #include "ct_result/model/inModel/ct_inresultmodelgrouptocopy.h" #include "ct_result/model/outModel/ct_outresultmodelgroupcopy.h" #include "ct_result/model/outModel/tools/ct_outresultmodelgrouptocopypossibilities.h" #include "ct_view/ct_stepconfigurabledialog.h" #include "tools/onf_alignementpointclusterdrawmanager.h" #include "ct_pointcloudindex/ct_pointcloudindexvector.h" #include "ct_itemdrawable/tools/iterator/ct_groupiterator.h" #include "ct_iterator/ct_pointiterator.h" #include "ct_itemdrawable/ct_image2d.h" #include #include #include // Alias for indexing models #define DEFin_resAlignements "resAlignement" #define DEFin_grpAlignements "grpAlignement" #define DEFin_alignements "alignement" #define DEFin_resDTM "resdtm" #define DEFin_DTMGrp "dtmgrp" #define DEFin_DTM "dtm" #define DEFin_resPlot "resPlot" #define DEFin_grp "grp" #define DEFin_ref "ref" #define DEFin_refDbh "refDbh" #define DEFin_refHeight "refHeight" #define DEFin_refID "refID" #define DEFin_refIDplot "refIDplot" #define DEFin_species "species" #define DEFin_resSc "resSc" #define DEFin_ScGrp "ScGrp" #define DEFin_Sc "Sc" #define DEFin_resSc2 "resSc2" #define DEFin_ScGrp2 "ScGrp2" #define DEFin_Sc2 "Sc2" // Constructor : initialization of parameters ONF_StepAffiliatePointAlignementsAndFieldInventory::ONF_StepAffiliatePointAlignementsAndFieldInventory(CT_StepInitializeData &dataInit) : CT_AbstractStep(dataInit) { _distThrehold = 3.0; _interactiveCorrection = true; _dataContainer = NULL; setManual(true); _m_status = 0; _m_doc = NULL; } ONF_StepAffiliatePointAlignementsAndFieldInventory::~ONF_StepAffiliatePointAlignementsAndFieldInventory() { } // Step description (tooltip of contextual menu) QString ONF_StepAffiliatePointAlignementsAndFieldInventory::getStepDescription() const { return tr("Apparier alignements et positions terrain"); } // Step detailled description QString ONF_StepAffiliatePointAlignementsAndFieldInventory::getStepDetailledDescription() const { return tr("To Do"); } // Step copy method CT_VirtualAbstractStep* ONF_StepAffiliatePointAlignementsAndFieldInventory::createNewInstance(CT_StepInitializeData &dataInit) { return new ONF_StepAffiliatePointAlignementsAndFieldInventory(dataInit); } //////////////////// PROTECTED METHODS ////////////////// // Creation and affiliation of IN models void ONF_StepAffiliatePointAlignementsAndFieldInventory::createInResultModelListProtected() { CT_InResultModelGroupToCopy *resIn_Plot = createNewInResultModelForCopy(DEFin_resPlot, tr("Placette"), "", true); resIn_Plot->setZeroOrMoreRootGroup(); resIn_Plot->addGroupModel("", DEFin_grp, CT_AbstractItemGroup::staticGetType(), tr("Groupe")); resIn_Plot->addItemModel(DEFin_grp, DEFin_ref, CT_Circle2D::staticGetType(), tr("Arbre")); resIn_Plot->addItemAttributeModel(DEFin_ref, DEFin_refDbh, QList() << CT_AbstractCategory::DATA_VALUE, CT_AbstractCategory::NUMBER, tr("DBH")); resIn_Plot->addItemAttributeModel(DEFin_ref, DEFin_refHeight, QList() << CT_AbstractCategory::DATA_VALUE, CT_AbstractCategory::NUMBER, tr("Height")); resIn_Plot->addItemAttributeModel(DEFin_ref, DEFin_refID, QList() << CT_AbstractCategory::DATA_ID, CT_AbstractCategory::STRING, tr("IDtree")); resIn_Plot->addItemAttributeModel(DEFin_ref, DEFin_refIDplot, QList() << CT_AbstractCategory::DATA_ID, CT_AbstractCategory::STRING, tr("IDplot")); resIn_Plot->addItemAttributeModel(DEFin_ref, DEFin_species, QList() << CT_AbstractCategory::DATA_VALUE, CT_AbstractCategory::STRING, tr("Species"), "", CT_InAbstractModel::C_ChooseOneIfMultiple, CT_InAbstractModel::F_IsOptional); CT_InResultModelGroup *resIn_Alignements = createNewInResultModel(DEFin_resAlignements, tr("Alignements"), "", true); resIn_Alignements->setZeroOrMoreRootGroup(); resIn_Alignements->addGroupModel("", DEFin_grpAlignements, CT_AbstractItemGroup::staticGetType(), tr("Groupe")); resIn_Alignements->addItemModel(DEFin_grpAlignements, DEFin_alignements, CT_PointCluster::staticGetType(), tr("Alignement")); CT_InResultModelGroup *resultScene = createNewInResultModel(DEFin_resSc, tr("Scène"), "", true); resultScene->setZeroOrMoreRootGroup(); resultScene->addGroupModel("", DEFin_ScGrp, CT_AbstractItemGroup::staticGetType(), tr("Group")); resultScene->addItemModel(DEFin_ScGrp, DEFin_Sc, CT_AbstractItemDrawableWithPointCloud::staticGetType(), tr("Scène")); CT_InResultModelGroup *resultScene2 = createNewInResultModel(DEFin_resSc2, tr("Scène2"), "", true); resultScene2->setZeroOrMoreRootGroup(); resultScene2->addGroupModel("", DEFin_ScGrp2, CT_AbstractItemGroup::staticGetType(), tr("Group")); resultScene2->addItemModel(DEFin_ScGrp2, DEFin_Sc2, CT_AbstractItemDrawableWithPointCloud::staticGetType(), tr("Scène2")); CT_InResultModelGroup *resultDTM = createNewInResultModel(DEFin_resDTM, tr("MNT"), "", true); resultDTM->setZeroOrMoreRootGroup(); resultDTM->addGroupModel("", DEFin_DTMGrp, CT_AbstractItemGroup::staticGetType(), tr("Group")); resultDTM->addItemModel(DEFin_DTMGrp, DEFin_DTM, CT_Image2D::staticGetType(), tr("MNT")); resultDTM->setMinimumNumberOfPossibilityThatMustBeSelectedForOneTurn(0); } // Creation and affiliation of OUT models void ONF_StepAffiliatePointAlignementsAndFieldInventory::createOutResultModelListProtected() { CT_OutResultModelGroupToCopyPossibilities *res = createNewOutResultModelToCopy(DEFin_resPlot); if(res != NULL) { res->addItemModel(DEFin_grp, _outSceneModelName, new CT_PointCluster(), tr("Cluster arbre")); res->addItemAttributeModel(_outSceneModelName, _outSceneIDClusterAttModelName, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_ID), tr("IDCluster")); res->addItemAttributeModel(_outSceneModelName, _outSceneCommentAttModelName, new CT_StdItemAttributeT(CT_AbstractCategory::DATA_VALUE), tr("Comment")); } } // Semi-automatic creation of step parameters DialogBox void ONF_StepAffiliatePointAlignementsAndFieldInventory::createPostConfigurationDialog() { CT_StepConfigurableDialog *configDialog = newStandardPostConfigurationDialog(); configDialog->addDouble(tr("Distance d'appariement maximale :"), "m", 0, 1e+10, 2, _distThrehold); configDialog->addBool(tr("Correction interactive"), "", "", _interactiveCorrection); } void ONF_StepAffiliatePointAlignementsAndFieldInventory::compute() { setManual(_interactiveCorrection); _dataContainer = new ONF_ActionAffiliatePointAlignementsAndFieldInventory_dataContainer(); CT_ResultGroup* resin_Scene = getInputResults().at(2); CT_ResultItemIterator itSC(resin_Scene, this, DEFin_Sc); if (itSC.hasNext()) { _dataContainer->_scenes.append( (CT_AbstractItemDrawableWithPointCloud*)itSC.next()); } CT_ResultGroup* resin_Scene2 = getInputResults().at(3); CT_ResultItemIterator itSC2(resin_Scene2, this, DEFin_Sc2); if (itSC2.hasNext()) { _dataContainer->_scenes2.append( (CT_AbstractItemDrawableWithPointCloud*)itSC2.next()); } CT_Image2D* dtm = NULL; if (getInputResults().size() > 4) { CT_ResultGroup* resin_DTM = getInputResults().at(4); CT_ResultItemIterator itDTM(resin_DTM, this, DEFin_DTM); if (itDTM.hasNext()) { dtm = (CT_Image2D*) itDTM.next(); } } _m_status = 0; QList inResultList = getInputResults(); CT_ResultGroup* resIn_Alignements = inResultList.at(1); _dataContainer->_drawManager = new ONF_AlignementPointClusterDrawManager(); _dataContainer->_newClusterDrawManager = new ONF_AlignementPointClusterDrawManager("Added Points"); CT_ResultGroupIterator itGrpSc(resIn_Alignements, this, DEFin_grpAlignements); while (itGrpSc.hasNext()) { const CT_AbstractItemGroup* grp = itGrpSc.next(); CT_PointCluster* alignement = (CT_PointCluster*) grp->firstItemByINModelName(this, DEFin_alignements); if (alignement != NULL) { _dataContainer->_alignements.append(alignement); alignement->setAlternativeDrawManager(_dataContainer->_drawManager); } } QList outResultList = getOutResultList(); CT_ResultGroup* resOut_positions = outResultList.at(0); _dataContainer->_result = resOut_positions; CT_ResultGroupIterator itGrp(resOut_positions, this, DEFin_grp); while (itGrp.hasNext()) { CT_StandardItemGroup* grp = (CT_StandardItemGroup*) itGrp.next(); CT_Circle2D* circle = (CT_Circle2D*) grp->firstItemByINModelName(this, DEFin_ref); if (circle != NULL) { ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition* treePos = new ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition(); treePos->_base(0) = circle->getCenterX(); treePos->_base(1) = circle->getCenterY(); treePos->_base(2) = 0; if (dtm != NULL) { treePos->_base(2) = dtm->valueAtCoords(treePos->_base(0), treePos->_base(1)); if (treePos->_base(2) == dtm->NA()) {treePos->_base(2) = 0;} } CT_AbstractItemAttribute* att = circle->firstItemAttributeByINModelName(resOut_positions, this, DEFin_refDbh); if (att != NULL) {treePos->_dbh = att->toFloat(circle, NULL);} if (treePos->_dbh <= 0) {treePos->_dbh = 7.5;} att = circle->firstItemAttributeByINModelName(resOut_positions, this, DEFin_refHeight); if (att != NULL) {treePos->_height = att->toFloat(circle, NULL);} if (treePos->_height <= 0) {treePos->_height = -1;} att = circle->firstItemAttributeByINModelName(resOut_positions, this, DEFin_refID); if (att != NULL) {treePos->_idTree = att->toString(circle, NULL);} att = circle->firstItemAttributeByINModelName(resOut_positions, this, DEFin_refIDplot); if (att != NULL) {treePos->_idPlot = att->toString(circle, NULL);} att = circle->firstItemAttributeByINModelName(resOut_positions, this, DEFin_species); if (att != NULL) {treePos->_species = att->toString(circle, NULL);} _dataContainer->_positions.append(treePos); treePos->_grp = grp; } } // Tri par ordre décroissant de diamètre qSort(_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 != NULL) { // Création du cluster CT_PointCluster *outCluster = NULL; // Fusion des scènes associées for (int i = 0 ; i < treePos->_alignementsIds.size() ; i++) { int id = treePos->_alignementsIds.at(i); CT_PointCluster* alignement = (CT_PointCluster*) _dataContainer->_alignements.at(id); if (alignement != NULL) { const CT_AbstractPointCloudIndex *pointCloudIndex = alignement->getPointCloudIndex(); CT_PointIterator itP(pointCloudIndex); while(itP.hasNext()) { size_t index = itP.next().currentGlobalIndex(); if (_dataContainer->_newCluster[id] || !_dataContainer->_droppedPointsIds.contains(index)) { if (outCluster == NULL) { outCluster = new CT_PointCluster(_outSceneModelName.completeName(), resOut_positions); } outCluster->addPoint(index); } } } } if (outCluster != NULL) { // ajout du cluster QString sceneName = QString("%1_%2").arg(treePos->_idPlot).arg(treePos->_idTree); outCluster->addItemAttribute(new CT_StdItemAttributeT(_outSceneIDClusterAttModelName.completeName(), CT_AbstractCategory::DATA_ID, resOut_positions, sceneName)); outCluster->addItemAttribute(new CT_StdItemAttributeT(_outSceneCommentAttModelName.completeName(), CT_AbstractCategory::DATA_VALUE, resOut_positions, treePos->_rmq)); treePos->_grp->addItemDrawable(outCluster); } } delete treePos; } for (int i = 0 ; i < _dataContainer->_alignements.size() ; i++) { _dataContainer->_alignements[i]->setAlternativeDrawManager(NULL); } 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 = (CT_PointCluster*) dataContainer->_alignements.at(ap); const CT_PointClusterBarycenter& bary = alignement->getBarycenter(); ONF_ActionAffiliatePointAlignementsAndFieldInventory_treePosition* bestPos = NULL; 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 != NULL) { bestPos->addAlignement(ap); dataContainer->_matched[ap] = true; } } } void ONF_StepAffiliatePointAlignementsAndFieldInventory::initManualMode() { if(_m_doc == NULL) { // create a new 3D document QColor col = Qt::black; _m_doc = getGuiContext()->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(NULL, // 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 = NULL; quitManualMode(); } } }