From 3b1af210afe1dba7a1d17ebda2592f0c1922effd Mon Sep 17 00:00:00 2001
From: Benjamin Jakimow <benjamin.jakimow@geo.hu-berlin.de>
Date: Mon, 17 Jul 2017 22:13:25 +0200
Subject: [PATCH] changed TSV icon VirtualRasterBuilder: added
 removeVirtualBands(), addVirtualBand(), insertVirtualBand(),
 addFilesAsStack(), addFilesAsMosaic(), improvements to saveVRT()

---
 timeseriesviewer/ui/icons/icon.png | Bin 2022 -> 129 bytes
 timeseriesviewer/ui/icons/icon.svg | 204 +++++++++++++++++++++++++
 timeseriesviewer/virtualrasters.py | 230 ++++++++++++++++-------------
 3 files changed, 329 insertions(+), 105 deletions(-)
 create mode 100644 timeseriesviewer/ui/icons/icon.svg

diff --git a/timeseriesviewer/ui/icons/icon.png b/timeseriesviewer/ui/icons/icon.png
index c0d802915cae1e3eb14b24e988a0f7833401f023..2b55fc08c55705329159aceaf26b3cf3d81f3207 100644
GIT binary patch
literal 129
zcmWN@$q~aK3;@7CRnS0;xrF6z#1)uHf+xa$r26=^dzCNu@sVxLgLkE#eLh~5m)my6
zC5^Y@qa<}{F?yEV$avVDSz$v5K9fb`bPZ@rtduGNxVs6Rr(yzWkD$q}eoHxoYH|z+
MS#bXqsjUI=2duv*5&!@I

literal 2022
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
Ef(g3bM*si-

diff --git a/timeseriesviewer/ui/icons/icon.svg b/timeseriesviewer/ui/icons/icon.svg
new file mode 100644
index 00000000..43ee2e2e
--- /dev/null
+++ b/timeseriesviewer/ui/icons/icon.svg
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="19.500002"
+   width="19.500002"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="icon.svg"
+   inkscape:export-filename="/Users/benjamin.jakimow/Repositories/QGIS_Plugins/hub-timeseriesviewer/timeseriesviewer/ui/icons/icon.png"
+   inkscape:export-xdpi="119.99998"
+   inkscape:export-ydpi="119.99998">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8">
+    <inkscape:perspective
+       id="perspective3486"
+       inkscape:persp3d-origin="16 : 10.666667 : 1"
+       inkscape:vp_z="32 : 16 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 16 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective3496" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective3600" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective7871" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective8710" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective9811" />
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       id="perspective4762" />
+    <clipPath
+       id="clipPath26">
+      <path
+         d="M 2362.38,3289.96 3754.11,6.80078 3641.8,151.695 2640.37,2534.35 3412.13,445.691 3334.48,520.086 2556,2631.38 3172.66,695.02 l -18.02,-0.004 -48.52,39.734 -622.04,1973.96 477.78,-1855.796 -59.5,44.93 -489.59,1907.296 353.27,-1804.34 -55.73,34.08 -355.81,1835.76 209.8,-1746.44 -51.89,28.52 -207.45,1766.52 72.29,-1692.23 -53.51,24.09 -66.25,1704.29 -86.87,-1635.36 -48.91,16.08 94.6,1658.46 -257.22,-1604.98 -45.65,12.57 259.68,1627.16 -445.14,-1576.09 -50.91,8.91 455.88,1590.29 -656.68,-1555.14 -53.13,2.14 666.01,1572.08 -928.64,-1561.46 -47.53,1.93 1056.19,1777.98 193.21,0 z"
+         inkscape:connector-curvature="0"
+         id="path28" />
+    </clipPath>
+  </defs>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1276"
+     inkscape:window-height="756"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="6.6775233"
+     inkscape:cx="5.9280981"
+     inkscape:cy="7.5000031"
+     inkscape:window-x="4"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg2"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0" />
+  <rect
+     style="fill:none;stroke:none"
+     id="rect6554"
+     width="19.499998"
+     height="19.499998"
+     x="0"
+     y="0" />
+  <rect
+     style="fill:#6e97c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419"
+     width="6.499999"
+     height="6.499999"
+     x="6.5"
+     y="0" />
+  <rect
+     style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-6"
+     width="6.499999"
+     height="6.499999"
+     x="13.000004"
+     y="0" />
+  <rect
+     style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-6-9"
+     width="6.499999"
+     height="6.499999"
+     x="6.5"
+     y="6.5"
+     inkscape:transform-center-x="-3.2499991"
+     inkscape:transform-center-y="-4.3333322" />
+  <rect
+     style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-0"
+     width="6.499999"
+     height="6.499999"
+     x="13.000004"
+     y="6.5" />
+  <rect
+     style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-6-7"
+     width="6.499999"
+     height="6.499999"
+     x="0"
+     y="0" />
+  <rect
+     style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-3"
+     width="6.499999"
+     height="6.499999"
+     x="0"
+     y="6.5" />
+  <rect
+     style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-5"
+     width="6.499999"
+     height="6.499999"
+     x="6.5"
+     y="13.000004" />
+  <rect
+     style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none"
+     id="rect6419-6-6"
+     width="6.499999"
+     height="6.499999"
+     x="0"
+     y="13.000004" />
+  <rect
+     y="13.000004"
+     x="13.000004"
+     height="6.499999"
+     width="6.499999"
+     id="rect8225"
+     style="display:inline;fill:#253e5b;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+  <g
+     id="g5821"
+     transform="translate(0.00243209,-0.24814311)"
+     style="fill:none;stroke:#ffffff;stroke-opacity:1">
+    <ellipse
+       ry="6.8272738"
+       rx="7.0345278"
+       cy="9.75"
+       cx="9.75"
+       id="path8227"
+       style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.89999998;stroke-opacity:1" />
+    <path
+       sodipodi:nodetypes="ccc"
+       inkscape:connector-curvature="0"
+       id="path8235"
+       d="m 12.364602,11.360681 -2.331606,0 -2.901555,-3.212435"
+       style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+  </g>
+</svg>
diff --git a/timeseriesviewer/virtualrasters.py b/timeseriesviewer/virtualrasters.py
index d59059e8..3dfb050f 100644
--- a/timeseriesviewer/virtualrasters.py
+++ b/timeseriesviewer/virtualrasters.py
@@ -21,7 +21,20 @@ class VirtualBand(object):
     def addSourceBand(self, path, bandIndex):
         self.sources.append(VirtualBandInputSource(path, bandIndex))
 
+    def removeSourceBand(self, bandOrIndex):
+        """
+        Removes a virtual band
+        :param bandOrIndex: int | VirtualBand
+        :return: The VirtualBand that was removed
+        """
+        if not isinstance(bandOrIndex, VirtualBand):
+            bandOrIndex = self.sources[bandOrIndex]
+        return self.sources.remove(bandOrIndex)
+
     def sourceFiles(self):
+        """
+        :return: list of file-paths to all source files
+        """
         files = set([inputSource.path for inputSource in self.sources])
         return sorted(list(files))
 
@@ -38,19 +51,85 @@ class VirtualRasterBuilder(object):
         self.vBands = []
         self.vMetadata = dict()
 
+
     def addVirtualBand(self, virtualBand):
+        """
+        Adds a virtual band
+        :param virtualBand: the VirtualBand to be added
+        :return: VirtualBand
+        """
         assert isinstance(virtualBand, VirtualBand)
         self.vBands.append(virtualBand)
+        return self[-1]
+
 
     def insertVirtualBand(self, i, virtualBand):
+        """
+        Inserts a VirtualBand
+        :param i: the insert position
+        :param virtualBand: the VirtualBand to be inserted
+        :return: the VirtualBand
+        """
         assert isinstance(virtualBand, VirtualBand)
         self.vBands.insert(i, virtualBand)
+        return self[i]
+
+
+
+    def removeVirtualBands(self, bandsOrIndices):
+        assert isinstance(bandsOrIndices, list)
+        to_remove = []
+        for bandOrIndex in bandsOrIndices:
+            if not isinstance(bandOrIndex, VirtualBand):
+                bandOrIndex = self.vBands[bandOrIndex]
+            to_remove.append(bandOrIndex)
+
+        for band in to_remove:
+            self.vBands.remove(band)
+        return to_remove
+
+
+    def removeVirtualBand(self, bandOrIndex):
+        r = self.removeVirtualBands([bandOrIndex])
+        return r[0]
 
     def addFilesAsMosaic(self, files):
-        pass
+        """
+        Shortcut to mosaic all input files. All bands will maintain their band position in the virtual file.
+        :param files: [list-of-file-paths]
+        """
+
+        for file in files:
+            ds = gdal.Open(file)
+            assert isinstance(ds, gdal.Dataset)
+            nb = ds.RasterCount
+            for b in range(nb):
+                if b+1 < len(self):
+                    #add new virtual band
+                    self.addVirtualBand(VirtualBand())
+                vBand = self[b]
+                assert isinstance(vBand, VirtualBand)
+                vBand.addSourceBand(file, b)
+        return self
 
     def addFilesAsStack(self, files):
-        pass
+        """
+        Shortcut to stack all input files, i.e. each band of an input file will be a new virtual band.
+        Bands in the virtual file will be ordered as file1-band1, file1-band n, file2-band1, file2-band,...
+        :param files: [list-of-file-paths]
+        :return: self
+        """
+        for file in files:
+            ds = gdal.Open(file)
+            assert isinstance(ds, gdal.Dataset)
+            nb = ds.RasterCount
+            ds = None
+            for b in range(nb):
+                #each new band is a new virtual band
+                vBand = self.addVirtualBand(VirtualBand())
+                assert isinstance(vBand, VirtualBand)
+                vBand.addSourceBand(file, b)
+        return self
 
     def sourceFiles(self):
         files = set()
@@ -59,7 +138,32 @@ class VirtualRasterBuilder(object):
             files.update(set(vBand.sourceFiles()))
         return sorted(list(files))
 
-    def saveVRT(self, pathVRT):
+    def saveVRT(self, pathVRT, **kwds):
+        """
+        :param pathVRT: path to VRT that is created
+        :param options --- can be be an array of strings, a string or let empty and filled from other keywords..
+        :param resolution --- 'highest', 'lowest', 'average', 'user'.
+        :param outputBounds --- output bounds as (minX, minY, maxX, maxY) in target SRS.
+        :param xRes, yRes --- output resolution in target SRS.
+        :param targetAlignedPixels --- whether to force output bounds to be multiple of output resolution.
+        :param bandList --- array of band numbers (index start at 1).
+        :param addAlpha --- whether to add an alpha mask band to the VRT when the source raster have none.
+        :param resampleAlg --- resampling mode.
+        :param outputSRS --- assigned output SRS.
+        :param allowProjectionDifference --- whether to accept input datasets have not the same projection. Note: they will *not* be reprojected.
+        :param srcNodata --- source nodata value(s).
+        :param callback --- callback method.
+        :param callback_data --- user data for callback.
+        :return: gdal.DataSet(pathVRT)
+        """
+
+        _kwds = dict()
+        supported = ['options','resolution','outputBounds','xRes','yRes','targetAlignedPixels','addAlpha','resampleAlg',
+        'outputSRS','allowProjectionDifference','srcNodata','VRTNodata','hideNodata','callback', 'callback_data']
+        for k in kwds.keys():
+            if k in supported:
+                _kwds[k] = kwds[k]
+
 
         dn = os.path.dirname(pathVRT)
         if not os.path.isdir(dn):
@@ -74,8 +178,7 @@ class VirtualRasterBuilder(object):
             if noData and srcNodata is None:
                 srcNodata = noData
 
-        vro = gdal.BuildVRTOptions(separate=True,
-                                   srcNodata=srcNodata)
+        vro = gdal.BuildVRTOptions(separate=True, **_kwds)
         #1. build a temporary VRT that described the spatial shifts of all input sources
         gdal.BuildVRT(pathVRT, srcFiles, options=vro)
         dsVRTDst = gdal.Open(pathVRT)
@@ -142,6 +245,22 @@ class VirtualRasterBuilder(object):
             info.append(str(vBand))
         return '\n'.join(info)
 
+    def __len__(self):
+        return len(self.vBands)
+
+    def __getitem__(self, slice):
+        return self.vBands[slice]
+
+    def __delitem__(self, slice):
+        self.removeVirtualBands(self[slice])
+
+    def __contains__(self, item):
+        return item in self.vBands
+
+
+    def __iter__(self):
+        return iter(self.mClasses)
+
 def createVirtualBandMosaic(bandFiles, pathVRT):
     drv = gdal.GetDriverByName('VRT')
 
@@ -175,7 +294,7 @@ def createVirtualBandStack(bandFiles, pathVRT):
 
     vrtOptions = gdal.BuildVRTOptions(
         # here we can use the options known from http://www.gdal.org/gdalbuildvrt.html
-        separate=True
+        separate=True,
     )
     vrtDS = gdal.BuildVRT(pathVRT, bandFiles, options=vrtOptions)
     vrtDS.FlushCache()
@@ -193,102 +312,3 @@ def createVirtualBandStack(bandFiles, pathVRT):
 
     return vrtDS
 
-
-def groupRapidEyeTiles(dirIn, dirOut):
-    """
-
-    :param dirIn:
-    :param dirOut:
-    :return:
-    """
-
-    files = file_search(dirIn, '*_RE*_3A_*2.tif', recursive=True)
-
-    if not os.path.exists(dirOut):
-        os.mkdir(dirOut)
-
-    sources = dict()
-    for file in files:
-        if not file.endswith('.tif'):
-            continue
-        dn = os.path.dirname(file)
-        bn = os.path.basename(file)
-        print(bn)
-        id, date, sensor, product, _ = tuple(bn.split('_'))
-
-        if not date in sources.keys():
-            sources[date] = []
-        sources[date].append(file)
-    for date, files in sources.items():
-        pathVRT = os.path.join(dirOut, 're_{}.vrt'.format(date))
-        createVirtualBandMosaic(files, pathVRT)
-
-def groupCBERS(dirIn, dirOut):
-    files = file_search(dirIn, 'CBERS*.tif', recursive=True)
-
-    if not os.path.exists(dirOut):
-        os.mkdir(dirOut)
-
-    CONTAINERS = dict()
-    for file in files:
-        dn = os.path.dirname(file)
-        bn = os.path.basename(file)
-        #basenames like CBERS_4_MUX_20150603_167_107_L4_BAND5_GRID_SURFACE.tif
-        splitted = bn.split('_')
-        id = '_'.join(splitted[:4])
-        bandName = splitted[7]
-
-        if id not in CONTAINERS.keys():
-            CONTAINERS[id] = dict()
-
-        bandSources = CONTAINERS[id]
-        if bandName not in bandSources.keys():
-            bandSources[bandName] = list()
-        bandSources[bandName].append(file)
-
-    #mosaic all scenes of same date
-    # and stack all bands related to the same channel
-    for id, bandSources in CONTAINERS.items():
-
-        pathVRT = id + '.vrt'
-        pathVRT = os.path.join(dirOut, pathVRT)
-        V = VirtualRasterBuilder()
-
-        #vrt = createVirtualBandStack(bandSources, pathVRT)
-        #add bands in sorted order
-        for bandName in sorted(bandSources.keys()):
-            vBandSources = bandSources[bandName]
-            VB = VirtualBand(name=bandName)
-            for path in vBandSources:
-                VB.addSourceBand(path, 0) #it's always one band only
-
-            V.addVirtualBand(VB)
-        #print(V)
-        V.saveVRT(pathVRT)
-        s = ""
-        #add ISO time stamp
-
-    pass
-
-def groupLandsat(dirIn, dirOut):
-
-    pass
-
-
-if __name__ == '__main__':
-    if True:
-        dirIn = r'H:\CBERS\hugo\Download20170523'
-        dirOut = r'H:\CBERS\VRTs'
-
-        groupCBERS(dirIn, dirOut)
-        exit(0)
-
-    if True:
-        dirIn = r'H:\CBERS\hugo\Download20170523'
-        dirOut = r'H:\CBERS\VRTs'
-        groupCBERS(dirIn, dirOut)
-
-    if True:
-        dirIn = r'H:\RapidEye\3A'
-        dirOut = r'H:\RapidEye\VRTs'
-        groupRapidEyeTiles(dirIn, dirOut)
\ No newline at end of file
-- 
GitLab