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):

Benjamin Jakimow
committed
"""
A QgsMapCanvasItem to show text
"""
def __init__(self, mapCanvas):
assert isinstance(mapCanvas, QgsMapCanvas)
super(MapCanvasInfoItem, self).__init__(mapCanvas)
self.mCanvas = mapCanvas

Benjamin Jakimow
committed
self.mText = dict()
self.mWrapChar = '\n'
self.mTextFormat = QgsTextFormat()
self.mTextFormat.setSizeUnit(QgsUnitTypes.RenderPixels)
self.mTextFormat.setFont(QFont('Helvetica', pointSize=10))
self.mTextFormat.setColor(QColor('yellow'))
def setWrapChar(self, c:str)->str:
"""
Sets a Wrap Character
:param c:
:return:
"""
self.mWrapChar = c
return self.wrapChar()

Benjamin Jakimow
committed
def wrapChar(self)->str:
return self.mWrapChar

Benjamin Jakimow
committed
def setText(self, text:str, alignment:Qt.Alignment=Qt.AlignTop | Qt.AlignHCenter):

Benjamin Jakimow
committed
self.mText[alignment] = text
def setTextFormat(self, format:QgsTextFormat):
assert isinstance(format, QgsTextFormat)
self.mTextFormat = format
self.updateCanvas()
def textFormat(self)->QgsTextFormat:
"""
Returns the text format.
:return: QgsTextFormat
"""
return self.mTextFormat
def font(self)->QFont:
"""
Returns the font used to write text on the map canvas.
:return: QFont
"""
return self.mTextFormat.font()
def setFont(self, font:QFont):
self.mTextFormat.setFont(font)
"""
Sets the map info color
:param color: QColor
"""

Benjamin Jakimow
committed
self.mTextFormat.setColor(color)
"""
Returns the info text color
:return: QColor
"""

Benjamin Jakimow
committed
return self.mTextFormat.color()

Benjamin Jakimow
committed
def paintText(self, painter, text:str, flags, rotation=0):
padding = 5
text = text.replace('\\n', '\n')
text = text.split(self.wrapChar())

Benjamin Jakimow
committed
nl = len(text)
#text = text.split('\\n')
r = QgsTextRenderer()

Benjamin Jakimow
committed
painter.setBrush(Qt.NoBrush)
painter.setPen(Qt.NoPen)
painter.setRenderHint(QPainter.Antialiasing)

Benjamin Jakimow
committed
context = QgsRenderContext()

Benjamin Jakimow
committed
# taken from QGIS Repo src/core/qgspallabeling.cpp
m2p = QgsMapToPixel(1, 0, 0, 0, 0, 0)
context.setMapToPixel(m2p)
context.setScaleFactor(QgsApplication.desktop().logicalDpiX() / 25.4)
context.setUseAdvancedEffects(True)
context.setPainter(painter)
#context.setExtent(self.mCanvas.extent())
#context.setExpressionContext(self.mCanvas.mapSettings().expressionContext())

Benjamin Jakimow
committed
vp = QRectF(painter.viewport())
#rect = self.mCanvas.extent().toRectF()

Benjamin Jakimow
committed
textFormat = self.mTextFormat
assert isinstance(textFormat, QgsTextFormat)
th = r.textHeight(context, textFormat, text, QgsTextRenderer.Rect)
tw = r.textWidth(context, textFormat, text)

Benjamin Jakimow
committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# area to place the text inside
rect = QRectF()
x = 0.5*vp.width()
y = 0.5*vp.height()
hAlign = QgsTextRenderer.AlignCenter
# horizontal position
if bool(flags & Qt.AlignLeft):
x = padding
hAlign = QgsTextRenderer.AlignLeft
elif bool(flags & Qt.AlignHCenter):
x = 0.5 * vp.width()
hAlign = QgsTextRenderer.AlignCenter
elif bool(flags & Qt.AlignRight):
x = vp.width() - padding
hAlign = QgsTextRenderer.AlignRight
# vertical position
if bool(flags & Qt.AlignTop):
y = padding + th - 0.5* (th / nl)
elif bool(flags & Qt.AlignVCenter):
y = 0.5 * (vp.height() + th)
elif bool(flags & Qt.AlignBottom):
y = vp.height() - padding #- th
poo = QPointF(x, y)
r.drawText(poo, rotation, hAlign, text, context, textFormat)
def setUpperLeft(self, text:str):
self.setText(text, Qt.AlignTop | Qt.AlignLeft)
def setMiddleLeft(self, text: str):
self.setText(text, Qt.AlignVCenter | Qt.AlignLeft)
def setLowerLeft(self, text: str):
self.setText(text, Qt.AlignBottom | Qt.AlignLeft)
def setUpperCenter(self, text:str):
self.setText(text, Qt.AlignTop | Qt.AlignHCenter)
def setMiddleCenter(self, text: str):
self.setText(text, Qt.AlignVCenter | Qt.AlignHCenter)
def setLowerCenter(self, text: str):
self.setText(text, Qt.AlignBottom | Qt.AlignHCenter)
def setUpperRight(self, text:str):
self.setText(text, Qt.AlignTop | Qt.AlignRight)
def setMiddleRight(self, text: str):
self.setText(text, Qt.AlignVCenter | Qt.AlignRight)
def setLowerRight(self, text: str):
self.setText(text, Qt.AlignBottom | Qt.AlignRight)
def clearText(self):
self.mText.clear()
def paint(self, painter, QStyleOptionGraphicsItem=None, QWidget_widget=None):
"""
Paints the crosshair
:param painter:
:param QStyleOptionGraphicsItem:
:param QWidget_widget:
:return:
"""

Benjamin Jakimow
committed
for alignment, text in self.mText.items():
if isinstance(text, str) and len(text) > 0:
self.paintText(painter, text, alignment)
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)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectSimple)
elif mapToolKey == MapTools.SelectFeatureByPolygon:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectPolygon)
elif mapToolKey == MapTools.SelectFeatureByFreehand:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectFreehand)
elif mapToolKey == MapTools.SelectFeatureByRadius:
self.mCanvas.setMapTool(self.mtSelectFeature)
self.mtSelectFeature.setSelectionMode(QgsMapToolSelectionHandler.SelectionMode.SelectRadius)
else:
print('Unknown MapTool key: {}'.format(mapToolKey))
# if undefined, set a current vector layer
if mapToolKey in [MapTools.SelectFeature, MapTools.SelectFeatureByPolygon, MapTools.SelectFeatureByRadius, MapTools.SelectFeatureByFreehand] \
and self.mCanvas.currentLayer() is None:
for vl in self.mCanvas.layers():
if isinstance(vl, QgsVectorLayer):
self.mCanvas.setCurrentLayer(vl)
break
class MapCanvas(QgsMapCanvas):
"""
A widget based on QgsMapCanvas to draw spatial data
"""
"""
Canvas specific commands
"""
UpdateMapItems = 5
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)
sigDestinationCrsChanged = pyqtSignal(QgsCoordinateReferenceSystem)

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()))
self.destinationCrsChanged.connect(lambda : self.sigDestinationCrsChanged.emit(self.crs()))
def userInputWidget(self)->QgsUserInputWidget:
"""
Returns the mapcanvas QgsUserInputWidget
:return: QgsUserInputWidget
"""
return self.mUserInputWidget
def infoItem(self)->MapCanvasInfoItem:
"""
Returns the MapCanvasInfoItem, e.g. to plot text on top of the map canvas
:return: MapCanvasInfoItem
"""
return self.mInfoItem
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)
"""
Sets the map canvas MapView
:param mapView: MapView
"""
from eotimeseriesviewer.mapvisualization import MapView

Benjamin Jakimow
committed
self.mInfoItem.setTextFormat(mapView.mapTextFormat())
self.addToRefreshPipeLine(mapView.mapBackgroundColor())
self.addToRefreshPipeLine(MapCanvas.Command.UpdateMapItems)
def setTSD(self, tsd:TimeSeriesDate):
Sets the TimeSeriesDate this map-canvas is linked to
if self.mTSD == tsd:
return
# disconnect old TSD
if isinstance(self.mTSD, TimeSeriesDate):
self.mTSD.sensor().sigNameChanged.disconnect(self.updateScope)
self.mTSD = tsd
if isinstance(tsd, TimeSeriesDate):
self.mTSD.sensor().sigNameChanged.connect(self.updateScope)
self.updateScope()
def updateScope(self):
"""
Updates map-canvas TSD variables
"""
from .mapvisualization import MapView
from .main import TimeSeriesViewer
varMVNumber = None
varMVName = None
varDate = None
varDOY = None
varSensor = None
tsd = self.tsd()
if isinstance(tsd, TimeSeriesDate):
varDate = str(tsd.date())
varDOY = tsd.doy()
varSensor = tsd.sensor().name()
mv = self.mapView()
if isinstance(mv, MapView):
varMVName = mv.name()
if isinstance(TimeSeriesViewer.instance(), TimeSeriesViewer):
mapViews = TimeSeriesViewer.instance().mapViews()
if mv in mapViews:
varMVNumber = mapViews.index(mv) + 1
scope = self.expressionContextScope()
scope.setVariable('map_view_num', varMVNumber, isStatic=False)
scope.setVariable('map_view', varMVName, isStatic=False)
scope.setVariable('map_date', varDate, isStatic=False)
scope.setVariable('map_doy', varDOY, isStatic=False)
scope.setVariable('map_sensor', varSensor, isStatic=False)
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):
self.mTimedRefreshPipeLine[SpatialPoint] = 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)
print('Unsupported argument: {} {}'.format(type(a), str(a)), file=sys.stderr)
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]
if self.mapView() is None or self.tsd() is None:
self.setLayers([])
self.mInfoItem.clearText()
self.update()
return
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:

Benjamin Jakimow
committed
loptions = QgsRasterLayer.LayerOptions(loadDefaultStyle=False)
sourceLayer = SensorProxyLayer(source, sensor=self.tsd().sensor(), options=loptions)
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 = ""
if command == MapCanvas.Command.UpdateMapItems:
#self.update()
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
return self.mCrosshairItem.crosshairStyle
def setCrosshairPosition(self, spatialPoint:SpatialPoint):

Benjamin Jakimow
committed
"""
Sets the position of the Crosshair.
:param spatialPoint: SpatialPoint
:param emitSignal: True (default). Set False to avoid emitting sigCrosshairPositionChanged
:return:
"""

Benjamin Jakimow
committed
point = spatialPoint.toCrs(self.mapSettings().destinationCrs())
if self.mCrosshairItem.mPosition != point:
self.mCrosshairItem.setPosition(point)

Benjamin Jakimow
committed
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:
"""
Creates 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])
nQuickLabelLayers = len(lyrWithSelectedFeatures)
m.setEnabled(nQuickLabelLayers > 0)
a.setToolTip('Writes the dates 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 CONFKEY_CLASSIFICATIONSCHEME, layerClassSchemes, setQuickClassInfo
if len(lyrWithSelectedFeatures) == 0:
a = m.addAction('No features selected.')
a.setToolTip('Select feature in the labeling panel to apply Quick label value on.')
a.setEnabled(False)
else:
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))

Benjamin Jakimow
committed
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())
if isinstance(mapLayer, SensorProxyLayer):
name = os.path.basename(mapLayer.source())
else:
name = mapLayer.name()
sub = m.addMenu(name)
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,
#b = isinstance(mapLayer, SensorProxyLayer) == False:
b = True:
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))