Newer
Older
# -*- coding: utf-8 -*-
"""
/***************************************************************************

Benjamin Jakimow
committed
EO Time Series Viewer
-------------------
begin : 2015-08-20
git sha : $Format:%H$
copyright : (C) 2017 by HU-Berlin
email : benjamin.jakimow@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. *
* *
***************************************************************************/
"""
# noinspection PyPep8Naming
from eotimeseriesviewer import CursorLocationMapTool
from qgis.core import *
from qgis.gui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtXml import QDomDocument
from .timeseries import TimeSeriesDate, SensorProxyLayer, SensorInstrument
from .externals.qps.crosshair.crosshair import CrosshairDialog, CrosshairStyle, CrosshairMapCanvasItem
from .externals.qps.maptools import *
from .labeling import quickLabelLayers, labelShortcutLayerClassificationSchemes, setQuickTSDLabelsForRegisteredLayers
from .externals.qps.classification.classificationscheme import ClassificationScheme, ClassInfo
from .externals.qps.utils import *
from .externals.qps.layerproperties import showLayerPropertiesDialog
import eotimeseriesviewer.settings
PROGRESS_TIMER = QTimer()
PROGRESS_TIMER.start(100)
def toQgsMimeDataUtilsUri(mapLayer:QgsMapLayer):
uri = QgsMimeDataUtils.Uri()
uri.name = mapLayer.name()
uri.providerKey = mapLayer.dataProvider().name()
uri.uri = mapLayer.source()
if isinstance(mapLayer, QgsRasterLayer):
uri.layerType = 'raster'
elif isinstance(mapLayer, QgsVectorLayer):
uri.layerType = 'vector'
else:
raise NotImplementedError()
return uri
class MapLoadingInfoItem(QgsMapCanvasItem):
def __init__(self, mapCanvas):
assert isinstance(mapCanvas, QgsMapCanvas)
super(MapLoadingInfoItem, self).__init__(mapCanvas)
self.mCanvas = mapCanvas
self.mProgressConnection = None
self.mCanvas.renderStarting.connect(lambda: self.showLoadingProgress(True))
#self.mCanvas.renderComplete.connect(lambda: self.showLoadingProgress(False))
PROGRESS_TIMER.timeout.connect(self.onProgressTimeOut)
self.mShowProgress = False
self.mIsVisible = True
def showLoadingProgress(self, showProgress: bool):
self.mShowProgress = showProgress
self.update()
def onProgressTimeOut(self):
if self.mShowProgress:
self.mCanvas.update()
def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
"""
Paints the crosshair
:param painter:
:param QStyleOptionGraphicsItem:
:param QWidget_widget:
:return:
"""
if True:
options = QStyleOptionProgressBar()
options.rect = QRect(0, 0, painter.window().width(), 25)
options.textAlignment = Qt.AlignCenter
options.progress = 0
options.maximum = 0
options.minimum = 0
QApplication.style().drawControl(QStyle.CE_ProgressBar, options, painter)
class MapCanvasInfoItem(QgsMapCanvasItem):
def __init__(self, mapCanvas):
assert isinstance(mapCanvas, QgsMapCanvas)
super(MapCanvasInfoItem, self).__init__(mapCanvas)
self.mCanvas = mapCanvas
self.mULText = None
self.mLRText = None
self.mURText = None
self.mVisibility = True
def setVisibility(self, b:bool):
:param b:
:return:
assert isinstance(b, bool)
old = self.mShow
self.mVisibility = b
if old != b:
self.mCanvas.update()
def visibility(self)->bool:
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
return self.mVisibility
def paintText(self, painter, text:str, position):
pen = QPen(Qt.SolidLine)
pen.setWidth(self.mCrosshairStyle.mThickness)
pen.setColor(self.mCrosshairStyle.mColor)
nLines = len(text.splitlines())
font = QFont('Courier', pointSize=10)
brush = self.mCanvas.backgroundBrush()
c = brush.color()
c.setAlpha(170)
brush.setColor(c)
painter.setBrush(brush)
painter.setPen(Qt.NoPen)
fm = QFontMetrics(font)
#background = QPolygonF(QRectF(backGroundPos, backGroundSize))
#painter.drawPolygon(background)
painter.setPen(pen)
painter.drawText(position, text)
painter.setFont(QFont('Courier', pointSize=10))
def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
"""
Paints the crosshair
:param painter:
:param QStyleOptionGraphicsItem:
:param QWidget_widget:
:return:
"""
if self.mLRText:
self.paintText(painter, self.mLRText, QPoint(0, 0))
class MapCanvasMapTools(QObject):
def __init__(self, canvas:QgsMapCanvas, cadDock:QgsAdvancedDigitizingDockWidget):
super(MapCanvasMapTools, self).__init__(canvas)
self.mCanvas = canvas
self.mCadDock = cadDock
self.mtZoomIn = QgsMapToolZoom(canvas, False)
self.mtZoomOut = QgsMapToolZoom(canvas, True)
self.mtMoveToCenter = MapToolCenter(canvas)
self.mtPan = QgsMapToolPan(canvas)
self.mtPixelScaleExtent = PixelScaleExtentMapTool(canvas)
self.mtFullExtentMapTool = FullExtentMapTool(canvas)
self.mtCursorLocation = CursorLocationMapTool(canvas, True)

Benjamin Jakimow
committed
self.mtAddFeature = QgsMapToolAddFeature(canvas, QgsMapToolCapture.CaptureNone, cadDock)
self.mtSelectFeature = QgsMapToolSelect(canvas)
from .externals.qps.maptools import MapTools
if mapToolKey == MapTools.ZoomIn:
self.mCanvas.setMapTool(self.mtZoomIn)
elif mapToolKey == MapTools.ZoomOut:
self.mCanvas.setMapTool(self.mtZoomOut)
elif mapToolKey == MapTools.Pan:
self.mCanvas.setMapTool(self.mtPan)
elif mapToolKey == MapTools.ZoomFull:
self.mCanvas.setMapTool(self.mtFullExtentMapTool)
elif mapToolKey == MapTools.ZoomPixelScale:
self.mCanvas.setMapTool(self.mtPixelScaleExtent)
elif mapToolKey == MapTools.CursorLocation:
self.mCanvas.setMapTool(self.mtCursorLocation)
elif mapToolKey == MapTools.SpectralProfile:
pass
elif mapToolKey == MapTools.TemporalProfile:
pass
elif mapToolKey == MapTools.MoveToCenter:
self.mCanvas.setMapTool(self.mtMoveToCenter)
elif mapToolKey == MapTools.AddFeature:
self.mCanvas.setMapTool(self.mtAddFeature)
elif mapToolKey == MapTools.SelectFeature:
self.mCanvas.setMapTool(self.mtSelectFeature)
else:
print('Unknown MapTool key: {}'.format(mapToolKey))
class MapCanvas(QgsMapCanvas):
"""
A widget based on QgsMapCanvas to draw spatial data
"""
"""
Canvas specific commands
"""
saveFileDirectories = dict()
sigShowProfiles = pyqtSignal(SpatialPoint, str)
sigSpatialExtentChanged = pyqtSignal(SpatialExtent)
#sigChangeDVRequest = pyqtSignal(QgsMapCanvas, str)
#sigChangeMVRequest = pyqtSignal(QgsMapCanvas, str)
#sigChangeSVRequest = pyqtSignal(QgsMapCanvas, QgsRasterRenderer)

Benjamin Jakimow
committed
sigCrosshairPositionChanged = pyqtSignal(SpatialPoint)
sigCrosshairVisibilityChanged = pyqtSignal(bool)

Benjamin Jakimow
committed
sigCrosshairStyleChanged = pyqtSignal(CrosshairStyle)
def __init__(self, parent=None):
super(MapCanvas, self).__init__(parent=parent)
self.mMapLayerStore = QgsProject.instance()
self.mMapTools = None
self.initMapTools()

benjamin.jakimow@geo.hu-berlin.de
committed
self.mCrosshairItem = CrosshairMapCanvasItem(self)
self.mInfoItem = MapCanvasInfoItem(self)
self.mProgressItem = MapLoadingInfoItem(self)
self.mUserInputWidget = QgsUserInputWidget(self)
self.mUserInputWidget.setObjectName('UserInputDockWidget')
self.mUserInputWidget.setAnchorWidget(self)
self.mUserInputWidget.setAnchorWidgetPoint(QgsFloatingWidget.TopRight)
self.mUserInputWidget.setAnchorPoint(QgsFloatingWidget.TopRight)
#self.mProgressBar = QProgressBar()
#self.mUserInputWidget.addUserInputWidget(self.mProgressBar)
self.mNeedsRefresh = False
self.mRenderingFinished = True
self.mIsRefreshing = False
t2 = time.time()
dt = t2 - self.mRefreshStartTime
self.sigMapRefreshed[float].emit(dt)
self.sigMapRefreshed[float, float].emit(self.mRefreshStartTime, t2)

benjamin.jakimow@geo.hu-berlin.de
committed
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
bg = eotimeseriesviewer.settings.value(eotimeseriesviewer.settings.Keys.MapBackgroundColor, default=QColor(0, 0, 0))
self.setContextMenuPolicy(Qt.DefaultContextMenu)
self.extentsChanged.connect(lambda : self.sigSpatialExtentChanged.emit(self.spatialExtent()))
def userInputWidget(self)->QgsUserInputWidget:
"""
Returns the mapcanvas QgsUserInputWidget
:return: QgsUserInputWidget
"""
return self.mUserInputWidget
def mapView(self):
"""
Returns the MapView this MapCanvas is linked to
:return:
"""
return self.mMapView
def mapTools(self)->MapCanvasMapTools:
"""
Returns the map tools of this MapCanvas
:return: MapCanvasMapTools
"""
return self.mMapTools
def initMapTools(self):
self.mCadDock = QgsAdvancedDigitizingDockWidget(self)
self.mCadDock.setVisible(False)
self.mMapTools = MapCanvasMapTools(self, self.mCadDock)
def setMapLayerStore(self, store):
"""
Sets the QgsMapLayerStore or QgsProject instance that is used to register map layers
:param store: QgsMapLayerStore | QgsProject
"""
assert isinstance(store, (QgsMapLayerStore, QgsProject))
self.mMapLayerStore = store
def renderingFinished(self)->bool:
"""
Returns whether the MapCanvas is processing a rendering task
:return: bool
"""
return self.mRenderingFinished

Benjamin Jakimow
committed
def mousePressEvent(self, event:QMouseEvent):
b = event.button() == Qt.LeftButton
if b and isinstance(self.mapTool(), QgsMapTool):
b = isinstance(self.mapTool(), (QgsMapToolIdentify,
CursorLocationMapTool,
SpectralProfileMapTool, TemporalProfileMapTool))
super(MapCanvas, self).mousePressEvent(event)
if b:
ms = self.mapSettings()
pointXY = ms.mapToPixel().toMapCoordinates(event.x(), event.y())
spatialPoint = SpatialPoint(ms.destinationCrs(), pointXY)
self.setCrosshairPosition(spatialPoint)
from eotimeseriesviewer.mapvisualization import MapView
assert isinstance(mapView, MapView)
self.mMapView = mapView
def setTSD(self, tsd:TimeSeriesDate):
Sets the TimeSeriesDate this map-canvas is linked to
assert isinstance(tsd, TimeSeriesDate)

Benjamin Jakimow
committed
scope = self.expressionContextScope()
scope.setVariable('map_date', str(tsd.date()), isStatic=True)
scope.setVariable('map_doy', tsd.doy(), isStatic=True)
scope.setVariable('map_sensor', tsd.sensor().name(), isStatic=False)
tsd.sensor().sigNameChanged.connect(lambda name: scope.setVariable('map_sensor', name))
def tsd(self)->TimeSeriesDate:
Returns the TimeSeriesDate
:return: TimeSeriesDate

Benjamin Jakimow
committed
def setSpatialExtent(self, extent:SpatialExtent):
"""
Sets the spatial extent
:param extent: SpatialExtent
"""
assert isinstance(extent, SpatialExtent)
extent = extent.toCrs(self.crs())
self.setExtent(extent)
def setSpatialCenter(self, center:SpatialPoint):
"""
Sets the SpatialCenter
:param center: SpatialPoint
"""
assert isinstance(center, SpatialPoint)
center = center.toCrs(self.crs())
self.setCenter(center)
def setFixedSize(self, size:QSize):
"""
Changes the map-canvas size
:param size: QSize
"""
assert isinstance(size, QSize)
if self.size() != size:
super(MapCanvas, self).setFixedSize(size)
if self.crs() != crs:
self.setDestinationCrs(crs)
"""
Shortcut to return self.mapSettings().destinationCrs()
:return: QgsCoordinateReferenceSystem
"""
return self.mapSettings().destinationCrs()
def setLayers(self, mapLayers):
"""
Set the map layers and, if necessary, registers the in a QgsMapLayerStore
:param mapLayers:
"""
self.mMapLayerStore.addMapLayers(mapLayers)
super(MapCanvas, self).setLayers(mapLayers)
def isVisibleToViewport(self)->bool:
"""
Returns whether the MapCanvas is visible to a user and not hidden behind the invisible regions of a scroll area.
:return: bool
"""
return self.visibleRegion().boundingRect().isValid()
def addToRefreshPipeLine(self, arguments: list):
"""
Adds commands or other arguments to a pipeline which will be handled during the next timed refresh.
:param arguments: argument | [list-of-arguments]
"""
if not isinstance(arguments, list):
arguments = [arguments]
if isinstance(a, SpatialExtent):
elif isinstance(a, SpatialPoint):
self.mTimedRefreshPipeLine[SpatialExtent] = a
elif isinstance(a, QColor):
self.mTimedRefreshPipeLine[QColor] = a
elif isinstance(a, MapCanvas.Command):
if not MapCanvas.Command in self.mTimedRefreshPipeLine.keys():
self.mTimedRefreshPipeLine[MapCanvas.Command] = []
# remove previous commands of same type, append command to end
while a in self.mTimedRefreshPipeLine[MapCanvas.Command]:
self.mTimedRefreshPipeLine[MapCanvas.Command].remove(a)
self.mTimedRefreshPipeLine[MapCanvas.Command].append(a)
else:
raise NotImplementedError('Unsupported argument: {}'.format(str(a)))
def timedRefresh(self):
"""
Called to refresh the map canvas with all things needed to be done with lazy evaluation
expected = []
existing = self.layers()
existingSources = [l.source() for l in existing]
for lyr in self.mMapView.layers():
assert isinstance(lyr, QgsMapLayer)
if isinstance(lyr, SensorProxyLayer):
if self.tsd().sensor() == lyr.sensor():
for source in self.tsd().sourceUris():
sourceLayer = None
if source in existingSources:
sourceLayer = existing[existingSources.index(source)]
else:
sourceLayer = SensorProxyLayer(source, sensor=self.tsd().sensor())
sourceLayer.setName(lyr.name())
sourceLayer.setCustomProperty('eotsv/sensorid', self.tsd().sensor().id())
try:
renderer = lyr.renderer()
if isinstance(renderer, QgsRasterRenderer):
sourceLayer.setRenderer(renderer.clone())
except Exception as exR:
s = ""
assert isinstance(sourceLayer, QgsRasterLayer)
expected.append(sourceLayer)
else:
# skip any other SensorProxyLayer that relates to another sensor
pass
else:
expected.append(lyr)
if len(self.mTimedRefreshPipeLine) == 0 and self.layers() == expected:
# there is nothing to do.
# look for new layers
lyrs = self.layers()
if lyrs != expected:
self.setLayers(expected)
if True:
# set sources first
keys = self.mTimedRefreshPipeLine.keys()
if QgsCoordinateReferenceSystem in keys:
self.setDestinationCrs(self.mTimedRefreshPipeLine[QgsCoordinateReferenceSystem])
if SpatialExtent in keys:
self.setSpatialExtent(self.mTimedRefreshPipeLine[SpatialExtent])
if SpatialPoint in keys:
self.setSpatialCenter(self.mTimedRefreshPipeLine[SpatialPoint])
if QColor in keys:
self.setCanvasColor(self.mTimedRefreshPipeLine[QColor])
if MapCanvas.Command in keys:
commands = self.mTimedRefreshPipeLine[MapCanvas.Command]
for command in commands:
assert isinstance(command, MapCanvas.Command)
if command == MapCanvas.Command.RefreshRenderer:
for px in [px for px in self.mMapView.layers() if isinstance(px, SensorProxyLayer)]:
for l in self.layers():
if isinstance(l, SensorProxyLayer) and l.sensor() == px.sensor():
try:
renderer = px.renderer().clone()
renderer.setInput(l.dataProvider())
l.setRenderer(renderer)
except Exception as ex:
s = ""
self.mTimedRefreshPipeLine.clear()
def setLayerVisibility(self, cls, isVisible:bool):
"""
:param cls: type of layer, e.g. QgsRasterLayer to set visibility of all layers of same type
QgsMapLayer instance to the visibility of a specific layer
:param isVisible: bool
"""
self.mMapLayerModel.setLayerVisibility(cls, isVisible)
self.addToRefreshPipeLine(MapCanvas.Command.RefreshVisibility)
def setCrosshairStyle(self, crosshairStyle:CrosshairStyle, emitSignal=True):
"""
Sets the CrosshairStyle
:param crosshairStyle: CrosshairStyle
:param emitSignal: Set to Fals to no emit a signal.
"""
from eotimeseriesviewer import CrosshairStyle
if crosshairStyle is None:

Benjamin Jakimow
committed
self.mCrosshairItem.crosshairStyle.setShow(False)
self.mCrosshairItem.update()
else:
assert isinstance(crosshairStyle, CrosshairStyle)

Benjamin Jakimow
committed
self.mCrosshairItem.setCrosshairStyle(crosshairStyle)

Benjamin Jakimow
committed
if emitSignal:
self.sigCrosshairStyleChanged.emit(self.mCrosshairItem.crosshairStyle())

Benjamin Jakimow
committed
def crosshairStyle(self)->CrosshairStyle:
"""
Returns the style of the Crosshair.
:return: CrosshairStyle
"""

Benjamin Jakimow
committed
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
return self.mCrosshairItem.crosshairStyle
def setCrosshairPosition(self, spatialPoint:SpatialPoint, emitSignal=True):
"""
Sets the position of the Crosshair.
:param spatialPoint: SpatialPoint
:param emitSignal: True (default). Set False to avoid emitting sigCrosshairPositionChanged
:return:
"""
point = spatialPoint.toCrs(self.mapSettings().destinationCrs())
self.mCrosshairItem.setPosition(point)
if emitSignal:
self.sigCrosshairPositionChanged.emit(point)
def crosshairPosition(self)->SpatialPoint:
"""Returns the last crosshair position"""
return self.mCrosshairItem.mPosition
def setCrosshairVisibility(self, b:bool, emitSignal=True):
"""
Sets the Crosshair visbility
:param b: bool
"""
if b and self.mCrosshairItem.mPosition is None:
self.mCrosshairItem.setPosition(self.spatialCenter())
self.sigCrosshairPositionChanged.emit(self.spatialCenter())
if b != self.mCrosshairItem.visibility():
self.mCrosshairItem.setVisibility(b)
if emitSignal:
self.sigCrosshairVisibilityChanged.emit(b)
def layerPaths(self):
:return: [list-of-str]

benjamin.jakimow@geo.hu-berlin.de
committed
return [str(l.source()) for l in self.layers()]
def pixmap(self):
"""
Returns the current map image as pixmap
return self.grab()
def contextMenu(self, pos:QPoint)->QMenu:
"""
Create the MapCanvas context menu with options relevant for pixel position ``pos``.
:param pos: QPoint
:return: QMenu
"""
mapSettings = self.mapSettings()
assert isinstance(mapSettings, QgsMapSettings)
pointGeo = mapSettings.mapToPixel().toMapCoordinates(pos.x(), pos.y())
assert isinstance(pointGeo, QgsPointXY)
from .main import TimeSeriesViewer
eotsv = TimeSeriesViewer.instance()

Benjamin Jakimow
committed
viewPortMapLayers = [l for l in self.layers() if isinstance(l, QgsMapLayer)]

Benjamin Jakimow
committed

Benjamin Jakimow
committed
viewPortRasterLayers = [l for l in viewPortMapLayers if isinstance(l, QgsRasterLayer) and SpatialExtent.fromLayer(l).toCrs(self.crs()).contains(pointGeo)]
viewPortSensorLayers = [l for l in viewPortRasterLayers if isinstance(l, SensorProxyLayer)]
viewPortVectorLayers = [l for l in viewPortMapLayers if isinstance(l, QgsVectorLayer)]

Benjamin Jakimow
committed
refSensorLayer = None
refRasterLayer = None
if len(viewPortRasterLayers) > 0:
refRasterLayer = viewPortRasterLayers[0]
if len(viewPortSensorLayers) > 0:
refSensorLayer = viewPortSensorLayers[0]
menu = QMenu()
if isinstance(self.tsd(), TimeSeriesDate):

Benjamin Jakimow
committed
tss = None
sourceUris = self.tsd().sourceUris()
for sl in viewPortSensorLayers:
if sl.source() in sourceUris:
tss = self.tsd()[sourceUris.index(sl.source())]
break
lyrWithSelectedFeatures = [l for l in quickLabelLayers() if l.isEditable() and l.selectedFeatureCount() > 0]
layerNames = ', '.join([l.name() for l in lyrWithSelectedFeatures])
m = menu.addMenu('Quick Labels'.format(self.tsd().date()))
nQuickLabelLayers = len(lyrWithSelectedFeatures)
m.setEnabled(nQuickLabelLayers > 0)
a = m.addAction('Set Date/Sensor attributes')
a.setToolTip('Writes the date ate and sensor quick labels of selected features in {}.'.format(layerNames))

Benjamin Jakimow
committed
a.triggered.connect(lambda *args, tsd = self.tsd(), tss=tss: setQuickTSDLabelsForRegisteredLayers(tsd, tss))
from .labeling import EDITOR_WIDGET_REGISTRY_KEY as QUICK_LABEL_KEY
from .labeling import CONFKEY_CLASSIFICATIONSCHEME, layerClassSchemes, setQuickClassInfo
for layer in lyrWithSelectedFeatures:
assert isinstance(layer, QgsVectorLayer)
csf = layerClassSchemes(layer)
if len(csf) > 0:
m.addSection(layer.name())
for (cs, field) in csf:
assert isinstance(cs, ClassificationScheme)
assert isinstance(field, QgsField)
classMenu = m.addMenu('"{}" ({})'.format(field.name(), field.typeName()))
for classInfo in cs:
assert isinstance(classInfo, ClassInfo)
a = classMenu.addAction('{} "{}"'.format(classInfo.label(), classInfo.name()))
a.setIcon(classInfo.icon())
a.triggered.connect(lambda _, vl=layer, f=field, c=classInfo: setQuickClassInfo(vl, f, c))

Benjamin Jakimow
committed
if isinstance(refSensorLayer, SensorProxyLayer):
m = menu.addMenu('Raster stretch...')
action = m.addAction('Linear')
action.triggered.connect(lambda *args, lyr=refSensorLayer: self.stretchToExtent(self.spatialExtent(), 'linear_minmax', layer=lyr, p=0.0))
action = m.addAction('Linear 5%')
action.triggered.connect(lambda *args, lyr=refSensorLayer: self.stretchToExtent(self.spatialExtent(), 'linear_minmax', layer=lyr, p=0.05))
action = m.addAction('Gaussian')
action.triggered.connect(lambda *args, lyr=refSensorLayer: self.stretchToExtent(self.spatialExtent(), 'gaussian', layer=lyr, n=3))
menu.addSeparator()
from .externals.qps.layerproperties import pasteStyleFromClipboard, pasteStyleToClipboard
b = isinstance(refRasterLayer, QgsRasterLayer)
a = menu.addAction('Copy Style')
a.setEnabled(b)
a.setToolTip('Copy the current layer style to clipboard')
a.triggered.connect(lambda *args, lyr=refRasterLayer: pasteStyleToClipboard(lyr))

Benjamin Jakimow
committed
a = menu.addAction('Paste Style')
a.setEnabled(b)
a.setEnabled('application/qgis.style' in QApplication.clipboard().mimeData().formats())
a.triggered.connect(lambda *args, lyr=refRasterLayer: self.onPasteStyleFromClipboard(lyr))
menu.addSeparator()
m = menu.addMenu('Layers...')
visibleLayers = viewPortRasterLayers + viewPortVectorLayers
for mapLayer in visibleLayers:
#sub = m.addMenu(mapLayer.name())
sub = m.addMenu(os.path.basename(mapLayer.source()))
if isinstance(mapLayer, SensorProxyLayer):
sub.setIcon(QIcon(':/timeseriesviewer/icons/icon.svg'))
elif isinstance(mapLayer, QgsRasterLayer):
sub.setIcon(QIcon(''))
elif isinstance(mapLayer, QgsVectorLayer):
wkbType = QgsWkbTypes.displayString(int(mapLayer.wkbType()))
if re.search('polygon', wkbType, re.I):
sub.setIcon(QIcon(r':/images/themes/default/mIconPolygonLayer.svg'))
elif re.search('line', wkbType, re.I):
sub.setIcon(QIcon(r':/images/themes/default/mIconLineLayer.svg'))
elif re.search('point', wkbType, re.I):
sub.setIcon(QIcon(r':/images/themes/default/mIconPointLayer.svg'))
a = sub.addAction('Properties...')
a.triggered.connect(lambda *args,
lyr = mapLayer,
c = self,
b = isinstance(mapLayer, SensorProxyLayer) == False:
showLayerPropertiesDialog(lyr, c, useQGISDialog=b))
a = sub.addAction('Zoom to Layer')
a.setIcon(QIcon(':/images/themes/default/mActionZoomToLayer.svg'))
a.triggered.connect(lambda *args, lyr=mapLayer: self.setSpatialExtent(SpatialExtent.fromLayer(lyr)))

Benjamin Jakimow
committed
a = sub.addAction('Copy Style')
a.setToolTip('Copy layer style to clipboard')
a.triggered.connect(lambda *args, lyr=mapLayer: pasteStyleToClipboard(lyr))
a = sub.addAction('Paste Style')
a.setToolTip('Paster layer style from clipboard')
a.setEnabled('application/qgis.style' in QApplication.clipboard().mimeData().formats())
a.triggered.connect(lambda *args, lyr=mapLayer: self.onPasteStyleFromClipboard(lyr))
menu.addSeparator()
action = menu.addAction('Zoom to full extent')
action.setIcon(QIcon(':/images/themes/default/mActionZoomFullExtent.svg'))
action.triggered.connect(lambda: self.setExtent(self.fullExtent()))
menu.addSeparator()
m = menu.addMenu('Crosshair...')
action = m.addAction('Show')
action.setCheckable(True)
action.setChecked(self.mCrosshairItem.visibility())
action.toggled.connect(self.setCrosshairVisibility)

Benjamin Jakimow
committed
def onCrosshairChange(*args):
style = CrosshairDialog.getCrosshairStyle(parent=self,
mapCanvas=self,
crosshairStyle=self.mCrosshairItem.crosshairStyle)

Benjamin Jakimow
committed
if isinstance(style, CrosshairStyle):
self.setCrosshairStyle(style)
action.triggered.connect(onCrosshairChange)
if isinstance(tsd, TimeSeriesDate):
menu.addSeparator()
m = menu.addMenu('Copy...')
action = m.addAction('Date')
action.triggered.connect(lambda: QApplication.clipboard().setText(str(tsd.date())))
action.setToolTip('Sends "" to the clipboard.'.format(str(tsd.date())))
action = m.addAction('Sensor')
action.triggered.connect(lambda: QApplication.clipboard().setText(tsd.sensor().name()))
action.setToolTip('Sends "" to the clipboard.'.format(tsd.sensor().name()))
action = m.addAction('Path')
action.triggered.connect(lambda: QApplication.clipboard().setText('\n'.join(tsd.sourceUris())))
action.setToolTip('Sends the {} source URI(s) to the clipboard.'.format(len(tsd)))
action = m.addAction('Map')
action.triggered.connect(lambda: QApplication.clipboard().setPixmap(self.pixmap()))
action.setToolTip('Copies this map into the clipboard.')

benjamin.jakimow@geo.hu-berlin.de
committed
m = menu.addMenu('Map Coordinates...')
ext = self.spatialExtent()
center = self.spatialExtent().spatialCenter()
action = m.addAction('Extent (WKT Coordinates)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktCoordinates()))
action = m.addAction('Extent (WKT Polygon)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktPolygon()))
m.addSeparator()
action = m.addAction('Map Center (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(center.asWkt()))

benjamin.jakimow@geo.hu-berlin.de
committed

benjamin.jakimow@geo.hu-berlin.de
committed
action.triggered.connect(lambda: QApplication.clipboard().setText(center.toString()))
action = m.addAction('Map Extent (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.asWktPolygon()))
action = m.addAction('Map Extent')
action.triggered.connect(lambda: QApplication.clipboard().setText(ext.toString()))

benjamin.jakimow@geo.hu-berlin.de
committed
m.addSeparator()
action = m.addAction('CRS (EPSG)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().authid()))
action = m.addAction('CRS (WKT)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().toWkt()))
action = m.addAction('CRS (Proj4)')
action.triggered.connect(lambda: QApplication.clipboard().setText(self.crs().toProj4()))
action = m.addAction('PNG')
action.triggered.connect(lambda: self.saveMapImageDialog('PNG'))
action = m.addAction('JPEG')
action.triggered.connect(lambda: self.saveMapImageDialog('JPG'))

benjamin.jakimow@geo.hu-berlin.de
committed

Benjamin Jakimow
committed
classSchemes = []
for layer in lyrWithSelectedFeaturs:
for classScheme in layerClassSchemes(layer):
assert isinstance(classScheme, ClassificationScheme)
if classScheme in classSchemes:
continue
classMenu = m.addMenu('Classification "{}"'.format(classScheme.name()))
assert isinstance(classMenu, QMenu)
for classInfo in classScheme:
assert isinstance(classInfo, ClassInfo)
a = classMenu.addAction(classInfo.name())
a.setIcon(classInfo.icon())
a.setToolTip('Write "{}" or "{}" to connected vector field attributes'.format(classInfo.name(), classInfo.label()))

Benjamin Jakimow
committed
a.triggered.connect(

Benjamin Jakimow
committed
applyShortcutsToRegisteredLayers(tsd, [ci]))
classSchemes.append(classScheme)
if isinstance(self.mTSD, TimeSeriesDate):
action = menu.addAction('Focus on Spatial Extent')
action.triggered.connect(self.onFocusToCurrentSpatialExtent)
action = menu.addAction('Hide Date')
action.triggered.connect(lambda: self.mTSD.setIsVisible(False))
if isinstance(eotsv, TimeSeriesViewer):
ts = eotsv.timeSeries()
action = menu.addAction('Remove Date')
action.triggered.connect(lambda *args, : ts.removeTSDs([tsd]))
#action = menu.addAction('Hide map view')
#action.triggered.connect(lambda: self.sigChangeMVRequest.emit(self, 'hide_mapview'))
#action = menu.addAction('Remove map view')
#action.triggered.connect(lambda: self.sigChangeMVRequest.emit(self, 'remove_mapview'))
return menu
def onFocusToCurrentSpatialExtent(self):
mapView = self.mapView()
from .mapvisualization import MapView
if isinstance(mapView, MapView):
mapView.timeSeries().focusVisibilityToExtent()

Benjamin Jakimow
committed
def onPasteStyleFromClipboard(self, lyr):
from .externals.qps.layerproperties import pasteStyleFromClipboard
pasteStyleFromClipboard(lyr)
if isinstance(lyr, SensorProxyLayer):
self.mMapView.sensorProxyLayer(lyr.sensor()).setRenderer(lyr.renderer().clone())
def contextMenuEvent(self, event:QContextMenuEvent):
"""
Create and shows the MapCanvas context menu.
:param event: QEvent
"""
assert isinstance(event, QContextMenuEvent)
menu = self.contextMenu(event.pos())
menu.exec_(event.globalPos())
from eotimeseriesviewer.utils import qgisInstance
iface = qgisInstance()
if isinstance(iface, QgisInterface):
grpNode= iface.layerTreeView().currentGroupNode()
assert isinstance(grpNode, QgsLayerTreeGroup)
for l in mapLayers:
if isinstance(l, QgsRasterLayer):
lqgis = iface.addRasterLayer(l.source(), l.name())
lqgis.setRenderer(l.renderer().clone())
lqgis = iface.addVectorLayer(l.source(), l.name(), 'ogr')
def stretchToCurrentExtent(self):
se = self.spatialExtent()

Benjamin Jakimow
committed
def stretchToExtent(self, spatialExtent:SpatialExtent, stretchType='linear_minmax', layer:QgsRasterLayer=None, **stretchArgs):
"""
:param spatialExtent: rectangle to get the image statistics for
:param stretchType: ['linear_minmax' (default), 'gaussian']
:param stretchArgs:
linear_minmax: 'p' percentage from min/max, e.g. +- 5 %
gaussian: 'n' mean +- n* standard deviations
:return:
"""

Benjamin Jakimow
committed
if not isinstance(layer, QgsRasterLayer):
layers = [l for l in self.layers() if isinstance(l, SensorProxyLayer)]
if len(layers) > 0:
layer = layers[0]
else:
layers = [l for l in self.layers() if isinstance(l, SensorProxyLayer)]
if len(layers) > 0:
layer = layers[0]

Benjamin Jakimow
committed
if not isinstance(layer, QgsRasterLayer):
return

Benjamin Jakimow
committed
r = layer.renderer()
dp = layer.dataProvider()
newRenderer = None
extent = spatialExtent.toCrs(layer.crs())
assert isinstance(dp, QgsRasterDataProvider)
def getCE(band):
stats = dp.bandStatistics(band, QgsRasterBandStats.All, extent, 256)
ce = QgsContrastEnhancement(dp.dataType(band))
d = (stats.maximumValue - stats.minimumValue)