dtcutter.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # -*- coding: utf-8 -*-
  2. """
  3. dtcutter
  4. `````````````
  5. """
  6. """
  7. Part of DigitizingTools, a QGIS plugin that
  8. subsumes different tools neded during digitizing sessions
  9. * begin : 2013-02-25
  10. * copyright : (C) 2013 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 qgis.PyQt import QtCore, QtGui, QtWidgets
  18. from qgis.core import *
  19. import dt_icons_rc
  20. import dtutils
  21. from dttools import DtDualToolSelectPolygon
  22. class DtCutWithPolygon(DtDualToolSelectPolygon):
  23. '''Cut out from active editable layer with selected polygon from another layer'''
  24. def __init__(self, iface, toolBar):
  25. super().__init__(iface, toolBar,
  26. QtGui.QIcon(":/cutter.png"),
  27. QtCore.QCoreApplication.translate("digitizingtools", "Cut with polygon (interactive)"),
  28. QtGui.QIcon(":/cutter_batch.png"),
  29. QtCore.QCoreApplication.translate("digitizingtools", "Cut with selected polygons"),
  30. geometryTypes = [3, 6], dtName = "dtCutter")
  31. self.enable()
  32. self.lastChoice = [None, False]
  33. def process(self):
  34. '''Function that does all the real work'''
  35. title = QtCore.QCoreApplication.translate("digitizingtools", "Cutter")
  36. showEmptyWarning = True
  37. choice = None
  38. fidsToDelete = []
  39. processLayer = self.iface.activeLayer()
  40. if processLayer.selectedFeatureCount() == 0:
  41. msgLst = dtutils.dtGetNoSelMessage()
  42. noSelMsg1 = msgLst[0]
  43. noSelMsg2 = msgLst[1]
  44. else:
  45. cutterGeoms = []
  46. for feat in processLayer.selectedFeatures():
  47. cutterGeom = feat.geometry()
  48. if not cutterGeom.isGeosValid():
  49. thisWarning = dtutils.dtGetInvalidGeomWarning(processLayer)
  50. dtutils.dtShowWarning(self.iface, thisWarning)
  51. continue
  52. else:
  53. cutterGeoms.append(cutterGeom)
  54. if len(cutterGeoms) == 0:
  55. return None # could be only invalid geoms selected
  56. processLayer.invertSelection()
  57. idsToProcess = []
  58. for aFeat in processLayer.selectedFeatures():
  59. # was: if isSameLayer:
  60. # for aFeat in processLayer.getFeatures()
  61. idsToProcess.append(aFeat.id())
  62. processLayer.beginEditCommand(QtCore.QCoreApplication.translate("editcommand", "Cut Features"))
  63. featuresBeingCut = 0
  64. noMatchWarning = dtutils.dtGetNotMatchingGeomWarning(processLayer)
  65. for cutterGeom in cutterGeoms:
  66. if cutterGeom.wkbType() == 6:
  67. cutterGeom = QgsGeometry.fromMultiPolygonXY(cutterGeom.asMultiPolygon())
  68. else:
  69. cutterGeom = QgsGeometry.fromPolygonXY(cutterGeom.asPolygon())
  70. bbox = cutterGeom.boundingBox()
  71. processLayer.selectByRect(bbox) # make a new selection
  72. for selFeat in processLayer.selectedFeatures():
  73. if idsToProcess.count(selFeat.id()) == 0:
  74. continue
  75. selGeom = selFeat.geometry()
  76. if selGeom.isGeosEqual(cutterGeom):
  77. continue # do not cut the same geometry
  78. if not selGeom.isGeosValid():
  79. thisWarning = dtutils.dtGetInvalidGeomWarning(processLayer)
  80. dtutils.dtShowWarning(self.iface, thisWarning)
  81. continue
  82. if cutterGeom.intersects(selGeom): # we have a candidate
  83. newGeom = selGeom.difference(cutterGeom)
  84. if newGeom != None:
  85. if newGeom.isEmpty() or newGeom.area() == 0:
  86. #selGeom is completely contained in cutterGeom
  87. if showEmptyWarning:
  88. choice = QtWidgets.QMessageBox.question(None, title,
  89. QtCore.QCoreApplication.translate("digitizingtools",
  90. "A feature would be completely removed by cutting. Delete this feature\'s dataset altogether?"),
  91. QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.YesToAll |
  92. QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.NoToAll |
  93. QtWidgets.QMessageBox.Cancel)
  94. if choice == QtWidgets.QMessageBox.Cancel:
  95. processLayer.destroyEditCommand()
  96. processLayer.removeSelection()
  97. return None
  98. else:
  99. showEmptyWarning = (choice == QtWidgets.QMessageBox.Yes or choice == QtWidgets.QMessageBox.No)
  100. if choice == QtWidgets.QMessageBox.Yes or choice == QtWidgets.QMessageBox.YesToAll:
  101. fidsToDelete.append(selFeat.id())
  102. else:
  103. if not self.geometryTypeMatchesLayer(processLayer, newGeom):
  104. newMsg = QtCore.QCoreApplication.translate(
  105. "digitizingtools", "New geometry")
  106. dtutils.dtShowWarning(self.iface, newMsg + ": " + noMatchWarning)
  107. selFeat.setGeometry(newGeom)
  108. processLayer.updateFeature(selFeat)
  109. featuresBeingCut += 1
  110. if len(fidsToDelete) > 0:
  111. for fid in fidsToDelete:
  112. if not processLayer.deleteFeature(fid):
  113. processLayer.destroyEditCommand()
  114. return None
  115. if featuresBeingCut > 0 or len(fidsToDelete) > 0:
  116. processLayer.endEditCommand()
  117. else: # nothing happened
  118. processLayer.destroyEditCommand()
  119. processLayer.removeSelection()
  120. self.iface.mapCanvas().refresh()