diff --git a/test/test_crosshair.py b/test/test_crosshair.py new file mode 100644 index 0000000000000000000000000000000000000000..37daec9ca25702a374d60c3b91a1184e42e54b3b --- /dev/null +++ b/test/test_crosshair.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +""" +*************************************************************************** + + --------------------- + Date : 30.11.2017 + Copyright : (C) 2017 by Benjamin Jakimow + Email : benjamin jakimow at geo dot hu-berlin dot de +*************************************************************************** +* * +* 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. * +* * +*************************************************************************** +""" +# noinspection PyPep8Naming + +from timeseriesviewer.utils import initQgisApplication +from PyQt5.QtGui import * +from PyQt5.QtCore import * +import unittest, tempfile + +from timeseriesviewer.mapcanvas import * +from timeseriesviewer.crosshair import * +from timeseriesviewer.utils import * +resourceDir = os.path.join(DIR_REPO,'qgisresources') +QGIS_APP = initQgisApplication() + +SHOW_GUI = True + +class testclassDialogTest(unittest.TestCase): + """Test rerources work.""" + + def setUp(self): + """Runs before each test.""" + pass + + def tearDown(self): + """Runs after each test.""" + pass + + def test_CrosshairWidget(self): + + ds = TestObjects.inMemoryImage() + + lyr = QgsRasterLayer(ds.GetFileList()[0]) + c = QgsMapCanvas() + store = QgsMapLayerStore() + store.addMapLayer(lyr) + c.setLayers([lyr]) + c.setDestinationCrs(lyr.crs()) + c.setExtent(lyr.extent()) + + w = CrosshairWidget() + self.assertIsInstance(w, CrosshairWidget) + self.assertIsInstance(w.mapCanvas, QgsMapCanvas) + self.assertTrue(len(w.mapCanvas.layers()), 0) + + w.copyCanvas(c) + + + + + + + if SHOW_GUI: + QGIS_APP.exec_() + + def test_CrosshairDialog(self): + + pass + + + + +if __name__ == "__main__": + SHOW_GUI = False + unittest.main() diff --git a/test/test_mapcanvas.py b/test/test_mapcanvas.py index 6690596f7524e6b49dd007f8b55c4a061998db1d..9c1475efb980add254e86fd83702674c9aeb4951 100644 --- a/test/test_mapcanvas.py +++ b/test/test_mapcanvas.py @@ -73,9 +73,6 @@ class testclassDialogTest(unittest.TestCase): self.assertTrue(lastPos == p2) - def test_CrosshairDialog(self): - - pass diff --git a/timeseriesviewer/crosshair.py b/timeseriesviewer/crosshair.py index b17eff9628dfb4e17d8e074f09e9093034657ea5..6824eaac5acd6d452e48f7d6dd0ffe25ddea9499 100644 --- a/timeseriesviewer/crosshair.py +++ b/timeseriesviewer/crosshair.py @@ -404,6 +404,25 @@ class CrosshairWidget(QWidget, loadUI('crosshairwidget.ui')): self.refreshCrosshairPreview() + def copyCanvas(self,mapCanvas:QgsMapCanvas): + """ + Copys layers,crs, extent and background color + :param mapCanvas: + :return: + """ + + assert isinstance(mapCanvas, QgsMapCanvas) + # copy layers + canvas = self.w.mapCanvasItem.canvas + lyrs = mapCanvas.layers() + canvas.setLayers(lyrs) + canvas.setDestinationCrs(mapCanvas.mapSettings().destinationCrs()) + canvas.setExtent(mapCanvas.extent()) + canvas.setCenter(mapCanvas.center()) + canvas.setCanvasColor(mapCanvas.canvasColor()) + self.w.refreshCrosshairPreview() + + def setCanvasColor(self, color): self.mapCanvas.setBackgroundColor(color) @@ -433,6 +452,7 @@ class CrosshairWidget(QWidget, loadUI('crosshairwidget.ui')): self.cbCrosshairShowDot.setChecked(style.mShowDot) self.cbShowPixelBoundaries.setChecked(style.mShowPixelBorder) self.cbShowDistanceMarker.setChecked(style.mShowDistanceMarker) + def crosshairStyle(self): style = CrosshairStyle() c = self.btnCrosshairColor.color() @@ -509,16 +529,7 @@ class CrosshairDialog(QgsDialog): :param mapCanvas: QgsMapCanvas :return: """ - assert isinstance(mapCanvas, QgsMapCanvas) - # copy layers - canvas = self.w.mapCanvasItem.canvas - lyrs = mapCanvas.layers() - canvas.setLayers(lyrs) - canvas.setDestinationCrs(mapCanvas.mapSettings().destinationCrs()) - canvas.setExtent(mapCanvas.extent()) - canvas.setCenter(mapCanvas.center()) - canvas.setCanvasColor(mapCanvas.canvasColor()) - self.w.refreshCrosshairPreview() + self.w.copyCanvas(mapCanvas) diff --git a/timeseriesviewer/utils.py b/timeseriesviewer/utils.py index 9ebc8015d8d295db4ae60cde8729e12b9e559867..8a4acde2650413596f15b69131a11091b9352e29 100644 --- a/timeseriesviewer/utils.py +++ b/timeseriesviewer/utils.py @@ -26,12 +26,10 @@ import os, sys, math, re, io, fnmatch from collections import defaultdict from qgis.core import * -from qgis.core import QgsPointXY, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsApplication, QgsRectangle, \ - QgsMapLayer, QgsRasterLayer, QgsVectorLayer, QgsRasterRenderer, QgsFeatureRenderer, QgsRasterDataProvider, QgsUnitTypes, QgsSingleBandPseudoColorRenderer #from qgis.gui import * -from qgis.gui import QgsMapCanvas, QgisInterface +from qgis.gui import * import qgis.utils from PyQt5.QtCore import * from PyQt5.QtWidgets import * @@ -1176,6 +1174,335 @@ def initQgisApplication(pythonPlugins=None, PATH_QGIS=None, qgisDebug=False, qgi return qgsApp + +class TestObjects(): + + @staticmethod + def inMemoryImage(nl=10, ns=20, nb=3, crs='EPSG:32632')->gdal.Dataset: + """ + Create an in-memory gdal.Dataset + :param nl: + :param ns: + :param nb: + :param crs: + :return: + """ + drv = gdal.GetDriverByName('GTiff') + assert isinstance(drv, gdal.Driver) + + path = '/vsimem/testimage.tif' + ds = drv.Create(path, ns, nl, bands=nb, eType=gdal.GDT_Float32) + + if isinstance(crs, str): + c = QgsCoordinateReferenceSystem(crs) + ds.SetProjection(c.toWkt()) + + gt = [1000,30,0, \ + 1000,0 ,-30] + + ds.SetGeoTransform(gt) + for b in range(1, nb + 1): + band = ds.GetRasterBand(b) + assert isinstance(band, gdal.Band) + array = np.random.random((nl, ns)) - 1 + band.WriteArray(array) + ds.FlushCache() + return ds + + + + @staticmethod + def inMemoryClassification(n=3, nl=10, ns=20, nb=1, crs='EPSG:32632'): + from .classificationscheme import ClassificationScheme + scheme = ClassificationScheme() + scheme.createClasses(n) + + drv = gdal.GetDriverByName('MEM') + assert isinstance(drv, gdal.Driver) + + + ds = drv.Create('', ns, nl, bands=nb, eType=gdal.GDT_Byte) + + if isinstance(crs, str): + c = QgsCoordinateReferenceSystem(crs) + ds.SetProjection(c.toWkt()) + + step = int(np.ceil(float(nl) / len(scheme))) + + assert isinstance(ds, gdal.Dataset) + for b in range(1, nb + 1): + band = ds.GetRasterBand(b) + array = np.zeros((nl, ns), dtype=np.uint8) - 1 + y0 = 0 + for i, c in enumerate(scheme): + y1 = min(y0 + step, nl - 1) + array[y0:y1, :] = c.label() + y0 += y1 + 1 + band.SetCategoryNames(scheme.classNames()) + band.SetColorTable(scheme.gdalColorTable()) + ds.FlushCache() + return ds + + @staticmethod + def qgisInterfaceMockup(): + + return QgisMockup() + + @staticmethod + def createDropEvent(mimeData:QMimeData): + """Creates a QDropEvent conaining the provided QMimeData""" + return QDropEvent(QPointF(0, 0), Qt.CopyAction, mimeData, Qt.LeftButton, Qt.NoModifier) + + + @staticmethod + def processingAlgorithm(): + + from qgis.core import QgsProcessingAlgorithm + + class TestProcessingAlgorithm(QgsProcessingAlgorithm): + + def __init__(self): + super(TestProcessingAlgorithm, self).__init__() + s = "" + + def createInstance(self): + return TestProcessingAlgorithm() + + def name(self): + return 'exmaplealg' + + def displayName(self): + return 'Example Algorithm' + + def groupId(self): + return 'exampleapp' + + def group(self): + return 'TEST APPS' + + def initAlgorithm(self, configuration=None): + self.addParameter(QgsProcessingParameterRasterLayer('pathInput', 'The Input Dataset')) + self.addParameter( + QgsProcessingParameterNumber('value', 'The value', QgsProcessingParameterNumber.Double, 1, False, + 0.00, 999999.99)) + self.addParameter(QgsProcessingParameterRasterDestination('pathOutput', 'The Output Dataset')) + + def processAlgorithm(self, parameters, context, feedback): + assert isinstance(parameters, dict) + assert isinstance(context, QgsProcessingContext) + assert isinstance(feedback, QgsProcessingFeedback) + + + outputs = {} + return outputs + + return TestProcessingAlgorithm() + + + + @staticmethod + def enmapBoxApplication(): + + from enmapbox.gui.applications import EnMAPBoxApplication + from enmapbox.gui.enmapboxgui import EnMAPBox + enmapbox = EnMAPBox.instance() + + class TestApp(EnMAPBoxApplication): + def __init__(self, enmapbox): + super(TestApp, self).__init__(enmapbox) + + self.name = 'TestApp' + self.licence = 'GPL-3' + self.version = '-12345' + + def menu(self, appMenu:QMenu)->QMenu: + menu = appMenu.addMenu('Test Menu') + action = menu.addAction('Test Action') + action.triggered.connect(self.onAction) + return menu + + def onAction(self): + print('TestApp action called') + + def processingAlgorithms(self): + return [TestObjects.processingAlgorithm()] + + return TestApp(enmapbox) + + + +class QgisMockup(QgisInterface): + """ + A "fake" QGIS Desktop instance that should provide all the inferfaces a plugin developer might need (and nothing more) + """ + + def pluginManagerInterface(self)->QgsPluginManagerInterface: + return self.mPluginManager + + @staticmethod + def create()->QgisInterface: + """ + Create the QgisMockup and sets the global variables + :return: QgisInterface + """ + + iface = QgisMockup() + + import qgis.utils + # import processing + # p = processing.classFactory(iface) + if not isinstance(qgis.utils.iface, QgisInterface): + + import processing + qgis.utils.iface = iface + processing.Processing.initialize() + + import pkgutil + prefix = str(processing.__name__ + '.') + for importer, modname, ispkg in pkgutil.walk_packages(processing.__path__, prefix=prefix): + try: + module = __import__(modname, fromlist="dummy") + if hasattr(module, 'iface'): + print(modname) + module.iface = iface + except: + pass + #set 'home_plugin_path', which is required from the QGIS Plugin manager + assert qgis.utils.iface == iface + qgis.utils.home_plugin_path = os.path.join(QgsApplication.instance().qgisSettingsDirPath(), *['python', 'plugins']) + return iface + + def __init__(self, *args): + # QgisInterface.__init__(self) + super(QgisMockup, self).__init__() + + self.mCanvas = QgsMapCanvas() + self.mCanvas.blockSignals(False) + self.mCanvas.setCanvasColor(Qt.black) + self.mCanvas.extentsChanged.connect(self.testSlot) + self.mLayerTreeView = QgsLayerTreeView() + self.mRootNode = QgsLayerTree() + self.mLayerTreeModel = QgsLayerTreeModel(self.mRootNode) + self.mLayerTreeView.setModel(self.mLayerTreeModel) + self.mLayerTreeMapCanvasBridge = QgsLayerTreeMapCanvasBridge(self.mRootNode, self.mCanvas) + self.mLayerTreeMapCanvasBridge.setAutoSetupOnFirstLayer(True) + + import pyplugin_installer.installer + PI = pyplugin_installer.instance() + self.mPluginManager = QgsPluginManagerMockup() + + self.ui = QMainWindow() + + + + self.mMessageBar = QgsMessageBar() + mainFrame = QFrame() + + self.ui.setCentralWidget(mainFrame) + self.ui.setWindowTitle('QGIS Mockup') + + + l = QHBoxLayout() + l.addWidget(self.mLayerTreeView) + l.addWidget(self.mCanvas) + v = QVBoxLayout() + v.addWidget(self.mMessageBar) + v.addLayout(l) + mainFrame.setLayout(v) + self.ui.setCentralWidget(mainFrame) + self.lyrs = [] + self.createActions() + + def iconSize(self, dockedToolbar=False): + return QSize(30,30) + + def testSlot(self, *args): + # print('--canvas changes--') + s = "" + + def mainWindow(self): + return self.ui + + + def addToolBarIcon(self, action): + assert isinstance(action, QAction) + + def removeToolBarIcon(self, action): + assert isinstance(action, QAction) + + + def addVectorLayer(self, path, basename=None, providerkey=None): + if basename is None: + basename = os.path.basename(path) + if providerkey is None: + bn, ext = os.path.splitext(basename) + + providerkey = 'ogr' + l = QgsVectorLayer(path, basename, providerkey) + assert l.isValid() + QgsProject.instance().addMapLayer(l, True) + self.mRootNode.addLayer(l) + self.mLayerTreeMapCanvasBridge.setCanvasLayers() + s = "" + + def legendInterface(self): + return None + + def addRasterLayer(self, path, baseName=''): + l = QgsRasterLayer(path, os.path.basename(path)) + self.lyrs.append(l) + QgsProject.instance().addMapLayer(l, True) + self.mRootNode.addLayer(l) + self.mLayerTreeMapCanvasBridge.setCanvasLayers() + return + + cnt = len(self.canvas.layers()) + + self.canvas.setLayerSet([QgsMapCanvasLayer(l)]) + l.dataProvider() + if cnt == 0: + self.canvas.mapSettings().setDestinationCrs(l.crs()) + self.canvas.setExtent(l.extent()) + + spatialExtent = SpatialExtent.fromMapLayer(l) + # self.canvas.blockSignals(True) + self.canvas.setDestinationCrs(spatialExtent.crs()) + self.canvas.setExtent(spatialExtent) + # self.blockSignals(False) + self.canvas.refresh() + + self.canvas.refresh() + + def createActions(self): + m = self.ui.menuBar().addAction('Add Vector') + m = self.ui.menuBar().addAction('Add Raster') + + def mapCanvas(self): + return self.mCanvas + + def mapNavToolToolBar(self): + super().mapNavToolToolBar() + + def messageBar(self, *args, **kwargs): + return self.mMessageBar + + def rasterMenu(self): + super().rasterMenu() + + def vectorMenu(self): + super().vectorMenu() + + def viewMenu(self): + super().viewMenu() + + def windowMenu(self): + super().windowMenu() + + def zoomFull(self, *args, **kwargs): + super().zoomFull(*args, **kwargs) + + + class PythonRunnerImpl(QgsPythonRunner): """ A Qgs PythonRunner implementation