Skip to content

Commit

Permalink
Port Convert Geometry Type to new API
Browse files Browse the repository at this point in the history
Includes partial support for Z/M types (values are lost during
conversion, but at least 2d geometries are exported)

TODO: full support for Z/M/curves
  • Loading branch information
nyalldawson committed Aug 20, 2017
1 parent 4d242c5 commit 51f8b1a
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 90 deletions.
108 changes: 59 additions & 49 deletions python/plugins/processing/algs/qgis/GeometryConvert.py
Expand Up @@ -29,13 +29,11 @@
QgsGeometry,
QgsFeatureSink,
QgsWkbTypes,
QgsApplication,
QgsProcessingUtils)
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector


class GeometryConvert(QgisAlgorithm):
Expand All @@ -56,12 +54,13 @@ def initAlgorithm(self, config=None):
self.tr('Multilinestrings'),
self.tr('Polygons')]

self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer')))
self.addParameter(ParameterSelection(self.TYPE,
self.tr('New geometry type'), self.types))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterEnum(self.TYPE,
self.tr('New geometry type'), options=self.types))

self.addOutput(OutputVector(self.OUTPUT, self.tr('Converted')))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Converted')))

def name(self):
return 'convertgeometrytype'
Expand All @@ -70,8 +69,8 @@ def displayName(self):
return self.tr('Convert geometry type')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
index = self.getParameterValue(self.TYPE)
source = self.parameterAsSource(parameters, self.INPUT, context)
index = self.parameterAsEnum(parameters, self.TYPE, context)

splitNodes = False
if index == 0:
Expand All @@ -88,107 +87,118 @@ def processAlgorithm(self, parameters, context, feedback):
else:
newType = QgsWkbTypes.Point

writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), newType, layer.crs(), context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), newType, source.sourceCrs())

features = QgsProcessingUtils.getFeatures(layer, context)
total = 100.0 / layer.featureCount() if layer.featureCount() else 0
features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0

for current, f in enumerate(features):
if feedback.isCanceled():
break

if not f.hasGeometry():
sink.addFeature(f, QgsFeatureSink.FastInsert)

geom = f.geometry()
geomType = geom.wkbType()

if geomType in [QgsWkbTypes.Point, QgsWkbTypes.Point25D]:
if QgsWkbTypes.geometryType(geomType) == QgsWkbTypes.PointGeometry and not QgsWkbTypes.isMultiType(geomType):
if newType == QgsWkbTypes.Point:
writer.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Cannot convert from {0} to {1}').format(geomType, newType))
elif geomType in [QgsWkbTypes.MultiPoint, QgsWkbTypes.MultiPoint25D]:
elif QgsWkbTypes.geometryType(geomType) == QgsWkbTypes.PointGeometry and QgsWkbTypes.isMultiType(geomType):
if newType == QgsWkbTypes.Point and splitNodes:
points = geom.asMultiPoint()
for p in points:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPoint(p))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Point:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(geom.centroid())
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Cannot convert from {0} to {1}').format(geomType, newType))
elif geomType in [QgsWkbTypes.LineString, QgsWkbTypes.LineString25D]:
elif QgsWkbTypes.geometryType(geomType) == QgsWkbTypes.LineGeometry and not QgsWkbTypes.isMultiType(geomType):
if newType == QgsWkbTypes.Point and splitNodes:
points = geom.asPolyline()
for p in points:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPoint(p))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Point:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(geom.centroid())
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.LineString:
writer.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Cannot convert from {0} to {1}').format(geomType, newType))
elif geomType in [QgsWkbTypes.MultiLineString, QgsWkbTypes.MultiLineString25D]:
elif QgsWkbTypes.geometryType(geomType) == QgsWkbTypes.LineGeometry and QgsWkbTypes.isMultiType(
geomType):
if newType == QgsWkbTypes.Point and splitNodes:
lines = geom.asMultiPolyline()
for line in lines:
for p in line:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPoint(p))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Point:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(geom.centroid())
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.LineString:
lines = geom.asMultiPolyline()
for line in lines:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPolyline(line))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.MultiLineString:
writer.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Cannot convert from {0} to {1}').format(geomType, newType))
elif geomType in [QgsWkbTypes.Polygon, QgsWkbTypes.Polygon25D]:
elif QgsWkbTypes.geometryType(geomType) == QgsWkbTypes.PolygonGeometry and not QgsWkbTypes.isMultiType(
geomType):
if newType == QgsWkbTypes.Point and splitNodes:
rings = geom.asPolygon()
for ring in rings:
for p in ring:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPoint(p))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Point:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(geom.centroid())
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.MultiLineString:
rings = geom.asPolygon()
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromMultiPolyline(rings))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Polygon:
writer.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Cannot convert from {0} to {1}').format(geomType, newType))
elif geomType in [QgsWkbTypes.MultiPolygon, QgsWkbTypes.MultiPolygon25D]:
elif QgsWkbTypes.geometryType(
geomType) == QgsWkbTypes.PolygonGeometry and QgsWkbTypes.isMultiType(
geomType):
if newType == QgsWkbTypes.Point and splitNodes:
polygons = geom.asMultiPolygon()
for polygon in polygons:
Expand All @@ -197,32 +207,32 @@ def processAlgorithm(self, parameters, context, feedback):
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPoint(p))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Point:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(geom.centroid())
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.LineString:
polygons = geom.asMultiPolygon()
for polygons in polygons:
for polygon in polygons:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPolyline(polygon))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType == QgsWkbTypes.Polygon:
polygons = geom.asMultiPolygon()
for polygon in polygons:
feat = QgsFeature()
feat.setAttributes(f.attributes())
feat.setGeometry(QgsGeometry.fromPolygon(polygon))
writer.addFeature(feat, QgsFeatureSink.FastInsert)
sink.addFeature(feat, QgsFeatureSink.FastInsert)
elif newType in [QgsWkbTypes.MultiLineString, QgsWkbTypes.MultiPolygon]:
writer.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
else:
raise GeoAlgorithmExecutionException(
raise QgsProcessingException(
self.tr('Cannot convert from {0} to {1}').format(geomType, newType))

feedback.setProgress(int(current * total))

del writer
return {self.OUTPUT: dest_id}
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -78,6 +78,7 @@
from .FindProjection import FindProjection
from .FixedDistanceBuffer import FixedDistanceBuffer
from .FixGeometry import FixGeometry
from .GeometryConvert import GeometryConvert
from .GeometryByExpression import GeometryByExpression
from .Gridify import Gridify
from .GridLine import GridLine
Expand Down Expand Up @@ -171,7 +172,6 @@
# from .ExtractByLocation import ExtractByLocation
# from .SelectByLocation import SelectByLocation
# from .SpatialJoin import SpatialJoin
# from .GeometryConvert import GeometryConvert
# from .SelectByAttributeSum import SelectByAttributeSum

pluginPath = os.path.normpath(os.path.join(
Expand All @@ -190,7 +190,6 @@ def getAlgs(self):
# SelectByLocation(),
# ExtractByLocation(),
# SpatialJoin(),
# GeometryConvert(),
# SelectByAttributeSum()
# ]
algs = [AddTableField(),
Expand Down Expand Up @@ -232,6 +231,7 @@ def getAlgs(self):
FixedDistanceBuffer(),
FixGeometry(),
GeometryByExpression(),
GeometryConvert(),
Gridify(),
GridLine(),
GridPolygon(),
Expand Down
Expand Up @@ -6,7 +6,7 @@
<GeometryType>1</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>5</FeatureCount>
<FeatureCount>6</FeatureCount>
<ExtentXMin>0.65385</ExtentXMin>
<ExtentXMax>8.00000</ExtentXMax>
<ExtentYMin>-1.00000</ExtentYMin>
Expand Down
Expand Up @@ -41,6 +41,12 @@
<ogr:intval>0</ogr:intval>
</ogr:convert_poly_centroid>
</gml:featureMember>
<gml:featureMember>
<ogr:convert_poly_centroid fid="polys.4">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:convert_poly_centroid>
</gml:featureMember>
<gml:featureMember>
<ogr:convert_poly_centroid fid="polys.5">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4.08045977011494,-0.218390804597701</gml:coordinates></gml:Point></ogr:geometryProperty>
Expand Down
Expand Up @@ -6,7 +6,7 @@
<GeometryType>5</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>5</FeatureCount>
<FeatureCount>6</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>10.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
Expand Down
Expand Up @@ -41,6 +41,12 @@
<ogr:intval>0</ogr:intval>
</ogr:convert_poly_multiline>
</gml:featureMember>
<gml:featureMember>
<ogr:convert_poly_multiline fid="polys.4">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:convert_poly_multiline>
</gml:featureMember>
<gml:featureMember>
<ogr:convert_poly_multiline fid="polys.5">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
Expand Down
Expand Up @@ -6,7 +6,7 @@
<GeometryType>1</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>32</FeatureCount>
<FeatureCount>33</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>10.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
Expand Down
Expand Up @@ -204,6 +204,12 @@
<ogr:intval>0</ogr:intval>
</ogr:convert_poly_nodes>
</gml:featureMember>
<gml:featureMember>
<ogr:convert_poly_nodes fid="polys.4">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:convert_poly_nodes>
</gml:featureMember>
<gml:featureMember>
<ogr:convert_poly_nodes fid="polys.5">
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,2</gml:coordinates></gml:Point></ogr:geometryProperty>
Expand Down

0 comments on commit 51f8b1a

Please sign in to comment.