Пример #1
0
class WMSAdapter(WMSAdapterBase):
    def __init__(self,
                 styles=None,
                 requires_time=False,
                 requires_elevation=False,
                 requires_version=False):
        super(WMSAdapter, self).__init__(styles=styles,
                                         requires_time=requires_time,
                                         requires_elevation=requires_elevation,
                                         requires_version=requires_version)
        self.cache = WMSCache(collection='pyramid__wms_cache')

    def get_feature_info(self, wherex, wherey, srs, query_layers, info_format,
                         feature_count, exceptions, *args, **kwargs):
        pixel = self.get_2d_dataset(query_layers, srs,
                                    (wherex, wherey, wherex, wherey), 1, 1,
                                    **kwargs)
        arr = None
        if pixel:
            arr = pixel.ReadAsArray()

        return HttpResponse(json.dumps(arr), mimetype='text/plain')

    def get_2d_dataset(self,
                       layers,
                       srs,
                       bbox,
                       width,
                       height,
                       styles=None,
                       bgcolor=None,
                       transparent=False,
                       time=None,
                       elevation=None,
                       v=None,
                       filter=None,
                       **kwargs):
        pyramid = Pyramid.objects(name=layers[0]).first()
        minx, miny, maxx, maxy = bbox

        # see if we need to transform the dataset
        default_srid = Pyramid.objects(name=layers[0]).first().srs

        s_srs = djgdal.SpatialReference(default_srid.decode('ascii'))

        print srs
        if not srs:
            t_srs = djgdal.SpatialReference(default_srid.decode('ascii'))
        else:
            t_srs = djgdal.SpatialReference(srs)

        #print t_srs, s_srs

        s_mins = Point(minx, miny, srid=t_srs.wkt)
        s_maxs = Point(maxx, maxy, srid=t_srs.wkt)
        s_mins.transform(s_srs.srid)
        s_maxs.transform(s_srs.srid)

        # figure out the pixel size.  if we're only after one pixel, like for GetFeatureInfo,
        # it's likely that pxsize will be 0.  In that case, set the pixel size to be the
        # smallest available.
        tminx, tminy, tmaxx, tmaxy = bbox
        minx = s_mins.x
        maxx = s_maxs.x
        miny = s_mins.y
        maxy = s_maxs.y
        pxsize = (maxx - minx) / width

        # case of only looking for one pixel
        if pxsize == 0:
            pxsize = pyramid.pxsize_at_levels[-1]
            maxx = maxx + pxsize
            maxy = maxy + pxsize

        # start with the furthest zoomed out tiles and work our way in, searching for the
        # nearest level to the query
        l = 0
        p = 999999999
        for level, px in enumerate(pyramid.pxsize_at_levels):
            if abs(px - pxsize) < p:
                l = level
                p = abs(px - pxsize)

        # open the index for that level, filter it by our bounding box.
        dataset = ogr.Open(pyramid.indices[l].encode('ascii'))
        index = dataset.GetLayer(0)
        index.ResetReading()
        index.SetSpatialFilterRect(minx, miny, maxx, maxy)
        f = index.GetNextFeature()

        # retrieve tiles
        tiles = []
        while f:
            Tile.objects.ensure_index('tile_name')
            Tile.objects.ensure_index('pyramid', 'tile_name')
            t = Tile.objects(pyramid=pyramid, level=l,
                             tile_name=f.location).first()
            fl = gdal.FileFromMemBuffer('/vsimem/' + t.tile_name, t.data)
            tiles.append(gdal.Open('/vsimem/' + t.tile_name))
            f = index.GetNextFeature()

        del index  # close the index

        # create our output dataset and stitch tiles into it by projecting them in.
        output = gdal.GetDriverByName('MEM').Create("TEMP", width, height,
                                                    pyramid.raster_count,
                                                    pyramid.data_type, [])
        output.SetGeoTransform([
            tminx, (tmaxx - tminx) / width, 0, tmaxy, 0,
            (tminy - tmaxy) / height
        ])
        output.SetProjection(t_srs.wkt)

        #print output.GetGeoTransform()

        for tile in tiles:
            #print tile.GetGeoTransform()
            #print tile.GetProjection()
            #print output.GetProjection()
            gdal.ReprojectImage(tile, output, None, None, gdal.GRA_Bilinear)

        return output

    def layerlist(self):
        for p in Pyramid.objects():
            yield p.name

    def nativesrs(self, layer):
        return Pyramid.objects(name=layer).first().srs

    def nativebbox(self):
        p = Pyramid.objects().first(
        )  # this is a bug.  nativebbox should take a layer, but currently doesn't.
        o = ogr.Open(p.indices[-1].encode('ascii'))
        l = o.GetLayer(0)
        minx, maxx, miny, maxy = l.GetExtent()
        del o
        return minx, miny, maxx, maxy

    def styles(self):
        if self.styles:
            return self.styles.keys()
        else:
            return {}

    def get_cache_record(self, layers, srs, bbox, width, height, styles,
                         format, bgcolor, transparent, time, elevation, v,
                         filter, **kwargs):
        locator = {
            'layers': layers,
            'srs': srs,
            'bbox': bbox,
            'width': width,
            'height': height,
            'styles': styles,
            'format': format,
            'bgcolor': bgcolor,
            'transparent': transparent,
            'time': time,
            'elevation': elevation,
            'v': v,
            'filter': filter
        }

        return self.cache.locate(**locator)

    def get_service_boundaries(self):
        return self.nativebbox()

    def get_layer_descriptions(self):
        ret = []
        for pyramid in Pyramid.objects.all():
            layer = dict()
            layer['name'] = pyramid.name
            layer['title'] = pyramid.title
            layer['srs'] = pyramid.srs
            layer['queryable'] = True
            o = ogr.Open(pyramid.indices[-1].encode('ascii'))
            l = o.GetLayer(0)
            minx, maxx, miny, maxy = l.GetExtent()
            layer['minx'] = minx
            layer['miny'] = miny
            layer['maxx'] = maxx
            layer['maxy'] = maxy
            s_srs = osr.SpatialReference()
            s_srs.ImportFromWkt(pyramid.srs)
            t_srs = osr.SpatialReference()
            t_srs.ImportFromEPSG(4326)
            crx = osr.CoordinateTransformation(s_srs, t_srs)
            ll_minx, ll_miny, _0 = crx.TransformPoint(minx, miny, 0)
            ll_maxx, ll_maxy, _0 = crx.TransformPoint(maxx, maxy, 0)

            layer['ll_minx'] = ll_minx
            layer['ll_miny'] = ll_miny
            layer['ll_maxx'] = ll_maxx
            layer['ll_maxy'] = ll_maxy
            layer['styles'] = []
            if isinstance(self.styles, dict):
                for style in self.styles.keys():
                    layer['styles'].append({
                        "name": style,
                        "title": style,
                        "legend_width": 0,
                        "legend_height": 0,
                        "legend_url": ""
                    })
                    if hasattr(self.styles[style], 'legend_url'):
                        layer['styles'][-1]['legend_url'] = self.styles[
                            style].legend_url
            ret.append(layer)
        return ret

    def get_valid_elevations(self, **kwargs):
        if 'layers' not in kwargs:
            return []
        else:
            p = Pyramid.objects(name=layers[0]).first()
            qs = Tile.objects(pyramid=p)
            if 'filter' in kwargs:
                qs = qs.filter(**kwargs['filter'])
            return qs.distinct('elevation')

    def get_valid_times(self, **kwargs):
        if 'layers' not in kwargs:
            return []
        else:
            p = Pyramid.objects(name=layers[0]).first()
            qs = Tile.objects(pyramid=p)
            if 'filter' in kwargs:
                qs = qs.filter(**kwargs['filter'])
            return qs.distinct('time')

    def get_valid_versions(self, group_by=None, **kwargs):
        if 'layers' not in kwargs:
            return []
        else:
            p = Pyramid.objects(name=layers[0]).first()
            qs = Tile.objects(pyramid=p)
            if 'filter' in kwargs:
                qs = qs.filter(**kwargs['filter'])
            return qs.distinct('version')

    def cache_result(self, item, **kwargs):
        locator = kwargs
        if 'fresh' in locator:
            del locator['fresh']
        self.cache.save(item, **kwargs)
Пример #2
0
class WMSAdapter(WMSAdapterBase):
    def __init__(self, styles=None, requires_time=False, requires_elevation=False, requires_version=False):
        super(WMSAdapter, self).__init__(
            styles=styles,
            requires_time=requires_time,
            requires_elevation=requires_elevation,
            requires_version=requires_version,
        )
        self.cache = WMSCache(collection="pyramid__wms_cache")

    def get_feature_info(
        self, wherex, wherey, srs, query_layers, info_format, feature_count, exceptions, *args, **kwargs
    ):
        pixel = self.get_2d_dataset(query_layers, srs, (wherex, wherey, wherex, wherey), 1, 1, **kwargs)
        arr = None
        if pixel:
            arr = pixel.ReadAsArray()

        return HttpResponse(json.dumps(arr), mimetype="text/plain")

    def get_2d_dataset(
        self,
        layers,
        srs,
        bbox,
        width,
        height,
        styles=None,
        bgcolor=None,
        transparent=False,
        time=None,
        elevation=None,
        v=None,
        filter=None,
        **kwargs
    ):
        pyramid = Pyramid.objects(name=layers[0]).first()
        minx, miny, maxx, maxy = bbox

        # see if we need to transform the dataset
        default_srid = Pyramid.objects(name=layers[0]).first().srs

        s_srs = djgdal.SpatialReference(default_srid.decode("ascii"))

        print srs
        if not srs:
            t_srs = djgdal.SpatialReference(default_srid.decode("ascii"))
        else:
            t_srs = djgdal.SpatialReference(srs)

        # print t_srs, s_srs

        s_mins = Point(minx, miny, srid=t_srs.wkt)
        s_maxs = Point(maxx, maxy, srid=t_srs.wkt)
        s_mins.transform(s_srs.srid)
        s_maxs.transform(s_srs.srid)

        # figure out the pixel size.  if we're only after one pixel, like for GetFeatureInfo,
        # it's likely that pxsize will be 0.  In that case, set the pixel size to be the
        # smallest available.
        tminx, tminy, tmaxx, tmaxy = bbox
        minx = s_mins.x
        maxx = s_maxs.x
        miny = s_mins.y
        maxy = s_maxs.y
        pxsize = (maxx - minx) / width

        # case of only looking for one pixel
        if pxsize == 0:
            pxsize = pyramid.pxsize_at_levels[-1]
            maxx = maxx + pxsize
            maxy = maxy + pxsize

        # start with the furthest zoomed out tiles and work our way in, searching for the
        # nearest level to the query
        l = 0
        p = 999999999
        for level, px in enumerate(pyramid.pxsize_at_levels):
            if abs(px - pxsize) < p:
                l = level
                p = abs(px - pxsize)

        # open the index for that level, filter it by our bounding box.
        dataset = ogr.Open(pyramid.indices[l].encode("ascii"))
        index = dataset.GetLayer(0)
        index.ResetReading()
        index.SetSpatialFilterRect(minx, miny, maxx, maxy)
        f = index.GetNextFeature()

        # retrieve tiles
        tiles = []
        while f:
            Tile.objects.ensure_index("tile_name")
            Tile.objects.ensure_index("pyramid", "tile_name")
            t = Tile.objects(pyramid=pyramid, level=l, tile_name=f.location).first()
            fl = gdal.FileFromMemBuffer("/vsimem/" + t.tile_name, t.data)
            tiles.append(gdal.Open("/vsimem/" + t.tile_name))
            f = index.GetNextFeature()

        del index  # close the index

        # create our output dataset and stitch tiles into it by projecting them in.
        output = gdal.GetDriverByName("MEM").Create("TEMP", width, height, pyramid.raster_count, pyramid.data_type, [])
        output.SetGeoTransform([tminx, (tmaxx - tminx) / width, 0, tmaxy, 0, (tminy - tmaxy) / height])
        output.SetProjection(t_srs.wkt)

        # print output.GetGeoTransform()

        for tile in tiles:
            # print tile.GetGeoTransform()
            # print tile.GetProjection()
            # print output.GetProjection()
            gdal.ReprojectImage(tile, output, None, None, gdal.GRA_Bilinear)

        return output

    def layerlist(self):
        for p in Pyramid.objects():
            yield p.name

    def nativesrs(self, layer):
        return Pyramid.objects(name=layer).first().srs

    def nativebbox(self):
        p = Pyramid.objects().first()  # this is a bug.  nativebbox should take a layer, but currently doesn't.
        o = ogr.Open(p.indices[-1].encode("ascii"))
        l = o.GetLayer(0)
        minx, maxx, miny, maxy = l.GetExtent()
        del o
        return minx, miny, maxx, maxy

    def styles(self):
        if self.styles:
            return self.styles.keys()
        else:
            return {}

    def get_cache_record(
        self,
        layers,
        srs,
        bbox,
        width,
        height,
        styles,
        format,
        bgcolor,
        transparent,
        time,
        elevation,
        v,
        filter,
        **kwargs
    ):
        locator = {
            "layers": layers,
            "srs": srs,
            "bbox": bbox,
            "width": width,
            "height": height,
            "styles": styles,
            "format": format,
            "bgcolor": bgcolor,
            "transparent": transparent,
            "time": time,
            "elevation": elevation,
            "v": v,
            "filter": filter,
        }

        return self.cache.locate(**locator)

    def get_service_boundaries(self):
        return self.nativebbox()

    def get_layer_descriptions(self):
        ret = []
        for pyramid in Pyramid.objects.all():
            layer = dict()
            layer["name"] = pyramid.name
            layer["title"] = pyramid.title
            layer["srs"] = pyramid.srs
            layer["queryable"] = True
            o = ogr.Open(pyramid.indices[-1].encode("ascii"))
            l = o.GetLayer(0)
            minx, maxx, miny, maxy = l.GetExtent()
            layer["minx"] = minx
            layer["miny"] = miny
            layer["maxx"] = maxx
            layer["maxy"] = maxy
            s_srs = osr.SpatialReference()
            s_srs.ImportFromWkt(pyramid.srs)
            t_srs = osr.SpatialReference()
            t_srs.ImportFromEPSG(4326)
            crx = osr.CoordinateTransformation(s_srs, t_srs)
            ll_minx, ll_miny, _0 = crx.TransformPoint(minx, miny, 0)
            ll_maxx, ll_maxy, _0 = crx.TransformPoint(maxx, maxy, 0)

            layer["ll_minx"] = ll_minx
            layer["ll_miny"] = ll_miny
            layer["ll_maxx"] = ll_maxx
            layer["ll_maxy"] = ll_maxy
            layer["styles"] = []
            if isinstance(self.styles, dict):
                for style in self.styles.keys():
                    layer["styles"].append(
                        {"name": style, "title": style, "legend_width": 0, "legend_height": 0, "legend_url": ""}
                    )
                    if hasattr(self.styles[style], "legend_url"):
                        layer["styles"][-1]["legend_url"] = self.styles[style].legend_url
            ret.append(layer)
        return ret

    def get_valid_elevations(self, **kwargs):
        if "layers" not in kwargs:
            return []
        else:
            p = Pyramid.objects(name=layers[0]).first()
            qs = Tile.objects(pyramid=p)
            if "filter" in kwargs:
                qs = qs.filter(**kwargs["filter"])
            return qs.distinct("elevation")

    def get_valid_times(self, **kwargs):
        if "layers" not in kwargs:
            return []
        else:
            p = Pyramid.objects(name=layers[0]).first()
            qs = Tile.objects(pyramid=p)
            if "filter" in kwargs:
                qs = qs.filter(**kwargs["filter"])
            return qs.distinct("time")

    def get_valid_versions(self, group_by=None, **kwargs):
        if "layers" not in kwargs:
            return []
        else:
            p = Pyramid.objects(name=layers[0]).first()
            qs = Tile.objects(pyramid=p)
            if "filter" in kwargs:
                qs = qs.filter(**kwargs["filter"])
            return qs.distinct("version")

    def cache_result(self, item, **kwargs):
        locator = kwargs
        if "fresh" in locator:
            del locator["fresh"]
        self.cache.save(item, **kwargs)