/**************************************************************************** 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_filterremoveupperoutliers.h" #include "ct_pointcloudindex/ct_pointcloudindexvector.h" #include "ct_view/ct_genericconfigurablewidget.h" #define checkAndSetValue(ATT, NAME, TYPE) if((value = settings->firstValueByTagName(NAME)) == NULL) { return false; } else { ATT = value->value().value(); } ONF_FilterRemoveUpperOutliers::ONF_FilterRemoveUpperOutliers(QString pluginName) : CT_AbstractFilter_XYZ(pluginName) { _resolution = 1.0; _threshold = 2; _dc = 1; } ONF_FilterRemoveUpperOutliers::ONF_FilterRemoveUpperOutliers(const ONF_FilterRemoveUpperOutliers &other) : CT_AbstractFilter_XYZ(other) { _resolution = other._resolution; _threshold = other._threshold; _dc = other._dc; } QString ONF_FilterRemoveUpperOutliers::getShortDisplayableName() const { return tr("Supprimer les points de hauteur abberante"); } QString ONF_FilterRemoveUpperOutliers::getDetailledDisplayableName() const { return QString("Filtered"); } CT_AbstractConfigurableWidget *ONF_FilterRemoveUpperOutliers::createConfigurationWidget() { CT_GenericConfigurableWidget* configDialog = new CT_GenericConfigurableWidget(); configDialog->addDouble(tr("Résolution de la grille de filtrage"), "m", 0.01, 1000, 2, _resolution); configDialog->addInt(tr("Nombre de points maximum d'une cellule éliminée"), "", 1, 1000, _threshold); configDialog->addInt(tr("Nombre de cases verticales autorisées entre la case filtrée et le voisinnage inférieur"), "", 0, 1000, _dc); return configDialog; } void ONF_FilterRemoveUpperOutliers::saveSettings(SettingsWriterInterface &writer) const { SuperClass::saveSettings(writer); writer.addParameter(this, "resolution", _resolution); writer.addParameter(this, "threshold", _threshold); writer.addParameter(this, "dc", _dc); } bool ONF_FilterRemoveUpperOutliers::restoreSettings(SettingsReaderInterface &reader) { if(!SuperClass::restoreSettings(reader)) return false; QVariant value; if(reader.parameter(this, "resolution", value)) _resolution = value.toDouble(); if(reader.parameter(this, "threshold", value)) _threshold = value.toInt(); if(reader.parameter(this, "dc", value)) _dc = value.toInt(); return true; } bool ONF_FilterRemoveUpperOutliers::filterPointCloudIndex() { if(inputPointCloudIndex() == nullptr) return false; if(!updateMinMax()) return false; _dimx = int(ceil((maxBBox()[0] - minBBox()[0])/_resolution)); _dimy = int(ceil((maxBBox()[1] - minBBox()[1])/_resolution)); _dimz = int(ceil((maxBBox()[2] - minBBox()[2])/_resolution)); QMap* > indexMap; CT_PointCloudIndexVector *outCloud = outputPointCloudIndex(); CT_PointIterator itP(inputPointCloudIndex()); while(itP.hasNext()) { const CT_Point &point = itP.next().currentPoint(); size_t pointIndex = itP.currentGlobalIndex(); outCloud->addIndex(pointIndex); size_t grdIndex = gridIndex(point(0), point(1), point(2)); if (!indexMap.contains(grdIndex)) {indexMap.insert(grdIndex, new QList());} QList *points = indexMap.value(grdIndex); points->append(pointIndex); } for (int xx = 0 ; xx < _dimx ; xx++) { for (int yy = 0 ; yy < _dimy ; yy++) { bool goDown = true; for (int zz = _dimz - 1 ; goDown && (zz > _dc) ; zz--) { size_t grdIndex = gridIndex(xx, yy, zz); if (indexMap.contains(grdIndex)) { QList *points = indexMap.value(grdIndex); if (points->size() <= _threshold) { int zzm = zz - _dc - 1; bool toremove = true; if (toremove && indexMap.contains(gridIndex(xx, yy, zzm))) {toremove = false;} if (toremove && (xx >= _dc) && (yy >= _dc) && indexMap.contains(gridIndex(xx-_dc, yy-_dc, zzm))) {toremove = false;} if (toremove && (xx >= _dc) && indexMap.contains(gridIndex(xx-_dc, yy, zzm))) {toremove = false;} if (toremove && (xx >= _dc) && (yy < _dimy - _dc) && indexMap.contains(gridIndex(xx-_dc, yy+_dc, zzm))) {toremove = false;} if (toremove && (yy >= _dc) && indexMap.contains(gridIndex(xx, yy-_dc, zzm))) {toremove = false;} if (toremove && (yy < _dimy - _dc) && indexMap.contains(gridIndex(xx, yy+_dc, zzm))) {toremove = false;} if (toremove && (xx < _dimx - _dc) && (yy >= _dc) && indexMap.contains(gridIndex(xx+_dc, yy-_dc, zzm))) {toremove = false;} if (toremove && (xx < _dimx - _dc) && (yy >= _dc) && indexMap.contains(gridIndex(xx+_dc, yy, zzm))) {toremove = false;} if (toremove && (xx < _dimx - _dc) && (yy < _dimy - _dc) && indexMap.contains(gridIndex(xx+_dc, yy+_dc, zzm))) {toremove = false;} if (toremove) { QListIterator it(*points); while (it.hasNext()) outCloud->removeIndex(it.next()); } else { goDown = false; } } else { goDown = false; } } } } } qDeleteAll(indexMap.values()); return true; } QString ONF_FilterRemoveUpperOutliers::getShortDescription() const { return tr("Supprimer les points au-dessus de la canopée"); } CT_AbstractConfigurableElement *ONF_FilterRemoveUpperOutliers::copy() const { return new ONF_FilterRemoveUpperOutliers(*this); } size_t ONF_FilterRemoveUpperOutliers::gridIndex(const double &x, const double &y, const double &z) const { int colx = int(floor((x - minBBox()[0]) / _resolution)); int liny = int(floor((y - minBBox()[1]) / _resolution)); int levz = int(floor((z - minBBox()[2]) / _resolution)); return gridIndex(colx, liny, levz); } size_t ONF_FilterRemoveUpperOutliers::gridIndex(const int &colx, const int &liny, const int &levz) const { return size_t(levz)*size_t(_dimx)*size_t(_dimy) + size_t(liny)*size_t(_dimx) + size_t(colx); }