Skip to content

Commit

Permalink
[processing][needs-docs] port Rectangle,ovals,diamonds algorithm to C++
Browse files Browse the repository at this point in the history
and make width, height and rotation parameters dynamic.

Old Python implementations marked as deprecated to maintain API
compatibility.
  • Loading branch information
alexbruy committed Jan 15, 2020
1 parent cf36172 commit c752919
Show file tree
Hide file tree
Showing 6 changed files with 298 additions and 0 deletions.
Expand Up @@ -29,6 +29,7 @@
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDistance,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsFeature,
QgsFeatureSink,
QgsGeometry,
Expand Down Expand Up @@ -58,6 +59,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagDeprecated

def initAlgorithm(self, config=None):
self.shapes = [self.tr('Rectangles'), self.tr('Diamonds'), self.tr('Ovals')]

Expand Down
Expand Up @@ -32,6 +32,7 @@
QgsPointXY,
QgsProcessing,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
Expand Down Expand Up @@ -60,6 +61,9 @@ def groupId(self):
def __init__(self):
super().__init__()

def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagDeprecated

def initAlgorithm(self, config=None):
self.shapes = [self.tr('Rectangles'), self.tr('Diamonds'), self.tr('Ovals')]

Expand Down
1 change: 1 addition & 0 deletions src/analysis/CMakeLists.txt
Expand Up @@ -115,6 +115,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmrastersurfacevolume.cpp
processing/qgsalgorithmrasterzonalstats.cpp
processing/qgsalgorithmreclassifybylayer.cpp
processing/qgsalgorithmrectanglesovalsdiamonds.cpp
processing/qgsalgorithmremoveduplicatesbyattribute.cpp
processing/qgsalgorithmremoveduplicatevertices.cpp
processing/qgsalgorithmremoveholes.cpp
Expand Down
209 changes: 209 additions & 0 deletions src/analysis/processing/qgsalgorithmrectanglesovalsdiamonds.cpp
@@ -0,0 +1,209 @@
/***************************************************************************
qgsalgorithmrectanglesovalsdiamonds.cpp
---------------------
begin : January 2020
copyright : (C) 2020 by Alexander Bruy
email : alexander dot bruy 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 "qgsalgorithmrectanglesovalsdiamonds.h"
#include "qgsapplication.h"

///@cond PRIVATE

QString QgsRectanglesOvalsDiamondsAlgorithm::name() const
{
return QStringLiteral( "rectanglesovalsdiamonds" );
}

QString QgsRectanglesOvalsDiamondsAlgorithm::displayName() const
{
return QObject::tr( "Rectangles, ovals, diamonds" );
}

QStringList QgsRectanglesOvalsDiamondsAlgorithm::tags() const
{
return QObject::tr( "buffer,grow,fixed,variable,distance,rectangle,oval,diamond,point" ).split( ',' );
}

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

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

QString QgsRectanglesOvalsDiamondsAlgorithm::shortHelpString() const
{
return QObject::tr( "Creates a rectangle, oval or diamond-shaped polygons from the input point layer using "
"specified width, height and (optional) rotation values." );
}

QString QgsRectanglesOvalsDiamondsAlgorithm::outputName() const
{
return QObject::tr( "Polygon" );
}

QList<int> QgsRectanglesOvalsDiamondsAlgorithm::inputLayerTypes() const
{
return QList<int>() << QgsProcessing::TypeVectorPoint;
}

QgsProcessing::SourceType QgsRectanglesOvalsDiamondsAlgorithm::outputLayerType() const
{
return QgsProcessing::TypeVectorPolygon;
}

QgsWkbTypes::Type QgsRectanglesOvalsDiamondsAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
{
QgsWkbTypes::Type outputWkbType = QgsWkbTypes::Polygon;
if ( QgsWkbTypes::hasM( inputWkbType ) )
{
outputWkbType = QgsWkbTypes::addM( outputWkbType );
}
if ( QgsWkbTypes::hasZ( inputWkbType ) )
{
outputWkbType = QgsWkbTypes::addZ( outputWkbType );
}

return outputWkbType;
}

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

void QgsRectanglesOvalsDiamondsAlgorithm::initParameters( const QVariantMap & )
{
addParameter( new QgsProcessingParameterEnum( QStringLiteral( "SHAPE" ), QObject::tr( "Shape" ), QStringList() << QObject::tr( "Rectangle" ) << QObject::tr( "Diamond" ) << QObject::tr( "Oval" ), false, 0 ) );

auto widthParam = qgis::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "WIDTH" ), QObject::tr( "Width" ), 1.0, QStringLiteral( "INPUT" ), false, 0.0 );
widthParam->setIsDynamic( true );
widthParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Width" ), QObject::tr( "Width" ), QgsPropertyDefinition::Double ) );
widthParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( widthParam.release() );

auto heightParam = qgis::make_unique < QgsProcessingParameterDistance >( QStringLiteral( "HEIGHT" ), QObject::tr( "Height" ), 1.0, QStringLiteral( "INPUT" ), false, 0.0 );
heightParam->setIsDynamic( true );
heightParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Height" ), QObject::tr( "Height" ), QgsPropertyDefinition::Double ) );
heightParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( heightParam.release() );

auto rotationParam = qgis::make_unique < QgsProcessingParameterNumber >( QStringLiteral( "ROTATION" ), QObject::tr( "Rotation" ), QgsProcessingParameterNumber::Double, 0.0, true, 0.0, 360.0 );
rotationParam->setIsDynamic( true );
rotationParam->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "Rotation" ), QObject::tr( "Rotation" ), QgsPropertyDefinition::Double ) );
rotationParam->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( rotationParam.release() );

addParameter( new QgsProcessingParameterNumber( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 5, false, 1 ) );
}

bool QgsRectanglesOvalsDiamondsAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
mShape = parameterAsEnum( parameters, QStringLiteral( "SHAPE" ), context );

mWidth = parameterAsDouble( parameters, QStringLiteral( "WIDTH" ), context );
mDynamicWidth = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "WIDTH" ) );
if ( mDynamicWidth )
mWidthProperty = parameters.value( QStringLiteral( "WIDTH" ) ).value< QgsProperty >();

mHeight = parameterAsDouble( parameters, QStringLiteral( "HEIGHT" ), context );
mDynamicHeight = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "HEIGHT" ) );
if ( mDynamicHeight )
mHeightProperty = parameters.value( QStringLiteral( "HEIGHT" ) ).value< QgsProperty >();

mRotation = parameterAsDouble( parameters, QStringLiteral( "ROTATION" ), context );
mDynamicRotation = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ROTATION" ) );
if ( mDynamicRotation )
mRotationProperty = parameters.value( QStringLiteral( "ROTATION" ) ).value< QgsProperty >();

mSegments = parameterAsDouble( parameters, QStringLiteral( "SEGMENTS" ), context );

return true;
}

QgsFeatureList QgsRectanglesOvalsDiamondsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
{
QgsFeature outFeature = feature;
if ( outFeature.hasGeometry() )
{
double width = mWidth;
if ( mDynamicWidth )
width = mWidthProperty.valueAsDouble( context.expressionContext(), width );

double height = mHeight;
if ( mDynamicHeight )
height = mHeightProperty.valueAsDouble( context.expressionContext(), height );

double rotation = mRotation;
if ( mDynamicRotation )
rotation = mRotationProperty.valueAsDouble( context.expressionContext(), rotation );

if ( width == 0 || height == 0 )
{
throw QgsProcessingException( QObject::tr( "Width and height should be greater than 0." ) );
}

double phi = rotation * M_PI / 180;
double xOffset = width / 2.0;
double yOffset = height / 2.0;
QgsPointXY point = outFeature.geometry().asPoint();
double x = point.x();
double y = point.y();

QgsPolylineXY ring;
switch ( mShape )
{
case 0:
// rectangle
ring << QgsPointXY( -xOffset, -yOffset )
<< QgsPointXY( -xOffset, yOffset )
<< QgsPointXY( xOffset, yOffset )
<< QgsPointXY( xOffset, -yOffset );
break;
case 1:
// diamond
ring << QgsPointXY( 0.0, -yOffset )
<< QgsPointXY( -xOffset, 0.0 )
<< QgsPointXY( 0.0, yOffset )
<< QgsPointXY( xOffset, 0.0 );
break;
case 2:
// oval
for ( int i = 0; i < mSegments; i ++ )
{
double t = ( 2 * M_PI ) / mSegments * i;
ring << QgsPointXY( xOffset * cos( t ), yOffset * sin( t ) );
}
break;
}

for ( int i = 0; i < ring.size(); ++i )
{
QgsPointXY p = ring[ i ];
double px = p.x();
double py = p.y();
ring[ i ] = QgsPointXY( px * cos( phi ) + py * sin( phi ) + x,
-px * sin( phi ) + py * cos( phi ) + y );
}

outFeature.setGeometry( QgsGeometry::fromPolygonXY( QgsPolygonXY() << ring ) );
}

return QgsFeatureList() << outFeature;
}

///@endcond
78 changes: 78 additions & 0 deletions src/analysis/processing/qgsalgorithmrectanglesovalsdiamonds.h
@@ -0,0 +1,78 @@
/***************************************************************************
qgsalgorithmrectanglesovalsdiamonds.h
----------------------
begin : January 2020
copyright : (C) 2020 by Alexander Bruy
email : alexander dot bruy 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 QGSALGORITHMRECTANGLESOVALSDIAMONDS_H
#define QGSALGORITHMRECTANGLESOVALSDIAMONDS_H

#define SIP_NO_FILE

#include "qgis_sip.h"
#include "qgsprocessingalgorithm.h"
#include "qgsapplication.h"

///@cond PRIVATE

/**
* Native rectangles, ovals, diamonds algorithm.
*/
class QgsRectanglesOvalsDiamondsAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{

public:

QgsRectanglesOvalsDiamondsAlgorithm() = 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;
QList<int> inputLayerTypes() const override;
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
QgsRectanglesOvalsDiamondsAlgorithm *createInstance() const override SIP_FACTORY;

protected:

QString outputName() const override;
QgsProcessing::SourceType outputLayerType() const override;
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override;

bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

private:
int mShape = 0;
int mSegments = 0;

double mWidth = 0.0;
bool mDynamicWidth = false;
QgsProperty mWidthProperty;

double mHeight = 0.0;
bool mDynamicHeight = false;
QgsProperty mHeightProperty;

double mRotation = 0.0;
bool mDynamicRotation = false;
QgsProperty mRotationProperty;
};

///@endcond PRIVATE

#endif // QGSALGORITHMRECTANGLESOVALSDIAMONDS_H


2 changes: 2 additions & 0 deletions src/analysis/processing/qgsnativealgorithms.cpp
Expand Up @@ -109,6 +109,7 @@
#include "qgsalgorithmrastersurfacevolume.h"
#include "qgsalgorithmrasterzonalstats.h"
#include "qgsalgorithmreclassifybylayer.h"
#include "qgsalgorithmrectanglesovalsdiamonds.h"
#include "qgsalgorithmremoveduplicatesbyattribute.h"
#include "qgsalgorithmremoveduplicatevertices.h"
#include "qgsalgorithmremoveholes.h"
Expand Down Expand Up @@ -306,6 +307,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsAlgorithmRemoveDuplicateVertices() );
addAlgorithm( new QgsReclassifyByLayerAlgorithm() );
addAlgorithm( new QgsReclassifyByTableAlgorithm() );
addAlgorithm( new QgsRectanglesOvalsDiamondsAlgorithm() );
addAlgorithm( new QgsRemoveDuplicatesByAttributeAlgorithm() );
addAlgorithm( new QgsRemoveHolesAlgorithm() );
addAlgorithm( new QgsRemoveNullGeometryAlgorithm() );
Expand Down

0 comments on commit c752919

Please sign in to comment.