Skip to content
Permalink
Browse files

[FEATURE] Add option to QgsGeometry::smooth to not smooth

segments shorter than a certain threshold or sharp corners
with an angle exceeding a threshold

Expose the angle threshold to processing smooth algorithm

Also:
- optimise QgsGeometry::smooth for new geometry classes
- Fix smooth does not work with geometries containing Z/M
  • Loading branch information
nyalldawson committed Sep 2, 2016
1 parent 01da222 commit 4d60d0cdb54cc75f15c4e841aa87a3fd6994c918
@@ -581,6 +581,7 @@ method to determine if a geometry is valid.</li>
<li>static bool compare( const QgsPolyline& p1, const QgsPolyline& p2, double epsilon ) has been renamed to comparePolylines</li>
<li>static bool compare( const QgsPolygon& p1, const QgsPolygon& p2, double epsilon ) has been renamed to comparePolygons</li>
<li>static bool compare( const QgsMultiPolygon& p1, const QgsMultiPolygon& p2, double epsilon ) has been renamed to compareMultiPolygons</li>
<li>smoothLine and smoothPolygon are no longer public API (use smooth() instead)</li>
</ul>

\subsection qgis_api_break_3_0_QgsGeometryAnalyzer QgsGeometryAnalyzer
@@ -849,14 +849,12 @@ class QgsGeometry
* @param offset fraction of line to create new vertices along, between 0 and 1.0
* eg the default value of 0.25 will create new vertices 25% and 75% along each line segment
* of the geometry for each iteration. Smaller values result in "tighter" smoothing.
* @param minimumDistance minimum segment length to apply smoothing to
* @param maxAngle maximum angle at node (0-180) at which smoothing will be applied
* @note added in 2.9
*/
QgsGeometry smooth( const unsigned int iterations, const double offset ) const;

/** Smooths a polygon using the Chaikin algorithm*/
QgsPolygon smoothPolygon( const QgsPolygon &polygon, const unsigned int iterations = 1, const double offset = 0.25 ) const;
/** Smooths a polyline using the Chaikin algorithm*/
QgsPolyline smoothLine( const QgsPolyline &polyline, const unsigned int iterations = 1, const double offset = 0.25 ) const;
QgsGeometry smooth( const unsigned int iterations = 1, const double offset = 0.25,
double minimumDistance = -1.0, double maxAngle = 180.0 ) const;

/** Creates and returns a new geometry engine
*/
@@ -444,6 +444,15 @@ qgis:singlesidedbuffer: >

The mitre limit parameter is only applicable for mitre join styles, and controls the maximum distance from the buffer to use when creating a mitred join.

qgis:smoothgeometry: >
This algorithm smooths 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 higher number of vertices and corners in the geometries smoothed out.

The iterations parameter dictates how many smoothing iterations will be applied to each geometry. A higher number of iterations results in smoother geometries with the cost of greater number of nodes in the geometries.

The offset parameter controls how "tightly" the smoothed geometries follow the original geometries. Smaller values results in a tighter fit, and larger values will create a looser fit.

The maximum angle parameter can be used to prevent smoothing of nodes with large angles. Any node where the angle of the segments to either side is larger then this will not be smoothed. Eg setting the maximum angle to 90 degrees or lower would preserve right angles in the geometry.

qgis:snappointstogrid: >
This algorithm modifies the position of points in a vector layer, so they fall in the coordinates of a grid.

@@ -38,6 +38,7 @@ class Smooth(GeoAlgorithm):
INPUT_LAYER = 'INPUT_LAYER'
OUTPUT_LAYER = 'OUTPUT_LAYER'
ITERATIONS = 'ITERATIONS'
MAX_ANGLE = 'MAX_ANGLE'
OFFSET = 'OFFSET'

def defineCharacteristics(self):
@@ -50,37 +51,37 @@ def defineCharacteristics(self):
self.tr('Iterations'), default=1, minValue=1, maxValue=10))
self.addParameter(ParameterNumber(self.OFFSET,
self.tr('Offset'), default=0.25, minValue=0.0, maxValue=0.5))
self.addParameter(ParameterNumber(self.MAX_ANGLE,
self.tr('Maximum node angle to smooth'), default=180.0, minValue=0.0, maxValue=180.0))
self.addOutput(OutputVector(self.OUTPUT_LAYER, self.tr('Smoothed')))

def processAlgorithm(self, progress):
layer = dataobjects.getObjectFromUri(
self.getParameterValue(self.INPUT_LAYER))
iterations = self.getParameterValue(self.ITERATIONS)
offset = self.getParameterValue(self.OFFSET)
max_angle = self.getParameterValue(self.MAX_ANGLE)

writer = self.getOutputFromName(
self.OUTPUT_LAYER).getVectorWriter(
layer.fields().toList(),
layer.wkbType(),
layer.crs())

outFeat = QgsFeature()

features = vector.features(layer)
total = 100.0 / len(features)

for current, inFeat in enumerate(features):
inGeom = inFeat.geometry()
attrs = inFeat.attributes()
for current, input_feature in enumerate(features):
output_feature = input_feature
if input_feature.geometry():
output_geometry = input_feature.geometry().smooth(iterations, offset, -1, max_angle)
if not output_geometry:
raise GeoAlgorithmExecutionException(
self.tr('Error smoothing geometry'))

outGeom = inGeom.smooth(iterations, offset)
if not outGeom:
raise GeoAlgorithmExecutionException(
self.tr('Error smoothing geometry'))
output_feature.setGeometry(output_geometry)

outFeat.setGeometry(outGeom)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat)
writer.addFeature(output_feature)
progress.setPercentage(int(current * total))

del writer
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>smoothed_lines</Name>
<ElementPath>smoothed_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:smoothed_lines fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,2 8.25,2.0 9.0,2.25 9.0,2.75 9.5,3.5 11,5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 1,-1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,0 2.0,1.5 2.25,2.0 2.75,2.0 3.0,2.25 3,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,1 5,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-3 10,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,-3 10,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines fid="lines.6">
</ogr:smoothed_lines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,15 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>smoothed_lines_max_angle</Name>
<ElementPath>smoothed_lines_max_angle</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:smoothed_lines_max_angle fid="lines.0">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,2 9,2 9.0,2.75 9.5,3.5 11,5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines_max_angle fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 1,-1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines_max_angle fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,0 2,2 3,2 3,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines_max_angle fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,1 5,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines_max_angle fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-3 10,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines_max_angle fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,-3 10,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
<gml:featureMember>
<ogr:smoothed_lines_max_angle fid="lines.6">
</ogr:smoothed_lines_max_angle>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -965,3 +965,31 @@ tests:
OUTPUT:
name: expected/simplify_grid_lines.gml
type: vector

- algorithm: qgis:smoothgeometry
name: Smooth (lines)
params:
INPUT_LAYER:
name: lines.gml
type: vector
ITERATIONS: 1
MAX_ANGLE: 180.0
OFFSET: 0.25
results:
OUTPUT_LAYER:
name: expected/smoothed_lines.gml
type: vector

- algorithm: qgis:smoothgeometry
name: Smooth (lines, with max angle)
params:
INPUT_LAYER:
name: lines.gml
type: vector
ITERATIONS: 1
MAX_ANGLE: 60.0
OFFSET: 0.25
results:
OUTPUT_LAYER:
name: expected/smoothed_lines_max_angle.gml
type: vector

0 comments on commit 4d60d0c

Please sign in to comment.
You can’t perform that action at this time.