Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[feature][processing] "Array of Offset Features" algorithm
This algorithm creates copies of features in a layer, by creating multiple offset versions of the feature. Each copy is displaced by a preset amount in the x/y/z/m axis.
- Loading branch information
1 parent
07366e8
commit abe4532
Showing
10 changed files
with
326 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
1 change: 1 addition & 0 deletions
1
python/plugins/processing/tests/testdata/expected/feature_array.prj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]] |
1 change: 1 addition & 0 deletions
1
python/plugins/processing/tests/testdata/expected/feature_array.qpj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 added
BIN
+388 Bytes
python/plugins/processing/tests/testdata/expected/feature_array.shx
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
/*************************************************************************** | ||
qgsalgorithmarrayfeatures.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 "qgsalgorithmarrayfeatures.h" | ||
|
||
///@cond PRIVATE | ||
|
||
QString QgsArrayFeaturesAlgorithm::name() const | ||
{ | ||
return QStringLiteral( "arrayfeatures" ); | ||
} | ||
|
||
QString QgsArrayFeaturesAlgorithm::displayName() const | ||
{ | ||
return QObject::tr( "Array of offset features" ); | ||
} | ||
|
||
QStringList QgsArrayFeaturesAlgorithm::tags() const | ||
{ | ||
return QObject::tr( "translate,duplicate,grid,spaced,moved,copy,features,objects,step,repeat" ).split( ',' ); | ||
} | ||
|
||
QString QgsArrayFeaturesAlgorithm::group() const | ||
{ | ||
return QObject::tr( "Vector geometry" ); | ||
} | ||
|
||
QString QgsArrayFeaturesAlgorithm::groupId() const | ||
{ | ||
return QStringLiteral( "vectorgeometry" ); | ||
} | ||
|
||
QString QgsArrayFeaturesAlgorithm::outputName() const | ||
{ | ||
return QObject::tr( "Offset" ); | ||
} | ||
|
||
QString QgsArrayFeaturesAlgorithm::shortHelpString() const | ||
{ | ||
return QObject::tr( "This algorithm creates copies of features in a layer, by creating multiple offset versions of each feature. " | ||
"Each copy is displaced by a preset amount in the x/y/z/m axis." ); | ||
} | ||
|
||
QString QgsArrayFeaturesAlgorithm::shortDescription() const | ||
{ | ||
return QObject::tr( "Creates multiple offset copies of features in a layer." ); | ||
} | ||
|
||
QgsArrayFeaturesAlgorithm *QgsArrayFeaturesAlgorithm::createInstance() const | ||
{ | ||
return new QgsArrayFeaturesAlgorithm(); | ||
} | ||
|
||
void QgsArrayFeaturesAlgorithm::initParameters( const QVariantMap & ) | ||
{ | ||
std::unique_ptr< QgsProcessingParameterNumber > count = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "COUNT" ), | ||
QObject::tr( "Number of features to create" ), QgsProcessingParameterNumber::Integer, | ||
10, true, 1 ); | ||
count->setIsDynamic( true ); | ||
count->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "COUNT" ), QObject::tr( "Number of features to create" ), QgsPropertyDefinition::IntegerPositiveGreaterZero ) ); | ||
count->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( count.release() ); | ||
|
||
std::unique_ptr< QgsProcessingParameterDistance > xOffset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_X" ), | ||
QObject::tr( "Step distance (x-axis)" ), | ||
0.0, QStringLiteral( "INPUT" ) ); | ||
xOffset->setIsDynamic( true ); | ||
xOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_X" ), QObject::tr( "Offset distance (x-axis)" ), QgsPropertyDefinition::Double ) ); | ||
xOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( xOffset.release() ); | ||
|
||
std::unique_ptr< QgsProcessingParameterDistance > yOffset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DELTA_Y" ), | ||
QObject::tr( "Step distance (y-axis)" ), | ||
0.0, QStringLiteral( "INPUT" ) ); | ||
yOffset->setIsDynamic( true ); | ||
yOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Y" ), QObject::tr( "Offset distance (y-axis)" ), QgsPropertyDefinition::Double ) ); | ||
yOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( yOffset.release() ); | ||
|
||
std::unique_ptr< QgsProcessingParameterNumber > zOffset = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_Z" ), | ||
QObject::tr( "Step distance (z-axis)" ), QgsProcessingParameterNumber::Double, | ||
0.0 ); | ||
zOffset->setIsDynamic( true ); | ||
zOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_Z" ), QObject::tr( "Offset distance (z-axis)" ), QgsPropertyDefinition::Double ) ); | ||
zOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( zOffset.release() ); | ||
|
||
std::unique_ptr< QgsProcessingParameterNumber > mOffset = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "DELTA_M" ), | ||
QObject::tr( "Step distance (m values)" ), QgsProcessingParameterNumber::Double, | ||
0.0 ); | ||
mOffset->setIsDynamic( true ); | ||
mOffset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DELTA_M" ), QObject::tr( "Offset distance (m values)" ), QgsPropertyDefinition::Double ) ); | ||
mOffset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); | ||
addParameter( mOffset.release() ); | ||
} | ||
|
||
bool QgsArrayFeaturesAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) | ||
{ | ||
mCount = parameterAsInt( parameters, QStringLiteral( "COUNT" ), context ); | ||
mDynamicCount = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "COUNT" ) ); | ||
if ( mDynamicCount ) | ||
mCountProperty = parameters.value( QStringLiteral( "COUNT" ) ).value< QgsProperty >(); | ||
|
||
mDeltaX = parameterAsDouble( parameters, QStringLiteral( "DELTA_X" ), context ); | ||
mDynamicDeltaX = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_X" ) ); | ||
if ( mDynamicDeltaX ) | ||
mDeltaXProperty = parameters.value( QStringLiteral( "DELTA_X" ) ).value< QgsProperty >(); | ||
|
||
mDeltaY = parameterAsDouble( parameters, QStringLiteral( "DELTA_Y" ), context ); | ||
mDynamicDeltaY = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Y" ) ); | ||
if ( mDynamicDeltaY ) | ||
mDeltaYProperty = parameters.value( QStringLiteral( "DELTA_Y" ) ).value< QgsProperty >(); | ||
|
||
mDeltaZ = parameterAsDouble( parameters, QStringLiteral( "DELTA_Z" ), context ); | ||
mDynamicDeltaZ = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_Z" ) ); | ||
if ( mDynamicDeltaZ ) | ||
mDeltaZProperty = parameters.value( QStringLiteral( "DELTA_Z" ) ).value< QgsProperty >(); | ||
|
||
mDeltaM = parameterAsDouble( parameters, QStringLiteral( "DELTA_M" ), context ); | ||
mDynamicDeltaM = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DELTA_M" ) ); | ||
if ( mDynamicDeltaM ) | ||
mDeltaMProperty = parameters.value( QStringLiteral( "DELTA_M" ) ).value< QgsProperty >(); | ||
|
||
return true; | ||
} | ||
|
||
QgsFeatureList QgsArrayFeaturesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * ) | ||
{ | ||
QgsFeatureList result = QgsFeatureList(); | ||
|
||
if ( feature.hasGeometry() ) | ||
{ | ||
QgsGeometry geometry = feature.geometry(); | ||
const QgsAttributes attr = feature.attributes(); | ||
|
||
int count = mCount; | ||
if ( mDynamicCount ) | ||
count = mCountProperty.valueAsInt( context.expressionContext(), count ); | ||
result.reserve( count + 1 ); | ||
|
||
double deltaX = mDeltaX; | ||
if ( mDynamicDeltaX ) | ||
deltaX = mDeltaXProperty.valueAsDouble( context.expressionContext(), deltaX ); | ||
double deltaY = mDeltaY; | ||
if ( mDynamicDeltaY ) | ||
deltaY = mDeltaYProperty.valueAsDouble( context.expressionContext(), deltaY ); | ||
double deltaZ = mDeltaZ; | ||
if ( mDynamicDeltaZ ) | ||
deltaZ = mDeltaZProperty.valueAsDouble( context.expressionContext(), deltaZ ); | ||
double deltaM = mDeltaM; | ||
if ( mDynamicDeltaM ) | ||
deltaM = mDeltaMProperty.valueAsDouble( context.expressionContext(), deltaM ); | ||
|
||
// we add the original feature only after adding initial z/m values if needed | ||
if ( deltaZ != 0 && !geometry.constGet()->is3D() ) | ||
geometry.get()->addZValue( 0 ); | ||
if ( deltaM != 0 && !geometry.constGet()->isMeasure() ) | ||
geometry.get()->addMValue( 0 ); | ||
|
||
{ | ||
QgsFeature original = feature; | ||
original.setGeometry( geometry ); | ||
QgsAttributes outAttrs = attr; | ||
outAttrs << QVariant( 0 ); | ||
original.setAttributes( outAttrs ); | ||
result << original; | ||
} | ||
|
||
for ( int i = 0; i < count; ++i ) | ||
{ | ||
QgsFeature offsetFeature = feature; | ||
geometry.translate( deltaX, deltaY, deltaZ, deltaM ); | ||
offsetFeature.setGeometry( geometry ); | ||
QgsAttributes outAttrs = attr; | ||
outAttrs << QVariant( i + 1 ); | ||
offsetFeature.setAttributes( outAttrs ); | ||
result << offsetFeature; | ||
} | ||
} | ||
else | ||
{ | ||
result << feature; | ||
} | ||
|
||
return result; | ||
} | ||
|
||
QgsWkbTypes::Type QgsArrayFeaturesAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const | ||
{ | ||
QgsWkbTypes::Type wkb = inputWkbType; | ||
if ( mDeltaZ != 0 ) | ||
wkb = QgsWkbTypes::addZ( wkb ); | ||
if ( mDeltaM != 0 ) | ||
wkb = QgsWkbTypes::addM( wkb ); | ||
return wkb; | ||
} | ||
|
||
QgsFields QgsArrayFeaturesAlgorithm::outputFields( const QgsFields &inputFields ) const | ||
{ | ||
QgsFields output = inputFields; | ||
output.append( QgsField( QStringLiteral( "instance" ), QVariant::Int ) ); | ||
return output; | ||
} | ||
|
||
///@endcond | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/*************************************************************************** | ||
qgsalgorithmarrayfeatures.h | ||
--------------------- | ||
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. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSALGORITHMARRAYFEATURES_H | ||
#define QGSALGORITHMARRAYFEATURES_H | ||
|
||
#define SIP_NO_FILE | ||
|
||
#include "qgis.h" | ||
#include "qgsprocessingalgorithm.h" | ||
|
||
///@cond PRIVATE | ||
|
||
/** | ||
* Native create array of features algorithm. | ||
*/ | ||
class QgsArrayFeaturesAlgorithm : public QgsProcessingFeatureBasedAlgorithm | ||
{ | ||
|
||
public: | ||
|
||
QgsArrayFeaturesAlgorithm() = default; | ||
QString name() const override; | ||
QString displayName() const override; | ||
QStringList tags() const override; | ||
QString group() const override; | ||
QString groupId() const override; | ||
QString shortHelpString() const override; | ||
QString shortDescription() const override; | ||
QgsArrayFeaturesAlgorithm *createInstance() const override SIP_FACTORY; | ||
void initParameters( const QVariantMap &configuration = QVariantMap() ) override; | ||
|
||
protected: | ||
QString outputName() const override; | ||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; | ||
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; | ||
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override; | ||
QgsFields outputFields( const QgsFields &inputFields ) const override; | ||
|
||
private: | ||
|
||
int mCount = 0; | ||
bool mDynamicCount = false; | ||
QgsProperty mCountProperty; | ||
|
||
double mDeltaX = 0.0; | ||
bool mDynamicDeltaX = false; | ||
QgsProperty mDeltaXProperty; | ||
|
||
double mDeltaY = 0.0; | ||
bool mDynamicDeltaY = false; | ||
QgsProperty mDeltaYProperty; | ||
|
||
double mDeltaZ = 0.0; | ||
bool mDynamicDeltaZ = false; | ||
QgsProperty mDeltaZProperty; | ||
|
||
double mDeltaM = 0.0; | ||
bool mDynamicDeltaM = false; | ||
QgsProperty mDeltaMProperty; | ||
|
||
}; | ||
|
||
|
||
///@endcond PRIVATE | ||
|
||
#endif // QGSALGORITHMARRAYFEATURES_H | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters