Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,12 @@ set(QGIS_ANALYSIS_SRCS
processing/pdal/qgsalgorithmpdalthinbydecimate.cpp
processing/pdal/qgsalgorithmpdalthinbyradius.cpp
processing/pdal/qgsalgorithmpdaltile.cpp
processing/pdal/qgsalgorithmpdalheightabovegroundnearestneighbour.cpp
processing/pdal/qgsalgorithmpdalheightabovegrounddelaunay.cpp
processing/pdal/qgsalgorithmpdalfilternoisestatistical.cpp
processing/pdal/qgsalgorithmpdalfilternoiseradius.cpp
processing/pdal/qgsalgorithmpdalclassifyground.cpp
processing/pdal/qgsalgorithmpdaltransform.cpp

raster/qgsalignraster.cpp
raster/qgsninecellfilter.cpp
Expand Down
116 changes: 116 additions & 0 deletions src/analysis/processing/pdal/qgsalgorithmpdalclassifyground.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/***************************************************************************
qgsalgorithmpdalclassifyground.cpp
---------------------
begin : December 2025
copyright : (C) 2025 by Jan Caha
email : jan.caha at outlook dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsalgorithmpdalclassifyground.h"

#include "qgspointcloudlayer.h"
#include "qgsrunprocess.h"

///@cond PRIVATE

QString QgsPdalClassifyGroundAlgorithm::name() const
{
return QStringLiteral( "classifyground" );
}

QString QgsPdalClassifyGroundAlgorithm::displayName() const
{
return QObject::tr( "Classify Ground Points" );
}

QString QgsPdalClassifyGroundAlgorithm::group() const
{
return QObject::tr( "Point cloud data management" );
}

QString QgsPdalClassifyGroundAlgorithm::groupId() const
{
return QStringLiteral( "pointclouddatamanagement" );
}

QStringList QgsPdalClassifyGroundAlgorithm::tags() const
{
return QObject::tr( "pdal,lidar,classify,ground,elevation" ).split( ',' );
}

QString QgsPdalClassifyGroundAlgorithm::shortHelpString() const
{
return QObject::tr( "Classifies ground points using the Simple Morphological Filter (SMRF) algorithm." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Parameters:" )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Cell Size - cell size for processing grid (in map units). Smaller values give finer detail but may increase noise." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Scalar - Threshold for steeper slopes. Higher value if the terrain is rough, otherwise real ground might be misclassified." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Slope - slope threshold (rise over run). How much slope is tolerated as ground. Should be higher for steep terrain." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Threshold - elevation threshold for separating ground from objects. Higher values allow larger deviations from the ground." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Window Size - maximum filter window size. Higher values better identify large buildings or objects, smaller values protect smaller features." );
}

QString QgsPdalClassifyGroundAlgorithm::shortDescription() const
{
return QObject::tr( "Classifies ground points using the Simple Morphological Filter (SMRF) algorithm." );
}

QgsPdalClassifyGroundAlgorithm *QgsPdalClassifyGroundAlgorithm::createInstance() const
{
return new QgsPdalClassifyGroundAlgorithm();
}

void QgsPdalClassifyGroundAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterPointCloudLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );

addParameter( new QgsProcessingParameterNumber( QStringLiteral( "CELL_SIZE" ), QObject::tr( "Grid Cell Size" ), Qgis::ProcessingNumberParameterType::Double, 1.0 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "SCALAR" ), QObject::tr( "Scalar" ), Qgis::ProcessingNumberParameterType::Double, 1.25 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "SLOPE" ), QObject::tr( "Slope" ), Qgis::ProcessingNumberParameterType::Double, 0.15 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "THRESHOLD" ), QObject::tr( "Threshold" ), Qgis::ProcessingNumberParameterType::Double, 0.5 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "WINDOW_SIZE" ), QObject::tr( "Window size" ), Qgis::ProcessingNumberParameterType::Double, 18.0 ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this label (and maybe some above) be more verbose, i.e., "Maximum filter window size"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mirrors parameters names in PDAL and PDAL Wrench, I would oppose changing the name.


addParameter( new QgsProcessingParameterPointCloudDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Classified Ground" ) ) );
}

QStringList QgsPdalClassifyGroundAlgorithm::createArgumentLists( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
Q_UNUSED( feedback );

QgsPointCloudLayer *layer = parameterAsPointCloudLayer( parameters, QStringLiteral( "INPUT" ), context, QgsProcessing::LayerOptionsFlag::SkipIndexGeneration );
if ( !layer )
throw QgsProcessingException( invalidPointCloudError( parameters, QStringLiteral( "INPUT" ) ) );

const QString outputName = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
QString outputFile = fixOutputFileName( layer->source(), outputName, context );
checkOutputFormat( layer->source(), outputFile );
setOutputValue( QStringLiteral( "OUTPUT" ), outputFile );

const double cellSize = parameterAsDouble( parameters, QStringLiteral( "CELL_SIZE" ), context );
const double scalar = parameterAsDouble( parameters, QStringLiteral( "SCALAR" ), context );
const double slope = parameterAsDouble( parameters, QStringLiteral( "SLOPE" ), context );
const double threshold = parameterAsDouble( parameters, QStringLiteral( "THRESHOLD" ), context );
const double windowSize = parameterAsDouble( parameters, QStringLiteral( "WINDOW_SIZE" ), context );

QStringList args = { QStringLiteral( "classify_ground" ), QStringLiteral( "--input=%1" ).arg( layer->source() ), QStringLiteral( "--output=%1" ).arg( outputFile ), QStringLiteral( "--cell-size=%1" ).arg( cellSize ), QStringLiteral( "--scalar=%1" ).arg( scalar ), QStringLiteral( "--slope=%1" ).arg( slope ), QStringLiteral( "--threshold=%1" ).arg( threshold ), QStringLiteral( "--window-size=%1" ).arg( windowSize ) };

applyCommonParameters( args, layer->crs(), parameters, context );
applyThreadsParameter( args, context );
return args;
}

///@endcond
52 changes: 52 additions & 0 deletions src/analysis/processing/pdal/qgsalgorithmpdalclassifyground.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/***************************************************************************
qgsalgorithmpdalclassifyground.h
---------------------
begin : December 2025
copyright : (C) 2025 by Jan Caha
email : jan.caha at outlook dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSALGORITHMPDALCLASSIFYGROUND_H
#define QGSALGORITHMPDALCLASSIFYGROUND_H

#define SIP_NO_FILE

#include "qgis_sip.h"
#include "qgspdalalgorithmbase.h"

///@cond PRIVATE

/**
* Native point cloud filter noise using radius algorithm.
*/
class QgsPdalClassifyGroundAlgorithm : public QgsPdalAlgorithmBase
{
public:
QgsPdalClassifyGroundAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QString group() const override;
QString groupId() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QString shortDescription() const override;
QgsPdalClassifyGroundAlgorithm *createInstance() const override SIP_FACTORY;

QStringList createArgumentLists( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

friend class TestQgsProcessingPdalAlgs;
};

///@endcond PRIVATE

#endif // QGSALGORITHMPDALCLASSIFYGROUND_H
109 changes: 109 additions & 0 deletions src/analysis/processing/pdal/qgsalgorithmpdalfilternoiseradius.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/***************************************************************************
qgsalgorithmpdalfilternoiseradius.cpp
---------------------
begin : December 2025
copyright : (C) 2025 by Jan Caha
email : jan.caha at outlook dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsalgorithmpdalfilternoiseradius.h"

#include "qgspointcloudlayer.h"
#include "qgsrunprocess.h"

///@cond PRIVATE

QString QgsPdalFilterNoiseRadiusAlgorithm::name() const
{
return QStringLiteral( "filternoiseradius" );
}

QString QgsPdalFilterNoiseRadiusAlgorithm::displayName() const
{
return QObject::tr( "Filter Noise (by radius algorithm)" );
}

QString QgsPdalFilterNoiseRadiusAlgorithm::group() const
{
return QObject::tr( "Point cloud data management" );
}

QString QgsPdalFilterNoiseRadiusAlgorithm::groupId() const
{
return QStringLiteral( "pointclouddatamanagement" );
}

QStringList QgsPdalFilterNoiseRadiusAlgorithm::tags() const
{
return QObject::tr( "pdal,lidar,filter,noise,radius" ).split( ',' );
}

QString QgsPdalFilterNoiseRadiusAlgorithm::shortHelpString() const
{
return QObject::tr( "Filter noise in a point cloud using radius algorithm." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "Points are marked as noise if they have fewer than the minimum number of neighbors within the specified radius." )
+ QStringLiteral( "\n\n" )
+ QObject::tr( "If 'Remove noise points' is enabled, noise points will be removed from the output, otherwise they are classified but retained." );
}

QString QgsPdalFilterNoiseRadiusAlgorithm::shortDescription() const
{
return QObject::tr( "Filter noise in a point cloud using radius algorithm." );
}

QgsPdalFilterNoiseRadiusAlgorithm *QgsPdalFilterNoiseRadiusAlgorithm::createInstance() const
{
return new QgsPdalFilterNoiseRadiusAlgorithm();
}

void QgsPdalFilterNoiseRadiusAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterPointCloudLayer( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "REMOVE_NOISE_POINTS" ), QObject::tr( "Remove noise points" ), false ) );

addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MIN_K" ), QObject::tr( "Minimum number of neighbors in radius" ), Qgis::ProcessingNumberParameterType::Integer, 2 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "RADIUS" ), QObject::tr( "Radius" ), Qgis::ProcessingNumberParameterType::Double, 1.0 ) );

addParameter( new QgsProcessingParameterPointCloudDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Filtered (radius algorithm)" ) ) );
}

QStringList QgsPdalFilterNoiseRadiusAlgorithm::createArgumentLists( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
Q_UNUSED( feedback );

QgsPointCloudLayer *layer = parameterAsPointCloudLayer( parameters, QStringLiteral( "INPUT" ), context, QgsProcessing::LayerOptionsFlag::SkipIndexGeneration );
if ( !layer )
throw QgsProcessingException( invalidPointCloudError( parameters, QStringLiteral( "INPUT" ) ) );

const QString outputName = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
QString outputFile = fixOutputFileName( layer->source(), outputName, context );
checkOutputFormat( layer->source(), outputFile );
setOutputValue( QStringLiteral( "OUTPUT" ), outputFile );

const double minK = parameterAsDouble( parameters, QStringLiteral( "MIN_K" ), context );
const double radius = parameterAsDouble( parameters, QStringLiteral( "RADIUS" ), context );

QString removeNoisePoints = "false";
if ( parameterAsBoolean( parameters, QStringLiteral( "REMOVE_NOISE_POINTS" ), context ) )
{
removeNoisePoints = "true";
}

QStringList args = { QStringLiteral( "filter_noise" ), QStringLiteral( "--input=%1" ).arg( layer->source() ), QStringLiteral( "--output=%1" ).arg( outputFile ), QStringLiteral( "--algorithm=radius" ), QStringLiteral( "--remove-noise-points=%1" ).arg( removeNoisePoints ), QStringLiteral( "--radius-min-k=%1" ).arg( minK ), QStringLiteral( "--radius-radius=%1" ).arg( radius ) };

applyCommonParameters( args, layer->crs(), parameters, context );
applyThreadsParameter( args, context );
return args;
}

///@endcond
52 changes: 52 additions & 0 deletions src/analysis/processing/pdal/qgsalgorithmpdalfilternoiseradius.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/***************************************************************************
qgsalgorithmpdalfilternoiseradius.h
---------------------
begin : December 2025
copyright : (C) 2025 by Jan Caha
email : jan.caha at outlook dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSALGORITHMPDALFILTERNOISERADIUS_H
#define QGSALGORITHMPDALFILTERNOISERADIUS_H

#define SIP_NO_FILE

#include "qgis_sip.h"
#include "qgspdalalgorithmbase.h"

///@cond PRIVATE

/**
* Native point cloud filter noise using radius algorithm.
*/
class QgsPdalFilterNoiseRadiusAlgorithm : public QgsPdalAlgorithmBase
{
public:
QgsPdalFilterNoiseRadiusAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QString group() const override;
QString groupId() const override;
QStringList tags() const override;
QString shortHelpString() const override;
QString shortDescription() const override;
QgsPdalFilterNoiseRadiusAlgorithm *createInstance() const override SIP_FACTORY;

QStringList createArgumentLists( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

friend class TestQgsProcessingPdalAlgs;
};

///@endcond PRIVATE

#endif // QGSALGORITHMPDALFILTERNOISERADIUS_H
Loading
Loading