mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #3441 from nyalldawson/simplify
Simplify features + fixes
This commit is contained in:
commit
88047cc984
@ -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 );
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
||||
|
@ -29,12 +29,13 @@ import os
|
||||
|
||||
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
|
||||
|
||||
@ -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'))
|
||||
@ -57,6 +59,13 @@ class SimplifyGeometries(GeoAlgorithm):
|
||||
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))
|
||||
|
||||
@ -65,6 +74,7 @@ class SimplifyGeometries(GeoAlgorithm):
|
||||
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
|
||||
@ -74,44 +84,27 @@ class SimplifyGeometries(GeoAlgorithm):
|
||||
|
||||
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
|
||||
|
15
python/plugins/processing/tests/testdata/expected/simplify_grid_lines.gfs
vendored
Normal file
15
python/plugins/processing/tests/testdata/expected/simplify_grid_lines.gfs
vendored
Normal file
@ -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>
|
33
python/plugins/processing/tests/testdata/expected/simplify_grid_lines.gml
vendored
Normal file
33
python/plugins/processing/tests/testdata/expected/simplify_grid_lines.gml
vendored
Normal file
@ -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>
|
15
python/plugins/processing/tests/testdata/expected/simplify_lines.gfs
vendored
Normal file
15
python/plugins/processing/tests/testdata/expected/simplify_lines.gfs
vendored
Normal file
@ -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>
|
48
python/plugins/processing/tests/testdata/expected/simplify_lines.gml
vendored
Normal file
48
python/plugins/processing/tests/testdata/expected/simplify_lines.gml
vendored
Normal file
@ -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>
|
15
python/plugins/processing/tests/testdata/expected/simplify_multilines.gfs
vendored
Normal file
15
python/plugins/processing/tests/testdata/expected/simplify_multilines.gfs
vendored
Normal file
@ -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>
|
33
python/plugins/processing/tests/testdata/expected/simplify_multilines.gml
vendored
Normal file
33
python/plugins/processing/tests/testdata/expected/simplify_multilines.gml
vendored
Normal file
@ -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>
|
15
python/plugins/processing/tests/testdata/expected/simplify_vis_lines.gfs
vendored
Normal file
15
python/plugins/processing/tests/testdata/expected/simplify_vis_lines.gfs
vendored
Normal file
@ -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>
|
33
python/plugins/processing/tests/testdata/expected/simplify_vis_lines.gml
vendored
Normal file
33
python/plugins/processing/tests/testdata/expected/simplify_vis_lines.gml
vendored
Normal file
@ -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>
|
@ -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
|
||||
|
15
python/plugins/processing/tests/testdata/simplify_lines.gfs
vendored
Normal file
15
python/plugins/processing/tests/testdata/simplify_lines.gfs
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<GMLFeatureClassList>
|
||||
<GMLFeatureClass>
|
||||
<Name>simplify_lines</Name>
|
||||
<ElementPath>simplify_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>
|
33
python/plugins/processing/tests/testdata/simplify_lines.gml
vendored
Normal file
33
python/plugins/processing/tests/testdata/simplify_lines.gml
vendored
Normal file
@ -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.08703339882121885</gml:X><gml:Y>-0.2624754420432236</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_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_lines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:simplify_lines fid="3">
|
||||
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-0.087033398821219,2.782318271119842 2.314145383104125,2.757563850687622 2.611198428290766,4.688408644400785 2.611198428290766,2.807072691552063 5.284675834970531,2.782318271119842 7.388801571709235,4.713163064833005 9.789980353634579,2.757563850687622 10.631630648330061,2.757563850687622</gml:coordinates></gml:LineString></ogr:geometryProperty>
|
||||
</ogr:simplify_lines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:simplify_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_lines>
|
||||
</gml:featureMember>
|
||||
<gml:featureMember>
|
||||
<ogr:simplify_lines fid="4">
|
||||
</ogr:simplify_lines>
|
||||
</gml:featureMember>
|
||||
</ogr:FeatureCollection>
|
@ -44,6 +44,8 @@ SET(QGIS_CORE_SRCS
|
||||
symbology-ng/qgssymbol.cpp
|
||||
symbology-ng/qgsvectorfieldsymbollayer.cpp
|
||||
|
||||
simplify/effectivearea.cpp
|
||||
|
||||
diagram/qgsdiagram.cpp
|
||||
diagram/qgshistogramdiagram.cpp
|
||||
diagram/qgspiediagram.cpp
|
||||
|
@ -70,17 +70,7 @@ bool QgsMapToPixelSimplifier::equalSnapToGrid( double x1, double y1, double x2,
|
||||
// https://github.com/postgis/postgis/blob/svn-trunk/liblwgeom/effectivearea.h
|
||||
// https://github.com/postgis/postgis/blob/svn-trunk/liblwgeom/effectivearea.c
|
||||
|
||||
#define LWDEBUG //
|
||||
#define LWDEBUGF //
|
||||
#define FP_MAX qMax
|
||||
#define FLAGS_GET_Z( flags ) ( ( flags ) & 0x01 )
|
||||
#define LW_MSG_MAXLEN 256
|
||||
#define lwalloc qgsMalloc
|
||||
#define lwfree qgsFree
|
||||
#define lwerror qWarning
|
||||
|
||||
#include "simplify/effectivearea.h"
|
||||
#include "simplify/effectivearea.c"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -175,75 +165,80 @@ QgsGeometry QgsMapToPixelSimplifier::simplifyGeometry(
|
||||
}
|
||||
|
||||
// Process each vertex...
|
||||
if ( simplifyAlgorithm == SnapToGrid )
|
||||
switch ( simplifyAlgorithm )
|
||||
{
|
||||
double gridOriginX = envelope.xMinimum();
|
||||
double gridOriginY = envelope.yMinimum();
|
||||
|
||||
// Use a factor for the maximum displacement distance for simplification, similar as GeoServer does
|
||||
float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f;
|
||||
|
||||
for ( int i = 0; i < numPoints; ++i )
|
||||
case SnapToGrid:
|
||||
{
|
||||
x = srcCurve.xAt( i );
|
||||
y = srcCurve.yAt( i );
|
||||
double gridOriginX = envelope.xMinimum();
|
||||
double gridOriginY = envelope.yMinimum();
|
||||
|
||||
if ( i == 0 ||
|
||||
!isGeneralizable ||
|
||||
!equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) ||
|
||||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
|
||||
// Use a factor for the maximum displacement distance for simplification, similar as GeoServer does
|
||||
float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f;
|
||||
|
||||
for ( int i = 0; i < numPoints; ++i )
|
||||
{
|
||||
output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) );
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
x = srcCurve.xAt( i );
|
||||
y = srcCurve.yAt( i );
|
||||
|
||||
r.combineExtentWith( x, y );
|
||||
if ( i == 0 ||
|
||||
!isGeneralizable ||
|
||||
!equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) ||
|
||||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
|
||||
{
|
||||
output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) );
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
}
|
||||
|
||||
r.combineExtentWith( x, y );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( simplifyAlgorithm == Visvalingam )
|
||||
{
|
||||
map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'Area' calculations.
|
||||
|
||||
EFFECTIVE_AREAS* ea;
|
||||
ea = initiate_effectivearea( srcCurve );
|
||||
|
||||
int set_area = 0;
|
||||
ptarray_calc_areas( ea, isaLinearRing ? 4 : 2, set_area, map2pixelTol );
|
||||
|
||||
for ( int i = 0; i < numPoints; ++i )
|
||||
case Visvalingam:
|
||||
{
|
||||
if ( ea->res_arealist[ i ] > map2pixelTol )
|
||||
map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'Area' calculations.
|
||||
|
||||
EFFECTIVE_AREAS ea( srcCurve );
|
||||
|
||||
int set_area = 0;
|
||||
ptarray_calc_areas( &ea, isaLinearRing ? 4 : 2, set_area, map2pixelTol );
|
||||
|
||||
for ( int i = 0; i < numPoints; ++i )
|
||||
{
|
||||
output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), ea->inpts.at( i ) );
|
||||
if ( ea.res_arealist[ i ] > map2pixelTol )
|
||||
{
|
||||
output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), ea.inpts.at( i ) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
destroy_effectivearea( ea );
|
||||
}
|
||||
else
|
||||
{
|
||||
map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations.
|
||||
|
||||
for ( int i = 0; i < numPoints; ++i )
|
||||
case Distance:
|
||||
{
|
||||
x = srcCurve.xAt( i );
|
||||
y = srcCurve.yAt( i );
|
||||
map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations.
|
||||
|
||||
isLongSegment = false;
|
||||
|
||||
if ( i == 0 ||
|
||||
!isGeneralizable ||
|
||||
( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) ||
|
||||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
|
||||
for ( int i = 0; i < numPoints; ++i )
|
||||
{
|
||||
output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) );
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
x = srcCurve.xAt( i );
|
||||
y = srcCurve.yAt( i );
|
||||
|
||||
hasLongSegments |= isLongSegment;
|
||||
isLongSegment = false;
|
||||
|
||||
if ( i == 0 ||
|
||||
!isGeneralizable ||
|
||||
( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) ||
|
||||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
|
||||
{
|
||||
output->insertVertex( QgsVertexId( 0, 0, output->numPoints() ), QgsPointV2( x, y ) );
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
|
||||
hasLongSegments |= isLongSegment;
|
||||
}
|
||||
|
||||
r.combineExtentWith( x, y );
|
||||
}
|
||||
|
||||
r.combineExtentWith( x, y );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,25 +24,6 @@
|
||||
|
||||
#include "effectivearea.h"
|
||||
|
||||
EFFECTIVE_AREAS* initiate_effectivearea( const QgsCurve& inpts )
|
||||
{
|
||||
//LWDEBUG( 2, "Entered initiate_effectivearea" );
|
||||
EFFECTIVE_AREAS *ea;
|
||||
ea = ( EFFECTIVE_AREAS* )lwalloc( sizeof( EFFECTIVE_AREAS ) );
|
||||
inpts.points( ea->inpts );
|
||||
ea->is3d = inpts.is3D();
|
||||
ea->initial_arealist = ( areanode* )lwalloc( ea->inpts.size() * sizeof( areanode ) );
|
||||
ea->res_arealist = ( double* )lwalloc( ea->inpts.size() * sizeof( double ) );
|
||||
return ea;
|
||||
}
|
||||
|
||||
void destroy_effectivearea( EFFECTIVE_AREAS *ea )
|
||||
{
|
||||
lwfree( ea->initial_arealist );
|
||||
lwfree( ea->res_arealist );
|
||||
lwfree( ea );
|
||||
}
|
||||
|
||||
static MINHEAP initiate_minheap( int npoints )
|
||||
{
|
||||
MINHEAP tree;
|
@ -22,20 +22,35 @@
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#include "qgsabstractgeometry.h"
|
||||
#include "qgscurve.h"
|
||||
#include "qgspointv2.h"
|
||||
|
||||
#ifndef _EFFECTIVEAREA_H
|
||||
#define _EFFECTIVEAREA_H 1
|
||||
|
||||
|
||||
#define LWDEBUG //
|
||||
#define LWDEBUGF //
|
||||
#define FP_MAX qMax
|
||||
#define FLAGS_GET_Z( flags ) ( ( flags ) & 0x01 )
|
||||
#define LW_MSG_MAXLEN 256
|
||||
#define lwalloc qgsMalloc
|
||||
#define lwfree qgsFree
|
||||
#define lwerror qWarning
|
||||
|
||||
|
||||
/**
|
||||
* This structure is placed in an array with one member per point.
|
||||
* It has links into the minheap rtee and kepps track of eliminated points.
|
||||
*/
|
||||
typedef struct
|
||||
struct areanode
|
||||
{
|
||||
double area;
|
||||
int treeindex;
|
||||
int prev;
|
||||
int next;
|
||||
} areanode;
|
||||
};
|
||||
|
||||
/**
|
||||
* This structure holds a minheap tree that is used to keep track of what points
|
||||
@ -43,27 +58,39 @@ typedef struct
|
||||
* When elliminating points the neighbor points has its effective area affected
|
||||
* and the minheap helps to resort efficient.
|
||||
*/
|
||||
typedef struct
|
||||
struct MINHEAP
|
||||
{
|
||||
int maxSize;
|
||||
int usedSize;
|
||||
areanode **key_array;
|
||||
} MINHEAP;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure to hold pointarray and it's arealist.
|
||||
*/
|
||||
typedef struct
|
||||
struct EFFECTIVE_AREAS
|
||||
{
|
||||
EFFECTIVE_AREAS( const QgsCurve& curve )
|
||||
: is3d( curve.is3D() )
|
||||
, initial_arealist( nullptr )
|
||||
, res_arealist( nullptr )
|
||||
{
|
||||
curve.points( inpts );
|
||||
initial_arealist = new areanode[ inpts.size()];
|
||||
res_arealist = new double[ inpts.size()];
|
||||
}
|
||||
|
||||
~EFFECTIVE_AREAS()
|
||||
{
|
||||
delete [] initial_arealist;
|
||||
delete [] res_arealist;
|
||||
}
|
||||
|
||||
bool is3d;
|
||||
QgsPointSequence inpts;
|
||||
areanode *initial_arealist;
|
||||
double *res_arealist;
|
||||
} EFFECTIVE_AREAS;
|
||||
|
||||
EFFECTIVE_AREAS* initiate_effectivearea( const QgsCurve &inpts );
|
||||
|
||||
void destroy_effectivearea( EFFECTIVE_AREAS *ea );
|
||||
};
|
||||
|
||||
void ptarray_calc_areas( EFFECTIVE_AREAS *ea, int avoid_collaps, int set_area, double trshld );
|
||||
|
||||
|
@ -711,7 +711,7 @@
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>5.000000000000000</double>
|
||||
<double>30.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.200000000000000</double>
|
||||
|
@ -74,6 +74,7 @@ class TestQgsMapToPixelGeometrySimplifier : public QObject
|
||||
void testIsGeneralizableByMapBoundingBox();
|
||||
void testWkbDimensionMismatch();
|
||||
void testCircularString();
|
||||
void testVisvalingam();
|
||||
|
||||
};
|
||||
|
||||
@ -194,5 +195,16 @@ void TestQgsMapToPixelGeometrySimplifier::testCircularString()
|
||||
QCOMPARE( simplifier.simplify( g ).exportToWkt(), WKT );
|
||||
}
|
||||
|
||||
void TestQgsMapToPixelGeometrySimplifier::testVisvalingam()
|
||||
{
|
||||
QString wkt( "LineString (0 0, 30 0, 31 30, 32 0, 40 0, 41 100, 42 0, 50 0)" );
|
||||
QgsGeometry g = QgsGeometry::fromWkt( wkt );
|
||||
|
||||
const QgsMapToPixelSimplifier simplifier( QgsMapToPixelSimplifier::SimplifyGeometry, 7, QgsMapToPixelSimplifier::Visvalingam );
|
||||
QString expectedWkt( "LineString (0 0, 40 0, 41 100, 42 0, 50 0)" );
|
||||
|
||||
QCOMPARE( simplifier.simplify( g ).exportToWkt(), expectedWkt );
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsMapToPixelGeometrySimplifier )
|
||||
#include "testqgsmaptopixelgeometrysimplifier.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user