Merge pull request #3441 from nyalldawson/simplify

Simplify features + fixes
This commit is contained in:
Nyall Dawson 2016-09-01 21:02:09 +10:00 committed by GitHub
commit 88047cc984
20 changed files with 447 additions and 128 deletions

View File

@ -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 );

View File

@ -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:

View File

@ -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

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View File

@ -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

View 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>

View 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>

View File

@ -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

View File

@ -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 );
}
}

View File

@ -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;

View File

@ -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 );

View File

@ -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>

View File

@ -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"