/**************************************************************************** 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_metriclaspointcrown.h" #include "ct_pointcloudindex/ct_pointcloudindexvector.h" #include "ct_iterator/ct_pointiterator.h" #include "ct_math/ct_mathstatistics.h" #include "ct_itemdrawable/ct_image2d.h" #include "ctliblas/tools/las/ct_lasdata.h" ONF_MetricLASPointCrown::ONF_MetricLASPointCrown(QString pluginName) : CT_AbstractMetric_LAS(pluginName) { declareAttributes(); } ONF_MetricLASPointCrown::ONF_MetricLASPointCrown(const ONF_MetricLASPointCrown &other) : CT_AbstractMetric_LAS(other) { declareAttributes(); m_configAndResults = other.m_configAndResults; } QString ONF_MetricLASPointCrown::getShortDisplayableName() const { return tr("Taux de pénétration dans les houppiers (LAS, Alti/Ht)"); } QString ONF_MetricLASPointCrown::getShortDescription() const { return tr("Ces métriques calculent des taux de pénétration dans les premiers mètres du sommet d'un houppier (où de tout nuage de point), en utilisant uniquement les premiers retours (first) du nuage de points.
" "Elles sont conçues pour être calculées sur des nuages de points à l'échelle de l'arbre et peuvent fonctionner indifféremment en altitude ou en hauteur.
" "Attention cependant, en zone de forte pente la soustraction de l'altitude du sol pour passer à un nuage en hauteur, conduit à une déformation du houppier. " "En cas de fort relief, il est donc conseillé de calculer ces métriques avec des nuages de points par houppier codés en altitude.
" "Le taux de pénétration sur les X premiers mètres, Pen_Xm, est le nombre de points first situés à plus de X m depuis l'apex (sommet de l'arbre) en descendant, divisé par le nombre de points first total dans le nuage de points. " "Le taux de pénétration sur les XX% supérieurs du houppier, Pen_TopXX, est le nombre de points first situés en-dessous des XX% supérieurs du houppier, divisé par le nombre de points first total dans le nuage de points. " "Un taux de pénétration élevé signifie que la partie du houppier concernée est très perméable et/ou étroite.

" "Attention : cette étape nécessite les attributs LAS, pour identifier les points first." "De plus, pour que ces indicateurs de pénétration aient du sens, il faut que les points sols soient inclus dans le nuage de points."); } QString ONF_MetricLASPointCrown::getDetailledDescription() const { return tr("Les indicateurs suivants peuvent être calculés :" "" ); } ONF_MetricLASPointCrown::Config ONF_MetricLASPointCrown::metricConfiguration() const { return m_configAndResults; } void ONF_MetricLASPointCrown::setMetricConfiguration(const ONF_MetricLASPointCrown::Config &conf) { m_configAndResults = conf; } CT_AbstractConfigurableElement *ONF_MetricLASPointCrown::copy() const { return new ONF_MetricLASPointCrown(*this); } void ONF_MetricLASPointCrown::computeMetric() { m_configAndResults._X_Apex.value = std::numeric_limits::quiet_NaN(); m_configAndResults._Y_Apex.value = std::numeric_limits::quiet_NaN(); m_configAndResults._Z_Apex.value = -std::numeric_limits::max(); m_configAndResults._Pen_1m.value = 0; m_configAndResults._Pen_2m.value = 0; m_configAndResults._Pen_3m.value = 0; m_configAndResults._Pen_4m.value = 0; m_configAndResults._Pen_5m.value = 0; m_configAndResults._Pen_Top25.value = 0; m_configAndResults._Pen_Top50.value = 0; m_configAndResults._Pen_Top75.value = 0; double minZ = std::numeric_limits::max(); bool empty = true; CT_PointIterator itP(pointCloud()); while(itP.hasNext()) { const CT_Point& point = itP.next().currentPoint(); if ((plotArea() == nullptr) || plotArea()->contains(point(0), point(1))) { if (point(2) > m_configAndResults._Z_Apex.value) { m_configAndResults._X_Apex.value = point(0); m_configAndResults._Y_Apex.value = point(1); m_configAndResults._Z_Apex.value = point(2); empty = false; } if (point(2) < minZ) {minZ = point(2);} } } if (!empty) { double deltaZ = m_configAndResults._Z_Apex.value - minZ; double distzTop25 = 0.25 * deltaZ; double distzTop50 = 0.50 * deltaZ; double distzTop75 = 0.75 * deltaZ; double n_FirstInf0 = 0; double n_FirstInf1 = 0; double n_FirstInf2 = 0; double n_FirstInf3 = 0; double n_FirstInf4 = 0; double n_FirstInf5 = 0; double n_FirstInfTop25 = 0; double n_FirstInfTop50 = 0; double n_FirstInfTop75 = 0; CT_AbstractPointAttributesScalar* attributeReturn_Number = static_cast(lasAttributes()->pointsAttributesAt(CT_LasDefine::Return_Number)); if(attributeReturn_Number != nullptr) { bool rnHasBeenSet; CT_PointIterator itP2(pointCloud()); while(itP2.hasNext()) { const CT_Point& point = itP2.next().currentPoint(); if ((plotArea() == nullptr) || plotArea()->contains(point(0), point(1))) { const size_t index = itP2.currentGlobalIndex(); const quint16 return_Number = quint16(attributeReturn_Number->scalarAsDoubleAt(index, &rnHasBeenSet)); double distZ = m_configAndResults._Z_Apex.value - point(2); // calculs pour les taux de pénétration if (return_Number == 1) { n_FirstInf0 += 1.0; if (distZ >= 1.0) { n_FirstInf1 += 1.0; } if (distZ >= 2.0) { n_FirstInf2 += 1.0; } if (distZ >= 3.0) { n_FirstInf3 += 1.0; } if (distZ >= 4.0) { n_FirstInf4 += 1.0; } if (distZ >= 5.0) { n_FirstInf5 += 1.0; } if (distZ >= distzTop25) { n_FirstInfTop25 += 1.0; } if (distZ >= distzTop50) { n_FirstInfTop50 += 1.0; } if (distZ >= distzTop75) { n_FirstInfTop75 += 1.0; } } } } } // Finalisation des calculs de taux de pénétration if (n_FirstInf0 > 0) { m_configAndResults._Pen_1m.value = n_FirstInf1 / n_FirstInf0; m_configAndResults._Pen_2m.value = n_FirstInf2 / n_FirstInf0; m_configAndResults._Pen_3m.value = n_FirstInf3 / n_FirstInf0; m_configAndResults._Pen_4m.value = n_FirstInf4 / n_FirstInf0; m_configAndResults._Pen_5m.value = n_FirstInf5 / n_FirstInf0; m_configAndResults._Pen_Top25.value = n_FirstInfTop25 / n_FirstInf0; m_configAndResults._Pen_Top50.value = n_FirstInfTop50 / n_FirstInf0; m_configAndResults._Pen_Top75.value = n_FirstInfTop75 / n_FirstInf0; } } setAttributeValueVaB(m_configAndResults._X_Apex); setAttributeValueVaB(m_configAndResults._Y_Apex); setAttributeValueVaB(m_configAndResults._Z_Apex); setAttributeValueVaB(m_configAndResults._Pen_1m); setAttributeValueVaB(m_configAndResults._Pen_2m); setAttributeValueVaB(m_configAndResults._Pen_3m); setAttributeValueVaB(m_configAndResults._Pen_4m); setAttributeValueVaB(m_configAndResults._Pen_5m); setAttributeValueVaB(m_configAndResults._Pen_Top25); setAttributeValueVaB(m_configAndResults._Pen_Top50); setAttributeValueVaB(m_configAndResults._Pen_Top75); } void ONF_MetricLASPointCrown::declareAttributes() { registerAttributeVaB(m_configAndResults._X_Apex, CT_AbstractCategory::DATA_X, "X_Apex"); registerAttributeVaB(m_configAndResults._Y_Apex, CT_AbstractCategory::DATA_Y, "Y_Apex"); registerAttributeVaB(m_configAndResults._Z_Apex, CT_AbstractCategory::DATA_NUMBER, "Z_Apex"); registerAttributeVaB(m_configAndResults._Pen_1m, CT_AbstractCategory::DATA_NUMBER, "Pen1m"); registerAttributeVaB(m_configAndResults._Pen_2m, CT_AbstractCategory::DATA_NUMBER, "Pen2m"); registerAttributeVaB(m_configAndResults._Pen_3m, CT_AbstractCategory::DATA_NUMBER, "Pen3m"); registerAttributeVaB(m_configAndResults._Pen_4m, CT_AbstractCategory::DATA_NUMBER, "Pen4m"); registerAttributeVaB(m_configAndResults._Pen_5m, CT_AbstractCategory::DATA_NUMBER, "Pen5m"); registerAttributeVaB(m_configAndResults._Pen_Top25, CT_AbstractCategory::DATA_NUMBER, "PenT25"); registerAttributeVaB(m_configAndResults._Pen_Top50, CT_AbstractCategory::DATA_NUMBER, "PenT50"); registerAttributeVaB(m_configAndResults._Pen_Top75, CT_AbstractCategory::DATA_NUMBER, "PenT75"); }