Skip to content
Snippets Groups Projects
main.py 39.5 KiB
Newer Older
unknown's avatar
unknown committed
# -*- coding: utf-8 -*-
"""
/***************************************************************************
unknown's avatar
unknown committed
                              -------------------
        begin                : 2015-08-20
        git sha              : $Format:%H$
        copyright            : (C) 2017 by HU-Berlin
        email                : benjamin.jakimow@geo.hu-berlin.de
unknown's avatar
unknown committed
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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
File "D:\Programs\OSGeo4W\apps\Python27\lib\multiprocessing\managers.py", line
528, in start
self._address = reader.recv()
EOFError
see https://github.com/pyinstaller/pyinstaller/wiki/Recipe-Multiprocessing
see https://github.com/CleanCut/green/issues/103 
path = os.path.abspath(os.path.join(sys.exec_prefix, '../../bin/pythonw.exe'))
if os.path.exists(path):
    multiprocessing.set_executable(path)
    sys.argv = [ None ]
import qgis.utils
from qgis.core import *
from qgis.gui import *
from eotimeseriesviewer.utils import *
from eotimeseriesviewer.timeseries import *
from eotimeseriesviewer.profilevisualization import SpectralTemporalVisualization
from eotimeseriesviewer import SpectralProfile, SpectralLibrary, SpectralLibraryPanel
from eotimeseriesviewer.externals.qps.maptools import MapTools, CursorLocationMapTool, QgsMapToolSelect, QgsMapToolSelectionHandler
from eotimeseriesviewer.externals.qps.cursorlocationvalue import CursorLocationInfoModel, CursorLocationInfoDock
import eotimeseriesviewer.labeling

Benjamin Jakimow's avatar
Benjamin Jakimow committed

EXTRA_SPECLIB_FIELDS = [
    QgsField('date', QVariant.String, 'varchar'),
    QgsField('doy', QVariant.Int, 'int'),
    QgsField('sensor', QVariant.String, 'varchar')
]
class TimeSeriesViewerUI(QMainWindow,
                         loadUI('timeseriesviewer.ui')):

    def __init__(self, parent=None):
        """Constructor."""
        super(TimeSeriesViewerUI, self).__init__(parent)
        # Set up the user interface from Designer.
        # After setupUI you can access any designer object by doing
        # self.<objectname>, and you can use autoconnect slots - see
        # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html
        # #widgets-and-dialogs-with-auto-connect
        self.setupUi(self)
        self.addActions(self.findChildren(QAction))
        from eotimeseriesviewer import TITLE, icon, __version__
        self.setWindowTitle('{} ({})'.format(TITLE, __version__))
        if sys.platform == 'darwin':
            self.menuBar().setNativeMenuBar(False)
        # set button default actions -> this will show the action icons as well
        # I don't know why this is not possible in the QDesigner when QToolButtons are
        # placed outside a toolbar

        area = None

        def addDockWidget(dock):
            """
            shortcut to add a created dock and return it
            :param dock:
            :return:
            """
            self.addDockWidget(area, dock)
            return dock

        area = Qt.LeftDockWidgetArea

        # self.dockRendering = addDockWidget(docks.RenderingDockUI(self))
            from eotimeseriesviewer.labeling import LabelingDock
            self.dockLabeling = addDockWidget(LabelingDock(self))
            self.dockLabeling.setHidden(True)
        from eotimeseriesviewer.sensorvisualization import SensorDockUI
        self.dockSensors = addDockWidget(SensorDockUI(self))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        from eotimeseriesviewer.mapvisualization import MapViewDock
        self.dockMapViews = addDockWidget(MapViewDock(self))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.dockCursorLocation = addDockWidget(CursorLocationInfoDock(self))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

Benjamin Jakimow's avatar
Benjamin Jakimow committed
        # self.tabifyDockWidget(self.dockMapViews, self.dockRendering)
        self.tabifyDockWidget(self.dockSensors, self.dockCursorLocation)
        area = Qt.BottomDockWidgetArea
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        # from timeseriesviewer.mapvisualization import MapViewDockUI
        # self.dockMapViews = addDockWidget(MapViewDockUI(self))

        self.dockTimeSeries = addDockWidget(TimeSeriesDockUI(self))
        from eotimeseriesviewer.profilevisualization import ProfileViewDockUI
        self.dockProfiles = addDockWidget(ProfileViewDockUI(self))
        from eotimeseriesviewer.labeling import LabelingDock
        self.dockLabeling = addDockWidget(LabelingDock(self))

        area = Qt.LeftDockWidgetArea
        self.dockAdvancedDigitizingDockWidget = addDockWidget(QgsAdvancedDigitizingDockWidget(self.dockLabeling.canvas(), self))
        self.dockAdvancedDigitizingDockWidget.setVisible(False)
        self.tabifyDockWidget(self.dockSensors, self.dockAdvancedDigitizingDockWidget)
        area = Qt.BottomDockWidgetArea
        panel = SpectralLibraryPanel(None)
        panel.setParent(self)
        self.dockSpectralLibrary = addDockWidget(panel)
        self.tabifyDockWidget(self.dockTimeSeries, self.dockSpectralLibrary)
        #except Exception as ex:
        #    print('Unable to create SpectralLibrary panel', file=sys.stderr)
        #    print(ex, file=sys.stderr)
        #    self.dockSpectralLibrary = None
        #    self.dockSpectralLibrary = None
        self.tabifyDockWidget(self.dockTimeSeries, self.dockProfiles)
        self.tabifyDockWidget(self.dockTimeSeries, self.dockLabeling)
        from eotimeseriesviewer.systeminfo import SystemInfoDock
        self.dockSystemInfo = addDockWidget(SystemInfoDock(self))
        self.dockSystemInfo.setVisible(False)

        for dock in self.findChildren(QDockWidget):
            if len(dock.actions()) > 0:
                s = ""
            self.menuPanels.addAction(dock.toggleViewAction())

        self.mMapToolActions = [self.actionZoomPixelScale,
                                self.actionZoomFullExtent,
                                self.actionZoomIn,
                                self.actionZoomOut,
                                self.actionPan,
                                self.actionIdentify]
        self.dockTimeSeries.raise_()

        for a in self.mMapToolActions:
            assert isinstance(a, QAction)
            a.toggled.connect(self.onActionToggled)
    def onActionToggled(self, b:bool):
        action = QApplication.instance().sender()
        assert isinstance(action, QAction)
        otherActions = [a for a in self.mMapToolActions if a != action]

        # enable / disable the other maptool actions
        if b is True:
            for a in otherActions:
                assert isinstance(a, QAction)
                a.setChecked(False)

        else:
            otherSelected = [a for a in otherActions if a.isChecked()]
            if len(otherSelected) == 0:
                action.setChecked(True)

        b = self.actionIdentify.isChecked()
        self.optionIdentifyCursorLocation.setEnabled(b)
        self.optionIdentifySpectralProfile.setEnabled(b)
        self.optionIdentifyTemporalProfile.setEnabled(b)
        self.optionMoveCenter.setEnabled(b)


    def _blockSignals(self, widgets, block=True):
        states = dict()
        if isinstance(widgets, dict):
            for w, block in widgets.items():
                states[w] = w.blockSignals(block)
        else:
            for w in widgets:
                states[w] = w.blockSignals(block)
        return states



    sigSubsetSizeChanged = pyqtSignal(QSize)
    def setSubsetSize(self, size, blockSignal=False):
        old = self.subsetSize()
        w = [self.spinBoxSubsetSizeX, self.spinBoxSubsetSizeY]
        if blockSignal:
            states = self._blockSignals(w, True)

        self.spinBoxSubsetSizeX.setValue(size.width())
        self.spinBoxSubsetSizeY.setValue(size.height())
        self._setUpdateBehaviour()

        if blockSignal:
            self._blockSignals(states)
        elif old != size:
            self.sigSubsetSizeChanged(size)


    def setProgress(self, value, valueMax=None, valueMin=0):
        p = self.progressBar
        if valueMin is not None and valueMin != self.progessBar.minimum():
            p.setMinimum(valueMin)
        if valueMax is not None and valueMax != self.progessBar.maximum():
            p.setMaximum(valueMax)
        self.progressBar.setValue(value)


Benjamin Jakimow's avatar
Benjamin Jakimow committed

LUT_MESSAGELOGLEVEL = {
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                Qgis.Info: 'INFO',
                Qgis.Critical: 'INFO',
                Qgis.Warning: 'WARNING',
                Qgis.Success: 'SUCCESS',
def showMessage(message, title, level):
    v = QgsMessageViewer()
    v.setTitle(title)
    #print('DEBUG MSG: {}'.format(message))
    v.setMessage(message, QgsMessageOutput.MessageHtml \
        if message.startswith('<html>')
    else QgsMessageOutput.MessageText)
    v.showMessage(True)



class TimeSeriesViewer(QgisInterface, QObject):

    _instance = None

    @staticmethod
    def instance():
        """
        Returns the TimeSeriesViewer instance
        :return:
        """
        return TimeSeriesViewer._instance

    sigCurrentLocationChanged = pyqtSignal([SpatialPoint],
                                           [SpatialPoint, QgsMapCanvas])
    sigCurrentSpectralProfilesChanged = pyqtSignal(list)
    sigCurrentTemporalProfilesChanged = pyqtSignal(list)
unknown's avatar
unknown committed


    def __init__(self):
unknown's avatar
unknown committed
        """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
        """
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        # assert TimeSeriesViewer.instance() is None

        QObject.__init__(self)
        QgisInterface.__init__(self)
        QApplication.processEvents()

        import eotimeseriesviewer.utils
        eotimeseriesviewer.utils.MAP_LAYER_STORES.insert(0, self.mapLayerStore())
        self.ui = TimeSeriesViewerUI()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        # Save reference to the QGIS interface
        import qgis.utils
        assert isinstance(qgis.utils.iface, QgisInterface)
        # init empty time series
        self.mTimeSeries.setDateTimePrecision(DateTimePrecision.Day)
        self.mTimeSeries.sigTimeSeriesDatesAdded.connect(self.onTimeSeriesChanged)
        # init other GUI components
        # self.ICP = D.scrollAreaSubsetContent.layout()
        # D.scrollAreaMapViews.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
        # self.BVP = self.ui.scrollAreaMapViews.layout()
        # D.dockNavigation.connectTimeSeries(self.TS)
        self.ui.dockTimeSeries.setTimeSeries(self.mTimeSeries)
        self.ui.dockSensors.setTimeSeries(self.mTimeSeries)
        self.spectralTemporalVis = SpectralTemporalVisualization(self.mTimeSeries, self.ui.dockProfiles)
        self.spectralTemporalVis.pixelLoader.sigLoadingFinished.connect(
            lambda dt: self.ui.dockSystemInfo.addTimeDelta('Pixel Profile', dt))
        assert isinstance(self, TimeSeriesViewer)

        from eotimeseriesviewer.mapvisualization import SpatialTemporalVisualization
        self.spatialTemporalVis = SpatialTemporalVisualization(self)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        # self.spatialTemporalVis.sigLoadingStarted.connect(self.ui.dockRendering.addStartedWork)
        # self.spatialTemporalVis.sigLoadingFinished.connect(self.ui.dockRendering.addFinishedWork)
        # self.spatialTemporalVis.sigShowProfiles.connect(self.spectralTemporalVis.loadCoordinate)
        self.spatialTemporalVis.sigShowProfiles.connect(self.onShowProfile)
        self.ui.dockMapViews.sigCrsChanged.connect(self.spatialTemporalVis.setCrs)
        self.ui.dockMapViews.sigMapSizeChanged.connect(self.spatialTemporalVis.setMapSize)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.ui.dockMapViews.sigMapCanvasColorChanged.connect(self.spatialTemporalVis.setMapBackgroundColor)
        self.spatialTemporalVis.sigCRSChanged.connect(self.ui.dockMapViews.setCrs)
        self.spatialTemporalVis.sigMapSizeChanged.connect(self.ui.dockMapViews.setMapSize)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.spectralTemporalVis.sigMoveToTSD.connect(self.showTimeSeriesDatum)
Benjamin Jakimow's avatar
Benjamin Jakimow committed

        self.spectralTemporalVis.ui.actionLoadProfileRequest.triggered.connect(self.ui.actionIdentifyTemporalProfile.trigger)
Benjamin Jakimow's avatar
Benjamin Jakimow committed


        tstv = self.ui.dockTimeSeries.tableView_TimeSeries
        assert isinstance(tstv, TimeSeriesTableView)
        tstv.sigMoveToDateRequest.connect(self.showTimeSeriesDatum)

        # init map tools
        self.mMapTools = []
        self.mCurrentMapLocation = None
        self.mCurrentMapSpectraLoading = 'TOP'

        def initMapToolAction(action, key):
            assert isinstance(action, QAction)
            assert isinstance(key, str)
            assert key in MapTools.mapToolKeys()
            action.triggered.connect(lambda: self.setMapTool(key))
            action.setProperty('eotsv/maptoolkey', key)
        initMapToolAction(self.ui.actionPan, MapTools.Pan)
        initMapToolAction(self.ui.actionZoomIn, MapTools.ZoomIn)
        initMapToolAction(self.ui.actionZoomOut, MapTools.ZoomOut)
        initMapToolAction(self.ui.actionZoomPixelScale, MapTools.ZoomPixelScale)
        initMapToolAction(self.ui.actionZoomFullExtent, MapTools.ZoomFull)
        initMapToolAction(self.ui.actionIdentify, MapTools.CursorLocation)

        initMapToolAction(self.ui.actionSelectFeatures, MapTools.SelectFeature)
        assert isinstance(self.ui.actionSelectFeatures, QAction)

        self.ui.optionSelectFeaturesRectangle.triggered.connect(self.onSelectFeatureOptionTriggered)
        self.ui.optionSelectFeaturesPolygon.triggered.connect(self.onSelectFeatureOptionTriggered)
        self.ui.optionSelectFeaturesFreehand.triggered.connect(self.onSelectFeatureOptionTriggered)
        self.ui.optionSelectFeaturesRadius.triggered.connect(self.onSelectFeatureOptionTriggered)

        m = QMenu()
        m.addAction(self.ui.optionSelectFeaturesRectangle)
        m.addAction(self.ui.optionSelectFeaturesPolygon)
        m.addAction(self.ui.optionSelectFeaturesFreehand)
        m.addAction(self.ui.optionSelectFeaturesRadius)

        self.ui.actionSelectFeatures.setMenu(m)
        # create edit toolbar
        tb = self.ui.toolBarEditing
        assert isinstance(tb, QToolBar)
        tb.addAction(self.ui.dockLabeling.actionToggleEditing())
        tb.addAction(self.ui.dockLabeling.actionSaveEdits())
        tb.addAction(self.ui.dockLabeling.actionAddFeature())
        self.ui.dockLabeling.sigMapExtentRequested.connect(self.setSpatialExtent)
        self.ui.dockLabeling.sigMapCenterRequested.connect(self.setSpatialCenter)

        initMapToolAction(self.ui.dockLabeling.actionAddFeature(), MapTools.AddFeature)


        self.ui.dockLabeling.sigVectorLayerChanged.connect(lambda : self.spatialTemporalVis.setCurrentLayer(self.ui.dockLabeling.currentVectorSource()))
        #initMapToolAction(self.ui.dockLabeling., MapTools.AddFeature)

        # set default map tool
        self.ui.actionPan.toggle()
        self.ui.dockCursorLocation.sigLocationRequest.connect(self.ui.actionIdentifyCursorLocationValues.trigger)
        self.ui.dockCursorLocation.mLocationInfoModel.setNodeExpansion(CursorLocationInfoModel.ALWAYS_EXPAND)
        #D.actionIdentifyMapLayers.triggered.connect(lambda: self.spatialTemporalVis.activateMapTool('identifyMapLayers'))
        self.ui.actionAddMapView.triggered.connect(self.spatialTemporalVis.MVC.createMapView)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.ui.actionAddTSD.triggered.connect(lambda : self.addTimeSeriesImages(None))
        self.ui.actionAddVectorData.triggered.connect(lambda : self.addVectorData())
        self.ui.actionRemoveTSD.triggered.connect(lambda: self.mTimeSeries.removeTSDs(self.ui.dockTimeSeries.selectedTimeSeriesDates()))
        self.ui.actionRefresh.triggered.connect(self.spatialTemporalVis.refresh)
        self.ui.actionLoadTS.triggered.connect(self.loadTimeSeriesDefinition)
        self.ui.actionClearTS.triggered.connect(self.clearTimeSeries)
        self.ui.actionSaveTS.triggered.connect(self.saveTimeSeriesDefinition)
        self.ui.actionAddTSExample.triggered.connect(self.loadExampleTimeSeries)
        self.ui.actionLoadTimeSeriesStack.triggered.connect(self.loadTimeSeriesStack)
        self.ui.actionShowCrosshair.toggled.connect(self.spatialTemporalVis.setCrosshairVisibility)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        # connect buttons with actions
        from eotimeseriesviewer.widgets import AboutDialogUI
        self.ui.actionAbout.triggered.connect(lambda: AboutDialogUI(self.ui).exec_())

        self.ui.actionSettings.triggered.connect(self.onShowSettingsDialog)
        import webbrowser
        from eotimeseriesviewer import DOCUMENTATION, SpectralLibrary, SpectralLibraryPanel, SpectralLibraryWidget
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        self.ui.actionShowOnlineHelp.triggered.connect(lambda: webbrowser.open(DOCUMENTATION))
Loading
Loading full blame...