| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- # -*- coding: utf-8 -*-
- """
- dtdigitizemedianline
- ````````````````````
- """
- """
- Part of DigitizingTools, a QGIS plugin that
- subsumes different tools neded during digitizing sessions
- * begin : 2013-02-25
- * copyright : (C) 2013 by Angelos Tzotsos
- * email : tzotsos@gmail.com
- 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 object
- from qgis.PyQt import QtCore, QtGui, QtWidgets
- from qgis.core import *
- from qgis.gui import *
- from dtmedianlinetool import DtMedianLineTool
- class DtMedianLine(object):
- '''Digitize median line by selecting vertices on adjacent polygons'''
- def __init__(self, iface, toolBar):
- # Save reference to the QGIS interface
- self.iface = iface
- self.canvas = self.iface.mapCanvas()
- #self.lineLayer = None
- self.selected_points = 0
- self.side1_x = []
- self.side1_y = []
- self.side2_x = []
- self.side2_y = []
- self.point_list = []
- #create action
- self.median_digitizer = QtWidgets.QAction(QtGui.QIcon(":/medianLine.png"),
- QtCore.QCoreApplication.translate("digitizingtools",
- "Digitize median line between adjacent polygons"),
- self.iface.mainWindow())
- self.median_digitizer.triggered.connect(self.run)
- self.iface.currentLayerChanged.connect(self.enable)
- toolBar.addAction(self.median_digitizer)
- self.enable()
- self.tool = DtMedianLineTool(self)
- self.tool.finishedDigitizing.connect(self.digitizingFinished)
- def reset(self):
- self.selected_points = 0
- del self.side1_x[:]
- del self.side1_y[:]
- del self.side2_x[:]
- del self.side2_y[:]
- del self.point_list[:]
- def enableTool(self):
- self.tool.activate()
- self.canvas.setMapTool(self.tool)
- #Connect to the DtSelectVertexTool
- self.tool.vertexFound.connect(self.storePoints)
- def disableTool(self):
- self.reset()
- #self.tool.deactivate()
- self.canvas.unsetMapTool(self.tool)
- self.tool.vertexFound.disconnect(self.storePoints)
- self.tool.deactivate()
- def deactivate(self):
- self.disableTool()
- self.median_digitizer.setChecked(False)
- def run(self):
- '''Function that does all the real work'''
- self.reset()
- layer = self.iface.activeLayer()
- title = QtCore.QCoreApplication.translate("digitizingtools",
- "Digitize median line")
- if layer.selectedFeatureCount() == 0:
- self.enableTool()
- #self.lineLayer = layer
- self.median_digitizer.setChecked(True)
- else:
- QtWidgets.QMessageBox.information(None, title,
- QtCore.QCoreApplication.translate("digitizingtools",
- "Please clear selection."))
- def storePoints(self, result):
- tmp_x = result[0].x()
- tmp_y = result[0].y()
- modulo = self.selected_points % 2
- if (modulo == 0): # Select first vertex
- if ((tmp_x in self.side1_x) and (tmp_y in self.side1_y)):
- #print "Point (%f,%f) already in list1" % (tmp_x, tmp_y)
- self.selected_points = self.selected_points + 1
- return
- else:
- #print "Point (%f,%f) added in list1" % (tmp_x, tmp_y)
- self.side1_x.append(tmp_x)
- self.side1_y.append(tmp_y)
- self.selected_points = self.selected_points + 1
- return
- else: # Select second vertex
- if ((tmp_x in self.side2_x) and (tmp_y in self.side2_y)):
- #print "Point (%f,%f) already in list2" % (tmp_x, tmp_y)
- self.selected_points = self.selected_points + 1
- return
- else:
- #print "Point (%f,%f) added in list2" % (tmp_x, tmp_y)
- self.side2_x.append(tmp_x)
- self.side2_y.append(tmp_y)
- self.selected_points = self.selected_points + 1
- return
- def digitizingFinished(self):
- #print "side1_x"
- #print self.side1_x
- #print "side1_y"
- #print self.side1_y
- #print "side2_x"
- #print self.side2_x
- #print "side2_y"
- #print self.side2_y
- (x, y) = median_polyline(self.side1_x, self.side1_y, self.side2_x,
- self.side2_y)
- #print "x"
- #print x
- #print "y"
- #print y
- for i in range(len(x)):
- p = QgsPoint(x[i], y[i])
- #print "current p is:"
- #print p
- self.point_list.append(p)
- # Debug
- #print "Point list:"
- #print self.point_list
- new_geom = QgsGeometry.fromPolyline(self.point_list)
- addGeometryToCadLayer(new_geom)
- self.canvas.refresh()
- self.reset()
- self.deactivate()
- def enable(self):
- '''Enables/disables the corresponding button.'''
- # Disable the Button by default
- self.reset()
- self.median_digitizer.setEnabled(False)
- layer = self.iface.activeLayer()
- if layer is not None:
- #Only for vector layers.
- if layer.type() == QgsMapLayer.VectorLayer:
- # only for polygon layers
- if layer.geometryType() == 2:
- # enable if editable
- self.median_digitizer.setEnabled(layer.isEditable())
- try:
- layer.editingStarted.disconnect(self.enable)
- # disconnect, will be reconnected
- except:
- pass
- try:
- layer.editingStopped.disconnect(self.enable)
- # when it becomes active layer again
- except:
- pass
- layer.editingStarted.connect(self.enable)
- layer.editingStopped.connect(self.enable)
- def getCadLayerByName(cadname):
- for anId, layer in QgsProject.instance().mapLayers().items():
- if layer.name() == cadname:
- if layer.isValid():
- return layer
- else:
- return None
- def addGeometryToCadLayer(g):
- pointName = "CadLayer Points"
- lineName = "CadLayer Lines"
- polygonName = "CadLayer Polygons"
- geom_type = g.type()
- # Points
- if geom_type == 0:
- theName = pointName
- theType = "Point"
- elif geom_type == 1:
- theName = lineName
- theType = "LineString"
- elif geom_type == 2:
- theName = polygonName
- theType = "Polygon"
- else:
- return
- if getCadLayerByName(theName) is None:
- vl = QgsVectorLayer(theType, theName, "memory")
- pr = vl.dataProvider()
- feat = QgsFeature()
- feat.setGeometry(g)
- pr.addFeatures([feat])
- vl.updateExtents()
- QgsProject.instance().addMapLayer(vl)
- else:
- layer = getCadLayerByName(theName)
- pr = layer.dataProvider()
- feat = QgsFeature()
- feat.setGeometry(g)
- pr.addFeatures([feat])
- layer.updateExtents()
- def median_polyline(xa, ya, xb, yb):
- """
- This function returns the median polyline of two polylines
- """
- def S(x1, y1, x2, y2):
- return (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)
- x = []
- y = []
- m = len(xa)
- if m != len(ya):
- return [], []
- n = len(xb)
- if n != len(yb):
- return [], []
- i = j = k = 0
- while (i < m - 1 and j < n - 1):
- x.append((xa[i] + xb[j]) / 2.0)
- y.append((ya[i] + yb[j]) / 2.0)
- k += 1
- if S(xa[i + 1], ya[i + 1], xb[j], yb[j]) < S(xa[i], ya[i], xb[j + 1],
- yb[j + 1]):
- i += 1
- else:
- j += 1
- if i < m - 1:
- j -= 1
- while i < m:
- i += 1
- if i >= m:
- break
- x.append((xa[i] + xb[j]) / 2.0)
- y.append((ya[i] + yb[j]) / 2.0)
- k += 1
- if j < n - 1:
- i -= 1
- while j < n:
- j += 1
- if j >= n:
- break
- x.append((xa[i] + xb[j]) / 2.0)
- y.append((ya[i] + yb[j]) / 2.0)
- k += 1
- x.append((xa[m - 1] + xb[n - 1]) / 2.0)
- y.append((ya[m - 1] + yb[n - 1]) / 2.0)
- return x, y
|