mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-27 00:33:48 -05:00
Port fix geometries alg to c++
This commit is contained in:
parent
07fd9cb83c
commit
7c5521ecdf
@ -222,11 +222,6 @@ qgis:fixeddistancebuffer: >
|
||||
|
||||
The miter limit parameter is only applicable for miter join styles, and controls the maximum distance from the offset curve to use when creating a mitered join.
|
||||
|
||||
qgis:fixgeometries: >
|
||||
This algorithm attempts to create a valid representation of a given invalid geometry without losing any of the input vertices. Already-valid geometries are returned without further intervention. Always outputs multi-geometry layer.
|
||||
|
||||
NOTE: M values will be dropped from the output.
|
||||
|
||||
qgis:frequencyanalysis: >
|
||||
This algorithm generates a table with frequency analysis of the values of a selected attribute from an input vector layer
|
||||
|
||||
|
@ -1,101 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
FixGeometry.py
|
||||
-----------------------
|
||||
Date : January 2017
|
||||
Copyright : (C) 2017 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. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
|
||||
__author__ = 'Alexander Bruy'
|
||||
__date__ = 'January 2017'
|
||||
__copyright__ = '(C) 2017, Alexander Bruy'
|
||||
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import (QgsWkbTypes,
|
||||
QgsFeatureSink,
|
||||
QgsFeatureRequest,
|
||||
QgsProcessingFeatureSource,
|
||||
QgsGeometry,
|
||||
QgsProcessing,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterFeatureSink)
|
||||
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
|
||||
|
||||
class FixGeometry(QgisAlgorithm):
|
||||
|
||||
INPUT = 'INPUT'
|
||||
OUTPUT = 'OUTPUT'
|
||||
|
||||
def tags(self):
|
||||
return self.tr('repair,invalid,geometry').split(',')
|
||||
|
||||
def group(self):
|
||||
return self.tr('Vector geometry')
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def initAlgorithm(self, config=None):
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input layer'), [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon]))
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Fixed geometries')))
|
||||
|
||||
def name(self):
|
||||
return 'fixgeometries'
|
||||
|
||||
def displayName(self):
|
||||
return self.tr('Fix geometries')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
source = self.parameterAsSource(parameters, self.INPUT, context)
|
||||
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())
|
||||
|
||||
features = source.getFeatures(QgsFeatureRequest(), QgsProcessingFeatureSource.FlagSkipGeometryValidityChecks)
|
||||
total = 100.0 / source.featureCount() if source.featureCount() else 0
|
||||
for current, inputFeature in enumerate(features):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
outputFeature = inputFeature
|
||||
if inputFeature.geometry():
|
||||
outputGeometry = inputFeature.geometry().makeValid()
|
||||
if not outputGeometry:
|
||||
feedback.pushInfo('makeValid failed for feature {}'.format(inputFeature.id()))
|
||||
|
||||
if outputGeometry.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(outputGeometry.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
|
||||
tmpGeometries = outputGeometry.asGeometryCollection()
|
||||
for g in tmpGeometries:
|
||||
if g.type() == inputFeature.geometry().type():
|
||||
try:
|
||||
g.convertToMultiType()
|
||||
outputFeature.setGeometry(QgsGeometry(g))
|
||||
sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
|
||||
except:
|
||||
pass
|
||||
feedback.setProgress(int(current * total))
|
||||
continue
|
||||
|
||||
outputGeometry.convertToMultiType()
|
||||
outputFeature.setGeometry(outputGeometry)
|
||||
|
||||
sink.addFeature(outputFeature, QgsFeatureSink.FastInsert)
|
||||
feedback.setProgress(int(current * total))
|
||||
|
||||
return {self.OUTPUT: dest_id}
|
@ -75,7 +75,6 @@ from .FieldsCalculator import FieldsCalculator
|
||||
from .FieldsMapper import FieldsMapper
|
||||
from .FindProjection import FindProjection
|
||||
from .FixedDistanceBuffer import FixedDistanceBuffer
|
||||
from .FixGeometry import FixGeometry
|
||||
from .GeometryConvert import GeometryConvert
|
||||
from .GeometryByExpression import GeometryByExpression
|
||||
from .Gridify import Gridify
|
||||
@ -216,7 +215,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
FieldsPyculator(),
|
||||
FindProjection(),
|
||||
FixedDistanceBuffer(),
|
||||
FixGeometry(),
|
||||
GeometryByExpression(),
|
||||
GeometryConvert(),
|
||||
Gridify(),
|
||||
|
@ -2729,7 +2729,7 @@ tests:
|
||||
# name: expected/zonal_statistics.gml
|
||||
# type: vector
|
||||
|
||||
- algorithm: qgis:fixgeometries
|
||||
- algorithm: native:fixgeometries
|
||||
name: Fix geometries
|
||||
params:
|
||||
INPUT:
|
||||
|
@ -928,7 +928,7 @@ QgsAbstractGeometry *_qgis_lwgeom_make_valid( const QgsAbstractGeometry *lwgeom_
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "original geom converted to GEOS" );
|
||||
QgsDebugMsgLevel( "original geom converted to GEOS", 4 );
|
||||
}
|
||||
|
||||
GEOSGeometry *geosout = LWGEOM_GEOS_makeValid( geosgeom, errorMessage );
|
||||
|
@ -78,6 +78,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsPromoteToMultipartAlgorithm() );
|
||||
addAlgorithm( new QgsSelectByLocationAlgorithm() );
|
||||
addAlgorithm( new QgsExtractByLocationAlgorithm() );
|
||||
addAlgorithm( new QgsFixGeometriesAlgorithm() );
|
||||
}
|
||||
|
||||
void QgsCentroidAlgorithm::initAlgorithm( const QVariantMap & )
|
||||
@ -1614,5 +1615,56 @@ QVariantMap QgsExtractByLocationAlgorithm::processAlgorithm( const QVariantMap &
|
||||
}
|
||||
|
||||
|
||||
QString QgsFixGeometriesAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "This algorithm attempts to create a valid representation of a given invalid geometry without "
|
||||
"losing any of the input vertices. Already-valid geometries are returned without further intervention. "
|
||||
"Always outputs multi-geometry layer.\n\n"
|
||||
"NOTE: M values will be dropped from the output." );
|
||||
}
|
||||
|
||||
QgsFixGeometriesAlgorithm *QgsFixGeometriesAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsFixGeometriesAlgorithm();
|
||||
}
|
||||
|
||||
QgsFeature QgsFixGeometriesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
if ( !feature.hasGeometry() )
|
||||
return feature;
|
||||
|
||||
QgsFeature outputFeature = feature;
|
||||
|
||||
QgsGeometry outputGeometry = outputFeature.geometry().makeValid();
|
||||
if ( !outputGeometry )
|
||||
{
|
||||
feedback->pushInfo( QObject::tr( "makeValid failed for feature %1 " ).arg( feature.id() ) );
|
||||
outputFeature.clearGeometry();
|
||||
return outputFeature;
|
||||
}
|
||||
|
||||
if ( outputGeometry.wkbType() == QgsWkbTypes::Unknown ||
|
||||
QgsWkbTypes::flatType( outputGeometry.geometry()->wkbType() ) == QgsWkbTypes::GeometryCollection )
|
||||
{
|
||||
// keep only the parts of the geometry collection with correct type
|
||||
const QList< QgsGeometry > tmpGeometries = outputGeometry.asGeometryCollection();
|
||||
QList< QgsGeometry > matchingParts;
|
||||
for ( const QgsGeometry &g : tmpGeometries )
|
||||
{
|
||||
if ( g.type() == feature.geometry().type() )
|
||||
matchingParts << g;
|
||||
}
|
||||
if ( !matchingParts.empty() )
|
||||
outputGeometry = QgsGeometry::collectGeometry( matchingParts );
|
||||
else
|
||||
outputGeometry = QgsGeometry();
|
||||
}
|
||||
|
||||
outputGeometry.convertToMultiType();
|
||||
outputFeature.setGeometry( outputGeometry );
|
||||
return outputFeature;
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
|
||||
|
@ -556,6 +556,29 @@ class QgsExtractByLocationAlgorithm : public QgsLocationBasedAlgorithm
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Native repair geometries algorithm.
|
||||
*/
|
||||
class QgsFixGeometriesAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
QgsFixGeometriesAlgorithm() = default;
|
||||
QString name() const override { return QStringLiteral( "fixgeometries" ); }
|
||||
QString displayName() const override { return QObject::tr( "Fix geometries" ); }
|
||||
virtual QStringList tags() const override { return QObject::tr( "repair,invalid,geometry,make,valid" ).split( ',' ); }
|
||||
QString group() const override { return QObject::tr( "Vector geometry" ); }
|
||||
QString shortHelpString() const override;
|
||||
QgsFixGeometriesAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
|
||||
protected:
|
||||
QString outputName() const override { return QObject::tr( "Fixed geometries" ); }
|
||||
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type type ) const override { return QgsWkbTypes::multiType( type ); }
|
||||
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSNATIVEALGORITHMS_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user