/**************************************************************************** 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_stepconverttintodtm.h" #include "ct_itemdrawable/tools/image2dtools/ct_image2dnaturalneighboursinterpolator.h" #include "ct_log/ct_logmanager.h" #define EPSILON 0.000001 ONF_StepConvertTINtoDTM::ONF_StepConvertTINtoDTM() : SuperClass() { _gridsize = 0.5; _convertNA = false; _gridMode = 1; _xBase = 0; _yBase = 0; _NAMode = 0; _naReplaceValue = 0; _name = tr("MNT"); } QString ONF_StepConvertTINtoDTM::description() const { return tr("Convertir un TIN en MNT"); } QString ONF_StepConvertTINtoDTM::detailledDescription() const { return tr(""); } QString ONF_StepConvertTINtoDTM::inputDescription() const { return SuperClass::inputDescription() + tr("

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

"); } QString ONF_StepConvertTINtoDTM::detailsDescription() const { return tr(""); } CT_VirtualAbstractStep* ONF_StepConvertTINtoDTM::createNewInstance() const { // cree une copie de cette etape return new ONF_StepConvertTINtoDTM(); } /////////////////////// PROTECTED /////////////////////// void ONF_StepConvertTINtoDTM::declareInputModels(CT_StepInModelStructureManager& manager) { manager.addResult(_inResult, tr("TIN")); manager.setZeroOrMoreRootGroup(_inResult, _inZeroOrMoreRootGroup); manager.addGroup(_inZeroOrMoreRootGroup, _inGroup); manager.addItem(_inGroup, _inTIN, tr("TIN")); manager.addItem(_inGroup, _inArea, tr("Emprise (optionnelle)")); } void ONF_StepConvertTINtoDTM::fillPostInputConfigurationDialog(CT_StepConfigurableDialog* postInputConfigDialog) { postInputConfigDialog->addDouble(tr("Résolution du raster :"), "cm", 1, 1000, 0, _gridsize, 100); 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->addBool(tr("Remplacer les valeurs NA par :"), "", "", _convertNA, tr("La section suivante définit s'il faut remplacer les valeurs manquantes du raster par une valeur indiquée.
Si cette case est coché, toutes les valeurs manquantes seront remplacée par la valeur indiquée.")); CT_ButtonGroup &bg_NAMode = postInputConfigDialog->addButtonGroup(_NAMode); postInputConfigDialog->addExcludeValue("", "", tr("Min(MNT)"), bg_NAMode, 0, tr("Les valeurs manquantes seront remplacées par la plus petite valeur observée dans le raster. ")); postInputConfigDialog->addExcludeValue("", "", tr("La valeur ci-dessous"), bg_NAMode, 1, tr("Les valeurs manquantes seront remplacées par la valeur choisie. ")); postInputConfigDialog->addDouble(tr("Valeur de remplacement des NA :"), "m", -std::numeric_limits::max(), std::numeric_limits::max(), 2, _naReplaceValue); postInputConfigDialog->addSeparationLine(); postInputConfigDialog->addText(tr("Quelle emprise utiliser pour le MNT ?"),"", "", 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_StepConvertTINtoDTM::declareOutputModels(CT_StepOutModelStructureManager& manager) { manager.addResultCopy(_inResult); manager.addItem(_inGroup, _outDTM, _name); } void ONF_StepConvertTINtoDTM::compute() { //double halfGridSize = _gridsize / 2.0; for (CT_StandardItemGroup* group : _inGroup.iterateOutputs(_inResult)) { for (const CT_Triangulation2D* tin : group->singularItems(_inTIN)) { const CT_AbstractGeometricalItem *emprise = group->singularItem(_inArea); if (tin != nullptr) { Eigen::Vector3d min, max; tin->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((min(0) - _xBase - 1) / _gridsize) * _gridsize + _xBase; minY = std::floor((min(1) - _yBase - 1) / _gridsize) * _gridsize + _yBase; while (minX < min(0)) {minX += _gridsize;}; while (minY < min(1)) {minY += _gridsize;}; while (minX > min(0)) {minX -= _gridsize;}; while (minY > min(1)) {minY -= _gridsize;}; } CT_Image2D* mnt = CT_Image2D::createImage2DFromXYCoords(minX, minY, maxX, maxY, _gridsize, 0, -9999, -9999); CT_DelaunayTriangulation *triangulation = tin->getDelaunayT(); CT_DelaunayTriangle* refTriangle = (CT_DelaunayTriangle*) triangulation->getRefTriangle(); for (int xx = 0 ; xx < mnt->xdim() ; xx++) { for (int yy = 0 ; yy < mnt->ydim() ; yy++) { Eigen::Vector3d coord = Eigen::Vector3d(0.0, 0.0, 0.0); mnt->getCellCenterCoordinates(xx, yy, coord); double z = -9999; refTriangle = triangulation->getZCoordForXY(coord(0), coord(1), z, refTriangle, false); if (refTriangle != nullptr) { mnt->setValue(xx, yy, (float)z); } } } QList indices; // extend by one cell for (int xx = 0 ; xx < mnt->xdim() ; xx++) { for (int yy = 0 ; yy < mnt->ydim() ; yy++) { if (mnt->value(xx, yy) == mnt->NA()) { if ( mnt->value(xx - 1, yy - 1) != mnt->NA() || mnt->value(xx - 1, yy ) != mnt->NA() || mnt->value(xx - 1, yy + 1) != mnt->NA() || mnt->value(xx , yy - 1) != mnt->NA() || mnt->value(xx , yy + 1) != mnt->NA() || mnt->value(xx + 1, yy - 1) != mnt->NA() || mnt->value(xx + 1, yy ) != mnt->NA() || mnt->value(xx + 1, yy + 1) != mnt->NA()) { size_t index = 0; mnt->index(xx, yy, index); indices.append(index); } } } } for (int i = 0 ; i < indices.size() ; i++) { size_t index = indices.at(i); Eigen::Vector3d coord = Eigen::Vector3d(0.0, 0.0, 0.0); mnt->getCellCenterCoordinates(index, coord); double z = -9999; refTriangle = triangulation->getZCoordForXY(coord(0), coord(1), z, refTriangle, true); if (refTriangle != nullptr) { mnt->setValueAtIndex(index, (float)z); } } setProgress(90); PS_LOG->addMessage(LogInterface::info, LogInterface::step, tr("Convertion terminée")); // ajout du raster MNT group->addSingularItem(_outDTM, mnt); mnt->computeMinMax(); if (_convertNA) { float minNaVal = mnt->dataMin(); if (_NAMode == 1) {minNaVal = static_cast(_naReplaceValue);} for (size_t index = 0 ; index < mnt->nCells() ; index++) { if (qFuzzyCompare(mnt->valueAtIndex(index),mnt->NA())) {mnt->setValueAtIndex(index, minNaVal);} } } } } } setProgress(100); }