Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added "eliminate sliver polygons" algorithm skeleton(still a draft fi…
…rst version)
- Loading branch information
Showing
2 changed files
with
187 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
""" | ||
*************************************************************************** | ||
Eliminate.py | ||
--------------------- | ||
Date : August 2012 | ||
Copyright : (C) 2013 by Bernhard Str�bl | ||
Email : bernhard.stroebl@jena.de | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
*************************************************************************** | ||
""" | ||
from processing.parameters.ParameterSelection import ParameterSelection | ||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException | ||
from PyQt4 import QtCore | ||
|
||
__author__ = 'Bernhard Strobl' | ||
__date__ = 'August 2013' | ||
__copyright__ = '(C) 2013, Bernhard Strobl' | ||
# This will get replaced with a git SHA1 when you do a git archive | ||
__revision__ = '$Format:%H$' | ||
|
||
from PyQt4.QtCore import * | ||
from qgis.core import * | ||
from processing.core.GeoAlgorithm import GeoAlgorithm | ||
from processing.tools import dataobjects | ||
from processing.parameters.ParameterVector import ParameterVector | ||
from processing.outputs.OutputVector import OutputVector | ||
|
||
|
||
class Eliminate(GeoAlgorithm): | ||
|
||
INPUT = "INPUT" | ||
OUTPUT = "OUTPUT" | ||
MODE = "MODE" | ||
|
||
MODES = ["Area", "Common boundary"] | ||
MODE_AREA = 0 | ||
MODE_BOUNDARY = 1 | ||
|
||
|
||
def defineCharacteristics(self): | ||
self.name = "Eliminate sliver polygons" | ||
self.group = "Vector geometry tools" | ||
self.addParameter(ParameterVector(self.INPUT, "Input layer", [ParameterVector.VECTOR_TYPE_POLYGON])) | ||
self.addParameter(ParameterSelection(self.MODE, "Segments", self.MODES)) | ||
self.addOutput(OutputVector(self.OUTPUT, "Cleaned layer")) | ||
|
||
def processAlgorithm(self, progress): | ||
inLayer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) | ||
boundary = self.getParameterValue(self.MODE) == self.MODE_BOUNDARY | ||
|
||
# keep references to the features to eliminate | ||
fidsToEliminate = inLayer.selectedFeaturesIds() | ||
|
||
|
||
provider = inLayer.dataProvider() | ||
output = self.getOutputFromName(self.OUTPUT) | ||
writer = output.getVectorWriter( provider.fields(), | ||
provider.geometryType(), | ||
inLayer.crs() ) | ||
|
||
#write all features to output layer | ||
iterator = inLayer.getFeatures() | ||
for feature in iterator: | ||
writer.addFeature(feature) | ||
|
||
#Open the layer to start cleaning it | ||
outFileName = output.value | ||
outLayer = QgsVectorLayer(outFileName, QtCore.QFileInfo(outFileName).completeBaseName(), "ogr") | ||
|
||
|
||
# delete features to be eliminated in outLayer | ||
outLayer.setSelectedFeatures(fidsToEliminate) | ||
outLayer.startEditing() | ||
|
||
if outLayer.deleteSelectedFeatures(): | ||
if self.saveChanges(outLayer): | ||
outLayer.startEditing() | ||
else: | ||
raise GeoAlgorithmExecutionException("Could not delete features") | ||
|
||
# ANALYZE | ||
start = 20.00 | ||
progress.setPercentage(start) | ||
add = 80.00 / len(fidsToEliminate) | ||
|
||
lastLen = 0 | ||
geomsToMerge = dict() | ||
|
||
# we go through the list and see if we find any polygons we can merge the selected with | ||
# if we have no success with some we merge and then restart the whole story | ||
while (lastLen != inLayer.selectedFeatureCount()): #check if we made any progress | ||
lastLen = inLayer.selectedFeatureCount() | ||
fidsToDeselect = [] | ||
|
||
#iterate over the polygons to eliminate | ||
for fid2Eliminate in inLayer.selectedFeaturesIds(): | ||
feat = QgsFeature() | ||
|
||
if inLayer.getFeatures( QgsFeatureRequest().setFilterFid( fid2Eliminate ).setSubsetOfAttributes([]) ).nextFeature( feat ): | ||
geom2Eliminate = feat.geometry() | ||
bbox = geom2Eliminate.boundingBox() | ||
fit = outLayer.getFeatures( QgsFeatureRequest().setFilterRect( bbox ) ) | ||
mergeWithFid = None | ||
mergeWithGeom = None | ||
max = 0 | ||
|
||
selFeat = QgsFeature() | ||
while fit.nextFeature(selFeat): | ||
selGeom = selFeat.geometry() | ||
|
||
if geom2Eliminate.intersects(selGeom): # we have a candidate | ||
iGeom = geom2Eliminate.intersection(selGeom) | ||
|
||
if boundary: | ||
selValue = iGeom.length() | ||
else: | ||
# we need a common boundary | ||
if 0 < iGeom.length(): | ||
selValue = selGeom.area() | ||
else: | ||
selValue = 0 | ||
|
||
if selValue > max: | ||
max = selValue | ||
mergeWithFid = selFeat.id() | ||
mergeWithGeom = QgsGeometry(selGeom) # deep copy of the geometry | ||
|
||
if mergeWithFid != None: # a successful candidate | ||
newGeom = mergeWithGeom.combine(geom2Eliminate) | ||
|
||
if outLayer.changeGeometry(mergeWithFid, newGeom): | ||
# write change back to disc | ||
if self.saveChanges(outLayer): | ||
outLayer.startEditing() | ||
else: | ||
return | ||
|
||
# mark feature as eliminated in inLayer | ||
fidsToDeselect.append(fid2Eliminate) | ||
else: | ||
raise GeoAlgorithmExecutionException("Could not replace geometry of feature with id %s" % (mergeWithFid)) | ||
|
||
start = start + add | ||
progress.setPercentage(start) | ||
# end for fid2Eliminate | ||
|
||
# deselect features that are already eliminated in inLayer | ||
inLayer.deselect(fidsToDeselect) | ||
|
||
#end while | ||
|
||
if inLayer.selectedFeatureCount() > 0: | ||
# copy all features that could not be eliminated to outLayer | ||
if outLayer.addFeatures(inLayer.selectedFeatures()): | ||
# inform user | ||
fidList = "" | ||
|
||
for fid in inLayer.selectedFeaturesIds(): | ||
if not fidList == "": | ||
fidList += ", " | ||
|
||
fidList += str(fid) | ||
|
||
raise GeoAlgorithmExecutionException("Could not eliminate features with these ids:\n%s" % (fidList)) | ||
else: | ||
raise GeoAlgorithmExecutionException("Could not add features") | ||
|
||
# stop editing outLayer and commit any pending changes | ||
self.saveChanges(outLayer) | ||
|
||
def saveChanges(self, outLayer): | ||
if not outLayer.commitChanges(): | ||
msg = "" | ||
for aStrm in outLayer.commitErrors(): | ||
msg = msg + "\n" + aStrm | ||
outLayer.rollBack() | ||
raise GeoAlgorithmExecutionException("Commit error:\n%s" % (msg)) |