From 134732780da79f59c4e28887edb67a635d494af9 Mon Sep 17 00:00:00 2001
From: Benjamin Jakimow <no.email>
Date: Wed, 21 Dec 2016 02:46:46 +0100
Subject: [PATCH] refactoring action based event handling

---
 timeseriesviewer/main.py       | 251 ++++++++++++++-------------------
 timeseriesviewer/timeseries.py | 161 ++++++++++++++++-----
 2 files changed, 234 insertions(+), 178 deletions(-)

diff --git a/timeseriesviewer/main.py b/timeseriesviewer/main.py
index 190315b1..09d5184c 100644
--- a/timeseriesviewer/main.py
+++ b/timeseriesviewer/main.py
@@ -221,51 +221,63 @@ class TimeSeriesItemModel(QAbstractItemModel):
 
 class BandView(QObject):
 
-    removeView = pyqtSignal(object)
+    sigAddBandView = pyqtSignal(object)
+    sigRemoveBandView = pyqtSignal(object)
 
-    def __init__(self, TS, recommended_bands=None):
+    def __init__(self, TS, recommended_bands=None, parent=None, showSensorNames=True):
         super(BandView, self).__init__()
+        self.ui = widgets.BandViewUI(parent)
+        self.ui.create()
+
+        #forward actions with reference to this band view
+        self.ui.actionAddBandView.triggered.connect(lambda : self.sigAddBandView.emit(self))
+        self.ui.actionRemoveBandView.triggered.connect(lambda: self.sigRemoveBandView.emit(self))
+
         assert type(TS) is TimeSeries
-        self.representation = collections.OrderedDict()
+        self.sensorViews = collections.OrderedDict()
         self.TS = TS
-        self.TS.sensorAdded.connect(self.checkSensors)
-        self.TS.changed.connect(self.checkSensors)
+        self.TS.sigSensorAdded.connect(self.addSensor)
+        self.TS.sigChanged.connect(self.removeSensor)
 
-        self.Sensors = self.TS.Sensors
+        self.mShowSensorNames = showSensorNames
 
-        import copy
-        for sensor in self.Sensors:
-            self.initSensor(copy.deepcopy(sensor))
+        for sensor in self.TS.Sensors:
+            self.addSensor(sensor)
 
+    def setTitle(self, title):
+        self.ui.labelViewName.setText(title)
 
+    def showSensorNames(self, b):
+        assert isinstance(b, bool)
+        self.mShowSensorNames = b
 
-    def checkSensors(self):
-        represented_sensors = set(self.representation.keys())
-        ts_sensors = set(self.TS.Sensors.keys())
+        for s,w in self.sensorViews.items():
+            w.showSensorName(b)
 
-        to_add = ts_sensors - represented_sensors
-        to_remove = represented_sensors - ts_sensors
-        for S in to_remove:
-            self.representation[S].getWidget().close()
-            self.representation.pop(S)
-        for S in to_add:
-            self.initSensor(S)
 
+    def removeSensor(self, sensor):
+        assert type(sensor) is SensorInstrument
+        assert sensor in self.sensorViews.keys()
+        self.sensorViews[sensor].close()
+        self.sensorViews.pop(sensor)
 
-    def initSensor(self, sensor):
+    def addSensor(self, sensor):
         """
         :param sensor:
         :return:
         """
         assert type(sensor) is SensorInstrument
-        if sensor not in self.representation.keys():
-            x = widgets.ImageChipViewSettings(sensor)
-            self.representation[sensor] = x
-
+        assert sensor not in self.sensorViews.keys()
+        w = widgets.ImageChipViewSettings(sensor)
+        w.showSensorName(self.mShowSensorNames)
+        self.sensorViews[sensor] = w
+        i = self.ui.mainLayout.count()-1
+        self.ui.mainLayout.insertWidget(i, w.ui)
+        s = ""
 
-    def getWidget(self, sensor):
+    def getSensorWidget(self, sensor):
         assert type(sensor) is SensorInstrument
-        return self.representation[sensor]
+        return self.sensorViews[sensor]
 
 class RenderJob(object):
 
@@ -564,32 +576,6 @@ def Array2Image(d3d):
     return QImage(d3d.data, ns, nl, QImage.Format_RGB888)
 
 
-class VerticalLabel(QLabel):
-    def __init__(self, text):
-        super(VerticalLabel, self).__init__(text)
-        self.update()
-        self.updateGeometry()
-
-
-    def paintEvent(self, ev):
-        p = QPainter(self)
-        p.rotate(-90)
-        rgn = QRect(-self.height(), 0, self.height(), self.width())
-        align = self.alignment()
-        self.hint = p.drawText(rgn, align, self.text())
-        p.end()
-
-        self.setMaximumWidth(self.hint.height())
-        self.setMinimumWidth(0)
-        self.setMaximumHeight(16777215)
-        self.setMinimumHeight(self.hint.width())
-
-    def sizeHint(self):
-        if hasattr(self, 'hint'):
-            return QSize(self.hint.height(), self.hint.width())
-        else:
-            return QSize(19, 50)
-
 
 class ImageChipBuffer(object):
 
@@ -741,14 +727,14 @@ class TimeSeriesViewer:
         # Create the dialog (after translation) and keep reference
         from timeseriesviewer.ui.widgets import TimeSeriesViewerUI
         self.ui = TimeSeriesViewerUI()
-        D = self.ui
+
 
         #init empty time series
         self.TS = TimeSeries()
         self.hasInitialCenterPoint = False
-        self.TS.datumAdded.connect(self.ua_datumAdded)
-        self.TS.changed.connect(self.timeseriesChanged)
-        self.TS.progress.connect(self.ua_TSprogress)
+        self.TS.sigTimeSeriesDatumAdded.connect(self.ua_datumAdded)
+        self.TS.sigChanged.connect(self.timeseriesChanged)
+        self.TS.sigProgress.connect(self.ua_TSprogress)
 
         #init TS model
         TSM = TimeSeriesTableModel(self.TS)
@@ -764,29 +750,36 @@ class TimeSeriesViewer:
 
         self.ValidatorPxX = QIntValidator(0,99999)
         self.ValidatorPxY = QIntValidator(0,99999)
-        D.btn_showPxCoordinate.clicked.connect(lambda: self.showSubsetsStart())
-        D.btn_selectByCoordinate.clicked.connect(self.ua_selectByCoordinate)
-        D.btn_selectByRectangle.clicked.connect(self.ua_selectByRectangle)
-        D.btn_addBandView.clicked.connect(lambda :self.ua_addBandView())
-
-        D.btn_addTSImages.clicked.connect(lambda :self.ua_addTSImages())
-        D.btn_addTSMasks.clicked.connect(lambda :self.ua_addTSMasks())
-        D.btn_loadTSFile.clicked.connect(self.ua_loadTSFile)
-        D.btn_saveTSFile.clicked.connect(self.ua_saveTSFile)
-        D.btn_addTSExample.clicked.connect(self.ua_loadExampleTS)
+
+        #connect actions with logic
+
+        #D.btn_showPxCoordinate.clicked.connect(lambda: self.showSubsetsStart())
+        D.actionSelectCenter.triggered.connect(self.ua_selectByCoordinate)
+        D.actionSelectArea.triggered.connect(self.ua_selectByRectangle)
+
+        D.actionAddBandView.triggered.connect(self.ua_addBandView)
+        #D.actionRemoveBandView.triggered.connect(self.ua_removeBandView)
+
+        D.actionAddTSD.triggered.connect(self.ua_addTSImages)
+        D.actionRemoveTSD.triggered.connect(self.ua_removeTSD)
+
+        D.actionLoadTS.triggered.connect(self.ua_loadTSFile)
+        D.actionClearTS.triggered.connect(self.ua_clear_TS)
+        D.actionSaveTS.triggered.connect(self.ua_saveTSFile)
+        D.actionAddTSExample.triggered.connect(self.ua_loadExampleTS)
+
         D.btn_labeling_clear.clicked.connect(D.tb_labeling_text.clear)
-        D.actionAdd_Images.triggered.connect(lambda :self.ua_addTSImages())
-        D.actionAdd_Masks.triggered.connect(lambda :self.ua_addTSMasks())
-        D.actionLoad_Time_Series.triggered.connect(self.ua_loadTSFile)
-        D.actionSave_Time_Series.triggered.connect(self.ua_saveTSFile)
-        D.actionLoad_Example_Time_Series.triggered.connect(self.ua_loadExampleTS)
         D.actionAbout.triggered.connect( \
             lambda: QMessageBox.about(self.ui, 'SenseCarbon TimeSeriesViewer', 'A viewer to visualize raster time series data'))
 
-        D.btn_removeTSD.clicked.connect(lambda : self.ua_removeTSD(None))
-        D.btn_removeTS.clicked.connect(self.ua_clear_TS)
 
-        D.sliderDOI.sliderMoved.connect(self.setDOILabel)
+        D.actionFirstTSD.triggered.connect(lambda: self.setDOISliderValue('first'))
+        D.actionLastTSD.triggered.connect(lambda: self.setDOISliderValue('last'))
+        D.actionNextTSD.triggered.connect(lambda: self.setDOISliderValue('next'))
+        D.actionPreviousTSD.triggered.connect(lambda: self.setDOISliderValue('previous'))
+
+
+        D.sliderDOI.valueChanged.connect(self.setDOI)
         D.spinBox_ncpu.setRange(0, multiprocessing.cpu_count())
 
 
@@ -796,22 +789,37 @@ class TimeSeriesViewer:
 
         if self.iface:
             self.canvas = self.iface.mapCanvas()
-
             self.RectangleMapTool = qgis_add_ins.RectangleMapTool(self.canvas)
             self.RectangleMapTool.rectangleDrawed.connect(self.setSpatialSubset)
             self.PointMapTool = qgis_add_ins.PointMapTool(self.canvas)
             self.PointMapTool.coordinateSelected.connect(self.setSpatialSubset)
-
+        else:
+            D.btnSelectCenterCoordinate.setEnabled(False)
+            D.btnSelectArea.setEnabled(False)
             #self.RectangleMapTool.connect(self.ua_selectByRectangle_Done)
 
-        self.ICP = self.ui.scrollArea_imageChip_content.layout()
-        self.ui.scrollArea_bandViews_content.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
-        self.BVP = self.ui.scrollArea_bandViews_content.layout()
+        self.ICP = D.scrollAreaSubsetContent.layout()
+        D.scrollAreaBandViewsContent.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
+        self.BVP = self.ui.scrollAreaBandViewsContent.layout()
 
         self.check_enabled()
         s = ""
 
-    def setDOILabel(self, i):
+
+    def setDOISliderValue(self, key):
+        ui = self.ui
+        v = ui.sliderDOI.value()
+        if key == 'first':
+            v = ui.sliderDOI.minimum()
+        elif key == 'last':
+            v = ui.sliderDOI.maximum()
+        elif key =='next':
+            v = min([v+1,ui.sliderDOI.maximum()])
+        elif key =='previous':
+            v = max([v - 1, ui.sliderDOI.minimum()])
+        ui.sliderDOI.setValue(v)
+
+    def setDOI(self, i):
         TSD = self.TS.data[i-1]
         self.ui.labelDOI.setText(str(TSD.date))
         s = ""
@@ -847,8 +855,6 @@ class TimeSeriesViewer:
             self.TS.loadFromFile(path)
             M.endResetModel()
 
-            self.refreshBandViews()
-
         self.check_enabled()
 
     def ua_saveTSFile(self):
@@ -955,9 +961,9 @@ class TimeSeriesViewer:
         hasQGIS = qgis_available
 
         #D.tabWidget_viewsettings.setEnabled(hasTS)
-        D.btn_showPxCoordinate.setEnabled(hasTS and hasTSV)
-        D.btn_selectByCoordinate.setEnabled(hasQGIS)
-        D.btn_selectByRectangle.setEnabled(hasQGIS)
+        #D.btn_showPxCoordinate.setEnabled(hasTS and hasTSV)
+        D.btnSelectCenterCoordinate.setEnabled(hasQGIS)
+        D.btnSelectArea.setEnabled(hasQGIS)
 
 
 
@@ -1081,7 +1087,7 @@ class TimeSeriesViewer:
                 viewList = list()
                 j = 1
                 for view in self.BAND_VIEWS:
-                    viewWidget = view.getWidget(TSD.sensor)
+                    viewWidget = view.getSensorWidget(TSD.sensor)
                     layerRenderer = viewWidget.layerRenderer()
 
                     #imageLabel = QLabel()
@@ -1122,7 +1128,7 @@ class TimeSeriesViewer:
                 if sensor not in LUT_RENDERER.keys():
                     LUT_RENDERER[sensor] = []
                 LUT_RENDERER[sensor].append(
-                    view.getWidget(sensor).layerRenderer()
+                    view.getSensorWidget(sensor).layerRenderer()
                 )
 
 
@@ -1187,72 +1193,31 @@ class TimeSeriesViewer:
         self.check_enabled()
 
 
-    def ua_addTSMasks(self, files=None):
-
-        if files is None:
-            files = QFileDialog.getOpenFileNames()
-
-        l = len(files)
-        if l > 0:
-            M = self.ui.tableView_TimeSeries.model()
-            M.beginResetModel()
-            self.TS.addMasks(files, raise_errors=False)
-            M.endResetModel()
 
-        self.check_enabled()
 
+    def ua_addBandView(self):
 
+        bandView = BandView(self.TS, showSensorNames=len(self.BAND_VIEWS)==0)
+        bandView.sigAddBandView.connect(self.ua_addBandView)
+        bandView.sigRemoveBandView.connect(self.ua_removeBandView)
 
-    def ua_addBandView(self):
-        bandView = BandView(self.TS)
         #bandView.removeView.connect(self.ua_removeBandView)
         self.BAND_VIEWS.append(bandView)
-        self.refreshBandViews()
-
-
-    def refreshBandViews(self):
-        if len(self.BAND_VIEWS) == 0 and len(self.TS) > 0:
-            self.ua_addBandView() # add two bandviews by default
-            self.ua_addBandView()
-
-        self.clearLayoutWidgets(self.BVP)
-
-        for i, BV in enumerate(self.BAND_VIEWS):
-            W = QWidget()
-
-            hl = QHBoxLayout()
-            hl.setSpacing(2)
-            hl.setMargin(0)
+        self.BVP.addWidget(bandView.ui)
 
+        bandView.setTitle('#{}'.format(len(self.BAND_VIEWS)))
 
-            textLabel = VerticalLabel('View {}'.format(i+1))
-            #textLabel = QLabel('View {}'.format(i+1))
-            textLabel.setToolTip('')
-            textLabel.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed)
-            hl.addWidget(textLabel)
-
-            for S in self.TS.Sensors.keys():
-                w = BV.getWidget(S).ui
-                if i > 0:
-                    w.setTitle(None) #show sensor name only on top
-                w.setMaximumSize(w.size())
-                #w.setMinimumSize(w.size())
-                w.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.MinimumExpanding)
-                #w.setBands(band_recommendation)
-                hl.addWidget(w)
-                s = ""
-
-            hl.addItem(QSpacerItem(1,1))
-            W.setLayout(hl)
-            self.BVP.addWidget(W)
-        self.BVP.addItem(QSpacerItem(1, 1))
-        self.check_enabled()
-
+    def ua_removeBandView(self, bandView):
+        #bandView.ui.setHidden(True)
+        self.BAND_VIEWS.remove(bandView)
+        self.BVP.removeWidget(bandView.ui)
+        bandView.ui.close()
+        self.BAND_VIEWS[0].showSensorNames(True)
+        for i, bv in enumerate(self.BAND_VIEWS):
+            bv.setTitle('#{}'.format(i+1))
+        #self.ui.scrollAreaBandViewsContent.update()
 
 
-    def ua_removeBandView(self, w):
-        self.BAND_VIEWS.remove(w)
-        self.refreshBandViews()
 
     def ua_clear_TS(self):
         #remove views
diff --git a/timeseriesviewer/timeseries.py b/timeseriesviewer/timeseries.py
index a2f56c99..2c1903f6 100644
--- a/timeseriesviewer/timeseries.py
+++ b/timeseriesviewer/timeseries.py
@@ -22,7 +22,27 @@ def transformGeometry(geom, crsSrc, crsDst, trans=None):
         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)
 
 
 class SensorInstrument(QObject):
@@ -37,12 +57,15 @@ class SensorInstrument(QObject):
                 , (5, 5., 5.): 'RE 5m' \
                     }
 
-    """
-    def fromGDALDataSet(self, ds):
-        assert isinstance(ds, gdal.Dataset)
-        nb = ds.RasterCount
-    """
 
+    LUT_Wavelenghts = dict({'B':480,
+                            'G':570,
+                            'R':660,
+                            'nIR':850,
+                            'swIR':1650,
+                            'swIR1':1650,
+                            'swIR2':2150
+                            })
     """
     Describes a Sensor Configuration
     """
@@ -78,12 +101,10 @@ class SensorInstrument(QObject):
         assert self.px_size_x > 0
         assert self.px_size_y > 0
 
-        wavelengths = None
-        #todo: find wavelength
-        if wavelengths is not None:
-            assert len(wavelengths) == self.nb
-
-        self.wavelengths = wavelengths
+        #find wavelength
+        wl, wlu = parseWavelength(refLyr)
+        self.wavelengths = np.asarray(wl)
+        self.wavelengthUnits = wlu
 
         if sensor_name is None:
             id = (self.nb, self.px_size_x, self.px_size_y)
@@ -95,6 +116,35 @@ class SensorInstrument(QObject):
 
         self.hashvalue = hash(','.join(self.bandNames))
 
+
+    def bandClosestToWavelength(self, wl, wl_unit='nm'):
+        """
+        Returns the band number (>=1) of the band closest to wavelength wl
+        :param wl:
+        :param wl_unit:
+        :return:
+        """
+        if not self.wavelengthsDefined():
+            return None
+
+        if wl in SensorInstrument.LUT_Wavelenghts.keys():
+            wl_unit = 'nm'
+            wl = SensorInstrument.LUT_Wavelenghts[wl]
+
+        wl = float(wl)
+        if self.wavelengthUnits != wl_unit:
+            wl = convertMetricUnit(wl, wl_unit, self.wavelengthUnits)
+
+
+        return np.argmin(np.abs(self.wavelengths - wl))+1
+
+
+
+
+    def wavelengthsDefined(self):
+        return self.wavelengths is not None and \
+                self.wavelengthUnits is not None
+
     def __eq__(self, other):
         return self.nb == other.nb and \
                self.px_size_x == other.px_size_x and \
@@ -358,15 +408,15 @@ class TimeSeriesDatum(QObject):
 
 
 class TimeSeries(QObject):
-    datumAdded = pyqtSignal(TimeSeriesDatum)
+    sigTimeSeriesDatumAdded = pyqtSignal(TimeSeriesDatum)
 
     #fire when a new sensor configuration is added
-    sensorAdded = pyqtSignal(SensorInstrument, name='sensorAdded')
-
-    changed = pyqtSignal()
-    progress = pyqtSignal(int,int,int, name='progress')
-    closed = pyqtSignal()
-    error = pyqtSignal(object)
+    sigSensorAdded = pyqtSignal(SensorInstrument)
+    sigSensorRemoved = pyqtSignal(SensorInstrument)
+    sigChanged = pyqtSignal()
+    sigProgress = pyqtSignal(int, int, int, name='progress')
+    sigClosed = pyqtSignal()
+    sigError = pyqtSignal(object)
 
     def __init__(self, imageFiles=None, maskFiles=None):
         QObject.__init__(self)
@@ -465,7 +515,7 @@ class TimeSeries(QObject):
 
     def _callback_error(self, error):
         six.print_(error, file=sys.stderr)
-        self.error.emit(error)
+        self.sigError.emit(error)
         self._callback_progress()
 
     def _callback_spatialchips(self, results):
@@ -474,12 +524,12 @@ class TimeSeries(QObject):
 
     def _callback_progress(self):
         self._callback_progress_done += 1
-        self.progress.emit(0, self._callback_progress_done, self._callback_progress_max)
+        self.sigProgress.emit(0, self._callback_progress_done, self._callback_progress_max)
 
         if self._callback_progress_done >= self._callback_progress_max:
             self._callback_progress_done = 0
             self._callback_progress_max = 0
-            self.progress.emit(0,0,1)
+            self.sigProgress.emit(0, 0, 1)
 
     def getSpatialChips_parallel(self, bbWkt, srsWkt, TSD_band_list, ncpu=1):
         assert type(bbWkt) is str and type(srsWkt) is str
@@ -529,7 +579,7 @@ class TimeSeries(QObject):
         assert isinstance(files, list)
         l = len(files)
 
-        self.progress.emit(0,0,l)
+        self.sigProgress.emit(0, 0, l)
         for i, file in enumerate(files):
 
             try:
@@ -537,10 +587,10 @@ class TimeSeries(QObject):
             except:
                 pass
 
-            self.progress.emit(0,i+1,l)
+            self.sigProgress.emit(0, i + 1, l)
 
-        self.progress.emit(0,0,1)
-        self.changed.emit()
+        self.sigProgress.emit(0, 0, 1)
+        self.sigChanged.emit()
 
     def addMask(self, pathMsk, raise_errors=True, mask_value=0, exclude_mask_value=True, _quiet=False):
         print('Add mask {}...'.format(pathMsk))
@@ -551,7 +601,7 @@ class TimeSeries(QObject):
             TSD = self.data[date]
 
             if not _quiet:
-                self.changed.emit()
+                self.sigChanged.emit()
 
             return TSD.setMask(pathMsk, raise_errors=raise_errors, mask_value=mask_value, exclude_mask_value=exclude_mask_value)
         else:
@@ -568,13 +618,13 @@ class TimeSeries(QObject):
     def clear(self):
         self.Sensors.clear()
         del self.data[:]
-        self.changed.emit()
+        self.sigChanged.emit()
 
 
     def removeDates(self, TSDs):
         for TSD in TSDs:
             self.removeTSD(TSD, _quiet=True)
-        self.changed.emit()
+        self.sigChanged.emit()
 
     def removeTSD(self, TSD, _quiet=False):
 
@@ -584,8 +634,9 @@ class TimeSeries(QObject):
         self.data.pop(TSD, None)
         if len(self.Sensors[S]) == 0:
             self.Sensors.pop(S)
+            self.sigSensorRemoved(S)
         if not _quiet:
-            self.changed.emit()
+            self.sigChanged.emit()
 
 
 
@@ -614,9 +665,9 @@ class TimeSeries(QObject):
                 #insert sorted
                 bisect.insort(self.data, TSD)
                 #self.data[TSD] = TSD
-                self.datumAdded.emit(TSD)
+                self.sigTimeSeriesDatumAdded.emit(TSD)
             if sensorAdded:
-                self.sensorAdded.emit(TSD.sensor)
+                self.sigSensorAdded.emit(TSD.sensor)
 
 
         except:
@@ -636,13 +687,13 @@ class TimeSeries(QObject):
         l = len(files)
         assert l > 0
 
-        self.progress.emit(0,0,l)
+        self.sigProgress.emit(0, 0, l)
         for i, file in enumerate(files):
             self.addFile(file, _quiet=True)
-            self.progress.emit(0,i+1,l)
+            self.sigProgress.emit(0, i + 1, l)
 
-        self.progress.emit(0,0,1)
-        self.changed.emit()
+        self.sigProgress.emit(0, 0, 1)
+        self.sigChanged.emit()
 
 
     def __len__(self):
@@ -715,6 +766,40 @@ regYYYYDOY = re.compile(r'(19|20)\d{5}')
 regYYYYMMDD = re.compile(r'(19|20)\d{2}-\d{2}-\d{2}')
 regYYYY = re.compile(r'(19|20)\d{2}')
 
+
+
+
+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('\d*\.\d+|\d+', value) #find floats
+            if len(tmp) == 0:
+                tmp = re.findall('\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
+
+
+
 def parseAcquisitionDate(text):
     match = regLandsatSceneID.search(text)
     if match:
@@ -742,3 +827,9 @@ def getDateTime64FromDOY(year, doy):
         if type(doy) is str:
             doy = int(doy)
         return np.datetime64('{:04d}-01-01'.format(year)) + np.timedelta64(doy-1, 'D')
+
+
+if __name__ == '__main__':
+
+    print convertMetricUnit(100, 'cm', 'm')
+    print convertMetricUnit(1, 'm', 'um')
\ No newline at end of file
-- 
GitLab