/**************************************************************************** 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_stepreducegroundpointdensity.h" #include "ct_log/ct_logmanager.h" #include "ct_itemdrawable/ct_image2d.h" #define EPSILON 0.000001 ONF_StepReduceGroundPointDensity::ONF_StepReduceGroundPointDensity() : SuperClass() { _resolution = 0.25; _mode = 1; _gridMode = 1; _xBase = 0; _yBase = 0; _offset = true; _name = tr("Sol (densité réduite)"); } QString ONF_StepReduceGroundPointDensity::description() const { return tr("Réduire la densité de points sols"); } QString ONF_StepReduceGroundPointDensity::detailledDescription() const { return tr(""); } QString ONF_StepReduceGroundPointDensity::inputDescription() const { return SuperClass::inputDescription() + tr("

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

"); } QString ONF_StepReduceGroundPointDensity::detailsDescription() const { return tr(""); } CT_VirtualAbstractStep* ONF_StepReduceGroundPointDensity::createNewInstance() const { return new ONF_StepReduceGroundPointDensity(); } //////////////////// PROTECTED METHODS ////////////////// void ONF_StepReduceGroundPointDensity::declareInputModels(CT_StepInModelStructureManager& manager) { manager.addResult(_inResult, tr("Scènes à filtrer"), "", true); manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup); manager.addGroup(_inZeroOrMoreRootGroup, _inGroup); manager.addItem(_inGroup, _inScene, tr("Scènes")); manager.addItem(_inGroup, _inArea, tr("Emprise (optionnelle)")); } void ONF_StepReduceGroundPointDensity::fillPostInputConfigurationDialog(CT_StepConfigurableDialog *postInputConfigDialog) { postInputConfigDialog->addDouble(tr("Résolution des cellules"), tr("m"), 0.01, 999.99, 2, _resolution); CT_ButtonGroup &bg_mode = postInputConfigDialog->addButtonGroup(_mode); postInputConfigDialog->addExcludeValue("", "", tr("Sélectionner les points les plus proche du centre de la cellule"), bg_mode, 1); postInputConfigDialog->addExcludeValue("", "", tr("Sélectionner les points les plus bas"), bg_mode, 0); postInputConfigDialog->addBool("", "", tr("Décaler la grille pour la centrer"), _offset); postInputConfigDialog->addString(tr("Nom à donner au raster"), "", _name, tr("Attention : ce paramètre ne peut être pris en compte qu'à l'ajout de l'étape ou au chargement d'un script.
Une modification de ce paramètre lors d'une reconfiguration des paramètres se répercutera dans les scripts exportés ultérieurement, mais pas dans la session en cours. ")); postInputConfigDialog->addSeparationLine(); postInputConfigDialog->addText(tr("Quelle emprise utiliser ?"),"", "", tr("La section suivante définit comment l'extension selon les axes X et Y du raster est déterminée.")); CT_ButtonGroup &bg_gridMode = postInputConfigDialog->addButtonGroup(_gridMode); postInputConfigDialog->addExcludeValue("", "", tr("La boite englobante de la scène"), bg_gridMode, 0, tr("Dans ce cas l'extension est directement calculée à partir des X et Y maximum et minimum des points de la scène d'entrée. ")); postInputConfigDialog->addExcludeValue("", "", tr("L'emprise précédement sélectionnée "), bg_gridMode, 2, tr("Cette option ne fonctionne que si une emprise a été séléctionnée dans les résultats d'entrée (optionnel). Dans ce cas c'est cette emprise qui détermine l'extension du raster. Cette option est utilisée dans le cas de dallages pré-définis. ")); postInputConfigDialog->addExcludeValue("", "", tr("Recaler par rapport aux coordonnées suivantes :"), bg_gridMode, 1, tr("Cette option calcule d'abord l'entension des points de la scène (comme la première option), mais l'agrandit de façon à ce que les coordonnées du coin en bas à gauche du raster tombe \"juste\" par rapport aux coordonnées indiquées (cette à dire qu'elles soient égales à ces coordonnées de référence plus un multiple de la résolution). C'est l'option par défaut, permettant des rasters cohérents entre eux. ")); postInputConfigDialog->addDouble(tr("Coordonnée X :"), "", -std::numeric_limits::max(), std::numeric_limits::max(), 4, _xBase, 1, tr("Coordonnée X de référence pour la troisième option. ")); postInputConfigDialog->addDouble(tr("Coordonnée Y :"), "", -std::numeric_limits::max(), std::numeric_limits::max(), 4, _yBase, 1, tr("Coordonnée Y de référence pour la troisième option. ")); } void ONF_StepReduceGroundPointDensity::declareOutputModels(CT_StepOutModelStructureManager& manager) { manager.addResultCopy(_inResult); manager.addItem(_inGroup, _outScene, _name); } void ONF_StepReduceGroundPointDensity::compute() { for (CT_StandardItemGroup* group : _inGroup.iterateOutputs(_inResult)) { if (isStopped()) {return;} const CT_AbstractItemDrawableWithPointCloud *inScene = group->singularItem(_inScene); const CT_AbstractGeometricalItem *emprise = group->singularItem(_inArea); if (inScene != nullptr) { Eigen::Vector3d min, max; inScene->boundingBox(min, max); // Creation du raster double minX = std::floor(min(0)*100.0) / 100.0; double minY = std::floor(min(1)*100.0) / 100.0; double maxX = std::ceil (max(0)*100.0) / 100.0; double maxY = std::ceil (max(1)*100.0) / 100.0; if (_gridMode == 2 && emprise != nullptr && emprise->hasBoundingBox()) { emprise->boundingBox(min, max); minX = min(0); minY = min(1); maxX = max(0) - EPSILON; maxY = max(1) - EPSILON; } else if (_gridMode == 1) { minX = std::floor((inScene->minX() - _xBase - 1) / _resolution) * _resolution + _xBase; minY = std::floor((inScene->minY() - _yBase - 1) / _resolution) * _resolution + _yBase; while (minX < min(0)) {minX += _resolution;}; while (minY < min(1)) {minY += _resolution;}; while (minX > min(0)) {minX -= _resolution;}; while (minY > min(1)) {minY -= _resolution;}; } if (_offset) { minX -= _resolution / 2.0; minY -= _resolution / 2.0; maxX += _resolution; maxY += _resolution; } CT_Image2D *rasterZ = CT_Image2D::createImage2DFromXYCoords(minX, minY, maxX, maxY, _resolution, 0, -9999.0, -9999.0); std::vector indices(rasterZ->nCells()); // Indices de la scène filtrée CT_PointCloudIndexVector *resPointCloudIndex = new CT_PointCloudIndexVector(); resPointCloudIndex->setSortType(CT_PointCloudIndexVector::NotSorted); CT_PointIterator itP(inScene->pointCloudIndex()); size_t n_points = itP.size(); PS_LOG->addMessage(LogInterface::info, LogInterface::step, QString(tr("%1 points à l'origine")).arg(n_points)); size_t i = 0; size_t nbOfFilteredPoints = 0; while(itP.hasNext()) { const CT_Point &point = itP.next().currentPoint(); size_t index; if (rasterZ->indexAtCoords(point(0), point(1), index)) { float val = rasterZ->valueAtIndex(index); float newVal = point(2); if (_mode == 1) // use distance to cell center instead of altitude { Eigen::Vector3d center; rasterZ->getCellCenterCoordinates(index, center); newVal = sqrt(pow(point(0) - center(0), 2) + pow(point(1) - center(1), 2)); } if (qFuzzyCompare(val, rasterZ->NA()) || newVal < val) { rasterZ->setValueAtIndex(index, newVal); indices[index] = itP.currentGlobalIndex(); } } ++i; if (i % 1000 == 0) {setProgress((float(i) / float(n_points)) * 99.0f);} } size_t ncells = rasterZ->nCells(); for (size_t cell = 0 ; cell < ncells ; cell++) { float zval = rasterZ->valueAtIndex(cell); if (!qFuzzyCompare(zval, rasterZ->NA())) { resPointCloudIndex->addIndex(indices[cell]); ++nbOfFilteredPoints; } } PS_LOG->addMessage(LogInterface::info, LogInterface::step, QString(tr("%1 points conservés")).arg(nbOfFilteredPoints)); if (resPointCloudIndex->size() > 0) { // creation et ajout de la scene resPointCloudIndex->setSortType(CT_PointCloudIndexVector::SortedInAscendingOrder); CT_Scene *outScene = new CT_Scene(PS_REPOSITORY->registerPointCloudIndex(resPointCloudIndex)); outScene->updateBoundingBox(); group->addSingularItem(_outScene, outScene); } delete rasterZ; } } }