Skip to content

Commit

Permalink
[FEATURE][processing] allow to create points on all parts in centroid…
Browse files Browse the repository at this point in the history
…s alg
  • Loading branch information
nirvn committed Mar 6, 2018
1 parent 0630b1c commit 0d92f96
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 12 deletions.
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ centroid_multipoly_all_parts.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>0.5</gml:X><gml:Y>0.5</gml:Y></gml:coord>
<gml:coord><gml:X>7.904761904761905</gml:X><gml:Y>5.095238095238095</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:centroid_multipoly_all_parts fid="multipolys.0">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.16666666666667,1.83333333333333</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:Bname>Test</ogr:Bname>
<ogr:Bintval>1</ogr:Bintval>
<ogr:Bfloatval>0.12300</ogr:Bfloatval>
</ogr:centroid_multipoly_all_parts>
</gml:featureMember>
<gml:featureMember>
<ogr:centroid_multipoly_all_parts fid="multipolys.1">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7.5,1.0</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:Bname xsi:nil="true"/>
<ogr:Bintval xsi:nil="true"/>
<ogr:Bfloatval xsi:nil="true"/>
</ogr:centroid_multipoly_all_parts>
</gml:featureMember>
<gml:featureMember>
<ogr:centroid_multipoly_all_parts fid="multipolys.1">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7.90476190476191,5.09523809523809</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:Bname xsi:nil="true"/>
<ogr:Bintval xsi:nil="true"/>
<ogr:Bfloatval xsi:nil="true"/>
</ogr:centroid_multipoly_all_parts>
</gml:featureMember>
<gml:featureMember>
<ogr:centroid_multipoly_all_parts fid="multipolys.2">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0.5,0.5</gml:coordinates></gml:Point></ogr:geometryProperty>
<ogr:Bname>Test</ogr:Bname>
<ogr:Bintval>2</ogr:Bintval>
<ogr:Bfloatval>-0.12300</ogr:Bfloatval>
</ogr:centroid_multipoly_all_parts>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="centroid_multipoly_all_parts" type="ogr:centroid_multipoly_all_parts_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="centroid_multipoly_all_parts_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="Bname" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="4"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Bintval" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Bfloatval" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="21"/>
<xs:fractionDigits value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
12 changes: 12 additions & 0 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -1169,6 +1169,18 @@ tests:
geometry:
precision: 7

- algorithm: native:centroids
name: Centroid (multipolygons)
params:
INPUT:
name: multipolys.gml
type: vector
ALL_PARTS: true
results:
OUTPUT:
name: expected/centroid_multipoly_all_parts.gml
type: vector

- algorithm: native:centroids
name: Centroid (points)
params:
Expand Down
71 changes: 60 additions & 11 deletions src/analysis/processing/qgsalgorithmcentroid.cpp
Expand Up @@ -16,6 +16,7 @@
***************************************************************************/

#include "qgsalgorithmcentroid.h"
#include "qgsgeometrycollection.h"

///@cond PRIVATE

Expand Down Expand Up @@ -49,12 +50,6 @@ QString QgsCentroidAlgorithm::outputName() const
return QObject::tr( "Centroids" );
}

void QgsCentroidAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Centroids" ), QgsProcessing::TypeVectorPoint ) );
}

QString QgsCentroidAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm creates a new point layer, with points representing the centroid of the geometries in an input layer.\n\n"
Expand All @@ -66,18 +61,72 @@ QgsCentroidAlgorithm *QgsCentroidAlgorithm::createInstance() const
return new QgsCentroidAlgorithm();
}

QgsFeatureList QgsCentroidAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &, QgsProcessingFeedback *feedback )
void QgsCentroidAlgorithm::initParameters( const QVariantMap & )
{
std::unique_ptr< QgsProcessingParameterBoolean> allParts = qgis::make_unique< QgsProcessingParameterBoolean >(
QStringLiteral( "ALL_PARTS" ),
QObject::tr( "Create point on surface for each part" ),
false );
allParts->setIsDynamic( true );
allParts->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "All parts" ), QObject::tr( "Create point on surface for each part" ), QgsPropertyDefinition::Boolean ) );
allParts->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
addParameter( allParts.release() );
}

bool QgsCentroidAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
mAllParts = parameterAsBool( parameters, QStringLiteral( "ALL_PARTS" ), context );
mDynamicAllParts = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "ALL_PARTS" ) );
if ( mDynamicAllParts )
mAllPartsProperty = parameters.value( QStringLiteral( "ALL_PARTS" ) ).value< QgsProperty >();

return true;
}

QgsFeatureList QgsCentroidAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
QgsFeatureList list;
QgsFeature feature = f;
if ( feature.hasGeometry() )
{
feature.setGeometry( feature.geometry().centroid() );
if ( !feature.geometry() )
QgsGeometry geom = feature.geometry();

bool allParts = mAllParts;
if ( mDynamicAllParts )
allParts = mAllPartsProperty.valueAsBool( context.expressionContext(), allParts );

if ( allParts && geom.isMultipart() )
{
const QgsGeometryCollection *geomCollection = static_cast<const QgsGeometryCollection *>( geom.constGet() );

for ( int i = 0; i < geomCollection->partCount(); ++i )
{
QgsGeometry partGeometry( geomCollection->geometryN( i )->clone() );
QgsGeometry outputGeometry = partGeometry.centroid();
if ( !outputGeometry )
{
feedback->pushInfo( QObject::tr( "Error calculating centroid for feature %1 part %2: %3" ).arg( feature.id() ).arg( i ).arg( outputGeometry.lastError() ) );
}
feature.setGeometry( outputGeometry );
list << feature;
}
}
else
{
feedback->pushInfo( QObject::tr( "Error calculating centroid for feature %1" ).arg( feature.id() ) );
QgsGeometry outputGeometry = feature.geometry().centroid();
if ( !outputGeometry )
{
feedback->pushInfo( QObject::tr( "Error calculating centroid for feature %1: %2" ).arg( feature.id() ).arg( outputGeometry.lastError() ) );
}
feature.setGeometry( outputGeometry );
list << feature;
}
}
return QgsFeatureList() << feature;
else
{
list << feature;
}
return list;
}

///@endcond
9 changes: 8 additions & 1 deletion src/analysis/processing/qgsalgorithmcentroid.h
Expand Up @@ -34,22 +34,29 @@ class QgsCentroidAlgorithm : public QgsProcessingFeatureBasedAlgorithm
public:

QgsCentroidAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QgsCentroidAlgorithm *createInstance() const override SIP_FACTORY;
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;

protected:

QString outputName() const override;
QgsProcessing::SourceType outputLayerType() const override { return QgsProcessing::TypeVectorPoint; }
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override { Q_UNUSED( inputWkbType ); return QgsWkbTypes::Point; }

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

private:

bool mAllParts = false;
bool mDynamicAllParts = false;
QgsProperty mAllPartsProperty;
};

///@endcond PRIVATE
Expand Down

0 comments on commit 0d92f96

Please sign in to comment.