| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- # -*- coding: utf-8 -*-
- """
- dtutils
- ---------
- Contains various utitlity functions
- some code from fTools plugin contained.
- """
- """
- Part of DigitizingTools, a QGIS plugin that
- subsumes different tools neded during digitizing sessions.
- * begin : 2013-02-25
- * copyright : (C) 2013 by Bernhard Ströbl
- * email : bernhard.stroebl@jena.de
- license
- ````````
- 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 builtins import range
- from builtins import str
- from qgis.PyQt import QtCore, QtGui, QtWidgets
- from qgis.core import *
- from qgis.gui import *
- def debug(msg):
- QtWidgets.QMessageBox.information(None, "debug", str(msg))
- def dtGetFeatureForId(layer, fid):
- '''Function that returns the QgsFeature with FeatureId *fid* in QgsVectorLayer *layer*'''
- feat = QgsFeature()
- if layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)).nextFeature(feat):
- return feat
- else:
- return None
- def dtCopyFeature(layer, srcFeature = None, srcFid = None):
- '''Copy the QgsFeature with FeatureId *srcFid* in *layer* and return it. Alternatively the
- source Feature can be given as paramter. The feature is not added to the layer!'''
- if srcFid != None:
- srcFeature = dtGetFeatureForId(layer, srcFid)
- if srcFeature:
- #get layer type
- layerType = layer.geometryType()
- if layerType == 0:
- dummyGeomTxt = 'Point()'
- elif layerType == 1:
- dummyGeomTxt = 'LineString()'
- elif layerType == 2:
- dummyGeomTxt = 'Polygon()'
- #set dummy geom
- dummyGeom = QgsGeometry.fromWkt(dummyGeomTxt)
- #copy the attribute values
- attributes = {i: v for i, v in enumerate(srcFeature.attributes())}
- newFeature = QgsVectorLayerUtils.createFeature(layer, dummyGeom, attributes)
- return newFeature
- else:
- return None
- def dtMakeFeaturesFromGeometries(layer, srcFeat, geometries):
- '''create new features from geometries and copy attributes from srcFeat'''
- newFeatures = []
- for aGeom in geometries:
- newFeat = dtCopyFeature(layer, srcFeat)
- newFeat.setGeometry(aGeom)
- newFeatures.append(newFeat)
- return newFeatures
- def dtGetVectorLayersByType(iface, geomType = None, skipActive = False):
- '''Returns a dict of layers [name: id] in the project for the given
- *geomType*; geomTypes are 0: point, 1: line, 2: polygon
- If *skipActive* is True the active Layer is not included.'''
- layerList = {}
- for anId, aLayer in QgsProject.instance().mapLayers().items():
- if 0 == aLayer.type(): # vectorLayer
- if skipActive and (iface.mapCanvas().currentLayer().id() == anId):
- continue
- else:
- if geomType:
- if isinstance(geomType, int):
- if aLayer.geometryType() == geomType:
- layerList[aLayer.name()] = [anId, aLayer]
- else:
- layerList[aLayer.name()] = [anId, aLayer]
- return layerList
- def dtChooseVectorLayer(iface, geomType = None, skipActive = True, msg = None):
- '''Offers a QInputDialog where the user can choose a Layer of type *geomType*.
- If *skipActive* is True the active Layer can not be chosen. *msg* is displayed as the dialog's message.'''
- layerList = dtGetVectorLayersByType(iface, geomType, skipActive)
- chooseFrom = []
- retValue = None
- if len(layerList) > 0:
- for aName in layerList:
- chooseFrom.append(aName)
- if not msg:
- msg = ""
- selectedLayer, ok = QtWidgets.QInputDialog.getItem(None,
- QtWidgets.QApplication.translate("dtutils", "Choose Layer"),
- msg, chooseFrom, editable = False)
- if ok:
- retValue = layerList[selectedLayer][1]
- return retValue
- def dtGetNoSelMessage():
- '''Returns an array of QStrings (default messages)'''
- noSelMsg1 = QtCore.QCoreApplication.translate("digitizingtools", "No Selection in layer")
- noSelMsg2 = QtCore.QCoreApplication.translate("digitizingtools", "Use all features for process?")
- return [noSelMsg1, noSelMsg2]
- def dtGetManySelMessage(layer):
- '''Returns an array of QStrings (default messages)'''
- manySelMsg = QtCore.QCoreApplication.translate("digitizingtools", "There are ")
- manySelMsg += str(layer.selectedFeatureCount())
- manySelMsg += QtCore.QCoreApplication.translate("digitizingtools", " features selected in layer " )
- manySelMsg += layer.name() + "."
- return manySelMsg
- def dtGetInvalidGeomWarning(layer):
- invalidGeomMsg = QtCore.QCoreApplication.translate("digitizingtools", "There are invalid geometries in layer ")
- invalidGeomMsg += layer.name()
- return invalidGeomMsg
- def dtGetNotMatchingGeomWarning(layer):
- notMatchingGeomMsg = QtCore.QCoreApplication.translate(
- "digitizingtools", "Geometry's type is not compatible with the following layer: ")
- notMatchingGeomMsg += layer.name() + ". "
- notMatchingGeomMsg += QtCore.QCoreApplication.translate(
- "digitizingtools", "Fix geometries before commiting changes.")
- return notMatchingGeomMsg
- def showSnapSettingsWarning(iface):
- title = QtCore.QCoreApplication.translate("digitizingtools", "Snap Tolerance")
- msg1 = QtCore.QCoreApplication.translate(
- "digitizingtools", "Could not snap vertex")
- msg2 = QtCore.QCoreApplication.translate("digitizingtools",
- "Have you set the tolerance in Settings > Snapping Options?")
- dtShowWarning(iface, msg1 + " " + msg2, title)
- def dtShowWarning(iface, msg, title = None):
- iface.messageBar().pushWarning(title, msg)
- def dtGetErrorMessage():
- '''Returns the default error message which can be appended'''
- return QtCore.QCoreApplication.translate("digitizingtools", "Error occured during")
- # code taken from fTools plugin
- def dtExtractPoints( geom ):
- '''Generate list of QgsPoints from QgsGeometry *geom* ( can be point, line, or polygon )'''
- multi_geom = QgsGeometry()
- temp_geom = []
- if geom.type() == 0: # it's a point
- if geom.isMultipart():
- temp_geom = geom.asMultiPoint()
- else:
- temp_geom.append(geom.asPoint())
- if geom.type() == 1: # it's a line
- if geom.isMultipart():
- multi_geom = geom.asMultiPolyline() #multi_geog is a multiline
- for i in multi_geom: #i is a line
- temp_geom.extend( i )
- else:
- temp_geom = geom.asPolyline()
- elif geom.type() == 2: # it's a polygon
- if geom.isMultipart():
- multi_geom = geom.asMultiPolygon() #multi_geom is a multipolygon
- for i in multi_geom: #i is a polygon
- for j in i: #j is a line
- temp_geom.extend( j )
- else:
- multi_geom = geom.asPolygon() #multi_geom is a polygon
- for i in multi_geom: #i is a line
- temp_geom.extend( i )
- return temp_geom
- # code adopted from ringer plugin
- def dtExtractRings(geom):
- '''Generate a list of QgsPolygons representing all rings within *geom* (= polygon)'''
- rings = []
- if geom.type() == 2: # it's a polygon
- if geom.isMultipart():
- multi_geom = geom.asMultiPolygon() #multi_geom is a multipolygon
- for poly in multi_geom:
- if len(poly) > 1:
- for aRing in poly[1:]:
- rings.append(QgsGeometry.fromPolygonXY([aRing]))
- else:
- poly = geom.asPolygon()
- if len(poly) > 1:
- for aRing in poly[1:]:
- rings.append(QgsGeometry.fromPolygonXY([aRing]))
- return rings
- def dtCombineSelectedPolygons(layer, iface, multiGeom = None, fillRings = True):
- '''
- make one polygon from selected polygons in layer, optionally fill
- all rings contained in the input polygons
- '''
- for aFeat in layer.selectedFeatures():
- aGeom = QgsGeometry(aFeat.geometry())
- if not aGeom.isGeosValid():
- thisWarning = dtGetInvalidGeomWarning(layer)
- dtShowWarning(iface, thisWarning)
- return None
- # fill rings contained in the polygon
- if aGeom.isMultipart():
- tempGeom = None
- for poly in aGeom.asMultiPolygon():
- if fillRings:
- noRingGeom = dtDeleteRings(poly)
- else:
- noRingGeom = poly
- if tempGeom == None:
- tempGeom = noRingGeom
- else:
- tempGeom = tempGeom.combine(noRingGeom)
- else:
- if fillRings:
- tempGeom = dtDeleteRings(aGeom.asPolygon())
- else:
- tempGeom = aGeom
- # make a large polygon from all selected
- if multiGeom == None:
- multiGeom = tempGeom
- else:
- multiGeom = multiGeom.combine(tempGeom)
- return multiGeom
- def dtSpatialindex(layer):
- """Creates a spatial index for the passed vector layer.
- """
- idx = QgsSpatialIndex()
- for ft in layer.getFeatures():
- idx.addFeature(ft)
- return idx
- def dtDeleteRings(poly):
- outGeom = QgsGeometry.fromPolygonXY(poly)
- if len(poly) > 1:
- # we have rings
- rings = dtExtractRings(outGeom)
- for aRing in rings:
- outGeom = outGeom.combine(aRing)
- return outGeom
- def dtGetDefaultAttributeMap(layer):
- attributeMap = {}
- dp = layer.dataProvider()
- for i in range(len(layer.fields())):
- attributeMap[i] = dp.defaultValue(i)
- return attributeMap
- def dtGetHighlightSettings():
- '''highlight a geom in a layer with highlight color from settings'''
- s = QtCore.QSettings()
- s.beginGroup("Map/highlight")
- buffer = s.value("buffer", "0.5")
- hexColor = s.value("color", "#ff0000")
- colorAlpha = s.value("colorAlpha", "128")
- minWidth = s.value("minWidth", "1")
- s.endGroup()
- color = QtGui.QColor()
- color.setNamedColor(hexColor)
- fillColor = QtGui.QColor()
- r, g, b, a = color.getRgb()
- fillColor.setRgb(r, g, b, int(colorAlpha))
- return [color, fillColor, float(buffer), float(minWidth)]
|