Skip to content

Commit

Permalink
Merge pull request #3441 from nyalldawson/simplify
Browse files Browse the repository at this point in the history
Simplify features + fixes
  • Loading branch information
nyalldawson committed Sep 1, 2016
2 parents 798817e + 56b77db commit 88047cc
Show file tree
Hide file tree
Showing 20 changed files with 446 additions and 127 deletions.
3 changes: 3 additions & 0 deletions python/core/qgsmaptopixelgeometrysimplifier.sip
Expand Up @@ -43,6 +43,9 @@ class QgsMapToPixelSimplifier : QgsAbstractGeometrySimplifier
//! Sets the local simplification algorithm of the vector layer managed
void setSimplifyAlgorithm( SimplifyAlgorithm simplifyAlgorithm );

//! Returns a simplified version the specified geometry
virtual QgsGeometry simplify( const QgsGeometry& geometry ) const;

//! Sets the tolerance of the vector layer managed
void setTolerance( double value );

Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/help/qgis.yaml
Expand Up @@ -429,6 +429,8 @@ qgis:setstyleforvectorlayer: >
qgis:simplifygeometries: >
This algorithm simplifies the geometries in a line or polygon layer. It creates a new layer with the same features as the ones in the input layer, but with geometries containing a lower number of vertices.

The algorithm gives a choice of simplification methods, including distance based (the "Douglas-Peucker" algorithm), area based ("Visvalingam" algorithm) and snapping geometries to grid.

qgis:singlepartstomultipart:


Expand Down
65 changes: 29 additions & 36 deletions python/plugins/processing/algs/qgis/SimplifyGeometries.py
Expand Up @@ -29,12 +29,13 @@

from qgis.PyQt.QtGui import QIcon

from qgis.core import Qgis, QgsFeature, QgsGeometry, QgsWkbTypes
from qgis.core import Qgis, QgsFeature, QgsGeometry, QgsWkbTypes, QgsMapToPixelSimplifier

from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.ProcessingLog import ProcessingLog
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterNumber
from processing.core.parameters import ParameterSelection
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector

Expand All @@ -46,6 +47,7 @@ class SimplifyGeometries(GeoAlgorithm):
INPUT = 'INPUT'
TOLERANCE = 'TOLERANCE'
OUTPUT = 'OUTPUT'
METHOD = 'METHOD'

def getIcon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'simplify.png'))
Expand All @@ -57,6 +59,13 @@ def defineCharacteristics(self):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),
[ParameterVector.VECTOR_TYPE_POLYGON, ParameterVector.VECTOR_TYPE_LINE]))
self.methods = [self.tr('Distance (Douglas-Peucker)'),
'Snap to grid',
'Area (Visvalingam)']
self.addParameter(ParameterSelection(
self.METHOD,
self.tr('Simplification method'),
self.methods, default=0))
self.addParameter(ParameterNumber(self.TOLERANCE,
self.tr('Tolerance'), 0.0, 10000000.0, 1.0))

Expand All @@ -65,6 +74,7 @@ def defineCharacteristics(self):
def processAlgorithm(self, progress):
layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
tolerance = self.getParameterValue(self.TOLERANCE)
method = self.getParameterValue(self.METHOD)

pointsBefore = 0
pointsAfter = 0
Expand All @@ -74,44 +84,27 @@ def processAlgorithm(self, progress):

features = vector.features(layer)
total = 100.0 / len(features)
for current, f in enumerate(features):
featGeometry = f.geometry()
attrs = f.attributes()
pointsBefore += self.geomVertexCount(featGeometry)
newGeometry = featGeometry.simplify(tolerance)
pointsAfter += self.geomVertexCount(newGeometry)
feature = QgsFeature()
feature.setGeometry(newGeometry)
feature.setAttributes(attrs)
writer.addFeature(feature)

if method != 0:
simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, tolerance, method)

for current, input_feature in enumerate(features):
out_feature = input_feature
if input_feature.geometry():
input_geometry = input_feature.geometry()
pointsBefore += input_geometry.geometry().nCoordinates()

if method == 0: # distance
output_geometry = input_geometry.simplify(tolerance)
else:
output_geometry = simplifier.simplify(input_geometry)

pointsAfter += output_geometry.geometry().nCoordinates()
out_feature.setGeometry(output_geometry)
writer.addFeature(out_feature)
progress.setPercentage(int(current * total))

del writer

ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Simplify: Input geometries have been simplified from %s to %s points' % (pointsBefore, pointsAfter)))

def geomVertexCount(self, geometry):
geomType = geometry.type()

if geomType == QgsWkbTypes.LineGeometry:
if geometry.isMultipart():
pointsList = geometry.asMultiPolyline()
points = sum(pointsList, [])
else:
points = geometry.asPolyline()
return len(points)
elif geomType == QgsWkbTypes.PolygonGeometry:
if geometry.isMultipart():
polylinesList = geometry.asMultiPolygon()
polylines = sum(polylinesList, [])
else:
polylines = geometry.asPolygon()

points = []
for l in polylines:
points.extend(l)

return len(points)
else:
return None
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>simplify_grid_lines</Name>
<ElementPath>simplify_grid_lines</ElementPath>
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>-0.08703</ExtentXMin>
<ExtentXMax>10.63163</ExtentXMax>
<ExtentYMin>-0.26248</ExtentYMin>
<ExtentYMax>4.98546</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-0.08703339882121899</gml:X><gml:Y>-0.262475442043224</gml:Y></gml:coord>
<gml:coord><gml:X>10.63163064833006</gml:X><gml:Y>4.985461689587426</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:simplify_grid_lines fid="1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.062278978388999,4.985461689587426 5.606483300589391,4.985461689587426</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_grid_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_grid_lines fid="3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.087033398821219,2.782318271119842 2.314145383104125,2.757563850687622 7.388801571709235,4.713163064833005 9.789980353634579,2.757563850687622 10.631630648330059,2.757563850687622</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_grid_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_grid_lines fid="2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>0.061493123772101,-0.237721021611003 1.967583497053045,-0.262475442043224 4.34400785854617,2.262475442043221 6.448133595284873,-0.262475442043224 10.606876227897841,-0.188212180746563</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_grid_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_grid_lines fid="4">
</ogr:simplify_grid_lines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>simplify_lines</Name>
<ElementPath>simplify_lines</ElementPath>
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>7</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>11.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
<ExtentYMax>5.00000</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>11</gml:X><gml:Y>5</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:simplify_lines fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,2 9,2 11,5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_lines fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 1,-1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_lines fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,0 3,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_lines fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,1 5,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_lines fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-3 10,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_lines fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,-3 10,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_lines fid="lines.6">
</ogr:simplify_lines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>simplify_multilines</Name>
<ElementPath>simplify_multilines</ElementPath>
<GeometryType>5</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>5.58042</ExtentXMax>
<ExtentYMin>-1.00000</ExtentYMin>
<ExtentYMax>4.11977</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-1</gml:Y></gml:coord>
<gml:coord><gml:X>5.58042226487524</gml:X><gml:Y>4.119769673704415</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:simplify_multilines fid="lines.1">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>-1,-1 1,-1</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
</ogr:simplify_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_multilines fid="lines.2">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>3,1 5,1</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>5.024184261036468,2.414779270633399 5,1</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
</ogr:simplify_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_multilines fid="lines.3">
</ogr:simplify_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_multilines fid="lines.4">
<ogr:geometryProperty><gml:MultiLineString srsName="EPSG:4326"><gml:lineStringMember><gml:LineString><gml:coordinates>2,0 3,3</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>2.944337811900192,4.04721689059501 5.459500959692898,4.119769673704415</gml:coordinates></gml:LineString></gml:lineStringMember><gml:lineStringMember><gml:LineString><gml:coordinates>3,3 5.58042226487524,2.946833013435702</gml:coordinates></gml:LineString></gml:lineStringMember></gml:MultiLineString></ogr:geometryProperty>
</ogr:simplify_multilines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>simplify_vis_lines</Name>
<ElementPath>simplify_vis_lines</ElementPath>
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>-0.08703</ExtentXMin>
<ExtentXMax>10.63163</ExtentXMax>
<ExtentYMin>-0.26248</ExtentYMin>
<ExtentYMax>4.98546</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-0.08703339882121899</gml:X><gml:Y>-0.262475442043224</gml:Y></gml:coord>
<gml:coord><gml:X>10.63163064833006</gml:X><gml:Y>4.985461689587426</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:simplify_vis_lines fid="1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.062278978388999,4.985461689587426 5.606483300589391,4.985461689587426</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_vis_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_vis_lines fid="3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.087033398821219,2.782318271119842 5.284675834970531,2.782318271119842 7.388801571709235,4.713163064833005 10.631630648330059,2.757563850687622</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_vis_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_vis_lines fid="2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>0.061493123772101,-0.237721021611003 1.967583497053045,-0.262475442043224 4.34400785854617,2.262475442043221 6.448133595284873,-0.262475442043224 10.606876227897841,-0.188212180746563</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:simplify_vis_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:simplify_vis_lines fid="4">
</ogr:simplify_vis_lines>
</gml:featureMember>
</ogr:FeatureCollection>
49 changes: 49 additions & 0 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -916,3 +916,52 @@ tests:
name: expected/extract_nodes_lines.gml
type: vector

- algorithm: qgis:simplifygeometries
name: Simplify (lines)
params:
INPUT:
name: lines.gml
type: vector
TOLERANCE: 1.0
results:
OUTPUT:
name: expected/simplify_lines.gml
type: vector

- algorithm: qgis:simplifygeometries
name: Simplify (multilines)
params:
INPUT:
name: multilines.gml
type: vector
TOLERANCE: 1.0
results:
OUTPUT:
name: expected/simplify_multilines.gml
type: vector

- algorithm: qgis:simplifygeometries
name: Simplify (visval)
params:
INPUT:
name: simplify_lines.gml
type: vector
METHOD: '2'
TOLERANCE: 1.0
results:
OUTPUT:
name: expected/simplify_vis_lines.gml
type: vector

- algorithm: qgis:simplifygeometries
name: Simplify (grid)
params:
INPUT:
name: simplify_lines.gml
type: vector
METHOD: '1'
TOLERANCE: 5.0
results:
OUTPUT:
name: expected/simplify_grid_lines.gml
type: vector

0 comments on commit 88047cc

Please sign in to comment.