Skip to content
Permalink
Browse files

Merge pull request #3808 from nyalldawson/processing_dupe_remove_rings

[processing] Remove duplicate fill holes algorithm
  • Loading branch information
nyalldawson committed Nov 29, 2016
2 parents 5b97b4a + 6bb4934 commit 57f17e31e2c3035d443ce09c6ef0ac80bb9d1387
@@ -54,8 +54,23 @@ class QgsCurvePolygon: public QgsSurface
void setInteriorRings( const QList<QgsCurve*>& rings );
/** Adds an interior ring to the geometry (takes ownership)*/
virtual void addInteriorRing( QgsCurve* ring /Transfer/ );
/** Removes ring. Exterior ring is 0, first interior ring 1, ...*/
bool removeInteriorRing( int nr );

/**
* Removes an interior ring from the polygon. The first interior ring has index 0.
* The corresponding ring is removed from the polygon and deleted. If a ring was successfully removed
* the function will return true. It is not possible to remove the exterior ring using this method.
* @see removeInteriorRings()
*/
bool removeInteriorRing( int ringIndex );

/**
* Removes the interior rings from the polygon. If the minimumAllowedArea
* parameter is specified then only rings smaller than this minimum
* area will be removed.
* @note added in QGIS 3.0
* @see removeInteriorRing()
*/
void removeInteriorRings( double minimumAllowedArea = -1 );

virtual void draw( QPainter& p ) const;
void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform,
@@ -345,6 +345,14 @@ class QgsGeometry
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( const QgsGeometry& newPart ) /PyName=addPartGeometry/;

/**
* Removes the interior rings from a (multi)polygon geometry. If the minimumAllowedArea
* parameter is specified then only rings smaller than this minimum
* area will be removed.
* @note added in QGIS 3.0
*/
QgsGeometry removeInteriorRings( double minimumAllowedArea = -1 ) const;

/** Translate this geometry by dx, dy
@return 0 in case of success*/
int translate( double dx, double dy );
@@ -130,6 +130,8 @@ qgis:deleteduplicategeometries: >
qgis:deleteholes: >
This algorithm takes a polygon layer and removes holes in polygons. It creates a new vector layer in which polygons with holes have been replaced by polygons with only their external ring. Attributes are not modified.

An optional minimum area parameter allows removing only holes which are smaller than a specified area threshold. Leaving this parameter as 0.0 results in all holes being removed.

qgis:densifygeometries:
This algorithm takes a polygon or line layer and generaates a new one in which the geometries have a larger number of vertices than the original one.

@@ -26,27 +26,41 @@

from qgis.core import QgsFeature, QgsGeometry
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import (ParameterVector,
ParameterNumber)
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector


class DeleteHoles(GeoAlgorithm):

INPUT = 'INPUT'
MIN_AREA = 'MIN_AREA'
OUTPUT = 'OUTPUT'

def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Delete holes')
self.group, self.i18n_group = self.trAlgorithm('Vector geometry tools')
self.tags = self.tr('remove,delete,drop,holes,rings,fill')

self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON]))
self.addParameter(ParameterNumber(self.MIN_AREA,
self.tr('Remove holes with area less than'), 0, 10000000.0, default=0.0, optional=True))

self.addOutput(OutputVector(self.OUTPUT, self.tr('Cleaned'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))

def processAlgorithm(self, progress):
layer = dataobjects.getObjectFromUri(
self.getParameterValue(self.INPUT))
min_area = self.getParameterValue(self.MIN_AREA)
if min_area is not None:
try:
min_area = float(min_area)
except:
pass
if min_area == 0.0:
min_area = -1.0

writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
layer.fields(),
@@ -56,28 +70,13 @@ def processAlgorithm(self, progress):
features = vector.features(layer)
total = 100.0 / len(features)

feat = QgsFeature()
for current, f in enumerate(features):
geometry = f.geometry()
if not geometry.isEmpty():
if geometry.isMultipart():
multi_polygon = geometry.asMultiPolygon()
for polygon in multi_polygon:
for ring in polygon[1:]:
polygon.remove(ring)
geometry = QgsGeometry.fromMultiPolygon(multi_polygon)

if f.hasGeometry():
if min_area is not None:
f.setGeometry(f.geometry().removeInteriorRings(min_area))
else:
polygon = geometry.asPolygon()
for ring in polygon[1:]:
polygon.remove(ring)
geometry = QgsGeometry.fromPolygon(polygon)
else:
geometry = QgsGeometry(None)

feat.setGeometry(geometry)
feat.setAttributes(f.attributes())
writer.addFeature(feat)
f.setGeometry(f.geometry().removeInteriorRings())
writer.addFeature(f)
progress.setPercentage(int(current * total))

del writer
@@ -55,6 +55,7 @@ def getIcon(self):
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Points along lines')
self.group, self.i18n_group = self.trAlgorithm('Vector geometry tools')
self.tags = self.tr('create,interpolate,points,lines')

self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),

This file was deleted.

This file was deleted.

@@ -0,0 +1,30 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>remove_holes</Name>
<ElementPath>remove_holes</ElementPath>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>2.00000</ExtentXMin>
<ExtentXMax>10.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
<ExtentYMax>6.00000</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>intval</Name>
<ElementPath>intval</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
<PropertyDefn>
<Name>floatval</Name>
<ElementPath>floatval</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>name</Name>
<ElementPath>name</ElementPath>
<Type>String</Type>
<Width>4</Width>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,40 @@
<?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>2</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:remove_holes fid="polys.4">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:remove_holes>
</gml:featureMember>
<gml:featureMember>
<ogr:remove_holes fid="polys.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>elim</ogr:name>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>
</ogr:remove_holes>
</gml:featureMember>
<gml:featureMember>
<ogr:remove_holes fid="polys.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7,0 7,-2 9,-2 9,0 7,0</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:name>ASDF</ogr:name>
<ogr:intval>0</ogr:intval>
</ogr:remove_holes>
</gml:featureMember>
<gml:featureMember>
<ogr:remove_holes fid="remove_holes.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,6 2,3 10,3 10,6 2,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>2.5,5.6 2.5,3.5 5.6,3.5 5.6,5.6 2.5,5.6</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>7.0,5.5 7,5 8,5 8.0,5.5 7.0,5.5</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>6.0,4.5 6.0,3.5 9.0,3.5 9.0,4.5 6.0,4.5</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:remove_holes>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>removed_holes</Name>
<ElementPath>removed_holes</ElementPath>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>4</FeatureCount>
<ExtentXMin>2.00000</ExtentXMin>
<ExtentXMax>10.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
<ExtentYMax>6.00000</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>intval</Name>
<ElementPath>intval</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
<PropertyDefn>
<Name>floatval</Name>
<ElementPath>floatval</ElementPath>
<Type>Real</Type>
</PropertyDefn>
<PropertyDefn>
<Name>name</Name>
<ElementPath>name</ElementPath>
<Type>String</Type>
<Width>4</Width>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,40 @@
<?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>2</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>10</gml:X><gml:Y>6</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:removed_holes fid="polys.4">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:removed_holes>
</gml:featureMember>
<gml:featureMember>
<ogr:removed_holes fid="polys.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>
<ogr:name>elim</ogr:name>
</ogr:removed_holes>
</gml:featureMember>
<gml:featureMember>
<ogr:removed_holes fid="polys.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6,1 10,1 10,-3 6,-3 6,1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:intval>0</ogr:intval>
<ogr:name>ASDF</ogr:name>
</ogr:removed_holes>
</gml:featureMember>
<gml:featureMember>
<ogr:removed_holes fid="remove_holes.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,6 2,3 10,3 10,6 2,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:removed_holes>
</gml:featureMember>
</ogr:FeatureCollection>

0 comments on commit 57f17e3

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