Skip to content
Snippets Groups Projects
main.py 40.2 KiB
Newer Older
unknown's avatar
unknown committed
# -*- coding: utf-8 -*-
"""
/***************************************************************************
 EnMAPBox
                                 A QGIS plugin
 EnMAP-Box V3
                              -------------------
        begin                : 2015-08-20
        git sha              : $Format:%H$
        copyright            : (C) 2015 by HU-Berlin
        email                : bj@geo.hu-berlin.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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
unknown's avatar
unknown committed

# Import the code for the dialog
import os, sys, re, fnmatch, collections, copy, traceback, six
from qgis.core import *
#os.environ['PATH'] += os.pathsep + r'C:\OSGeo4W64\bin'

from osgeo import gdal, ogr, osr, gdal_array

Benjamin Jakimow's avatar
Benjamin Jakimow committed
DEBUG = True
import qgis.analysis
unknown's avatar
unknown committed
try:
    from qgis.gui import *
unknown's avatar
unknown committed
    import qgis
unknown's avatar
unknown committed
    import qgis_add_ins
unknown's avatar
unknown committed
    qgis_available = True
    #import console.console_output
    #console.show_console()
    #sys.stdout = console.console_output.writeOut()
    #sys.stderr = console.console_output.writeOut()
unknown's avatar
unknown committed
except:
    print('Can not find QGIS instance')
unknown's avatar
unknown committed
    qgis_available = False

import numpy as np
Benjamin Jakimow's avatar
Benjamin Jakimow committed
import sys, bisect, multiprocessing, site
Benjamin Jakimow's avatar
Benjamin Jakimow committed
from PyQt4.QtCore import *
from PyQt4.QtGui import *
Benjamin Jakimow's avatar
Benjamin Jakimow committed
from PyQt4.uic.Compiler.qtproxies import QtGui, QtCore
Benjamin Jakimow's avatar
Benjamin Jakimow committed
#abbreviations
from timeseriesviewer import jp, mkdir, DIR_SITE_PACKAGES, file_search, dprint
Benjamin Jakimow's avatar
Benjamin Jakimow committed

site.addsitedir(DIR_SITE_PACKAGES)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

#I don't know why, but this is required to run this in QGIS
#todo: still required?
Benjamin Jakimow's avatar
Benjamin Jakimow committed
path = os.path.abspath(jp(sys.exec_prefix, '../../bin/pythonw.exe'))
unknown's avatar
unknown committed
if os.path.exists(path):
    multiprocessing.set_executable(path)
    sys.argv = [ None ]
unknown's avatar
unknown committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
#ensure that required non-standard modules are available
unknown's avatar
unknown committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
class SpatialExtent(QgsRectangle):

    @staticmethod
    def fromMapCanvas(mapCanvas):
        assert isinstance(mapCanvas, QgsMapCanvas)
        extent = mapCanvas.extent()
        crs = mapCanvas.mapSettings().destinationCrs()
        return SpatialExtent(crs, extent)



Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __init__(self, crs, *args):
        assert isinstance(crs, QgsCoordinateReferenceSystem)
        super(SpatialExtent, self).__init__(*args)
        self.mCrs = crs

    def setCrs(self, crs):
        assert isinstance(crs, QgsCoordinateReferenceSystem)
        self.mCrs = crs

    def crs(self):
        return self.mCrs

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def toCrs(self, crs):
        assert isinstance(crs, QgsCoordinateReferenceSystem)
        box = QgsRectangle(self)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        if self.mCrs != crs:
            trans = QgsCoordinateTransform(self.mCrs, crs)
            box = trans.transformBoundingBox(box)
        return SpatialExtent(crs, box)

    def __copy__(self):
        return SpatialExtent(self.crs(), QgsRectangle(self))

    def combineExtentWith(self, *args):
        if args is None:
            return
        elif isinstance(args[0], SpatialExtent):
            extent2 = args[0].toCrs(self.crs())
            self.combineExtentWith(QgsRectangle(extent2))
        else:
            super(SpatialExtent, self).combineExtentWith(*args)

    def setCenter(self, centerPoint, crs=None):

        if crs and crs != self.crs():
            trans = QgsCoordinateTransform(crs, self.crs())
            centerPoint = trans.transform(centerPoint)

        delta = centerPoint - self.center()
        self.setXMaximum(self.xMaximum() + delta.x())
        self.setXMinimum(self.xMinimum() + delta.x())
        self.setYMaximum(self.yMaximum() + delta.y())
        self.setYMinimum(self.yMinimum() + delta.y())


    def __cmp__(self, other):
        if other is None: return 1
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        s = ""

    def __eq__(self, other):
        s = ""

    def __sub__(self, other):
        raise NotImplementedError()

    def __mul__(self, other):
        raise NotImplementedError()

    def upperLeft(self):
        return self.xMinimum(), self.yMaximum()

    def lowerRight(self):
        return self.xMaximum(), self.yMinimum()

    def __repr__(self):

        return '{} {} {}'.format(self.upperLeft(), self.lowerRight(), self.crs().authid())


Benjamin Jakimow's avatar
Benjamin Jakimow committed
from timeseriesviewer.ui.widgets import *
from timeseriesviewer.timeseries import TimeSeries, TimeSeriesDatum, SensorInstrument


unknown's avatar
unknown committed
class TimeSeriesTableModel(QAbstractTableModel):
    columnames = ['date','sensor','ns','nl','nb','image','mask']
unknown's avatar
unknown committed

    def __init__(self, TS, parent=None, *args):
        super(QAbstractTableModel, self).__init__()
        assert isinstance(TS, TimeSeries)
        self.TS = TS

    def rowCount(self, parent = QModelIndex()):
        return len(self.TS)

    def columnCount(self, parent = QModelIndex()):
        return len(self.columnames)

    def removeRows(self, row, count , parent=QModelIndex()):
        self.beginRemoveRows(parent, row, row+count-1)
        toRemove = self._data[row:row+count]
        for i in toRemove:
            self._data.remove(i)

        self.endRemoveRows()

unknown's avatar
unknown committed
    def getDateFromIndex(self, index):
        if index.isValid():
            i = index.row()
            if i >= 0 and i < len(self.TS):
                return self.TS.getTSDs()[i]
unknown's avatar
unknown committed
        return None
unknown's avatar
unknown committed

    def getTimeSeriesDatumFromIndex(self, index):

        if index.isValid():
            i = index.row()
            if i >= 0 and i < len(self.TS):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                return self.TS.data[i]
unknown's avatar
unknown committed

        return None



    def data(self, index, role = Qt.DisplayRole):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        if role is None or not index.isValid():
unknown's avatar
unknown committed
            return None


        value = None
        ic_name = self.columnames[index.column()]
        TSD = self.getTimeSeriesDatumFromIndex(index)
        keys = list(TSD.__dict__.keys())
        if role == Qt.DisplayRole or role == Qt.ToolTipRole:
            if ic_name == 'name':
                value = os.path.basename(TSD.pathImg)
            elif ic_name == 'sensor':
                if role == Qt.ToolTipRole:
                    value = TSD.sensor.getDescription()
                else:
                    value = str(TSD.sensor)
unknown's avatar
unknown committed
            elif ic_name == 'date':
                value = '{}'.format(TSD.date)
            elif ic_name == 'image':
                value = TSD.pathImg
            elif ic_name == 'mask':
                value = TSD.pathMsk
            elif ic_name in keys:
                value = TSD.__dict__[ic_name]
            else:
                s = ""
        elif role == Qt.BackgroundColorRole:
            value = None
        elif role == Qt.UserRole:
unknown's avatar
unknown committed

        return value

    #def flags(self, index):
    #    return Qt.ItemIsEnabled

    def flags(self, index):
        if index.isValid():
            item = self.getTimeSeriesDatumFromIndex(index)
            cname = self.columnames[index.column()]
            if cname.startswith('d'): #relative values can be edited
                flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable
            else:
                flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
            return flags
            #return item.qt_flags(index.column())
        return None

    def headerData(self, col, orientation, role):
        if Qt is None:
            return None
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.columnames[col]
        elif orientation == Qt.Vertical and role == Qt.DisplayRole:
            return col
        return None

unknown's avatar
unknown committed
class TimeSeriesItemModel(QAbstractItemModel):
unknown's avatar
unknown committed

unknown's avatar
unknown committed
    def __init__(self, TS):
unknown's avatar
unknown committed
        QAbstractItemModel.__init__(self)
        #self.rootItem = TreeItem[]
unknown's avatar
unknown committed
        assert type(TS) is TimeSeries
        self.TS = TS
unknown's avatar
unknown committed

    def index(self, row, column, parent = QModelIndex()):
        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()

    def setData(self, index, value, role = Qt.EditRole):
        if role == Qt.EditRole:
            row = index.row()

            return False
        return False

    def data(self, index, role=Qt.DisplayRole):
        data = None
        if role == Qt.DisplayRole or role == Qt.EditRole:
            data = 'sampletext'


        return data

    def flags(self, QModelIndex):
        return Qt.ItemIsSelectable

    def rowCount(self, index=QModelIndex()):
unknown's avatar
unknown committed
        return len(self.TS)
unknown's avatar
unknown committed

    #---------------------------------------------------------------------------
    def columnCount(self, index=QModelIndex()):
        return 1


class TimeSeriesDateViewManager(QObject):
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def __init__(self, timeSeriesViewer):
        assert isinstance(timeSeriesViewer, TimeSeriesViewer)
        super(TimeSeriesDateViewManager, self).__init__()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.TSV = timeSeriesViewer
        self.TSDViews = list()
        self.mapViewManager = self.TSV.mapViewManager
        self.mapViewManager.sigMapViewAdded.connect(self.addMapView)
        self.mapViewManager.sigMapViewRemoved.connect(self.removeMapView)
        self.mapViewManager.sigMapViewVisibility.connect(self.setMapViewVisibility)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.setSpatialExtent(self.TSV.TS.getMaxSpatialExtent())
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.setMaxTSDViews()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.L = self.TSV.ui.scrollAreaSubsetContent.layout()
        self.setSubsetSize(QSize(100,50))


    def activateMapTool(self, key):
        for tsdv in self.TSDViews:
            tsdv.activateMapTool(key)


Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def setSubsetSize(self, size):
        assert isinstance(size, QSize)
        self.subsetSize = size
        for tsdv in self.TSDViews:
            tsdv.setSubsetSize(size)
        self.adjustScrollArea()

Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def adjustScrollArea(self):

        m = self.L.contentsMargins()
        n = len(self.TSDViews)
        if n > 0:
            refTSDView = self.TSDViews[0]
            size = refTSDView.ui.size()

            w = n * size.width() + (n-1) * (m.left()+ m.right())
            h = max([refTSDView.ui.minimumHeight() + m.top() + m.bottom(),
                     self.TSV.ui.scrollAreaSubsets.height()-25])

            self.L.parentWidget().setFixedSize(w,h)


Benjamin Jakimow's avatar
Benjamin Jakimow committed
        assert isinstance(TS, TimeSeries)
        self.TS = TS
        self.TS.sigTimeSeriesDatesAdded.connect(self.createTSDViews)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def setMaxTSDViews(self, n=-1):
        self.nMaxTSDViews = n
        #todo: remove views

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.extent = extent
        if extent:
            assert isinstance(extent, SpatialExtent)
            tsdviews = sorted(self.TSDViews, key=lambda t:t.TSD)
            for tsdview in tsdviews:
                tsdview.setSpatialExtent(extent)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def navToDOI(self, TSD):
        assert isinstance(TSD, TimeSeriesDatum)
        #get widget related to TSD
        tsdviews = [t for t in self.TSDViews if t.TSD == TSD]
        if len(tsdviews) > 0:
            i = self.TSDViews.index(tsdviews[0])+1.5
            n = len(self.TSDViews)

            scrollBar = self.TSV.ui.scrollAreaSubsets.horizontalScrollBar()
            smin = scrollBar.minimum()
            smax = scrollBar.maximum()
            v = smin + (smax - smin) * float(i) / n
            scrollBar.setValue(int(round(v)))

    def setMapViewVisibility(self, bandView, isVisible):
        assert isinstance(bandView, MapViewDefinition)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        assert isinstance(isVisible, bool)

        for tsdv in self.TSDViews:
            tsdv.setMapViewVisibility(bandView, isVisible)
Benjamin Jakimow's avatar
Benjamin Jakimow committed


    def addMapView(self, bandView):
        assert isinstance(bandView, MapViewDefinition)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        w = self.L.parentWidget()
        w.setUpdatesEnabled(False)

        for tsdv in self.TSDViews:
            tsdv.ui.setUpdatesEnabled(False)

        for tsdv in self.TSDViews:
            tsdv.insertMapView(bandView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        for tsdv in self.TSDViews:
            tsdv.ui.setUpdatesEnabled(True)

        w.setUpdatesEnabled(True)



    def removeMapView(self, bandView):
        assert isinstance(bandView, MapViewDefinition)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        for tsdv in self.TSDViews:
            tsdv.removeMapView(bandView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def createTSDViews(self, timeSeriesDates):
        for TSD in timeSeriesDates:
            assert isinstance(TSD, TimeSeriesDatum)
            tsdView = TimeSeriesDatumView(TSD)
            tsdView.setSubsetSize(self.subsetSize)
            tsdView.sigExtentsChanged.connect(self.setSpatialExtent)
            for i, bandView in enumerate(self.mapViewManager):
                tsdView.insertMapView(bandView)
            if self.extent:
                tsdView.setSpatialExtent(self.extent)
            self.addTSDView(tsdView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed


    def removeTSD(self, TSD):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        tsdvs = [tsdv for tsdv in self.TSDViews if tsdv.TSD == TSD]
        assert len(tsdvs) == 1
        self.removeTSDView(tsdvs[0])

    def removeTSDView(self, TSDV):
        assert isinstance(TSDV, TimeSeriesDatumView)
        self.TSDViews.remove(TSDV)

    def addTSDView(self, TSDV):
        assert isinstance(TSDV, TimeSeriesDatumView)

        if len(self.TSDViews) < 10:
            pass

        bisect.insort(self.TSDViews, TSDV)

        TSDV.ui.setParent(self.L.parentWidget())
        self.L.addWidget(TSDV.ui)

        self.adjustScrollArea()
        #self.TSV.ui.scrollAreaSubsetContent.update()
        #self.TSV.ui.scrollAreaSubsets.update()
        s = ""



class MapViewDefinition(QObject):
    sigRemoveMapView = pyqtSignal(object)
    sigHideMapView = pyqtSignal()
    sigShowMapView = pyqtSignal()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __init__(self, recommended_bands=None, parent=None, showSensorNames=True):
        super(MapViewDefinition, self).__init__()
        self.ui = MapViewDefinitionUI(self, parent=parent)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.ui.create()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        #forward actions with reference to this band view
        self.ui.actionRemoveMapView.triggered.connect(lambda: self.sigRemoveMapView.emit(self))
        self.ui.sigHideMapView.connect(lambda : self.sigHideMapView.emit())
        self.ui.sigShowMapView.connect(lambda: self.sigShowMapView.emit())
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.sensorViews = collections.OrderedDict()
        self.mShowSensorNames = showSensorNames
Benjamin Jakimow's avatar
Benjamin Jakimow committed


    def setVisibility(self, isVisible):
        self.ui.setVisibility(isVisible)


    def visibility(self):
        return self.ui.visibility()

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def setTitle(self, title):
        self.mTitle = title
        self.ui.labelName.setText(title)
        self.sigTitleChanged.emit(self.mTitle)
        return self.mTitle
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def showSensorNames(self, b):
        assert isinstance(b, bool)
        self.mShowSensorNames = b
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        for s,w in self.sensorViews.items():
            w.showSensorName(b)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def removeSensor(self, sensor):
        assert type(sensor) is SensorInstrument
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        if sensor in self.sensorViews.keys():
            self.sensorViews[sensor].close()
            self.sensorViews.pop(sensor)
            return True
        else:
            return False

    def hasSensor(self, sensor):
        assert type(sensor) is SensorInstrument
        return sensor in self.sensorViews.keys()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def addSensor(self, sensor):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        """
        :param sensor:
        :return:
        """
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        assert type(sensor) is SensorInstrument
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        assert sensor not in self.sensorViews.keys()
        #w.showSensorName(False)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.sensorViews[sensor] = w
        l = self.ui.sensorList
        l.addWidget(w.ui)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def getSensorWidget(self, sensor):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        assert type(sensor) is SensorInstrument
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        return self.sensorViews[sensor]
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed


class MapViewManager(QObject):
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    sigSensorAdded = pyqtSignal(SensorInstrument)
    sigSensorRemoved = pyqtSignal(SensorInstrument)
    sigMapViewAdded = pyqtSignal(MapViewDefinition)
    sigMapViewRemoved = pyqtSignal(MapViewDefinition)
    sigMapViewVisibility = pyqtSignal(MapViewDefinition, bool)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def __init__(self, timeSeriesViewer):
        assert isinstance(timeSeriesViewer, TimeSeriesViewer)
        super(MapViewManager, self).__init__()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.TSV = timeSeriesViewer
        self.ui = self.TSV.ui
        self.mapViewsDefinitions = []
        self.mapViewButtons = dict()

Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def removeSensor(self, sensor):
        assert isinstance(sensor, SensorInstrument)

        removed = False
        for view in self.mapViewsDefinitions:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            removed = removed and view.removeSensor(sensor)

        if removed:
            self.sigSensorRemoved(sensor)


    def createMapView(self):
        btnList = self.TSV.ui.dockMapViews.BVButtonList
        btn = QToolButton(btnList)
        btnList.layout().insertWidget(btnList.layout().count() - 1, btn)

        mapView = MapViewDefinition(parent=self.TSV.ui.dockMapViews.scrollAreaMapViews, showSensorNames=False)
        mapView.sigRemoveMapView.connect(self.removeMapView)
        mapView.sigShowMapView.connect(lambda : self.sigMapViewVisibility.emit(mapView, mapView.visibility()))
        mapView.sigHideMapView.connect(lambda: self.sigMapViewVisibility.emit(mapView, mapView.visibility()))
        #mapView.sigTitleChanged.connect(btn.setText)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.mapViewButtons[mapView] = btn
        self.mapViewsDefinitions.append(mapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        for sensor in self.TSV.TS.Sensors:
            mapView.addSensor(sensor)

        btn.clicked.connect(lambda : self.showMapViewDefinition(mapView))
        self.refreshMapViewTitles()
        self.sigMapViewAdded.emit(mapView)

        if len(self) == 1:
            self.showMapViewDefinition(mapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def removeMapView(self, mapView):
        assert isinstance(mapView, MapViewDefinition)
        btn = self.mapViewButtons[mapView]
        btnList = self.TSV.ui.dockMapViews.BVButtonList
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        idx = self.mapViewsDefinitions.index(mapView)
        self.mapViewsDefinitions.remove(mapView)
        self.mapViewButtons.pop(mapView)
        mapView.ui.setVisible(False)
        l = self.ui.dockMapViews.scrollAreaMapsViewDockContent.layout()

        for d in self.recentMapViewDefinitions():
            d.ui.setVisible(False)
            l.removeWidget(d.ui)
        l.removeWidget(mapView.ui)
        mapView.ui.close()
        self.refreshMapViewTitles()
        self.sigMapViewRemoved.emit(mapView)

        if len(self) > 0:
            #show previous mapViewDefinition
            idxNext = max([idx-1, 0])
            self.showMapViewDefinition(self.mapViewsDefinitions[idxNext])

    def refreshMapViewTitles(self):
        for i, mapView in enumerate(self.mapViewsDefinitions):
            number = i+1
            title = '#{}'.format(number)
            mapView.setTitle(title)
            btn = self.mapViewButtons[mapView]
            btn.setText('{}'.format(number))
            btn.setToolTip('Show definition for map view {}'.format(number))
            btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
            s = ""
    def showMapViewDefinition(self, mapViewDefinition):
        assert mapViewDefinition in self.mapViewsDefinitions
        assert isinstance(mapViewDefinition, MapViewDefinition)
        l = self.ui.dockMapViews.scrollAreaMapsViewDockContent.layout()
        for d in self.recentMapViewDefinitions():
            d.ui.setVisible(False)
            l.removeWidget(d.ui)
        l.insertWidget(l.count() - 1, mapViewDefinition.ui)
        mapViewDefinition.ui.setVisible(True)

    def recentMapViewDefinitions(self):
        parent = self.ui.dockMapViews.scrollAreaMapsViewDockContent
        return [ui.mapViewDefinition() for ui in parent.findChildren(MapViewDefinitionUI)]


    def setMapViewVisibility(self, bandView, isVisible):
        assert isinstance(bandView, MapViewDefinition)
Benjamin Jakimow's avatar
Benjamin Jakimow committed



    def __len__(self):
        return len(self.mapViewsDefinitions)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def __iter__(self):
        return iter(self.mapViewsDefinitions)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def __getitem__(self, key):
        return self.mapViewsDefinitions[key]
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def __contains__(self, mapView):
        return mapView in self.mapViewsDefinitions
Benjamin Jakimow's avatar
Benjamin Jakimow committed


class TimeSeriesDatumView(QObject):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def __init__(self, TSD, parent=None):

        super(TimeSeriesDatumView, self).__init__()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.ui = TimeSeriesDatumViewUI(parent)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.ui.create()

        self.TSD = None
        self.mapCanvases = dict()
        self.mapOrder = []
        self.setTimeSeriesDatum(TSD)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.L = self.ui.layout()
        self.wOffset = self.L.count()-1
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.setSubsetSize(QSize(150,100))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        for c in self.mapCanvases.values():
    def setMapViewVisibility(self, bandView, isVisible):
        self.mapCanvases[bandView].setVisible(isVisible)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def setSpatialExtent(self, spatialExtent):
        assert isinstance(spatialExtent, SpatialExtent)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        for c in self.mapCanvases.values():
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def setSubsetSize(self, size):
        assert isinstance(size, QSize)
        assert size.width() > 5 and size.height() > 5
        self.subsetSize = size
        m = self.L.contentsMargins()

        self.ui.labelTitle.setFixedWidth(size.width())
        self.ui.line.setFixedWidth(size.width())

        #apply new subset size to existing canvases
        for c in self.mapCanvases.values():
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            c.setFixedSize(size)

        self.ui.setFixedWidth(size.width() + 2*(m.left() + m.right()))
        n = len(self.mapCanvases)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        #todo: improve size forecast
        self.ui.setMinimumHeight((n+1) * size.height())


    def setTimeSeriesDatum(self, TSD):
        assert isinstance(TSD, TimeSeriesDatum)
        self.TSD = TSD
        self.ui.labelTitle.setText(str(TSD.date))

        for c in self.mapCanvases.values():
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            c.setLayer(self.TSD.pathImg)

    def removeMapView(self, bandView):
        self.mapOrder.remove(bandView)
        canvas = self.mapCanvases.pop(bandView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.L.removeWidget(canvas)
        canvas.close()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        for c in self.mapCanvases.values():
    def insertMapView(self, bandView, i=-1):
        assert isinstance(bandView, MapViewDefinition)
        assert bandView not in self.mapOrder
        if len(self.mapCanvases) != len(self.mapOrder):
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        assert i >= -1 and i <= len(self.mapOrder)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        if i == -1:
            i = len(self.mapCanvases)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        canvas.setLayer(self.TSD.pathImg)
        canvas.setFixedSize(self.subsetSize)
        canvas.extentsChanged.connect(lambda : self.sigExtentsChanged.emit(canvas.spatialExtent()))

Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.mapCanvases[bandView] = canvas
        self.mapOrder.insert(i, bandView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.L.insertWidget(self.wOffset + i, canvas)

    def __lt__(self, other):

        return self.TSD < other.TSD


    def __init__(self, TSD, renderer, destinationId=None):
        assert isinstance(TSD, TimeSeriesDatum)
        assert isinstance(renderer, QgsRasterRenderer)
        self.TSD = TSD
        self.renderer = renderer
        self.destinationId = destinationId

    def __eq__(self, other):
        if not isinstance(other, RenderJob):
            return False
        return self.TSD == other.TSD and \
               self.renderer == other.renderer and \
               self.destinationId == other.destinationId
Benjamin Jakimow's avatar
Benjamin Jakimow committed

list2str = lambda ll : '\n'.join([str(l) for l in ll])
unknown's avatar
unknown committed

    def __init__(self, iface, TSV_UI):
        super(QgsInstanceInteraction, self).__init__()
        self.iface = iface
        self.ui = TSV_UI
        self.cbVectorLayer = TSV_UI.cbQgsVectorLayer
benjamin.jakimow@geo.hu-berlin.de's avatar
benjamin.jakimow@geo.hu-berlin.de committed
        s = ""
    def getVectorLayerRepresentation(self):
        if self.ui.gbQgsVectorLayer.isChecked():
            lyr = self.cbVectorLayer.currentLayer()
            alpha = self.ui.sliderQgsVectorTransparency.value()
            return lyr
        else:
            return None
class TimeSeriesViewer:
unknown's avatar
unknown committed

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        from timeseriesviewer.ui.widgets import TimeSeriesViewerUI
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.ui = TimeSeriesViewerUI()
        if iface:
            import timeseriesviewer
            timeseriesviewer.QGIS_TSV_BRIDGE = QgsInstanceInteraction(iface, self.ui)
            self.ui.setQgsLinkWidgets()

        #init empty time series
        self.TS = TimeSeries()
        self.hasInitialCenterPoint = False
        self.TS.sigTimeSeriesDatesAdded.connect(self.datesAdded)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.TS.sigProgress.connect(self.ua_TSprogress)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        #init TS model
        TSM = TimeSeriesTableModel(self.TS)
        D = self.ui
        #self.ICP = D.scrollAreaSubsetContent.layout()
        #D.scrollAreaMapViews.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        #self.BVP = self.ui.scrollAreaMapViews.layout()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        D.tableView_TimeSeries.setModel(TSM)
        D.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
        self.mapViewManager = MapViewManager(self)
        self.timeSeriesDateViewManager = TimeSeriesDateViewManager(self)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

unknown's avatar
unknown committed
        self.ValidatorPxX = QIntValidator(0,99999)
        self.ValidatorPxY = QIntValidator(0,99999)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        #connect actions with logic

        #D.btn_showPxCoordinate.clicked.connect(lambda: self.showSubsetsStart())
        #connect actions with logic
        D.actionSelectCenter.triggered.connect(lambda : self.timeSeriesDateViewManager.activateMapTool('selectCenter'))
        D.actionSelectArea.triggered.connect(lambda : self.timeSeriesDateViewManager.activateMapTool('selectArea'))
        D.actionZoomMaxExtent.triggered.connect(lambda : self.zoomTo('maxExtent'))
        D.actionZoomPixelScale.triggered.connect(lambda: self.zoomTo('pixelScale'))
        D.actionZoomIn.triggered.connect(lambda: self.timeSeriesDateViewManager.activateMapTool('zoomIn'))
        D.actionZoomOut.triggered.connect(lambda: self.timeSeriesDateViewManager.activateMapTool('zoomOut'))
        D.actionPan.triggered.connect(lambda: self.timeSeriesDateViewManager.activateMapTool('pan'))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        D.actionAddMapView.triggered.connect(self.mapViewManager.createMapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        D.actionAddTSD.triggered.connect(self.ua_addTSImages)
        D.actionRemoveTSD.triggered.connect(self.removeTimeSeriesDates)
        D.actionRedraw.triggered.connect(self.timeSeriesDateViewManager.redraw)
        D.actionLoadTS.triggered.connect(self.loadTimeSeries)
        D.actionClearTS.triggered.connect(self.clearTimeSeries)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        D.actionSaveTS.triggered.connect(self.ua_saveTSFile)
        D.actionAddTSExample.triggered.connect(self.ua_loadExampleTS)

        #connect buttons with actions
        D.btnClearLabelList.clicked.connect(D.tbCollectedLabels.clear)
        D.actionAbout.triggered.connect(lambda: AboutDialogUI(self.ui).exec_())
        D.actionSettings.triggered.connect(lambda : PropertyDialogUI(self.ui).exec_())
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        D.actionFirstTSD.triggered.connect(lambda: self.setDOISliderValue('first'))
        D.actionLastTSD.triggered.connect(lambda: self.setDOISliderValue('last'))
        D.actionNextTSD.triggered.connect(lambda: self.setDOISliderValue('next'))
        D.actionPreviousTSD.triggered.connect(lambda: self.setDOISliderValue('previous'))


        D.sliderDOI.valueChanged.connect(self.setDOI)
unknown's avatar
unknown committed

        D.actionSetSubsetSize.triggered.connect(lambda : self.timeSeriesDateViewManager.setSubsetSize(
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                                                self.ui.subsetSize()))
        D.actionSetExtent.triggered.connect(lambda: self.timeSeriesDateViewManager.setSpatialExtent(self.ui.spatialExtent()))
        self.canvasCrs = QgsCoordinateReferenceSystem()
    def zoomTo(self, key):
        if key == 'maxExtent':
            ext = self.TS.getMaxSpatialExtent(self.ui.crs())
            self.timeSeriesDateViewManager.setSpatialExtent(ext)
unknown's avatar
unknown committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed

    def setDOISliderValue(self, key):
        ui = self.ui
        v = ui.sliderDOI.value()
        if key == 'first':
            v = ui.sliderDOI.minimum()
        elif key == 'last':
            v = ui.sliderDOI.maximum()
        elif key =='next':
            v = min([v+1,ui.sliderDOI.maximum()])
        elif key =='previous':
            v = max([v - 1, ui.sliderDOI.minimum()])
        ui.sliderDOI.setValue(v)

    def setDOI(self, i):
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        TSD = None

        if len(self.TS) == 0:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            text = '<empty timeseries>'
        else:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            TSD = self.TS.data[i - 1]
            text = str(TSD.date)

        self.ui.labelDOIValue.setText(text)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        if TSD:
            self.timeSeriesDateViewManager.navToDOI(TSD)
Benjamin Jakimow's avatar
Benjamin Jakimow committed


    def icon(self):
        return TimeSeriesViewer.icon()

Benjamin Jakimow's avatar
Benjamin Jakimow committed
    def timeseriesChanged(self):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        D.sliderDOI.setMinimum(1)
        l = len(self.TS.data)
        D.sliderDOI.setMaximum(l)
        #get meaningfull tick intervall
        for tickInterval in [1,5,10,25,50,100,200]:
            if (D.sliderDOI.size().width() / float(l) * tickInterval) > 5:
                break
        D.sliderDOI.setTickInterval(tickInterval)

        if not self.hasInitialCenterPoint:
            if len(self.TS.data) > 0:
                extent = self.TS.getMaxSpatialExtent(self.canvasCrs)
                self.timeSeriesDateViewManager.setSubsetSize(self.ui.subsetSize())
                self.timeSeriesDateViewManager.setSpatialExtent(extent)
                self.ui.setSpatialExtent(extent)
                self.hasInitialCenterPoint = True

            if len(self.mapViewManager) == 0:
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                # add two empty band-views by default
                self.mapViewManager.createMapView()
                self.mapViewManager.createMapView()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        if path is None or path is False:
            path = QFileDialog.getOpenFileName(self.ui, 'Open Time Series file', '')
            M = self.ui.tableView_TimeSeries.model()
            M.beginResetModel()
            self.clearTimeSeries()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
            self.TS.loadFromFile(path, n_max=n_max)
            M.endResetModel()

    def ua_saveTSFile(self):
        path = QFileDialog.getSaveFileName(self.ui, caption='Save Time Series file')
        if path is not None:
            self.TS.saveToFile(path)


    def ua_loadExampleTS(self):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        from timeseriesviewer import PATH_EXAMPLE_TIMESERIES
        if not os.path.exists(PATH_EXAMPLE_TIMESERIES):
            QMessageBox.information(self.ui, 'File not found', '{} - this file describes an exemplary time series.'.format(path_example))