From 61bab9c1c5b45fe4de97de8016f5fe46ea0b7c90 Mon Sep 17 00:00:00 2001 From: AG Date: Wed, 18 Apr 2018 10:25:28 +0100 Subject: [PATCH] move to QGIS 3.0 with PyQt5 --- __init__.py | 2 +- metadata.txt | 13 +-- paralleloffset.py | 144 +++++++++++++------------ paralleloffsetdialog.py | 16 +-- resources.py | 8 +- ui_paralleloffset.py | 89 +++++++-------- ui_paralleloffset.ui | 232 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 374 insertions(+), 130 deletions(-) create mode 100644 ui_paralleloffset.ui diff --git a/__init__.py b/__init__.py index 62481f3..d16af30 100644 --- a/__init__.py +++ b/__init__.py @@ -49,5 +49,5 @@ def email(): def classFactory(iface): # load ParallelOffset class from file ParallelOffset - from paralleloffset import ParallelOffset + from .paralleloffset import ParallelOffset return ParallelOffset(iface) diff --git a/metadata.txt b/metadata.txt index 2d69cfe..eec33df 100644 --- a/metadata.txt +++ b/metadata.txt @@ -10,9 +10,10 @@ [general] name=Line Offset -qgisMinimumVersion=2.0 -description=Creates a parallell line at a given distance -version=0.1 +qgisMinimumVersion=2.99 +qgisMaximumVersion=3.99 +description=Creates a parallel line of a selected polyline feature at a given distance +version=0.2 author=City and County of Swansea email=steven.gardiner@swansea.gov.uk @@ -26,9 +27,9 @@ email=steven.gardiner@swansea.gov.uk # tags are comma separated with spaces allowed tags= -homepage= -tracker= -repository= +homepage=https://github.com/stevengardiner/ParallelOffset_plugin/tree/master +tracker=https://github.com/stevengardiner/ParallelOffset_plugin/issues +repository=https://github.com/stevengardiner/ParallelOffset_plugin/tree/master icon=icon.png # experimental flag experimental=False diff --git a/paralleloffset.py b/paralleloffset.py index 8003ae0..afa1e58 100644 --- a/paralleloffset.py +++ b/paralleloffset.py @@ -20,18 +20,19 @@ ***************************************************************************/ """ # Import the PyQt and QGIS libraries -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * #Import other Libraries from qgis.core import * from shapely.geometry import LineString from qgis.utils import iface # Initialize Qt resources from file resources.py -import resources +from .resources import * # Import the code for the dialog -from paralleloffsetdialog import ParallelOffsetDialog - +from .paralleloffsetdialog import ParallelOffsetDialog +import os class ParallelOffset: @@ -39,7 +40,8 @@ def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory - self.plugin_dir = QFileInfo(QgsApplication.qgisUserDbFilePath()).path() + "/python/plugins/paralleloffset" + #self.plugin_dir = QFileInfo(QgsApplication.qgisUserDbFilePath()).path() + "/python/plugins/paralleloffset" + self.plugin_dir = os.path.realpath(__file__) # initialize locale localePath = "" locale = QSettings().value("locale/userLocale")[0:2] @@ -63,7 +65,7 @@ def initGui(self): QIcon(":/plugins/paralleloffset/icon.png"), u"Line Offset", self.iface.mainWindow()) # connect the action to the run method - QObject.connect(self.action, SIGNAL("triggered()"), self.run) + self.action.triggered.connect(self.run) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) @@ -82,66 +84,68 @@ def run(self): result = self.dlg.exec_() # See if OK was pressed if result == 1: - layers = iface.legendInterface().layers() - if len(layers) != 0: - #Check that there is a selected layer - layer = iface.mapCanvas().currentLayer() - if layer.type() == 0: - #check selected layer is a vector layer - if layer.geometryType() == 1: - #check to see if selected layer is a linestring geometry - if len(layer.selectedFeatures()) != 0: - #Dir = float(self.dlg.ui.radLeft.isChecked() - layers = iface.legendInterface().layers() - Lexists = "false" - #check to see if the virtual layer already exists - for layer in layers: - if layer.name() == "Parallel_Offset": - Lexists = "true" - vl = layer - #if it doesn't exist create it - if Lexists == "false": - vl = QgsVectorLayer("Linestring?field=offset:integer&field=direction:string(10)&field=method:string(10)","Parallel_Offset","memory") - #vl = QgsVectorLayer("Linestring", "Parallel_Offset", "memory") - pr = vl.dataProvider() - vl.startEditing() - #pr.addAttributes( [ QgsField("offset", Double), QgsField("direction", String), QgsField("method", String) ] ) - else: - pr = vl.dataProvider() - vl.startEditing() - - #get the direction - Dir = 'right' - if self.dlg.ui.radLeft.isChecked(): - Dir = 'left' - #get the method - if self.dlg.ui.radRound.isChecked(): - js = 1 - if self.dlg.ui.radMitre.isChecked(): - js = 2 - if self.dlg.ui.radBevel.isChecked(): - js = 3 - #get the offset - loffset = float(self.dlg.ui.txtDistance.text()) - - #create the new feature from the selection - - for feature in layer.selectedFeatures(): - geom = feature.geometry() - h = geom.asPolyline() - line = LineString(h) - nline = line.parallel_offset(loffset, Dir,resolution=16,join_style=js,mitre_limit=10.0) - #turn nline back into a polyline and add it to the map as a new layer. - fet = QgsFeature() - fet.setGeometry(QgsGeometry.fromWkt(str(nline))) - fet.setAttributes( [loffset,Dir ,js] ) - pr.addFeatures( [ fet ] ) - vl.commitChanges() - QgsMapLayerRegistry.instance().addMapLayer(vl) - mc=self.iface.mapCanvas() - mc.refresh() - - - # do something useful (delete the line containing pass and - # substitute with your code) - #pass + layers = iface.layerTreeCanvasBridge().rootGroup().layerOrder() + if len(layers) != 0: + #Check that there is a selected layer + layer = iface.mapCanvas().currentLayer() + if layer.type() == 0: + #check selected layer is a vector layer + if layer.geometryType() == 1: + #check to see if selected layer is a linestring geometry + if len(layer.selectedFeatures()) != 0: + #Dir = float(self.dlg.radLeft.isChecked() + layers = iface.layerTreeCanvasBridge().rootGroup().layerOrder() + Lexists = "false" + #check to see if the virtual layer already exists + for layer in layers: + if layer.name() == "Parallel_Offset": + Lexists = "true" + vl = layer + #if it doesn't exist create it + if Lexists == "false": + vl = QgsVectorLayer("Linestring?field=offset:integer&field=direction:string(10)&field=method:string(10)","Parallel_Offset","memory") + #vl = QgsVectorLayer("Linestring", "Parallel_Offset", "memory") + pr = vl.dataProvider() + vl.startEditing() + #pr.addAttributes( [ QgsField("offset", Double), QgsField("direction", String), QgsField("method", String) ] ) + else: + pr = vl.dataProvider() + vl.startEditing() + + #get the direction + Dir = 'right' + if self.dlg.radLeft.isChecked(): + Dir = 'left' + #get the method + if self.dlg.radRound.isChecked(): + js = 1 + if self.dlg.radMitre.isChecked(): + js = 2 + if self.dlg.radBevel.isChecked(): + js = 3 + #get the offset + #loffset = float(self.dlg.txtDistance.text()) + loffset = self.dlg.sbDistance.value() + + #create the new feature from the selection + + for feature in layer.selectedFeatures(): + geom = feature.geometry() + h = geom.asPolyline() + line = LineString(h) + for i in range(self.dlg.sbNumberLines.value()): + nline = line.parallel_offset(loffset*(i+1), Dir,resolution=16,join_style=js,mitre_limit=10.0) + #turn nline back into a polyline and add it to the map as a new layer. + fet = QgsFeature() + fet.setGeometry(QgsGeometry.fromWkt(str(nline))) + fet.setAttributes( [loffset,Dir ,js] ) + pr.addFeatures( [ fet ] ) + vl.commitChanges() + QgsProject.instance().addMapLayer(vl) + mc=self.iface.mapCanvas() + mc.refresh() + + + # do something useful (delete the line containing pass and + # substitute with your code) + #pass diff --git a/paralleloffsetdialog.py b/paralleloffsetdialog.py index f156e0e..77b54f0 100644 --- a/paralleloffsetdialog.py +++ b/paralleloffsetdialog.py @@ -20,14 +20,18 @@ ***************************************************************************/ """ -from PyQt4 import QtCore, QtGui -from ui_paralleloffset import Ui_ParallelOffset +import os + +from PyQt5 import uic,QtCore, QtGui,QtWidgets + +FORM_CLASS, _ = uic.loadUiType(os.path.join( + os.path.dirname(__file__), 'ui_paralleloffset.ui')) + # create the dialog for zoom to point -class ParallelOffsetDialog(QtGui.QDialog): +class ParallelOffsetDialog(QtWidgets.QDialog,FORM_CLASS): def __init__(self): - QtGui.QDialog.__init__(self) + QtWidgets.QDialog.__init__(self) # Set up the user interface from Designer. - self.ui = Ui_ParallelOffset() - self.ui.setupUi(self) + self.setupUi(self) diff --git a/resources.py b/resources.py index 555d75f..bee07fe 100644 --- a/resources.py +++ b/resources.py @@ -7,9 +7,9 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore +from PyQt5 import QtCore -qt_resource_data = "\ +qt_resource_data = b"\ \x00\x00\x06\x10\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ @@ -111,7 +111,7 @@ \xae\x5a\xa5\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ " -qt_resource_name = "\ +qt_resource_name = b"\ \x00\x07\ \x07\x3b\xe0\xb3\ \x00\x70\ @@ -126,7 +126,7 @@ \x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ " -qt_resource_struct = "\ +qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ diff --git a/ui_paralleloffset.py b/ui_paralleloffset.py index 6994aea..f5b4e1a 100644 --- a/ui_paralleloffset.py +++ b/ui_paralleloffset.py @@ -7,86 +7,89 @@ # # WARNING! All changes made in this file will be lost! -from PyQt4 import QtCore, QtGui +from PyQt5.QtCore import * +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * -try: - _fromUtf8 = QtCore.QString.fromUtf8 -except AttributeError: - def _fromUtf8(s): - return s + + +def _fromUtf8(s): + return s try: - _encoding = QtGui.QApplication.UnicodeUTF8 + _encoding = QApplication.UnicodeUTF8 def _translate(context, text, disambig): - return QtGui.QApplication.translate(context, text, disambig, _encoding) + return QApplication.translate(context, text, disambig, _encoding) except AttributeError: def _translate(context, text, disambig): - return QtGui.QApplication.translate(context, text, disambig) + return QApplication.translate(context, text, disambig) class Ui_ParallelOffset(object): def setupUi(self, ParallelOffset): ParallelOffset.setObjectName(_fromUtf8("ParallelOffset")) ParallelOffset.resize(344, 310) - self.buttonBox = QtGui.QDialogButtonBox(ParallelOffset) - self.buttonBox.setGeometry(QtCore.QRect(-20, 260, 341, 32)) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox = QDialogButtonBox(ParallelOffset) + self.buttonBox.setGeometry(QRect(-20, 260, 341, 32)) + self.buttonBox.setOrientation(Qt.Horizontal) + self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok) self.buttonBox.setObjectName(_fromUtf8("buttonBox")) - self.txtDistance = QtGui.QLineEdit(ParallelOffset) - self.txtDistance.setGeometry(QtCore.QRect(230, 20, 81, 20)) - font = QtGui.QFont() + self.txtDistance = QLineEdit(ParallelOffset) + self.txtDistance.setGeometry(QRect(230, 20, 81, 20)) + font = QFont() font.setPointSize(10) self.txtDistance.setFont(font) - self.txtDistance.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.txtDistance.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter) self.txtDistance.setObjectName(_fromUtf8("txtDistance")) - self.label = QtGui.QLabel(ParallelOffset) - self.label.setGeometry(QtCore.QRect(20, 20, 201, 16)) - font = QtGui.QFont() + self.label = QLabel(ParallelOffset) + self.label.setGeometry(QRect(20, 20, 201, 16)) + font = QFont() font.setPointSize(10) self.label.setFont(font) self.label.setObjectName(_fromUtf8("label")) - self.label_2 = QtGui.QLabel(ParallelOffset) - self.label_2.setGeometry(QtCore.QRect(20, 70, 141, 16)) - font = QtGui.QFont() + self.label_2 = QLabel(ParallelOffset) + self.label_2.setGeometry(QRect(20, 70, 141, 16)) + font = QFont() font.setPointSize(10) self.label_2.setFont(font) self.label_2.setObjectName(_fromUtf8("label_2")) - self.gbDirection = QtGui.QGroupBox(ParallelOffset) - self.gbDirection.setGeometry(QtCore.QRect(230, 70, 81, 61)) + self.gbDirection = QGroupBox(ParallelOffset) + self.gbDirection.setGeometry(QRect(230, 70, 81, 61)) self.gbDirection.setTitle(_fromUtf8("")) self.gbDirection.setObjectName(_fromUtf8("gbDirection")) - self.radLeft = QtGui.QRadioButton(self.gbDirection) - self.radLeft.setGeometry(QtCore.QRect(10, 10, 82, 18)) + self.radLeft = QRadioButton(self.gbDirection) + self.radLeft.setGeometry(QRect(10, 10, 82, 18)) self.radLeft.setChecked(True) self.radLeft.setObjectName(_fromUtf8("radLeft")) - self.radRight = QtGui.QRadioButton(self.gbDirection) - self.radRight.setGeometry(QtCore.QRect(10, 30, 82, 18)) + self.radRight = QRadioButton(self.gbDirection) + self.radRight.setGeometry(QRect(10, 30, 82, 18)) self.radRight.setObjectName(_fromUtf8("radRight")) - self.label_3 = QtGui.QLabel(ParallelOffset) - self.label_3.setGeometry(QtCore.QRect(20, 150, 171, 16)) - font = QtGui.QFont() + self.label_3 = QLabel(ParallelOffset) + self.label_3.setGeometry(QRect(20, 150, 171, 16)) + font = QFont() font.setPointSize(10) self.label_3.setFont(font) self.label_3.setObjectName(_fromUtf8("label_3")) - self.gbMethod = QtGui.QGroupBox(ParallelOffset) - self.gbMethod.setGeometry(QtCore.QRect(230, 150, 81, 81)) + self.gbMethod = QGroupBox(ParallelOffset) + self.gbMethod.setGeometry(QRect(230, 150, 81, 81)) self.gbMethod.setTitle(_fromUtf8("")) self.gbMethod.setObjectName(_fromUtf8("gbMethod")) - self.radRound = QtGui.QRadioButton(self.gbMethod) - self.radRound.setGeometry(QtCore.QRect(10, 10, 82, 18)) + self.radRound = QRadioButton(self.gbMethod) + self.radRound.setGeometry(QRect(10, 10, 82, 18)) self.radRound.setChecked(True) self.radRound.setObjectName(_fromUtf8("radRound")) - self.radMitre = QtGui.QRadioButton(self.gbMethod) - self.radMitre.setGeometry(QtCore.QRect(10, 30, 82, 18)) + self.radMitre = QRadioButton(self.gbMethod) + self.radMitre.setGeometry(QRect(10, 30, 82, 18)) self.radMitre.setObjectName(_fromUtf8("radMitre")) - self.radBevel = QtGui.QRadioButton(self.gbMethod) - self.radBevel.setGeometry(QtCore.QRect(10, 50, 82, 18)) + self.radBevel = QRadioButton(self.gbMethod) + self.radBevel.setGeometry(QRect(10, 50, 82, 18)) self.radBevel.setObjectName(_fromUtf8("radBevel")) self.retranslateUi(ParallelOffset) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), ParallelOffset.accept) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), ParallelOffset.reject) - QtCore.QMetaObject.connectSlotsByName(ParallelOffset) + self.buttonBox.accepted.connect(ParallelOffset.accept) + self.buttonBox.rejected.connect(ParallelOffset.accept) + #QObject.connect(self.buttonBox, SIGNAL(_fromUtf8("accepted()")), ParallelOffset.accept) + #QObject.connect(self.buttonBox, SIGNAL(_fromUtf8("rejected()")), ParallelOffset.reject) + QMetaObject.connectSlotsByName(ParallelOffset) def retranslateUi(self, ParallelOffset): ParallelOffset.setWindowTitle(_translate("ParallelOffset", "ParallelOffset", None)) diff --git a/ui_paralleloffset.ui b/ui_paralleloffset.ui new file mode 100644 index 0000000..75cf9e9 --- /dev/null +++ b/ui_paralleloffset.ui @@ -0,0 +1,232 @@ + + + ParallelOffset + + + + 0 + 0 + 288 + 249 + + + + ParallelOffset + + + + + + + 10 + + + + Enter the offset distance (meters) + + + + + + + Enter the number of parallel lines + + + + + + + + 10 + + + + Enter the offset side + + + + + + + + + + + + 10 + 10 + 82 + 18 + + + + Left + + + true + + + + + + 10 + 30 + 82 + 18 + + + + Right + + + + + + + + + 10 + + + + Enter the offset line method + + + + + + + + + + + + 10 + 10 + 82 + 18 + + + + Round + + + true + + + + + + 10 + 30 + 82 + 18 + + + + Mitre + + + + + + 10 + 50 + 82 + 18 + + + + Bevel + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + 1 + + + 99999 + + + 1 + + + + + + + 99999.000000000000000 + + + 100.000000000000000 + + + + + + + + + buttonBox + accepted() + ParallelOffset + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ParallelOffset + reject() + + + 316 + 260 + + + 286 + 274 + + + + + + + 10 + + + 10 + + + true + + + true + + + true + + +