dtmedianline.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. # -*- coding: utf-8 -*-
  2. """
  3. dtdigitizemedianline
  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 Angelos Tzotsos
  11. * email : tzotsos@gmail.com
  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 range
  18. from builtins import object
  19. from qgis.PyQt import QtCore, QtGui, QtWidgets
  20. from qgis.core import *
  21. from qgis.gui import *
  22. from dtmedianlinetool import DtMedianLineTool
  23. class DtMedianLine(object):
  24. '''Digitize median line by selecting vertices on adjacent polygons'''
  25. def __init__(self, iface, toolBar):
  26. # Save reference to the QGIS interface
  27. self.iface = iface
  28. self.canvas = self.iface.mapCanvas()
  29. #self.lineLayer = None
  30. self.selected_points = 0
  31. self.side1_x = []
  32. self.side1_y = []
  33. self.side2_x = []
  34. self.side2_y = []
  35. self.point_list = []
  36. #create action
  37. self.median_digitizer = QtWidgets.QAction(QtGui.QIcon(":/medianLine.png"),
  38. QtCore.QCoreApplication.translate("digitizingtools",
  39. "Digitize median line between adjacent polygons"),
  40. self.iface.mainWindow())
  41. self.median_digitizer.triggered.connect(self.run)
  42. self.iface.currentLayerChanged.connect(self.enable)
  43. toolBar.addAction(self.median_digitizer)
  44. self.enable()
  45. self.tool = DtMedianLineTool(self)
  46. self.tool.finishedDigitizing.connect(self.digitizingFinished)
  47. def reset(self):
  48. self.selected_points = 0
  49. del self.side1_x[:]
  50. del self.side1_y[:]
  51. del self.side2_x[:]
  52. del self.side2_y[:]
  53. del self.point_list[:]
  54. def enableTool(self):
  55. self.tool.activate()
  56. self.canvas.setMapTool(self.tool)
  57. #Connect to the DtSelectVertexTool
  58. self.tool.vertexFound.connect(self.storePoints)
  59. def disableTool(self):
  60. self.reset()
  61. #self.tool.deactivate()
  62. self.canvas.unsetMapTool(self.tool)
  63. self.tool.vertexFound.disconnect(self.storePoints)
  64. self.tool.deactivate()
  65. def deactivate(self):
  66. self.disableTool()
  67. self.median_digitizer.setChecked(False)
  68. def run(self):
  69. '''Function that does all the real work'''
  70. self.reset()
  71. layer = self.iface.activeLayer()
  72. title = QtCore.QCoreApplication.translate("digitizingtools",
  73. "Digitize median line")
  74. if layer.selectedFeatureCount() == 0:
  75. self.enableTool()
  76. #self.lineLayer = layer
  77. self.median_digitizer.setChecked(True)
  78. else:
  79. QtWidgets.QMessageBox.information(None, title,
  80. QtCore.QCoreApplication.translate("digitizingtools",
  81. "Please clear selection."))
  82. def storePoints(self, result):
  83. tmp_x = result[0].x()
  84. tmp_y = result[0].y()
  85. modulo = self.selected_points % 2
  86. if (modulo == 0): # Select first vertex
  87. if ((tmp_x in self.side1_x) and (tmp_y in self.side1_y)):
  88. #print "Point (%f,%f) already in list1" % (tmp_x, tmp_y)
  89. self.selected_points = self.selected_points + 1
  90. return
  91. else:
  92. #print "Point (%f,%f) added in list1" % (tmp_x, tmp_y)
  93. self.side1_x.append(tmp_x)
  94. self.side1_y.append(tmp_y)
  95. self.selected_points = self.selected_points + 1
  96. return
  97. else: # Select second vertex
  98. if ((tmp_x in self.side2_x) and (tmp_y in self.side2_y)):
  99. #print "Point (%f,%f) already in list2" % (tmp_x, tmp_y)
  100. self.selected_points = self.selected_points + 1
  101. return
  102. else:
  103. #print "Point (%f,%f) added in list2" % (tmp_x, tmp_y)
  104. self.side2_x.append(tmp_x)
  105. self.side2_y.append(tmp_y)
  106. self.selected_points = self.selected_points + 1
  107. return
  108. def digitizingFinished(self):
  109. #print "side1_x"
  110. #print self.side1_x
  111. #print "side1_y"
  112. #print self.side1_y
  113. #print "side2_x"
  114. #print self.side2_x
  115. #print "side2_y"
  116. #print self.side2_y
  117. (x, y) = median_polyline(self.side1_x, self.side1_y, self.side2_x,
  118. self.side2_y)
  119. #print "x"
  120. #print x
  121. #print "y"
  122. #print y
  123. for i in range(len(x)):
  124. p = QgsPoint(x[i], y[i])
  125. #print "current p is:"
  126. #print p
  127. self.point_list.append(p)
  128. # Debug
  129. #print "Point list:"
  130. #print self.point_list
  131. new_geom = QgsGeometry.fromPolyline(self.point_list)
  132. addGeometryToCadLayer(new_geom)
  133. self.canvas.refresh()
  134. self.reset()
  135. self.deactivate()
  136. def enable(self):
  137. '''Enables/disables the corresponding button.'''
  138. # Disable the Button by default
  139. self.reset()
  140. self.median_digitizer.setEnabled(False)
  141. layer = self.iface.activeLayer()
  142. if layer is not None:
  143. #Only for vector layers.
  144. if layer.type() == QgsMapLayer.VectorLayer:
  145. # only for polygon layers
  146. if layer.geometryType() == 2:
  147. # enable if editable
  148. self.median_digitizer.setEnabled(layer.isEditable())
  149. try:
  150. layer.editingStarted.disconnect(self.enable)
  151. # disconnect, will be reconnected
  152. except:
  153. pass
  154. try:
  155. layer.editingStopped.disconnect(self.enable)
  156. # when it becomes active layer again
  157. except:
  158. pass
  159. layer.editingStarted.connect(self.enable)
  160. layer.editingStopped.connect(self.enable)
  161. def getCadLayerByName(cadname):
  162. for anId, layer in QgsProject.instance().mapLayers().items():
  163. if layer.name() == cadname:
  164. if layer.isValid():
  165. return layer
  166. else:
  167. return None
  168. def addGeometryToCadLayer(g):
  169. pointName = "CadLayer Points"
  170. lineName = "CadLayer Lines"
  171. polygonName = "CadLayer Polygons"
  172. geom_type = g.type()
  173. # Points
  174. if geom_type == 0:
  175. theName = pointName
  176. theType = "Point"
  177. elif geom_type == 1:
  178. theName = lineName
  179. theType = "LineString"
  180. elif geom_type == 2:
  181. theName = polygonName
  182. theType = "Polygon"
  183. else:
  184. return
  185. if getCadLayerByName(theName) is None:
  186. vl = QgsVectorLayer(theType, theName, "memory")
  187. pr = vl.dataProvider()
  188. feat = QgsFeature()
  189. feat.setGeometry(g)
  190. pr.addFeatures([feat])
  191. vl.updateExtents()
  192. QgsProject.instance().addMapLayer(vl)
  193. else:
  194. layer = getCadLayerByName(theName)
  195. pr = layer.dataProvider()
  196. feat = QgsFeature()
  197. feat.setGeometry(g)
  198. pr.addFeatures([feat])
  199. layer.updateExtents()
  200. def median_polyline(xa, ya, xb, yb):
  201. """
  202. This function returns the median polyline of two polylines
  203. """
  204. def S(x1, y1, x2, y2):
  205. return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
  206. x = []
  207. y = []
  208. m = len(xa)
  209. if m != len(ya):
  210. return [], []
  211. n = len(xb)
  212. if n != len(yb):
  213. return [], []
  214. i = j = k = 0
  215. while (i < m - 1 and j < n - 1):
  216. x.append((xa[i] + xb[j]) / 2.0)
  217. y.append((ya[i] + yb[j]) / 2.0)
  218. k += 1
  219. if S(xa[i + 1], ya[i + 1], xb[j], yb[j]) < S(xa[i], ya[i], xb[j + 1],
  220. yb[j + 1]):
  221. i += 1
  222. else:
  223. j += 1
  224. if i < m - 1:
  225. j -= 1
  226. while i < m:
  227. i += 1
  228. if i >= m:
  229. break
  230. x.append((xa[i] + xb[j]) / 2.0)
  231. y.append((ya[i] + yb[j]) / 2.0)
  232. k += 1
  233. if j < n - 1:
  234. i -= 1
  235. while j < n:
  236. j += 1
  237. if j >= n:
  238. break
  239. x.append((xa[i] + xb[j]) / 2.0)
  240. y.append((ya[i] + yb[j]) / 2.0)
  241. k += 1
  242. x.append((xa[m - 1] + xb[n - 1]) / 2.0)
  243. y.append((ya[m - 1] + yb[n - 1]) / 2.0)
  244. return x, y