From 63738da11512d16ae6acdfe59258d73ccfc2a7d5 Mon Sep 17 00:00:00 2001 From: jorgealmerio Date: Wed, 6 Feb 2019 12:33:06 -0300 Subject: [PATCH] Porting to Qgis 3 (#16) * port to qgis 3 * Porting to Qgis 3 rev01 * Removed unnecessary changes for porting * Rev01 after Tests --- __init__.py | 2 +- metadata.txt | 10 +++++---- vectorbender.py | 40 +++++++++++++++++------------------ vectorbenderdialog.py | 42 ++++++++++++++++++------------------- vectorbenderhelp.py | 10 +++++---- vectorbendertransformers.py | 32 ++++++++++++++-------------- 6 files changed, 70 insertions(+), 66 deletions(-) diff --git a/__init__.py b/__init__.py index 7a68e96..0b00ab9 100644 --- a/__init__.py +++ b/__init__.py @@ -22,5 +22,5 @@ """ def classFactory(iface): # load VectorBender class from file VectorBender - from vectorbender import VectorBender + from .vectorbender import VectorBender return VectorBender(iface) diff --git a/metadata.txt b/metadata.txt index 2ea81ba..1321f61 100644 --- a/metadata.txt +++ b/metadata.txt @@ -10,10 +10,11 @@ [general] name=Vector Bender -qgisMinimumVersion=2.2 +qgisMinimumVersion=2.99 +qgisMaximumVersion=3.99 description=Does to vectors what georefencers does to raster. This feature is also known as "rubber sheeting". category=Vector -version=0.1.1 +version=3.0.0 author=Olivier Dalang email=olivier.dalang@gmail.com @@ -23,8 +24,9 @@ email=olivier.dalang@gmail.com # Uncomment the following line and add your changelog entries: changelog=- 2014-05-22 - Version 0.0 : intial release -- 2014-05-26 - Version 0.1 : linear and uniform transformation method, scipy dependency no more needed, better management of pinned points -- 2014-07-17 - Version 0.1.1 : fixed bug due to misspelling + - 2014-05-26 - Version 0.1 : linear and uniform transformation method, scipy dependency no more needed, better management of pinned points + - 2014-07-17 - Version 0.1.1 : fixed bug due to misspelling + - 2019-01-18 - Version 3.0.0 : Updated to Qgis 3 (Thanks to Jorge Almerio) diff --git a/vectorbender.py b/vectorbender.py index f30b646..810ea69 100644 --- a/vectorbender.py +++ b/vectorbender.py @@ -21,8 +21,9 @@ """ # Import the PyQt and QGIS libraries -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from qgis.PyQt.QtCore import * +from qgis.PyQt.QtWidgets import * +from qgis.PyQt.QtGui import * from qgis.core import * from qgis.gui import * @@ -40,14 +41,14 @@ if StrictVersion(matplotlib.__version__) < StrictVersion(minVersion): dependenciesStatus=1 QgsMessageLog.logMessage("Matplotlib version too old (%s instead of %s). You won't be able to use the bending algorithm" % (matplotlib.__version__,minVersion), 'VectorBender') -except Exception, e: +except Exception: QgsMessageLog.logMessage("Matplotlib is missing. You won't be able to use the bending algorithm", 'VectorBender') dependenciesStatus = 0 # Other classes -from vectorbendertransformers import * -from vectorbenderdialog import VectorBenderDialog -from vectorbenderhelp import VectorBenderHelp +from .vectorbendertransformers import * +from .vectorbenderdialog import VectorBenderDialog +from .vectorbenderhelp import VectorBenderHelp class VectorBender: @@ -103,16 +104,15 @@ def determineTransformationType(self): 0 if no pairs Found 1 if one pair found => translation 2 if two pairs found => linear - 3 if two pairs found => linear - 4 if three or more pairs found => bending - 5 if bending but unmet dependencies""" + 3 if three pairs found => affine + 4 if four or more pairs found => bending""" pairsLayer = self.dlg.pairsLayer() if pairsLayer is None: return 0 - featuresCount = len(pairsLayer.selectedFeaturesIds()) if self.dlg.restrictBox_pairsLayer.isChecked() else len(pairsLayer.allFeatureIds()) + featuresCount = len(pairsLayer.selectedFeatureIds()) if self.dlg.restrictBox_pairsLayer.isChecked() else len(pairsLayer.allFeatureIds()) if featuresCount == 1: return 1 @@ -159,7 +159,7 @@ def run(self): # Starting to iterate features = toBendLayer.getFeatures() if not self.dlg.restrictBox_toBendLayer.isChecked() else toBendLayer.selectedFeatures() - count = toBendLayer.pendingFeatureCount() if not self.dlg.restrictBox_toBendLayer.isChecked() else len(features) + count = toBendLayer.featureCount() if not self.dlg.restrictBox_toBendLayer.isChecked() else len(features) self.dlg.displayMsg( "Starting to iterate through %i features..." % count ) QCoreApplication.processEvents() @@ -174,7 +174,7 @@ def run(self): #TODO : this cood be much simple if we could iterate through to vertices and use QgsGeometry.moveVertex(x,y,index), but QgsGeometry.vertexAt(index) doesn't tell wether the index exists, so there's no clean way to iterate... - if geom.type() == QGis.Point: + if geom.type() == QgsWkbTypes.PointGeometry: if not geom.isMultipart(): # SINGLE PART POINT @@ -189,7 +189,7 @@ def run(self): newListA.append( self.transformer.map(p) ) newGeom = QgsGeometry.fromMultiPoint( newListA ) - elif geom.type() == QGis.Line: + elif geom.type() == QgsWkbTypes.LineGeometry: if not geom.isMultipart(): # SINGLE PART LINESTRING @@ -197,7 +197,7 @@ def run(self): newListA = [] for p in listA: newListA.append( self.transformer.map(p) ) - newGeom = QgsGeometry.fromPolyline( newListA ) + newGeom = QgsGeometry.fromPolylineXY( newListA ) else: # MULTI PART LINESTRING @@ -208,9 +208,9 @@ def run(self): for p in listB: newListB.append( self.transformer.map(p) ) newListA.append( newListB ) - newGeom = QgsGeometry.fromMultiPolyline( newListA ) + newGeom = QgsGeometry.fromMultiPolylineXY( newListA ) - elif geom.type() == QGis.Polygon: + elif geom.type() == QgsWkbTypes.PolygonGeometry: if not geom.isMultipart(): # SINGLE PART POLYGON @@ -221,7 +221,7 @@ def run(self): for p in listB: newListB.append( self.transformer.map(p) ) newListA.append( newListB ) - newGeom = QgsGeometry.fromPolygon( newListA ) + newGeom = QgsGeometry.fromPolygonXY( newListA ) else: # MULTI PART POLYGON @@ -235,7 +235,7 @@ def run(self): newListC.append( self.transformer.map(p) ) newListB.append( newListC ) newListA.append( newListB ) - newGeom = QgsGeometry.fromMultiPolygon( newListA ) + newGeom = QgsGeometry.fromMultiPolygonXY( newListA ) else: # FALLBACK, JUST IN CASE ;) @@ -252,7 +252,7 @@ def run(self): features = pairsLayer.getFeatures() if not self.dlg.restrictBox_pairsLayer.isChecked() else pairsLayer.selectedFeatures() - count = pairsLayer.pendingFeatureCount() if not self.dlg.restrictBox_pairsLayer.isChecked() else len(features) + count = pairsLayer.featureCount() if not self.dlg.restrictBox_pairsLayer.isChecked() else len(features) self.dlg.progressBar.setValue( 0 ) self.dlg.displayMsg( "Starting to transform %i pairs to pins..." % count ) QCoreApplication.processEvents() @@ -266,7 +266,7 @@ def run(self): geom = feature.geometry().asPolyline() - newGeom = QgsGeometry.fromPolyline( [geom[-1],geom[-1]] ) + newGeom = QgsGeometry.fromPolylineXY( [geom[-1],geom[-1]] ) pairsLayer.changeGeometry( feature.id(), newGeom ) pairsLayer.endEditCommand() diff --git a/vectorbenderdialog.py b/vectorbenderdialog.py index d5c7a23..e5f92d9 100644 --- a/vectorbenderdialog.py +++ b/vectorbenderdialog.py @@ -1,20 +1,20 @@ # -*- coding: utf-8 -*- - -from PyQt4 import uic -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from qgis.PyQt import uic, QtWidgets +from qgis.PyQt.QtWidgets import QMessageBox +from qgis.PyQt.QtCore import * +from qgis.PyQt.QtGui import * from qgis.core import * from qgis.gui import * import os.path -from vectorbendertransformers import * +from .vectorbendertransformers import * -class VectorBenderDialog(QWidget): +class VectorBenderDialog(QtWidgets.QDialog): def __init__(self, iface, vb): - QWidget.__init__(self) + QtWidgets.QDialog.__init__(self) uic.loadUi(os.path.join(os.path.dirname(__file__),'ui_main.ui'), self) self.setFocusPolicy(Qt.ClickFocus) #self.setWindowModality( Qt.ApplicationModal ) @@ -58,13 +58,13 @@ def toBendLayer(self): Returns the current toBend layer depending on what is choosen in the comboBox_pairsLayer """ layerId = self.comboBox_toBendLayer.itemData(self.comboBox_toBendLayer.currentIndex()) - return QgsMapLayerRegistry.instance().mapLayer(layerId) + return QgsProject.instance().mapLayer(layerId) def pairsLayer(self): """ Returns the current pairsLayer layer depending on what is choosen in the comboBox_pairsLayer """ layerId = self.comboBox_pairsLayer.itemData(self.comboBox_pairsLayer.currentIndex()) - return QgsMapLayerRegistry.instance().mapLayer(layerId) + return QgsProject.instance().mapLayer(layerId) def bufferValue(self): """ Returns the current buffer value depending on the input in the spinbox @@ -126,10 +126,10 @@ def updateLayersComboboxes(self): self.comboBox_toBendLayer.clear() self.comboBox_pairsLayer.clear() - for layer in self.iface.legendInterface().layers(): + for layer in QgsProject.instance().mapLayers().values(): if layer.type() == QgsMapLayer.VectorLayer: self.comboBox_toBendLayer.addItem( layer.name(), layer.id() ) - if layer.geometryType() == QGis.Line : + if layer.geometryType() == QgsWkbTypes.LineGeometry : self.comboBox_pairsLayer.addItem( layer.name(), layer.id() ) if oldBendLayer is not None: @@ -190,13 +190,13 @@ def createMemoryLayer(self): suffix = "" name = "Vector Bender" - while len( QgsMapLayerRegistry.instance().mapLayersByName( name+suffix ) ) > 0: + while len( QgsProject.instance().mapLayersByName( name+suffix ) ) > 0: if suffix == "": suffix = " 1" else: suffix = " "+str(int(suffix)+1) newMemoryLayer = QgsVectorLayer("Linestring", name+suffix, "memory") newMemoryLayer.loadNamedStyle(os.path.join(os.path.dirname(__file__),'PairStyle.qml'), False) - QgsMapLayerRegistry.instance().addMapLayer(newMemoryLayer) + QgsProject.instance().addMapLayer(newMemoryLayer) self.updateLayersComboboxes() @@ -211,17 +211,17 @@ def displayMsg(self, msg, error=False): self.statusLabel.setText( msg ) def hidePreview(self): if self.rubberBands is not None: - self.rubberBands[0].reset(QGis.Polygon) - self.rubberBands[1].reset(QGis.Polygon) - self.rubberBands[2].reset(QGis.Polygon) + self.rubberBands[0].reset(QgsWkbTypes.PolygonGeometry) + self.rubberBands[1].reset(QgsWkbTypes.PolygonGeometry) + self.rubberBands[2].reset(QgsWkbTypes.PolygonGeometry) self.rubberBands = None def showPreview(self): - self.rubberBands = (QgsRubberBand(self.iface.mapCanvas(), QGis.Polygon),QgsRubberBand(self.iface.mapCanvas(), QGis.Polygon),QgsRubberBand(self.iface.mapCanvas(), QGis.Polygon)) + self.rubberBands = (QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry),QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry),QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry)) - self.rubberBands[0].reset(QGis.Polygon) - self.rubberBands[1].reset(QGis.Polygon) - self.rubberBands[2].reset(QGis.Polygon) + self.rubberBands[0].reset(QgsWkbTypes.PolygonGeometry) + self.rubberBands[1].reset(QgsWkbTypes.PolygonGeometry) + self.rubberBands[2].reset(QgsWkbTypes.PolygonGeometry) pairsLayer = self.pairsLayer() @@ -263,7 +263,7 @@ def showPreview(self): # Events def eventFilter(self,object,event): - if event.type() == QEvent.FocusIn: + if event.type() == QEvent.WindowActivate: self.refreshStates() return False diff --git a/vectorbenderhelp.py b/vectorbenderhelp.py index 9aed876..d959537 100644 --- a/vectorbenderhelp.py +++ b/vectorbenderhelp.py @@ -20,17 +20,19 @@ ***************************************************************************/ """ # Import the PyQt and QGIS libraries -from PyQt4.QtCore import * -from PyQt4.QtGui import * +from qgis.PyQt import QtWidgets +from qgis.PyQt.QtWidgets import QTextBrowser, QVBoxLayout, QPushButton +from qgis.PyQt.QtCore import * +from qgis.PyQt.QtGui import * from qgis.core import * # Basic dependencies import os.path -class VectorBenderHelp(QDialog): +class VectorBenderHelp(QtWidgets.QDialog): def __init__(self): - QDialog.__init__(self) + QtWidgets.QDialog.__init__(self) self.setMinimumWidth(600) self.setMinimumHeight(450) diff --git a/vectorbendertransformers.py b/vectorbendertransformers.py index 6aac595..1c975a2 100644 --- a/vectorbendertransformers.py +++ b/vectorbendertransformers.py @@ -5,7 +5,7 @@ try: #we silently fail the import here since message is already taken car in vectorbender.py import matplotlib.tri -except Exception, e: +except Exception: pass class Transformer(): @@ -20,8 +20,8 @@ def __init__(self, pairsLayer, restrictToSelection): for feature in features: geom = feature.geometry().asPolyline() - self.pointsA.append( QgsPoint(geom[0].x(),geom[0].y()) ) - self.pointsB.append( QgsPoint(geom[-1].x(),geom[-1].y()) ) + self.pointsA.append( QgsPointXY(geom[0].x(),geom[0].y()) ) + self.pointsB.append( QgsPointXY(geom[-1].x(),geom[-1].y()) ) def map(self, p): return p @@ -35,7 +35,7 @@ def __init__(self, pairsLayer, restrictToSelection, buff): assert len(self.pointsA)>=3 assert len(self.pointsA)==len(self.pointsB) - self.hull = QgsGeometry.fromMultiPoint( self.pointsA ).convexHull() + self.hull = QgsGeometry.fromMultiPointXY( self.pointsA ).convexHull() # If there is a buffer, we add a ring outside the hull so that the transformation smoothly stops if buff>0: @@ -56,7 +56,7 @@ def map(self, p): if triangle==-1: # No triangle found : don't change the point - return QgsPoint(p[0], p[1]) + return QgsPointXY(p[0], p[1]) else: # Triangle found : adapt it from the old mesh to the new mesh a1 = self.pointsA[self.delaunay.triangles[triangle][0]] @@ -92,7 +92,7 @@ def fromTriangularToCartesian(self, l,t1,t2,t3): """ l is a triplet for barycentric coordinates """ x = l[0]*t1.x()+l[1]*t2.x()+l[2]*t3.x() y = l[0]*t1.y()+l[1]*t2.y()+l[2]*t3.y() - return QgsPoint(x,y) + return QgsPointXY(x,y) class AffineTransformer(Transformer): def __init__(self, pairsLayer, restrictToSelection): @@ -116,8 +116,8 @@ def __init__(self, pairsLayer, restrictToSelection): [a,b,c] M = [d,e,f] - [0,0,1] - + [0,0,1] + [x11] [x12] 1] M * [y11] = [y12] [ 1 ] [ 1 ] @@ -130,7 +130,7 @@ def __init__(self, pairsLayer, restrictToSelection): 3] M * [y31] = [y32] [ 1 ] [ 1 ] - Equations to solve + Equations to solve [ a*x11+b*y11+c = x12, d*x11+e*y11+f = y12, @@ -175,8 +175,8 @@ def __init__(self, pairsLayer, restrictToSelection): def map(self, p): - return QgsPoint( self.a*p.x()+self.b*p.y()+self.c, self.d*p.x()+self.e*p.y()+self.f ) - + return QgsPointXY( self.a*p.x()+self.b*p.y()+self.c, self.d*p.x()+self.e*p.y()+self.f ) + class LinearTransformer(Transformer): def __init__(self, pairsLayer, restrictToSelection): Transformer.__init__(self, pairsLayer, restrictToSelection) @@ -204,16 +204,16 @@ def __init__(self, pairsLayer, restrictToSelection): def map(self, p): #move to origin (translation part 1) - p = QgsPoint( p.x()-self.dx1, p.y()-self.dy1 ) + p = QgsPointXY( p.x()-self.dx1, p.y()-self.dy1 ) #scale - p = QgsPoint( self.ds*p.x(), self.ds*p.y() ) + p = QgsPointXY( self.ds*p.x(), self.ds*p.y() ) #rotation - p = QgsPoint( math.cos(self.da)*p.x() - math.sin(self.da)*p.y(), math.sin(self.da)*p.x() + math.cos(self.da)*p.y() ) + p = QgsPointXY( math.cos(self.da)*p.x() - math.sin(self.da)*p.y(), math.sin(self.da)*p.x() + math.cos(self.da)*p.y() ) #remove to right spot (translation part 2) - p = QgsPoint( p.x()+self.dx2, p.y()+self.dy2 ) + p = QgsPointXY( p.x()+self.dx2, p.y()+self.dy2 ) return p @@ -229,5 +229,5 @@ def __init__(self, pairsLayer, restrictToSelection): self.dy = self.pointsB[0].y()-self.pointsA[0].y() def map(self, p): - return QgsPoint(p[0]+self.dx, p[1]+self.dy) + return QgsPointXY(p[0]+self.dx, p[1]+self.dy)