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

Benjamin Jakimow
committed
import sys, re, collections, traceback

Benjamin Jakimow
committed
import bisect
from qgis import *
from qgis.core import *
from qgis.gui import *

Benjamin Jakimow
committed
from qgis.PyQt.QtGui import *
from qgis.PyQt.QtWidgets import *
from qgis.PyQt.QtCore import *

Benjamin Jakimow
committed
from osgeo import gdal
from timeseriesviewer.utils import SpatialExtent, loadUI

benjamin.jakimow@geo.hu-berlin.de
committed
gdal.SetConfigOption('VRT_SHARED_SOURCE', '0') #!important. really. do not change this.

Benjamin Jakimow
committed
from timeseriesviewer import SETTINGS, messageLog
from timeseriesviewer.dateparser import parseDateFromDataSet
def transformGeometry(geom, crsSrc, crsDst, trans=None):
if trans is None:
assert isinstance(crsSrc, QgsCoordinateReferenceSystem)
assert isinstance(crsDst, QgsCoordinateReferenceSystem)
return transformGeometry(geom, None, None, trans=QgsCoordinateTransform(crsSrc, crsDst))
else:
assert isinstance(trans, QgsCoordinateTransform)
return trans.transform(geom)
METRIC_EXPONENTS = {
"nm":-9,"um": -6, "mm":-3, "cm":-2, "dm":-1, "m": 0,"hm":2, "km":3
}
#add synonyms
METRIC_EXPONENTS['nanometers'] = METRIC_EXPONENTS['nm']
METRIC_EXPONENTS['micrometers'] = METRIC_EXPONENTS['um']
METRIC_EXPONENTS['millimeters'] = METRIC_EXPONENTS['mm']
METRIC_EXPONENTS['centimeters'] = METRIC_EXPONENTS['cm']
METRIC_EXPONENTS['decimeters'] = METRIC_EXPONENTS['dm']
METRIC_EXPONENTS['meters'] = METRIC_EXPONENTS['m']
METRIC_EXPONENTS['hectometers'] = METRIC_EXPONENTS['hm']
METRIC_EXPONENTS['kilometers'] = METRIC_EXPONENTS['km']
def convertMetricUnit(value, u1, u2):
assert u1 in METRIC_EXPONENTS.keys()
assert u2 in METRIC_EXPONENTS.keys()
e1 = METRIC_EXPONENTS[u1]
e2 = METRIC_EXPONENTS[u2]
return value * 10**(e1-e2)
def getDS(pathOrDataset):
if isinstance(pathOrDataset, gdal.Dataset):
return pathOrDataset
else:
ds = gdal.Open(pathOrDataset)
assert isinstance(ds, gdal.Dataset)
return ds
class SensorInstrument(QObject):
SensorNameSettingsPrefix = 'SensorName.'
sigNameChanged = pyqtSignal(str)
LUT_Wavelengths = dict({'B':480,
'G':570,
'R':660,
'nIR':850,
'swIR':1650,
'swIR1':1650,
'swIR2':2150
})
def __init__(self, pathImg, sensor_name=None):
super(SensorInstrument, self).__init__()
ds = getDS(pathImg)
self.nb, nl, ns, crs, self.px_size_x, self.px_size_y = getSpatialPropertiesFromDataset(ds)
self.bandDataType = ds.GetRasterBand(1).DataType
self.pathImg = ds.GetFileList()[0]
self.bandNames = [ds.GetRasterBand(b+1).GetDescription() for b in range(self.nb)]
self.TS = None
assert self.px_size_x > 0
assert self.px_size_y > 0
wl, wlu = parseWavelengthFromDataSet(ds)
self.wavelengthUnits = wlu
if wl is None:
self.wavelengths = None
else:
self.wavelengths = np.asarray(wl)
self._id = '{}b{}m'.format(self.nb, self.px_size_x)
if wl is not None:
self._id += ';'.join([str(w) for w in self.wavelengths])+str(self.wavelengthUnits)
if sensor_name is None:
sensor_name = '{}bands@{}m'.format(self.nb, self.px_size_x)
sensor_name = SETTINGS.value(self._sensorSettingsKey(), sensor_name)
self.setName(sensor_name)
def id(self):
return self._id
def _sensorSettingsKey(self):
return SensorInstrument.SensorNameSettingsPrefix+self._id
def setName(self, name):
self._name = name
SETTINGS.setValue(self._sensorSettingsKey(), name)
self.sigNameChanged.emit(self.name())
def name(self):
return self._name
def dataType(self, p_int):
return self.bandDataType
def bandClosestToWavelength(self, wl, wl_unit='nm'):
"""

benjamin.jakimow@geo.hu-berlin.de
committed
Returns the band index (>=0) of the band closest to wavelength wl
:param wl:
:param wl_unit:
:return:
"""
if not self.wavelengthsDefined():
return None
if wl in SensorInstrument.LUT_Wavelengths.keys():
wl = SensorInstrument.LUT_Wavelengths[wl]
wl = float(wl)
if self.wavelengthUnits != wl_unit:
wl = convertMetricUnit(wl, wl_unit, self.wavelengthUnits)

benjamin.jakimow@geo.hu-berlin.de
committed
return np.argmin(np.abs(self.wavelengths - wl))
def wavelengthsDefined(self):
return self.wavelengths is not None and \
self.wavelengthUnits is not None

Benjamin Jakimow
committed
if not isinstance(other, SensorInstrument):
return False
return self.nb == other.nb and \
self.px_size_x == other.px_size_x and \
self.px_size_y == other.px_size_y
def __hash__(self):
return hash(self.id())
return str(self.__class__) +' ' + self.name()
info.append(self.name())
info.append('{} Bands'.format(self.nb))
info.append('Band\tName\tWavelength')
for b in range(self.nb):
if self.wavelengths is not None:
wl = str(self.wavelengths[b])
else:
wl = 'unknown'
info.append('{}\t{}\t{}'.format(b + 1, self.bandNames[b], wl))
return '\n'.join(info)
def verifyInputImage(path, vrtInspection=''):
if path is None or not isinstance(path, str):

benjamin.jakimow@geo.hu-berlin.de
committed
#logger.error('{}GDAL unable to open: '.format(vrtInspection, path))

benjamin.jakimow@geo.hu-berlin.de
committed
if ds.RasterCount == 0 and len(ds.GetSubDatasets()) > 0:
#logger.error('Can not open container {}.\nPlease specify a subdataset'.format(path))
if ds.GetDriver().ShortName == 'VRT':
vrtInspection = 'VRT Inspection {}\n'.format(path)

benjamin.jakimow@geo.hu-berlin.de
committed
nextFiles = set(ds.GetFileList()) - set([path])
validSrc = [verifyInputImage(p, vrtInspection=vrtInspection) for p in nextFiles]
if not all(validSrc):
return False
from timeseriesviewer.dateparser import parseDateFromDataSet
date = parseDateFromDataSet(ds)
if date is None:
return False

benjamin.jakimow@geo.hu-berlin.de
committed
return True
def pixel2coord(gt, x, y):
"""Returns global coordinates from pixel x, y coords"""
"""https://scriptndebug.wordpress.com/2014/11/24/latitudelongitude-of-each-pixel-using-python-and-gdal/"""
xoff, a, b, yoff, d, e = gt
xp = a * x + b * y + xoff
yp = d * x + e * y + yoff
return (xp, yp)
class TimeSeriesDatum(QObject):
@staticmethod
def createFromPath(path):
"""
Creates a valid TSD or returns None if this is impossible
:param path:
:return:
"""
if verifyInputImage(path):
tsd = TimeSeriesDatum(None, path)
except :
pass
return tsd
"""
Collects all data sets related to one sensor
"""
sigVisibilityChanged = pyqtSignal(bool)
sigRemoveMe = pyqtSignal()
def __init__(self, timeSeries, pathImg):
super(TimeSeriesDatum,self).__init__()
ds = getDS(pathImg)
self.pathImg = ds.GetFileList()[0] if isinstance(pathImg, gdal.Dataset) else pathImg
self.timeSeries = timeSeries
self.nb, self.nl, self.ns, self.crs, px_x, px_y = getSpatialPropertiesFromDataset(ds)
self.sensor = SensorInstrument(ds)
self.date = parseDateFromDataSet(ds)
assert self.date is not None, 'Unable to find acquisition date of {}'.format(pathImg)
from timeseriesviewer.dateparser import DOYfromDatetime64
self.doy = DOYfromDatetime64(self.date)
gt = ds.GetGeoTransform()
UL = QgsPointXY(*pixel2coord(gt, 0, 0))
LR = QgsPointXY(*pixel2coord(gt, self.ns, self.nl))
self._spatialExtent = SpatialExtent(self.crs, UL, LR)
self.srs_wkt = str(self.crs.toWkt())
def rank(self):
return self.timeSeries.index(self)
def setVisibility(self, b):
old = self.mVisibility
self.mVisibility = b
if old != self.mVisibility:
self.sigVisibilityChanged.emit(b)
def isVisible(self):
return self.mVisibility
def getDate(self):
return np.datetime64(self.date)
def getSpatialReference(self):
return self.crs
return self._spatialExtent
def __repr__(self):
return 'TS Datum {} {}'.format(self.date, str(self.sensor))
def __eq__(self, other):
return self.date == other.date and self.sensor.id() == other.sensor.id()
def __lt__(self, other):
if self.date < other.date:
return True

benjamin.jakimow@geo.hu-berlin.de
committed
elif self.date > other.date:
return False
return self.sensor.id() < other.sensor.id()
def __hash__(self):
return hash((self.date,self.sensor.id()))
class TimeSeriesTableView(QTableView):
def __init__(self, parent=None):
super(TimeSeriesTableView, self).__init__(parent)
def contextMenuEvent(self, event):
menu = QMenu(self)

benjamin.jakimow@geo.hu-berlin.de
committed
a = menu.addAction('Copy value(s)')
a.triggered.connect(self.onCopyValues)
a = menu.addAction('Check')
a.triggered.connect(lambda : self.onSetCheckState(Qt.Checked))
a = menu.addAction('Uncheck')
a.triggered.connect(lambda: self.onSetCheckState(Qt.Unchecked))

benjamin.jakimow@geo.hu-berlin.de
committed
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
def onSetCheckState(self, checkState):
indices = self.selectionModel().selectedIndexes()
rows = sorted(list(set([i.row() for i in indices])))
model = self.model()
if isinstance(model, TimeSeriesTableModel):
for r in rows:
idx = model.index(r,0)
model.setData(idx, checkState, Qt.CheckStateRole)
def onCopyValues(self):
indices = self.selectionModel().selectedIndexes()
model = self.model()
if isinstance(model, TimeSeriesTableModel):
from collections import OrderedDict
R = OrderedDict()
for idx in indices:
if not idx.row() in R.keys():
R[idx.row()] = []
R[idx.row()].append(model.data(idx, Qt.DisplayRole))
info = []
for k, values in R.items():
info.append(';'.join([str(v) for v in values]))
info = '\n'.join(info)
QApplication.clipboard().setText(info)
s = ""
def selectSelectedObservations(b):
assert isinstance(b, bool)
class TimeSeriesDockUI(QgsDockWidget, loadUI('timeseriesdock.ui')):
def __init__(self, parent=None):
super(TimeSeriesDockUI, self).__init__(parent)
self.setupUi(self)
self.btnAddTSD.setDefaultAction(parent.actionAddTSD)
self.btnRemoveTSD.setDefaultAction(parent.actionRemoveTSD)
self.btnLoadTS.setDefaultAction(parent.actionLoadTS)
self.btnSaveTS.setDefaultAction(parent.actionSaveTS)
self.btnClearTS.setDefaultAction(parent.actionClearTS)
self.progressBar.setMinimum(0)
self.setProgressInfo(0,100, 'Add images to fill time series')
self.progressBar.setValue(0)
self.progressInfo.setText(None)
self.frameFilters.setVisible(False)
self.setTimeSeries(None)
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
def setStatus(self):
from timeseriesviewer.timeseries import TimeSeries
if isinstance(self.TS, TimeSeries):
ndates = len(self.TS)
nsensors = len(set([tsd.sensor for tsd in self.TS]))
msg = '{} scene(s) from {} sensor(s)'.format(ndates, nsensors)
if ndates > 1:
msg += ', {} to {}'.format(str(self.TS[0].date), str(self.TS[-1].date))
self.progressInfo.setText(msg)
def setProgressInfo(self, nDone, nMax, message=None):
if self.progressBar.maximum() != nMax:
self.progressBar.setMaximum(nMax)
self.progressBar.setValue(nDone)
self.progressInfo.setText(message)
QgsApplication.processEvents()
if nDone == nMax:
QTimer.singleShot(3000, lambda: self.setStatus())
def onSelectionChanged(self, *args):
self.btnRemoveTSD.setEnabled(self.SM is not None and len(self.SM.selectedRows()) > 0)
def selectedTimeSeriesDates(self):
if self.SM is not None:
return [self.TSM.data(idx, Qt.UserRole) for idx in self.SM.selectedRows()]
return []
def setTimeSeries(self, TS):
from timeseriesviewer.timeseries import TimeSeries
self.TS = TS
self.TSM = None
self.SM = None
self.timeSeriesInitialized = False
if isinstance(TS, TimeSeries):
from timeseriesviewer.timeseries import TimeSeriesTableModel
self.TSM = TimeSeriesTableModel(self.TS)
self.tableView_TimeSeries.setModel(self.TSM)
self.SM = QItemSelectionModel(self.TSM)
self.tableView_TimeSeries.setSelectionModel(self.SM)
self.SM.selectionChanged.connect(self.onSelectionChanged)
self.tableView_TimeSeries.horizontalHeader().setResizeMode(QHeaderView.ResizeToContents)
TS.sigLoadingProgress.connect(self.setProgressInfo)
self.onSelectionChanged()
sigTimeSeriesDatesAdded = pyqtSignal(list)
sigTimeSeriesDatesRemoved = pyqtSignal(list)
sigLoadingProgress = pyqtSignal(int, int, str)
sigSensorAdded = pyqtSignal(SensorInstrument)
sigSensorRemoved = pyqtSignal(SensorInstrument)
sigRuntimeStats = pyqtSignal(dict)
def __init__(self, imageFiles=None, maskFiles=None):
QObject.__init__(self)
#define signals
#fire when a new TSD is added
#self.data = collections.OrderedDict()
self.data = list()
self.shape = None
self.Sensors = collections.OrderedDict()
self.Pool = None
if imageFiles is not None:
self.addFiles(imageFiles)
if maskFiles is not None:
self.addMasks(maskFiles)
_sep = ';'
return list(self.Sensors.keys())
images = []
masks = []
with open(path, 'r') as f:
lines = f.readlines()
for l in lines:
if re.match('^[ ]*[;#&]', l):
continue
parts = re.split('[\n'+TimeSeries._sep+']', l)
parts = [p for p in parts if p != '']
images.append(parts[0])
if len(parts) > 1:
masks.append(parts[1])
if n_max:
n_max = min([len(images), n_max])
self.addFiles(images[0:n_max])
else:
self.addFiles(images)
#self.addMasks(masks)
def saveToFile(self, path):
if path is None or len(path) == 0:
lines = []
lines.append('#Time series definition file: {}'.format(np.datetime64('now').astype(str)))
line = TSD.pathImg
lines.append(line)
lines = [l+'\n' for l in lines]
messageLog('Time series source images written to {}'.format(path))

benjamin.jakimow@geo.hu-berlin.de
committed
def getPixelSizes(self):
r = []
for sensor in self.Sensors.keys():
r.append((QgsRectangle(sensor.px_size_x, sensor.px_size_y)))
return r
return None
def getMaxSpatialExtent(self, crs=None):
if len(self.data) == 0:

Benjamin Jakimow
committed
assert isinstance(extent, SpatialExtent)
extent.combineExtentWith(TSD.spatialExtent())
x, y = extent.upperRight()
if y > 0:
s =""

Benjamin Jakimow
committed
if isinstance(crs, QgsCoordinateReferenceSystem):
extent = extent.toCrs(crs)

benjamin.jakimow@geo.hu-berlin.de
committed
def tsdFromPath(self, path):
for tsd in self.data:
if tsd.pathImg == path:
return tsd
return False
def getObservationDates(self):
return [tsd.getDate() for tsd in self.data]

benjamin.jakimow@geo.hu-berlin.de
committed
def getTSD(self, pathOfInterest):
for tsd in self.data:
if tsd.pathImg == pathOfInterest:
return tsd
return None
def getTSDs(self, dateOfInterest=None, sensorOfInterest=None):

benjamin.jakimow@geo.hu-berlin.de
committed
tsds = self.data[:]
if dateOfInterest:

benjamin.jakimow@geo.hu-berlin.de
committed
tsds = [tsd for tsd in tsds if tsd.getDate() == dateOfInterest]
if sensorOfInterest:
tsds = [tsd for tsd in tsds if tsd.sensor == sensorOfInterest]
self.removeDates(self[:])
assert type(TSD) is TimeSeriesDatum
self.data.remove(TSD)
TSD.timeSeries = None
removed.append(TSD)
self.Sensors[S].remove(TSD)
if len(self.Sensors[S]) == 0:
self.Sensors.pop(S)
self.sigSensorRemoved.emit(S)
self.sigTimeSeriesDatesRemoved.emit(removed)
def addTimeSeriesDates(self, timeSeriesDates):
assert isinstance(timeSeriesDates, list)
added = list()
for TSD in timeSeriesDates:
assert isinstance(TSD, TimeSeriesDatum)
try:
sensorAdded = False
existingSensors = list(self.Sensors.keys())
if TSD.sensor not in existingSensors:
self.Sensors[TSD.sensor] = list()
sensorAdded = True
else:
TSD.sensor = existingSensors[existingSensors.index(TSD.sensor)]
if TSD in self.data:
print('Time series date-time already added ({} {}). \nPlease use VRTs to mosaic images with same acquisition date-time.'.format(str(TSD), TSD.pathImg), file=sys.stderr)
else:
self.Sensors[TSD.sensor].append(TSD)
#insert sorted
bisect.insort(self.data, TSD)
TSD.timeSeries = self
TSD.sigRemoveMe.connect(lambda : self.removeDates([TSD]))
added.append(TSD)
if sensorAdded:
self.sigSensorAdded.emit(TSD.sensor)
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback, limit=2)
if len(added) > 0:
self.sigTimeSeriesDatesAdded.emit(added)
if isinstance(files, str):
files = [files]
files = [f for f in files if f is not None]
nMax = len(files)
nDone = 0
self.sigLoadingProgress.emit(0,nMax, 'Start loading {} files...'.format(nMax))
t0 = np.datetime64('now')
tsd = TimeSeriesDatum.createFromPath(file)
if tsd is None:
msg = 'Unable to add: {}'.format(os.path.basename(file))
self.addTimeSeriesDates([tsd])
msg = 'Added {}'.format(os.path.basename(file))
self.sigRuntimeStats.emit({'dt_addTSD':np.datetime64('now')-t0})
nDone += 1
self.sigLoadingProgress.emit(nDone, nMax, msg)
def __len__(self):
return len(self.data)
def __iter__(self):
return iter(self.data)
def __getitem__(self, slice):
return self.data[slice]
def __delitem__(self, slice):
self.removeDates(slice)
def __contains__(self, item):
return item in self.data
def __repr__(self):
info = []
info.append('TimeSeries:')
l = len(self)
info.append(' Scenes: {}'.format(l))
class TimeSeriesTableModel(QAbstractTableModel):
def __init__(self, TS, parent=None, *args):
super(TimeSeriesTableModel, self).__init__()
assert isinstance(TS, TimeSeries)
self.cnDate = 'Date'
self.cnSensor = 'Sensor'
self.cnNS = 'ns'
self.cnNL = 'nl'
self.cnNB = 'nb'
self.cnCRS = 'CRS'
self.cnImage = 'Image'
self.mColumnNames = [self.cnDate, self.cnSensor, \
self.cnNS, self.cnNL, self.cnNB, \
self.cnCRS, self.cnImage]
self.TS = TS
self.sensors = set()
self.TS.sigTimeSeriesDatesRemoved.connect(self.removeTSDs)
self.TS.sigTimeSeriesDatesAdded.connect(self.addTSDs)
self.items = []
self.sortColumnIndex = 0
self.sortOrder = Qt.AscendingOrder
self.addTSDs([tsd for tsd in self.TS])
def removeTSDs(self, tsds):
#self.TS.removeDates(tsds)
for tsd in tsds:
if tsd in self.TS:
#remove from TimeSeries first.
self.TS.removeDates([tsd])
elif tsd in self.items:
idx = self.getIndexFromDate(tsd)
self.removeRows(idx.row(), 1)
#self.sort(self.sortColumnIndex, self.sortOrder)
def tsdChanged(self, tsd):
idx = self.getIndexFromDate(tsd)
self.dataChanged.emit(idx, idx)
i = self.mColumnNames.index(self.cnSensor)
idx0 = self.createIndex(0, i)
idx1 = self.createIndex(self.rowCount(), i)
self.dataChanged.emit(idx0, idx1)
for tsd in tsds:
assert isinstance(tsd, TimeSeriesDatum)
row = bisect.bisect_left(self.items, tsd)
self.beginInsertRows(QModelIndex(), row, row)
self.items.insert(row, tsd)
self.endInsertRows()
#self.sort(self.sortColumnIndex, self.sortOrder)
for tsd in tsds:
assert isinstance(tsd, TimeSeriesDatum)
tsd.sigVisibilityChanged.connect(lambda: self.tsdChanged(tsd))
for sensor in set([tsd.sensor for tsd in tsds]):
if sensor not in self.sensors:
self.sensors.add(sensor)
sensor.sigNameChanged.connect(self.sensorsChanged)
def sort(self, col, order):
if self.rowCount() == 0:
return
self.layoutAboutToBeChanged.emit()
colName = self.mColumnNames[col]
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
r = order != Qt.AscendingOrder
if colName in ['date','ns','nl','sensor']:
self.items.sort(key = lambda d:d.__dict__[colName], reverse=r)
self.layoutChanged.emit()
s = ""
def rowCount(self, parent = QModelIndex()):
return len(self.items)
def removeRows(self, row, count , parent=QModelIndex()):
self.beginRemoveRows(parent, row, row+count-1)
toRemove = self.items[row:row+count]
for tsd in toRemove:
self.items.remove(tsd)
self.endRemoveRows()
def getIndexFromDate(self, tsd):
return self.createIndex(self.items.index(tsd),0)
def getDateFromIndex(self, index):
if index.isValid():
return self.items[index.row()]
return None
def getTimeSeriesDatumFromIndex(self, index):
if index.isValid():
i = index.row()
if i >= 0 and i < len(self.items):
return self.items[i]
return None
def columnCount(self, parent = QModelIndex()):
return len(self.mColumnNames)
def data(self, index, role = Qt.DisplayRole):
if role is None or not index.isValid():
return None
value = None
columnName = self.mColumnNames[index.column()]
TSD = self.getTimeSeriesDatumFromIndex(index)
assert isinstance(TSD, TimeSeriesDatum)
keys = list(TSD.__dict__.keys())
if role == Qt.DisplayRole or role == Qt.ToolTipRole:
elif columnName == self.cnSensor:
if role == Qt.ToolTipRole:
value = TSD.sensor.getDescription()
else:
value = TSD.sensor.name()
elif columnName == self.cnCRS:
crs = TSD.crs
assert isinstance(crs, QgsCoordinateReferenceSystem)
value = crs.description()
elif columnName in keys:
value = TSD.__dict__[columnName]
else:
s = ""
elif role == Qt.CheckStateRole:
if columnName == self.cnDate:
value = Qt.Checked if TSD.isVisible() else Qt.Unchecked
elif role == Qt.BackgroundColorRole:
value = None
elif role == Qt.UserRole:
value = TSD
return value
def setData(self, index, value, role=None):
if role is None or not index.isValid():
return None
if role is Qt.UserRole:
s = ""
columnName = self.mColumnNames[index.column()]
TSD = self.getTimeSeriesDatumFromIndex(index)
if columnName == self.cnDate and role == Qt.CheckStateRole:
TSD.setVisibility(value != Qt.Unchecked)
return True
else:
return False
return False
def flags(self, index):
if index.isValid():
columnName = self.mColumnNames[index.column()]
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
if columnName == self.cnDate: #allow check state
flags = flags | Qt.ItemIsUserCheckable
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.mColumnNames[col]
elif orientation == Qt.Vertical and role == Qt.DisplayRole:
return col
return None
def getSpatialPropertiesFromDataset(ds):
assert isinstance(ds, gdal.Dataset)
nb = ds.RasterCount
nl = ds.RasterYSize
ns = ds.RasterXSize
proj = ds.GetGeoTransform()
px_x = float(abs(proj[1]))
px_y = float(abs(proj[5]))
crs = QgsCoordinateReferenceSystem(ds.GetProjection())
return nb, nl, ns, crs, px_x, px_y
def parseWavelengthFromDataSet(ds):
assert isinstance(ds, gdal.Dataset)
wl = None
wlu = None
#see http://www.harrisgeospatial.com/docs/ENVIHeaderFiles.html for supported wavelength units
regWLkey = re.compile('.*wavelength[_ ]*$', re.I)
regWLUkey = re.compile('.*wavelength[_ ]*units?$', re.I)
regNumeric = re.compile(r"([-+]?\d*\.\d+|[-+]?\d+)", re.I)
regWLU = re.compile('((micro|nano|centi)meters)|(um|nm|mm|cm|m|GHz|MHz)', re.I)
for domain in ds.GetMetadataDomainList():
md = ds.GetMetadata_Dict(domain)
for key, value in md.items():
if wl is None and regWLkey.search(key):
numbers = regNumeric.findall(value)
if len(numbers) == ds.RasterCount:
wl = [float(n) for n in numbers]
if wlu is None and regWLUkey.search(key):
match = regWLU.search(value)
if match:
names = ['nanometers', 'micrometers', 'millimeters', 'centimeters', 'decimeters']
si = ['nm', 'um', 'mm', 'cm', 'dm']
if wlu in names:
wlu = si[names.index(wlu)]
return wl, wlu
def parseWavelength(lyr):
wl = None
wlu = None
assert isinstance(lyr, QgsRasterLayer)
md = [l.split('=') for l in str(lyr.metadata()).splitlines() if 'wavelength' in l.lower()]
#see http://www.harrisgeospatial.com/docs/ENVIHeaderFiles.html for supported wavelength units
regWLU = re.compile('((micro|nano|centi)meters)|(um|nm|mm|cm|m|GHz|MHz)')
for kv in md:
key, value = kv
key = key.lower()
if key == 'center wavelength':
tmp = re.findall(r'\d*\.\d+|\d+', value) #find floats
tmp = re.findall(r'\d+', value) #find integers
if len(tmp) == lyr.bandCount():
wl = [float(w) for w in tmp]
if key == 'wavelength units':
match = regWLU.search(value)
if match:
wlu = match.group()
names = ['nanometers','micrometers','millimeters','centimeters','decimenters']
si = ['nm','um','mm','cm','dm']
if wlu in names:
wlu = si[names.index(wlu)]
return wl, wlu
if __name__ == '__main__':
q = QApplication([])
p = QProgressBar()
p.setRange(0,0)
p.show()
q.exec_()

benjamin.jakimow@geo.hu-berlin.de
committed
print(convertMetricUnit(100, 'cm', 'm'))
print(convertMetricUnit(1, 'm', 'um'))