Skip to content
Permalink
Browse files

[FEATURE][processing] Filter Vertices by M and Filter Vertices by Z a…

…lgorithms

Adds two new algorithms, for filtering line/polygon vertices by their
M or Z values. A minimum and maximum M/Z value can be entered, and
if the vertices fall outside these ranges they will be discarded
from the output geometry.

Both min and max filter value can also be data defined, so can
vary per feature.
  • Loading branch information
nyalldawson committed Jul 21, 2018
1 parent f685d11 commit 97e0db6245c9385ca17b31ea7d3378b56b33d9e8
Showing with 395 additions and 0 deletions.
  1. BIN python/plugins/processing/tests/testdata/expected/filter_by_m.dbf
  2. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_m.prj
  3. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_m.qpj
  4. BIN python/plugins/processing/tests/testdata/expected/filter_by_m.shp
  5. BIN python/plugins/processing/tests/testdata/expected/filter_by_m.shx
  6. BIN python/plugins/processing/tests/testdata/expected/filter_by_m_no_max.dbf
  7. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_m_no_max.prj
  8. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_m_no_max.qpj
  9. BIN python/plugins/processing/tests/testdata/expected/filter_by_m_no_max.shp
  10. BIN python/plugins/processing/tests/testdata/expected/filter_by_m_no_max.shx
  11. BIN python/plugins/processing/tests/testdata/expected/filter_by_m_no_min.dbf
  12. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_m_no_min.prj
  13. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_m_no_min.qpj
  14. BIN python/plugins/processing/tests/testdata/expected/filter_by_m_no_min.shp
  15. BIN python/plugins/processing/tests/testdata/expected/filter_by_m_no_min.shx
  16. BIN python/plugins/processing/tests/testdata/expected/filter_by_z.dbf
  17. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_z.prj
  18. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_z.qpj
  19. BIN python/plugins/processing/tests/testdata/expected/filter_by_z.shp
  20. BIN python/plugins/processing/tests/testdata/expected/filter_by_z.shx
  21. BIN python/plugins/processing/tests/testdata/expected/filter_by_z_no_max.dbf
  22. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_z_no_max.prj
  23. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_z_no_max.qpj
  24. BIN python/plugins/processing/tests/testdata/expected/filter_by_z_no_max.shp
  25. BIN python/plugins/processing/tests/testdata/expected/filter_by_z_no_max.shx
  26. BIN python/plugins/processing/tests/testdata/expected/filter_by_z_no_min.dbf
  27. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_z_no_min.prj
  28. +1 −0 python/plugins/processing/tests/testdata/expected/filter_by_z_no_min.qpj
  29. BIN python/plugins/processing/tests/testdata/expected/filter_by_z_no_min.shp
  30. BIN python/plugins/processing/tests/testdata/expected/filter_by_z_no_min.shx
  31. +1 −0 python/plugins/processing/tests/testdata/lines_z.cpg
  32. BIN python/plugins/processing/tests/testdata/lines_z.dbf
  33. +1 −0 python/plugins/processing/tests/testdata/lines_z.prj
  34. +1 −0 python/plugins/processing/tests/testdata/lines_z.qpj
  35. BIN python/plugins/processing/tests/testdata/lines_z.shp
  36. BIN python/plugins/processing/tests/testdata/lines_z.shx
  37. +74 −0 python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
  38. +1 −0 src/analysis/CMakeLists.txt
  39. +194 −0 src/analysis/processing/qgsalgorithmfilterpoints.cpp
  40. +108 −0 src/analysis/processing/qgsalgorithmfilterpoints.h
  41. +3 −0 src/analysis/processing/qgsnativealgorithms.cpp
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
UTF-8
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
@@ -5818,4 +5818,78 @@ tests:
fields:
fid: skip

- algorithm: native:filterpointsbym
name: Filter by m no max
params:
INPUT:
name: lines_m.shp
type: vector
MIN: 0.6
results:
OUTPUT:
name: expected/filter_by_m_no_max.shp
type: vector

- algorithm: native:filterpointsbym
name: Filter by m no min
params:
INPUT:
name: lines_m.shp
type: vector
MAX: 0.6
results:
OUTPUT:
name: expected/filter_by_m_no_min.shp
type: vector

- algorithm: native:filterpointsbym
name: Filter by m
params:
INPUT:
name: lines_m.shp
type: vector
MAX: 0.7
MIN: 0.4
results:
OUTPUT:
name: expected/filter_by_m.shp
type: vector

- algorithm: native:filterpointsbyz
name: Filter by z no max
params:
INPUT:
name: lines_z.shp
type: vector
MIN: 0.6
results:
OUTPUT:
name: expected/filter_by_z_no_max.shp
type: vector

- algorithm: native:filterpointsbyz
name: Filter by z no min
params:
INPUT:
name: lines_z.shp
type: vector
MAX: 0.6
results:
OUTPUT:
name: expected/filter_by_z_no_min.shp
type: vector

- algorithm: native:filterpointsbyz
name: Filter by z
params:
INPUT:
name: lines_z.shp
type: vector
MAX: 0.7
MIN: 0.4
results:
OUTPUT:
name: expected/filter_by_z.shp
type: vector

# See ../README.md for a description of the file format
@@ -42,6 +42,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmextractvertices.cpp
processing/qgsalgorithmfiledownloader.cpp
processing/qgsalgorithmfilter.cpp
processing/qgsalgorithmfilterpoints.cpp
processing/qgsalgorithmfixgeometries.cpp
processing/qgsalgorithmimportphotos.cpp
processing/qgsalgorithmintersection.cpp
@@ -0,0 +1,194 @@
/***************************************************************************
qgsalgorithmfilterpoints.cpp
----------------------------
begin : July 2018
copyright : (C) 2018 by Nyall Dawson
email : nyall dot dawson at gmail 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 "qgsalgorithmfilterpoints.h"

///@cond PRIVATE


QString QgsFilterPointsAlgorithmBase::group() const
{
return QObject::tr( "Vector geometry" );
}

QString QgsFilterPointsAlgorithmBase::groupId() const
{
return QStringLiteral( "vectorgeometry" );
}

QString QgsFilterPointsAlgorithmBase::outputName() const
{
return QObject::tr( "Filtered" );
}

QString QgsFilterPointsAlgorithmBase::shortHelpString() const
{
return QObject::tr( "Filters away vertices based on their %1, returning geometries with only "
"vertex points that have a %1 ≥ the specified minimum value and ≤ "
"the maximum value.\n\n"
"If the minimum value is not specified than only the maximum value is tested, "
"and similarly if the maximum value is not specified than only the minimum value is tested.\n\n"
"The resultant geometries created by this algorithm may not be valid "
"and may need to be run through the \"Repair geometries\" algorithm to ensure "
"their validity." ).arg( componentString() );
}

QList<int> QgsFilterPointsAlgorithmBase::inputLayerTypes() const
{
return QList<int>() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon;
}

void QgsFilterPointsAlgorithmBase::initParameters( const QVariantMap & )
{
auto min = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "MIN" ),
QObject::tr( "Minimum" ), QgsProcessingParameterNumber::Double, QVariant(), true );
min->setIsDynamic( true );
min->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Minimum" ), QObject::tr( "Minimum value" ), QgsPropertyDefinition::Double ) );
min->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( min.release() );

auto max = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "MAX" ),
QObject::tr( "Maximum" ), QgsProcessingParameterNumber::Double, QVariant(), true );
max->setIsDynamic( true );
max->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Maximum" ), QObject::tr( "Maximum value" ), QgsPropertyDefinition::Double ) );
max->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( max.release() );
}

bool QgsFilterPointsAlgorithmBase::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
if ( parameters.contains( QStringLiteral( "MIN" ) ) && parameters.value( QStringLiteral( "MIN" ) ).isValid() )
mMin = parameterAsDouble( parameters, QStringLiteral( "MIN" ), context );
else
mMin = std::numeric_limits<double>::quiet_NaN();

mDynamicMin = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "MIN" ) );
if ( mDynamicMin )
mMinProperty = parameters.value( QStringLiteral( "MIN" ) ).value< QgsProperty >();

if ( parameters.contains( QStringLiteral( "MAX" ) ) && parameters.value( QStringLiteral( "MAX" ) ).isValid() )
mMax = parameterAsDouble( parameters, QStringLiteral( "MAX" ), context );
else
mMax = std::numeric_limits<double>::quiet_NaN();

mDynamicMax = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "MAX" ) );
if ( mDynamicMax )
mMaxProperty = parameters.value( QStringLiteral( "MAX" ) ).value< QgsProperty >();

return true;
}

QgsFeatureList QgsFilterPointsAlgorithmBase::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
{
QgsFeature f = feature;
if ( f.hasGeometry() )
{
QgsGeometry geometry = f.geometry();
double min = mMin;
if ( mDynamicMin )
min = mMinProperty.valueAsDouble( context.expressionContext(), std::numeric_limits<double>::quiet_NaN() );

double max = mMax;
if ( mDynamicMax )
max = mMaxProperty.valueAsDouble( context.expressionContext(), std::numeric_limits<double>::quiet_NaN() );

filter( geometry, min, max );
f.setGeometry( geometry );
}
return QgsFeatureList() << f;
}

//
// QgsFilterPointsByM
//

QString QgsFilterPointsByM::name() const
{
return QStringLiteral( "filterpointsbym" );
}

QString QgsFilterPointsByM::displayName() const
{
return QObject::tr( "Filter vertices by m value" );
}

QStringList QgsFilterPointsByM::tags() const
{
return QObject::tr( "filter,points,vertex,m" ).split( ',' );
}

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

QString QgsFilterPointsByM::componentString() const
{
return QObject::tr( "m-value" );
}

void QgsFilterPointsByM::filter( QgsGeometry &geometry, double min, double max ) const
{
geometry.filterVertices( [min, max]( const QgsPoint & point )->bool
{
return ( std::isnan( min ) || point.m() >= min )
&& ( std::isnan( max ) || point.m() <= max );
} );
}


//
// QgsFilterPointsByZ
//

QString QgsFilterPointsByZ::name() const
{
return QStringLiteral( "filterpointsbyz" );
}

QString QgsFilterPointsByZ::displayName() const
{
return QObject::tr( "Filter vertices by z value" );
}

QStringList QgsFilterPointsByZ::tags() const
{
return QObject::tr( "filter,points,vertex,z" ).split( ',' );
}

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

QString QgsFilterPointsByZ::componentString() const
{
return QObject::tr( "z-value" );
}

void QgsFilterPointsByZ::filter( QgsGeometry &geometry, double min, double max ) const
{
geometry.filterVertices( [min, max]( const QgsPoint & point )->bool
{
return ( std::isnan( min ) || point.z() >= min )
&& ( std::isnan( max ) || point.z() <= max );
} );
}

///@endcond


0 comments on commit 97e0db6

Please sign in to comment.
You can’t perform that action at this time.