dtsplitfeature.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. # -*- coding: utf-8 -*-
  2. """
  3. dtsplitfeature
  4. `````````````
  5. """
  6. """
  7. Part of DigitizingTools, a QGIS plugin that
  8. subsumes different tools neded during digitizing sessions
  9. * begin : 2017-06-12
  10. * copyright : (C) 2017 by Bernhard Ströbl
  11. * email : bernhard.stroebl@jena.de
  12. This program is free software; you can redistribute it and/or modify
  13. it under the terms of the GNU General Public License as published by
  14. the Free Software Foundation; either version 2 of the License, or
  15. (at your option) any later version.
  16. """
  17. from builtins import str
  18. from builtins import range
  19. from qgis.PyQt import QtCore, QtGui, QtWidgets
  20. from qgis.core import *
  21. from qgis.gui import *
  22. import dt_icons_rc
  23. from dttools import DtSingleEditTool, DtSplitFeatureTool
  24. import dtutils
  25. class DtSplitFeature(DtSingleEditTool):
  26. '''Split feature'''
  27. def __init__(self, iface, toolBar):
  28. super().__init__(iface, toolBar,
  29. QtGui.QIcon(":/splitfeature.png"),
  30. QtCore.QCoreApplication.translate("digitizingtools", "Split Features"),
  31. geometryTypes = [2, 3, 5, 6], crsWarning = False, dtName = "dtSplitFeature")
  32. self.tool = DtSplitFeatureTool(self.iface)
  33. self.tool.finishedDigitizing.connect(self.digitizingFinished)
  34. self.reset()
  35. self.enable()
  36. def reset(self):
  37. self.editLayer = None
  38. self.feature = None
  39. self.rubberBand = None
  40. def digitizingFinished(self, splitGeom):
  41. title = QtCore.QCoreApplication.translate("digitizingtools", "Split Features")
  42. hlColor, hlFillColor, hlBuffer, hlMinWidth = dtutils.dtGetHighlightSettings()
  43. selIds = self.editLayer.selectedFeatureIds()
  44. self.editLayer.removeSelection()
  45. if self.editLayer.crs().srsid() != QgsProject.instance().crs().srsid():
  46. splitGeom.transform(QgsCoordinateTransform(
  47. QgsProject.instance().crs(), self.editLayer.crs(),
  48. QgsProject.instance()
  49. ))
  50. splitterPList = dtutils.dtExtractPoints(splitGeom)
  51. featuresToAdd = [] # store new features in this array
  52. featuresToKeep = {} # store geoms that will stay with their id as key
  53. featuresToSplit = {}
  54. topoEditEnabled = QgsProject.instance().topologicalEditing()
  55. topoTestPointsAll = [] # store all topoTestPoints for all parts
  56. for aFeat in self.editLayer.getFeatures(QgsFeatureRequest(splitGeom.boundingBox())):
  57. anId = aFeat.id()
  58. # work either on selected or all features if no selection exists
  59. if len(selIds) == 0 or selIds.count(anId) != 0:
  60. aGeom = aFeat.geometry()
  61. if splitGeom.intersects(aGeom):
  62. featuresToSplit[anId] = aFeat
  63. if len(featuresToSplit) > 0:
  64. self.editLayer.beginEditCommand(QtCore.QCoreApplication.translate("editcommand", "Features split"))
  65. for anId, aFeat in list(featuresToSplit.items()):
  66. aGeom = aFeat.geometry()
  67. wasMultipart = aGeom.isMultipart() and len(aGeom.asGeometryCollection()) > 1
  68. splitResult = []
  69. geomsToSplit = []
  70. if wasMultipart:
  71. keepGeom = None
  72. for aPart in aGeom.asGeometryCollection():
  73. if splitGeom.intersects(aPart):
  74. geomsToSplit.append(aPart)
  75. else:
  76. if keepGeom == None:
  77. keepGeom = aPart
  78. else:
  79. keepGeom = keepGeom.combine(aPart)
  80. else:
  81. geomsToSplit.append(aGeom)
  82. for thisGeom in geomsToSplit:
  83. try:
  84. result, newGeometries, topoTestPoints = thisGeom.splitGeometry(splitterPList, topoEditEnabled)
  85. except:
  86. self.iface.messageBar().pushCritical(title,
  87. dtutils.dtGetErrorMessage() + QtCore.QCoreApplication.translate(
  88. "digitizingtools", "splitting of feature") + " " + str(aFeat.id()))
  89. return None
  90. topoTestPointsAll.append(topoTestPoints)
  91. if result == 0: # success
  92. if len(newGeometries) > 0:
  93. splitResult = newGeometries
  94. if wasMultipart:
  95. splitResult.append(thisGeom)
  96. if wasMultipart and len(splitResult) > 1:
  97. takeThisOne = -1
  98. while takeThisOne == -1:
  99. for i in range(len(splitResult)):
  100. aNewGeom = splitResult[i]
  101. hl = QgsHighlight(self.iface.mapCanvas(), aNewGeom, self.editLayer)
  102. hl.setColor(hlColor)
  103. hl.setFillColor(hlFillColor)
  104. hl.setBuffer(hlBuffer)
  105. hl.setWidth(hlMinWidth)
  106. hl.show()
  107. answer = QtWidgets.QMessageBox.question(
  108. None, QtCore.QCoreApplication.translate("digitizingtools", "Split Multipart Feature"),
  109. QtCore.QCoreApplication.translate("digitizingtools", "Create new feature from this part?"),
  110. QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel | QtWidgets.QMessageBox.NoToAll)
  111. hl.hide()
  112. hl = None
  113. if answer == QtWidgets.QMessageBox.Yes:
  114. takeThisOne = i
  115. break
  116. elif answer == QtWidgets.QMessageBox.NoToAll:
  117. keepGeom = aGeom
  118. newGeoms = []
  119. takeThisOne = -2
  120. break
  121. elif answer == QtWidgets.QMessageBox.Cancel:
  122. self.editLayer.destroyEditCommand()
  123. return None
  124. if takeThisOne == -2:
  125. break
  126. elif takeThisOne >= 0:
  127. newGeoms = [splitResult.pop(takeThisOne)]
  128. if len(splitResult) > 0: #should be
  129. for aNewGeom in splitResult:
  130. if keepGeom == None:
  131. keepGeom = aNewGeom
  132. else:
  133. keepGeom = keepGeom.combine(aNewGeom)
  134. else: # singlePart
  135. keepGeom = thisGeom
  136. newGeoms = newGeometries
  137. newFeatures = dtutils.dtMakeFeaturesFromGeometries(self.editLayer, aFeat, newGeoms)
  138. featuresToAdd = featuresToAdd + newFeatures
  139. aFeat.setGeometry(keepGeom)
  140. featuresToKeep[anId] = aFeat
  141. for anId, aFeat in list(featuresToKeep.items()):
  142. aGeom = aFeat.geometry()
  143. self.editLayer.updateFeature(aFeat)
  144. if len(featuresToAdd) > 0:
  145. if self.editLayer.addFeatures(featuresToAdd):
  146. for topoTestPoint in topoTestPointsAll:
  147. for pt in topoTestPoint:
  148. self.editLayer.addTopologicalPoints(pt)
  149. self.editLayer.endEditCommand()
  150. else:
  151. self.editLayer.destroyEditCommand()
  152. else:
  153. self.editLayer.destroyEditCommand()
  154. if hasattr(self.editLayer, "selectByIds"): # since QGIS 2.16
  155. self.editLayer.selectByIds(selIds)
  156. else:
  157. self.editLayer.setSelectedFeatures(selIds)
  158. def process(self):
  159. self.canvas.setMapTool(self.tool)
  160. self.act.setChecked(True)
  161. self.editLayer = self.iface.activeLayer()