This is an automated email from the ASF dual-hosted git repository.

fgreg pushed a commit to branch SDAP-149
in repository https://gitbox.apache.org/repos/asf/incubator-sdap-nexus.git


The following commit(s) were added to refs/heads/SDAP-149 by this push:
     new f498e9c  SDAP-149 Generate images directly from data
f498e9c is described below

commit f498e9cbd9eef702af138235656af6cb416b2420
Author: Kevin M. Gill <[email protected]>
AuthorDate: Mon Nov 5 09:55:14 2018 -0800

    SDAP-149 Generate images directly from data
    
    Initial work.
---
 analysis/setup.py                                  |   2 +-
 .../algorithms/imaging/ColorTableHandler.py        |  26 ++-
 .../algorithms/imaging/LayerListHandler.py         | 143 +++++++++++++-
 .../webservice/algorithms/imaging/colortable.py    |   7 +-
 .../webservice/algorithms/imaging/colortables.py   |  73 ++++++-
 analysis/webservice/algorithms/imaging/layer.py    | 135 +++++++++++++
 .../webservice/algorithms/imaging/mapprocessing.py |   4 +
 .../webservice/algorithms/imaging/mrf_reader.py    |  85 ++++----
 .../webservice/algorithms/imaging/reprojection.py  | 220 +++++++++++++++------
 data-access/requirements.txt                       |   2 +-
 data-access/setup.py                               |   4 +-
 docker/nexus-webapp/Dockerfile                     |   1 +
 docker/spark-mesos-base/Dockerfile                 |   1 +
 13 files changed, 582 insertions(+), 121 deletions(-)

diff --git a/analysis/setup.py b/analysis/setup.py
index 42903cb..1603073 100644
--- a/analysis/setup.py
+++ b/analysis/setup.py
@@ -16,7 +16,7 @@
 
 import setuptools
 
-__version__ = '1.5'
+__version__ = '1.6'
 
 setuptools.setup(
     name="nexusanalysis",
diff --git a/analysis/webservice/algorithms/imaging/ColorTableHandler.py 
b/analysis/webservice/algorithms/imaging/ColorTableHandler.py
index 9c798ac..0e06c0a 100644
--- a/analysis/webservice/algorithms/imaging/ColorTableHandler.py
+++ b/analysis/webservice/algorithms/imaging/ColorTableHandler.py
@@ -75,9 +75,23 @@ class ColorTableHandler(BaseHandler):
             values.append((value, value_high))
         return values
 
+    def _create_colortable(self, color_table, min_value, max_value, num_items, 
units):
+        colors = ColorTableHandler._create_hex_color_list(color_table, 
num_items)
+        labels = ColorTableHandler._create_labels(min_value, max_value, units, 
num_items)
+        values = ColorTableHandler._create_values(min_value, max_value, 
num_items)
+        return colors, labels, values
+
+    def _create_from_sdap(self, ds, color_table, force_min, force_max, 
num_items, units):
+        stats = self._tile_service.get_dataset_overall_stats(ds)
+        min_value = force_min if force_min is not None else stats["minValue"]
+        max_value = force_max if force_max is not None else stats["maxValue"]
+        return self._create_colortable(color_table, min_value, max_value, 
num_items, units)
+
     def calc(self, computeOptions, **args):
         ds = computeOptions.get_argument("ds")
 
+        generic = computeOptions.get_boolean_arg("generic", False)
+
         color_table_identifier = computeOptions.get_argument("ct", "rainbow")
         color_table = colortables.get_color_table(color_table_identifier)
 
@@ -88,16 +102,12 @@ class ColorTableHandler(BaseHandler):
         num_items = np.array((2048, num_items)).min()
         num_items = np.array((255, num_items)).max()
 
-        stats = self._tile_service.get_dataset_overall_stats(ds)
-
         units = computeOptions.get_argument("units", "&deg;c")
 
-        min_value = force_min if force_min is not None else stats["minValue"]
-        max_value = force_max if force_max is not None else stats["maxValue"]
-
-        colors = ColorTableHandler._create_hex_color_list(color_table, 
num_items)
-        labels = ColorTableHandler._create_labels(min_value, max_value, units, 
num_items)
-        values = ColorTableHandler._create_values(min_value, max_value, 
num_items)
+        if generic is False:
+            colors, labels, values = self._create_from_sdap(ds, color_table, 
force_min, force_max, num_items, units)
+        else:
+            colors, labels, values = self._create_colortable(color_table, 
force_min, force_max, num_items, units)
 
         return ColorTableResponse({
             "units": units,
diff --git a/analysis/webservice/algorithms/imaging/LayerListHandler.py 
b/analysis/webservice/algorithms/imaging/LayerListHandler.py
index f5dd078..fcb2f0d 100644
--- a/analysis/webservice/algorithms/imaging/LayerListHandler.py
+++ b/analysis/webservice/algorithms/imaging/LayerListHandler.py
@@ -17,6 +17,11 @@ import json
 import ConfigParser
 import pkg_resources
 import uuid
+import sys
+import uuid
+import json
+import hashlib
+import layer
 
 from webservice.NexusHandler import NexusHandler as BaseHandler
 from webservice.NexusHandler import nexus_handler
@@ -47,6 +52,109 @@ class LayerListHandler(BaseHandler):
         BaseHandler.__init__(self)
         self.imagery_config = ConfigParser.RawConfigParser()
         self.imagery_config.readfp(pkg_resources.resource_stream(__name__, 
"config.ini"), filename='config.ini')
+        self.static_layers_base = self.imagery_config.get("tileserver", 
"mrf.base")
+        self.parse_static_layers()
+
+    def build_colorbar_url(self, colorbarSpec):
+        if colorbarSpec is None:
+            return None
+        url = 
"{sdap_base}/imaging/colortable?ds={ds}&ct={ct}&min={min}&max={max}&units={units}&generic=true".format(
+            sdap_base=self.imagery_config.get("imaging", "imaging.endpoint"),
+            ds=colorbarSpec["productLabel"],
+            ct=colorbarSpec["colorbarName"],
+            min=colorbarSpec["minValue"],
+            max=colorbarSpec["maxValue"],
+            units=colorbarSpec["units"]
+        )
+        return url
+
+    def build_layer_for_projection(self, layer_def, product_suffix, 
endpoint_proj, layerProjection, tileMatrixSet):
+        layer = {}
+        layer["UUID"] = str(uuid.uuid4())
+        layer["DataID"] = layer_def["productLabel"]
+        layer["ProductLabel"] = "%s%s" % (layer_def["productLabel"], 
product_suffix)
+        layer["CrmShortName"] = layer_def["crmShortName"] if 
layer_def["crmShortName"] is not None else layer_def[
+            "productLabel"]
+        layer["enabled"] = layer_def["enabled"]
+        layer["mission"] = layer_def["mission"]
+        layer["instrument"] = layer_def["instrument"]
+        layer["parameter"] = layer_def["parameter"]
+        layer["ProductType"] = layer_def["productType"]
+        layer["ServiceProtocol"] = layer_def["serviceProtocol"]
+        layer["EndPoint"] = layer_def["endpoint"].format(proj=endpoint_proj)
+        layer["WMSEndPoint"] = ""
+        layer["wmsLayer"] = "0"
+        layer["LayerTitle"] = layer_def["layerTitle"]
+        layer["LayerService"] = layer_def["layerService"]
+        layer["LayerProjection"] = layerProjection
+        layer["availableForAnalysis"] = layer_def["availableForAnalysis"]
+        layer["analysisDatasetName"] = layer_def["analysisDatasetName"]
+        layer["ThumbnailImage"] = layer_def["thumbnailImage"]
+        layer["bounding"] = {
+            "westbc": layer_def["bounding"]["west"],
+            "eastbc": layer_def["bounding"]["east"],
+            "northbc": layer_def["bounding"]["north"],
+            "southbc": layer_def["bounding"]["south"]
+        }
+        layer["LayerSubtitle"] = layer_def["layerSubtitle"]
+        layer["legend"] = ""
+        layer["wmts"] = {
+            "tileMatrixSet": tileMatrixSet,
+            "tileLayerName": layer_def["wmtsLayerName"],
+            "tileFormat": layer_def["wmtsFormat"]
+        }
+
+        layer["nativeResolution"] = "9km"
+        if layer_def["availability"] is not None:
+            layer["availability"] = {
+                "start": layer_def["availability"]["start"],
+                "end": layer_def["availability"]["end"]
+            }
+        else:
+            layer["availability"] = None
+        layer["keywords"] = layer_def["keywords"]
+        layer["utilityLayer"] = layer_def["utilityLayer"]
+        layer["depths"] = layer_def["depthSpec"]
+        layer["type"] = layer_def["type"]
+        layer["colorbar"] = self.build_colorbar_url(layer_def["colorbar"])
+        return layer
+
+    def build_layer(self, layer_def, basemap):
+        layers = []
+        if layer_def["hasGlobal"] is True and basemap == 
layer_def["baseLayer"] and layer_def["overridesSdap"] is False:
+            layers.append(self.build_layer_for_projection(layer_def,
+                                                     "",
+                                                     "geo",
+                                                     
layer_def["layerProjectionGlobal"],
+                                                     
layer_def["wmtsGlobalMatrixSet"]))
+        if layer_def["hasNorth"] is True and basemap == layer_def["baseLayer"] 
and layer_def["overridesSdap"] is False:
+            layers.append(self.build_layer_for_projection(layer_def,
+                                                     "-arctic",
+                                                     "arctic",
+                                                     
layer_def["layerProjectionNorth"],
+                                                     
layer_def["wmtsNorthMatrixSet"]))
+        if layer_def["hasSouth"] is True and basemap == layer_def["baseLayer"] 
and layer_def["overridesSdap"] is False:
+            layers.append(self.build_layer_for_projection(layer_def,
+                                                     "-antarctic",
+                                                     "antarctic",
+                                                     
layer_def["layerProjectionSouth"],
+                                                     
layer_def["wmtsSouthMatrixSet"]))
+        return layers
+
+    def build_layer_config(self, layer_list, basemap):
+        compiled_layers = []
+
+        for entry in layer_list:
+            compiled_layers += self.build_layer(entry, basemap)
+
+        return compiled_layers
+
+    def parse_static_layers(self):
+        sys.path.insert(0, self.static_layers_base)
+        import layers
+
+
+
 
     def _build_layer_spec(self, ds):
         layer = {
@@ -93,13 +201,40 @@ class LayerListHandler(BaseHandler):
         }
         return layer
 
+
+    def apply_layer_overrides(self, sdap_layer):
+        layer_overrides = layer.getLayerByLabel(sdap_layer["ProductLabel"])
+        if layer_overrides["crmShortName"] is not None:
+            sdap_layer["CrmShortName"] = layer_overrides["crmShortName"]
+        if layer_overrides["layerTitle"] is not None:
+            sdap_layer["LayerTitle"] = layer_overrides["layerTitle"]
+        if layer_overrides["layerSubtitle"] is not None:
+            sdap_layer["LayerSubtitle"] = layer_overrides["layerSubtitle"]
+        if layer_overrides["keywords"] is not None:
+            sdap_layer["keywords"] = layer_overrides["keywords"]
+        if layer_overrides["instrument"] is not None:
+            sdap_layer["instrument"] = layer_overrides["instrument"]
+        if layer_overrides["mission"] is not None:
+            sdap_layer["mission"] = layer_overrides["mission"]
+        if layer_overrides["parameter"] is not None:
+            sdap_layer["parameter"] = layer_overrides["parameter"]
+
+
+
     def calc(self, computeOptions, **args):
-        ds_list = self._tile_service.get_dataseries_list()
+        basemaps = computeOptions.get_boolean_arg("basemaps", False)
 
         layers = []
-        for ds in ds_list:
-            layer = self._build_layer_spec(ds)
-            layers.append(layer)
+
+        if basemaps is False:
+            ds_list = self._tile_service.get_dataseries_list()
+            for ds in ds_list:
+                sdap_layer = self._build_layer_spec(ds)
+                self.apply_layer_overrides(sdap_layer)
+                layers.append(sdap_layer)
+
+        compiled_layers = self.build_layer_config(layer.getLayers(), basemaps)
+        layers += compiled_layers
 
         return LayerListResponse({
             "Layers": {
diff --git a/analysis/webservice/algorithms/imaging/colortable.py 
b/analysis/webservice/algorithms/imaging/colortable.py
index 7592b4a..3356477 100644
--- a/analysis/webservice/algorithms/imaging/colortable.py
+++ b/analysis/webservice/algorithms/imaging/colortable.py
@@ -15,13 +15,18 @@
 
 import numpy as np
 import math
-
+import types
 
 class ColorTable:
 
     def __init__(self, identifier, name, spec):
         self.identifier = identifier
         self.name = name
+
+        # If the list of colors was passed in as a list of hex strings 
("ABCDEFFF"), convert them to RGB values
+        if isinstance(spec[0], types.StringType):
+            spec = [[int(p[i:i+2], 16) for i in range(0, 6, 2)] for p in spec]
+
         self.spec = np.array(spec)
 
     def get_color(self, fraction):
diff --git a/analysis/webservice/algorithms/imaging/colortables.py 
b/analysis/webservice/algorithms/imaging/colortables.py
index b1a6392..38afe13 100644
--- a/analysis/webservice/algorithms/imaging/colortables.py
+++ b/analysis/webservice/algorithms/imaging/colortables.py
@@ -1282,7 +1282,78 @@ 
COLORTABLES.append(colortable.ColorTable("NEO_modis_aer_od",
                                          ]
                                          ))
 
-
+COLORTABLES.append(colortable.ColorTable("IMERG_Rain_Rate",
+                                         "IMERG_Rain_Rate",
+                                         [
+                                             "bfbfbfff",
+                                             "007c53ff",
+                                             "00814dff",
+                                             "008548ff",
+                                             "008a41ff",
+                                             "008e3aff",
+                                             "009333ff",
+                                             "00972bff",
+                                             "009c22ff",
+                                             "00a019ff",
+                                             "00a50fff",
+                                             "00aa05ff",
+                                             "05ae00ff",
+                                             "11b300ff",
+                                             "1db700ff",
+                                             "29bc00ff",
+                                             "37c000ff",
+                                             "44c500ff",
+                                             "53c900ff",
+                                             "62ce00ff",
+                                             "71d200ff",
+                                             "81d700ff",
+                                             "92db00ff",
+                                             "a3e000ff",
+                                             "b5e400ff",
+                                             "c8e900ff",
+                                             "dbee00ff",
+                                             "eef200ff",
+                                             "f7eb00ff",
+                                             "fbdf00ff",
+                                             "ffd201ff",
+                                             "ffc305ff",
+                                             "ffb50aff",
+                                             "ffa70eff",
+                                             "ff9913ff",
+                                             "ff8d17ff",
+                                             "ff811cff",
+                                             "ff7520ff",
+                                             "ff6a25ff",
+                                             "ff6029ff",
+                                             "ff562eff",
+                                             "ff4c33ff",
+                                             "ff3628ff",
+                                             "ff1e1eff",
+                                             "ff1414ff",
+                                             "ff0a0aff",
+                                             "ff0000ff",
+                                             "f40000ff",
+                                             "ea0000ff",
+                                             "e00000ff",
+                                             "d60000ff",
+                                             "cc0000ff",
+                                             "c10000ff",
+                                             "b70000ff",
+                                             "ad0000ff",
+                                             "a30000ff",
+                                             "990000ff",
+                                             "8e0000ff",
+                                             "840000ff",
+                                             "7a0000ff",
+                                             "700000ff",
+                                             "660000ff",
+                                             "5b0000ff",
+                                             "510000ff",
+                                             "470000ff",
+                                             "3d0000ff",
+                                             "330000ff"
+                                         ]
+                                         ))
 
 def get_color_table(identifier):
     assert identifier is not None and (isinstance(identifier, 
types.StringType) or isinstance(identifier, types.UnicodeType))
diff --git a/analysis/webservice/algorithms/imaging/layer.py 
b/analysis/webservice/algorithms/imaging/layer.py
new file mode 100644
index 0000000..5fcb5be
--- /dev/null
+++ b/analysis/webservice/algorithms/imaging/layer.py
@@ -0,0 +1,135 @@
+import time
+from datetime import datetime
+
+__LAYERS__ = []
+
+
+def colorbar(productLabel,
+             minValue,
+             maxValue,
+             colorbarName,
+             units
+             ):
+    return {
+        "productLabel": productLabel,
+        "minValue": minValue,
+        "maxValue": maxValue,
+        "colorbarName": colorbarName,
+        "units": units
+    }
+
+def bounding(north=90.0,
+           south=-90.0,
+           east=180.0,
+           west=-180.0):
+    return {
+        "north": north,
+        "south": south,
+        "east": east,
+        "west": west
+    }
+
+def depthspec(title="Depth", units="m", labels=[], values=[]):
+
+    return {
+        "title": title,
+        "labels": labels,
+        "values": values,
+        "units": units,
+    }
+
+def addlayer(
+    productLabel,
+    crmShortName=None,
+    enabled=True,
+    mission="",
+    instrument="Unspecified",
+    parameter="Unspecified",
+    productType="Mosaic",
+    serviceProtocol="GIBS",
+    endpoint="",
+    layerTitle="",
+    layerService="wmtstiled",
+    hasGlobal=True,
+    hasNorth=True,
+    hasSouth=True,
+    thumbnailImage=None,
+    layerSubtitle="",
+    availableForAnalysis=False,
+    analysisDatasetName="",
+    layerProjectionGlobal="EPSG:4326",
+    layerProjectionNorth="EPSG:3413",
+    layerProjectionSouth="EPSG:3031",
+    wmtsGlobalMatrixSet="EPSG4326",
+    wmtsNorthMatrixSet="EPSG3413",
+    wmtsSouthMatrixSet="EPSG3031",
+    wmtsLayerName="",
+    wmtsFormat="image/png",
+    colorbar=None,
+    availability=None,
+    keywords=[],
+    utilityLayer=False,
+    baseLayer=False,
+    depthSpec=None,
+    bounding=bounding(),
+    type="observation",
+    overridesSdap=False):
+
+    global __LAYERS__
+
+    layer = {
+        "productLabel": productLabel,
+        "crmShortName": crmShortName,
+        "enabled": enabled,
+        "mission": mission,
+        "instrument": instrument,
+        "parameter": parameter,
+        "productType": productType,
+        "serviceProtocol": serviceProtocol,
+        "endpoint": endpoint,
+        "layerTitle": layerTitle,
+        "layerService": layerService,
+        "hasGlobal": hasGlobal,
+        "hasNorth": hasNorth,
+        "hasSouth": hasSouth,
+        "thumbnailImage": thumbnailImage,
+        "bounding": bounding,
+        "layerSubtitle": layerSubtitle,
+        "availableForAnalysis": availableForAnalysis,
+        "analysisDatasetName": analysisDatasetName,
+        "layerProjectionGlobal": layerProjectionGlobal,
+        "layerProjectionNorth": layerProjectionNorth,
+        "layerProjectionSouth": layerProjectionSouth,
+        "wmtsGlobalMatrixSet": wmtsGlobalMatrixSet,
+        "wmtsNorthMatrixSet": wmtsNorthMatrixSet,
+        "wmtsSouthMatrixSet": wmtsSouthMatrixSet,
+        "wmtsLayerName": wmtsLayerName,
+        "wmtsFormat": wmtsFormat,
+        "availability": availability,
+        "keywords": keywords,
+        "utilityLayer": utilityLayer,
+        "baseLayer": baseLayer,
+        "colorbar": colorbar,
+        "depthSpec": depthSpec,
+        "type":type,
+        "overridesSdap": overridesSdap
+    }
+
+    __LAYERS__.append(layer)
+
+
+
+def timestamp(year, month, day):
+    dt = datetime(year, month, day)
+    ts = time.mktime(dt.timetuple())
+    return int(ts * 1000)
+
+
+def getLayers():
+    return __LAYERS__
+
+def getLayerByLabel(label):
+    for l in __LAYERS__:
+        if l["productLabel"] == label:
+            return l
+    return None
\ No newline at end of file
diff --git a/analysis/webservice/algorithms/imaging/mapprocessing.py 
b/analysis/webservice/algorithms/imaging/mapprocessing.py
index 3b97dc9..9b1721d 100644
--- a/analysis/webservice/algorithms/imaging/mapprocessing.py
+++ b/analysis/webservice/algorithms/imaging/mapprocessing.py
@@ -29,6 +29,7 @@ import multiprocessing
 
 import colortables
 import colorization
+import reprojection
 
 NO_DATA_IMAGE = None
 
@@ -308,6 +309,9 @@ def process_tiles_to_map(nexus_tiles, stats, reqd_tllr, 
width=None, height=None,
 
     data = trim_map_to_requested_tllr(data, reqd_tllr, tiles_tllr)
     data = expand_map_to_requested_tllr(data, reqd_tllr, tiles_tllr, x_res, 
y_res)
+
+    #data = reprojection.reproject_rgba_map(data, 
reprojection.TargetProjection.NORTH)
+
     if width is not None and height is not None:
         data = imresize(data, (height, width), interp=interpolation)
 
diff --git a/analysis/webservice/algorithms/imaging/mrf_reader.py 
b/analysis/webservice/algorithms/imaging/mrf_reader.py
index cf0267c..addb5bd 100644
--- a/analysis/webservice/algorithms/imaging/mrf_reader.py
+++ b/analysis/webservice/algorithms/imaging/mrf_reader.py
@@ -17,8 +17,13 @@ import os
 import math
 import xml.etree.ElementTree as ET
 import struct
+import numpy as np
+
 
 class MrfMeta:
+    """
+    Implements a basic MRF metadata reader
+    """
 
     def __init__(self, mrf_meta_path):
         self.__mrf_meta_path = mrf_meta_path
@@ -62,13 +67,17 @@ class MrfMeta:
             self.projection = proj_el.text
 
         rsets = root.find("./Rsets")
-        self.rsets_model = rsets.attrib["model"]
-        self.rsets_scale = rsets.attrib["scale"]
-
-
+        if rsets is not None:
+            if "model" in rsets.attrib:
+                self.rsets_model = rsets.attrib["model"]
+            if "scale" in rsets.attrib:
+                self.rsets_scale = rsets.attrib["scale"]
 
 
 class MrfReader:
+    """
+    Implements a basic MRF tile data reader
+    """
 
     def __init__(self, mrf_path):
         self.__mrf_path = mrf_path
@@ -87,68 +96,48 @@ class MrfReader:
 
         len_base = w * h
         low = 1
-        idx_size = int(os.path.getsize(self.__idx_path))
-        len_tiles = idx_size / 16
-        print "Number of tiles:", len_tiles
 
         self.__levels = []
         self.__rows = []
         self.__cols = []
 
-        self.__levels.append(0)
-        self.__rows.append(h)
-        self.__cols.append(w)
-
         while len_base > low:
             self.__levels.append(len_base)
-            w = int(math.ceil(float(w) / 2.0))
-            h = int(math.ceil(float(h) / 2.0))
             self.__rows.append(h)
             self.__cols.append(w)
+
+            w = int(math.ceil(float(w) / 2.0))
+            h = int(math.ceil(float(h) / 2.0))
             len_base = w * h
 
         self.__levels.append(1)
+        self.__rows.append(h)
+        self.__cols.append(w)
 
+    def __read_offset_and_size(self, tile):
+        with open(self.__idx_path, "rb") as idx_file:
+            idx_file.seek(16 * tile, os.SEEK_SET)
+            offset, size = struct.unpack(">2Q", idx_file.read(16))
+            return offset, size
 
+    def __read_tile_data(self, offset, size):
+        with open(self.__data_path) as mrf_file:
+            mrf_file.seek(offset, os.SEEK_SET)
+            return mrf_file.read(size)
 
     def get_tile_bytes(self, tilematrix, tilerow, tilecol):
-        tilematrix = tilematrix + 2
-        level = self.__levels[len(self.__levels) - tilematrix]
-        row = self.__rows[len(self.__levels) - tilematrix]
-        col = self.__cols[len(self.__levels) - tilematrix]
-        #print tilerow, tilecol, level, row, col
-        #assert tilerow > row - 1, "Tile row exceeds the maximum"
-        #assert tilecol > col - 1, "Tole col exceeds the maximum"
-
-        level_start = 0
-
-        for idx in range(0, len(self.__levels)):
-            val = self.__levels[idx]
-            if idx > 0 and self.__levels[idx - 1] == level:
-                break
-            level_start += val
-
-        tile = (tilerow * col) + tilecol + level_start
-
-        offset = 0
-        size = 0
-        buffer = None
-
-        with open(self.__idx_path) as idx_file:
-            idx_file.seek(16 * tile)
-            offset = struct.unpack('L', idx_file.read(8))[0]
-            size = struct.unpack('L', idx_file.read(8))[0]
-
-        with open(self.__mrf_path) as mrf_file:
-            print offset, size
-            mrf_file.seek(offset)
-            buffer = mrf_file.read(size)
+        tilematrix += 1
 
-        return buffer
+        cols = self.__cols[-(tilematrix + 1)]
+        rows = self.__rows[-(tilematrix + 1)]
 
+        assert tilecol < cols, "Tile column exceeds maximum columns for this 
layer/tile matrix"
+        assert tilerow < rows, "Tile row exceeds maximum rows for this 
layer/tile matrix"
 
-if __name__ == "__main__":
+        level_start = np.array(self.__levels[: - (tilematrix + 1) ]).sum()
+        tile = (tilerow * cols) + tilecol + level_start
 
-    mrf_path = 
"/Users/kgill/data/ASCATB-L2-Coastal/ASCATB-L2-Coastal/MRF-GEO/2018/ASCATBL2Coastal_2018254_.mrf"
+        offset, size = self.__read_offset_and_size(tile)
+        tile_data = self.__read_tile_data(offset, size)
+        return tile_data
 
-    reader = MrfReader(mrf_path)
\ No newline at end of file
diff --git a/analysis/webservice/algorithms/imaging/reprojection.py 
b/analysis/webservice/algorithms/imaging/reprojection.py
index 7c22f2b..9c4abe2 100644
--- a/analysis/webservice/algorithms/imaging/reprojection.py
+++ b/analysis/webservice/algorithms/imaging/reprojection.py
@@ -18,76 +18,186 @@ import numpy as np, sys
 from osgeo import gdal, osr
 from osgeo.gdalconst import *
 import tempfile
+from PIL import Image
 
 gdal.AllRegister()
 
 
 
-def reproject_2d_matrix(from_data):
+class TargetProjection:
+    NORTH = "north"
+    SOUTH = "south"
 
-    #sr.SetWellKnownGeogCS("EPSG:4326")
-    output_raster = "foo.tif"
+latitude_origin_north = 52.6
+latitude_origin_south = -52.6
 
+dst_proj4_north = '+proj=stere +lat_0=90 +lat_ts=52.6 +lon_0=-45 +k=1 +x_0=0 
+y_0=0 +datum=WGS84 +units=m +no_defs'
+dst_proj4_south = '+proj=stere +lat_0=-90 +lat_ts=-52.6 +lon_0=0 +k=1 +x_0=0 
+y_0=0 +datum=WGS84 +units=m +no_defs'
+
+
+def create_global_dataset(data):
     driver = gdal.GetDriverByName("MEM")
-    dataset = driver.Create(output_raster, from_data.shape[1], 
from_data.shape[0], 1, gdal.GDT_Float32)
-    gt = (-180.0, (360.0 / float(from_data.shape[1])), 0, -90.0, 0, (180.0 / 
float(from_data.shape[0])))
-    dataset.SetGeoTransform(gt)
+    src_ds = driver.Create("", data.shape[1], data.shape[0], 1, gdal.GDT_Byte)
+    gt = (-180.0,
+          (360.0 / float(data.shape[1])),
+          0,
+          90.0,
+          0,
+          -(180.0 / float(data.shape[0])))
+
+    sr = osr.SpatialReference()
+    sr.ImportFromEPSG(4326)
+
+    src_ds.SetProjection(sr.ExportToWkt())
+    src_ds.SetGeoTransform(gt)
+    src_ds.GetRasterBand(1).WriteArray(data)
 
-    dataset.GetRasterBand(1).WriteArray(np.flip(from_data, axis=0))
+    return src_ds
 
+def create_north_dataset(data, latitude_cutoff=latitude_origin_north):
+
+    lat_cutoff_pixel = int(round((90 - latitude_cutoff) / 180.0 * 
float(data.shape[0])))
+    data_cutoff = data[:lat_cutoff_pixel]
+    driver = gdal.GetDriverByName("MEM")
+    src_ds = driver.Create("", data_cutoff.shape[1], data_cutoff.shape[0], 1, 
gdal.GDT_Byte)
+    gt = (-180.0,
+          (360.0 / float(data_cutoff.shape[1])),
+          0,
+          90.0,
+          0,
+          -((90 - latitude_cutoff) / float(data_cutoff.shape[0])))
+    print gt
     sr = osr.SpatialReference()
     sr.ImportFromEPSG(4326)
-    dataset.SetProjection(sr.ExportToWkt())
-
-    outSpatialRef = osr.SpatialReference()
-    outSpatialRef.ImportFromEPSG(3031)
-
-    from_sr = sr
-    to_sr = outSpatialRef
-
-    pixel_spacing = 105000.
-    tx = osr.CoordinateTransformation(from_sr, to_sr)
-    geo_t = dataset.GetGeoTransform()
-    print geo_t
-    x_size = dataset.RasterXSize  # Raster xsize
-    y_size = dataset.RasterYSize  # Raster ysize
-    # Work out the boundaries of the new dataset in the target projection
-    (ulx, uly, ulz) = tx.TransformPoint(geo_t[0], geo_t[3])
-    (lrx, lry, lrz) = tx.TransformPoint(geo_t[0] + geo_t[1] * x_size, geo_t[3] 
+ geo_t[5] * y_size)
-
-    #dest_cols = int((lrx - ulx) / pixel_spacing)
-    #dest_rows = int((uly - lry) / pixel_spacing)
-    #print dest_cols, dest_rows
-    #print dest_cols, dest_rows
-    dest = driver.Create('', from_data.shape[1], from_data.shape[0], 1, 
gdal.GDT_Float32)
-    # Calculate the new geotransform
-    new_geo = (ulx, pixel_spacing, geo_t[2], \
-               uly, geo_t[4], -pixel_spacing)
-    # Set the geotransform
-    dest.SetGeoTransform(new_geo)
-    dest.SetProjection(to_sr.ExportToWkt())
-
-
-    res = gdal.ReprojectImage(dataset, dest,
-                              from_sr.ExportToWkt(), """PROJCS["WGS 84 / NSIDC 
Sea Ice Polar Stereographic North",GEOGCS["WGS 
84",DATUM["WGS_1984",SPHEROID["WGS 
84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Polar_Stereographic"],PARAMETER["latitude_of_origin",70],PARAMETER[
 [...]
-                              gdal.GRA_Bilinear)
-
-    a = dest.GetRasterBand(1).ReadAsArray()
-    return a
-
-def reproject_rgba_map(from_data):
-    from_data[:, :, 0] = reproject_2d_matrix(from_data[:, :, 0])
-    from_data[:, :, 1] = reproject_2d_matrix(from_data[:, :, 1])
-    from_data[:, :, 2] = reproject_2d_matrix(from_data[:, :, 2])
-    from_data[:, :, 3] = reproject_2d_matrix(from_data[:, :, 3])
 
+    src_ds.SetProjection(sr.ExportToWkt())
+    src_ds.SetGeoTransform(gt)
 
-if __name__ == "__main__":
+    src_ds.GetRasterBand(1).WriteArray(data_cutoff)
+
+    return src_ds
+
+
+def create_south_dataset(data, latitude_cutoff=latitude_origin_south):
+    lat_cutoff_pixel = int(round((90 - latitude_cutoff) / 180.0 * 
float(data.shape[0])))
+
+    data_cutoff = data[lat_cutoff_pixel:]
+    driver = gdal.GetDriverByName("GTiff")
+    src_ds = driver.Create("test_south.tif", data_cutoff.shape[1], 
data_cutoff.shape[0], 1, gdal.GDT_Byte)
+    gt = (-180.0,
+          (360.0 / float(data_cutoff.shape[1])),
+          0,
+          latitude_cutoff,
+          0,
+          -((latitude_cutoff - -90) / float(data_cutoff.shape[0])))
+
+    print gt
+    sr = osr.SpatialReference()
+    sr.ImportFromEPSG(4326)
+
+    src_ds.SetProjection(sr.ExportToWkt())
+    src_ds.SetGeoTransform(gt)
+
+    src_ds.GetRasterBand(1).WriteArray(data_cutoff)
+
+    return src_ds
+
+
+
+def reproject_2d_matrix(from_data, target_proj):
+    srs = osr.SpatialReference()
 
-    data = np.zeros((512, 1024, 4))
-    data[250:260, 0:1024, :] = 255
-    data[0:512, 512:522, :] = 255
+    if target_proj == TargetProjection.NORTH:
+        src_ds = create_north_dataset(from_data, latitude_origin_north)
+        srs.ImportFromProj4(dst_proj4_north)
+        dst_wkt = srs.ExportToWkt()
+    elif target_proj == TargetProjection.SOUTH:
+        src_ds = create_south_dataset(from_data, latitude_origin_south)
+        srs.ImportFromProj4(dst_proj4_south)
+        dst_wkt = srs.ExportToWkt()
+    else:
+        raise Exception("Unsupported target projection")
 
-    reproject_rgba_map(data)
+    error_threshold = 0.125  # error threshold --> use same value as in 
gdalwarp
+    resampling = gdal.GRA_NearestNeighbour
+
+    tmp_ds = gdal.AutoCreateWarpedVRT(src_ds,
+                                      None,  # src_wkt : left to default value 
--> will use the one from source
+                                      dst_wkt,
+                                      resampling,
+                                      error_threshold)
+
+
+    dst_xsize = tmp_ds.RasterXSize
+    dst_ysize = tmp_ds.RasterYSize
+    dst_gt = tmp_ds.GetGeoTransform()
+
+    tmp_ds = None
+
+    dst_ds = gdal.GetDriverByName('MEM').Create('', dst_xsize, dst_ysize, 
src_ds.RasterCount)
+    dst_ds.SetProjection(dst_wkt)
+    dst_ds.SetGeoTransform(dst_gt)
+    dst_ds.GetRasterBand(1).SetNoDataValue(0)
+
+    res = gdal.ReprojectImage(src_ds,
+                                dst_ds,
+                                None,  # src_wkt : left to default value --> 
will use the one from source
+                                None,  # dst_wkt : left to default value --> 
will use the one from destination
+                                resampling,
+                                0,  # WarpMemoryLimit : left to default value
+                                error_threshold,
+                                None,  # Progress callback : could be left to 
None or unspecified for silent progress
+                                None,
+                                ("SOURCE_EXTRA=125",)) # Progress callback 
user data)
+
+    assert res == 0, 'Error in ReprojectImage'
+
+    return dst_ds.GetRasterBand(1).ReadAsArray()
+
+def reproject_rgba_map(from_data, target_proj):
+    data_0 = reproject_2d_matrix(from_data[:, :, 0], target_proj)
+    data_1 = reproject_2d_matrix(from_data[:, :, 1], target_proj)
+    data_2 = reproject_2d_matrix(from_data[:, :, 2], target_proj)
+    data_3 = reproject_2d_matrix(from_data[:, :, 3], target_proj)
+
+    dest_data = np.zeros((data_0.shape[0], data_0.shape[1], 4))
+    dest_data[:, :, 0] = data_0
+    dest_data[:, :, 1] = data_1
+    dest_data[:, :, 2] = data_2
+    dest_data[:, :, 3] = data_3
+
+
+    return dest_data
+
+
+
+
+def create_test_data(h=512, w=1024):
+    data = np.zeros((h, w, 4))
+
+    h_mid = h / 2
+    w_mid = w / 2
+    data[h_mid-10:h_mid+10, 0:w, 0:2] = 255
+    data[0:h, w_mid-5:w_mid+5, 0:2] = 255
+    data[:, :, 3] = 255
+    return data
+
+
+def read_test_data():
+    path = "test_pre.png"
+    image = Image.open(path)
+    im = np.copy(np.asarray(image, dtype=np.uint8))
+    return im
+
+
+if __name__ == "__main__":
+    data = read_test_data()
+    out_data = reproject_rgba_map(data, TargetProjection.SOUTH)
+    im = Image.fromarray(np.asarray(out_data, dtype=np.uint8))
+    im.save("test_warp.png")
+    #im = Image.fromarray(np.asarray(out_data, dtype=np.uint8))
+    #im.save("test_warp.tif")
+
+    #reproject_rgba_map(data)
 
 
diff --git a/data-access/requirements.txt b/data-access/requirements.txt
index 1901db2..651f776 100644
--- a/data-access/requirements.txt
+++ b/data-access/requirements.txt
@@ -14,7 +14,7 @@ futures==3.1.1
 ipython==5.3.0
 ipython-genutils==0.2.0
 jmespath==0.9.3
-nexusproto==1.0.0-SNAPSHOT
+nexusproto==1.0.0
 numpy==1.11.1
 pathlib2==2.2.1
 pexpect==4.2.1
diff --git a/data-access/setup.py b/data-access/setup.py
index 532dede..031ccb0 100644
--- a/data-access/setup.py
+++ b/data-access/setup.py
@@ -16,7 +16,7 @@
 import setuptools
 from Cython.Build import cythonize
 
-__version__ = '0.32'
+__version__ = '0.33'
 
 setuptools.setup(
     name="nexus-data-access",
@@ -36,7 +36,7 @@ setuptools.setup(
         'cassandra-driver==3.5.0',
         'pysolr==3.7.0',
         'requests',
-        'nexusproto==1.0.0-SNAPSHOT',
+        'nexusproto==1.0.0',
         'shapely'
     ],
 
diff --git a/docker/nexus-webapp/Dockerfile b/docker/nexus-webapp/Dockerfile
index 3b2d5f9..94ea293 100644
--- a/docker/nexus-webapp/Dockerfile
+++ b/docker/nexus-webapp/Dockerfile
@@ -82,6 +82,7 @@ ARG 
APACHE_NEXUSPROTO=https://github.com/apache/incubator-sdap-nexusproto.git
 ARG APACHE_NEXUSPROTO_BRANCH=master
 ARG APACHE_NEXUS=https://github.com/apache/incubator-sdap-nexus.git
 ARG APACHE_NEXUS_BRANCH=master
+ARG REBUILD_CODE=1
 RUN /tmp/install_nexusproto.sh $APACHE_NEXUSPROTO $APACHE_NEXUSPROTO_BRANCH && 
\
     /tmp/install_nexus.sh $APACHE_NEXUS $APACHE_NEXUS_BRANCH $NEXUS_SRC
 
diff --git a/docker/spark-mesos-base/Dockerfile 
b/docker/spark-mesos-base/Dockerfile
index 784f56c..4c27bd6 100644
--- a/docker/spark-mesos-base/Dockerfile
+++ b/docker/spark-mesos-base/Dockerfile
@@ -125,6 +125,7 @@ RUN yum install -y mesa-libGL.x86_64
 # Install nexusproto
 ARG APACHE_NEXUSPROTO=https://github.com/apache/incubator-sdap-nexusproto.git
 ARG APACHE_NEXUSPROTO_BRANCH=master
+ARG REBUILD_CODE=1
 COPY install_nexusproto.sh ./install_nexusproto.sh
 RUN ./install_nexusproto.sh $APACHE_NEXUSPROTO $APACHE_NEXUSPROTO_BRANCH
 

Reply via email to