Ejemplo n.º 1
0
    def handle(self, request):
        decoder = WMS13GetMapDecoder(request.GET)

        bbox = decoder.bbox
        time = decoder.time
        crs = decoder.crs
        layers = decoder.layers

        if not layers:
            raise InvalidParameterException("No layers specified", "layers")

        srid = crss.parseEPSGCode(
            crs, (crss.fromShortCode, crss.fromURN, crss.fromURL))
        if srid is None:
            raise InvalidCRS(crs, "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        subsets = Subsets((
            Trim("x", minx, maxx),
            Trim("y", miny, maxy),
        ),
                          crs=crs)
        if time:
            subsets.append(time)

        # TODO: adjust way to get to renderer

        styles = decoder.styles

        if styles:
            styles = styles.split(',')

        from eoxserver.services.ows.wms.layerquery import LayerQuery

        render_map = LayerQuery().create_map(
            layers=layers,
            styles=styles,
            bbox=bbox,
            crs=crs,
            width=decoder.width,
            height=decoder.height,
            format=decoder.format,
            transparent=decoder.transparent,
            bgcolor=decoder.bgcolor,
            time=time,
            range=decoder.dim_range,
            bands=None,
            wavelengths=None,
            elevation=None,
            cql=decoder.cql,
        )

        from eoxserver.render.mapserver.map_renderer import MapserverMapRenderer

        return MapserverMapRenderer().render_map(render_map)
Ejemplo n.º 2
0
    def bbox(self):
        bbox = self._bbox
        crs = self.crs
        srid = crss.parseEPSGCode(
            self.crs, (crss.fromShortCode, crss.fromURN, crss.fromURL))
        if srid is None:
            raise InvalidCRS(crs, "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        return (minx, miny, maxx, maxy)
Ejemplo n.º 3
0
    def handle(self, request):
        decoder = WMS13GetMapDecoder(request.GET)

        bbox = decoder.bbox
        time = decoder.time
        crs = decoder.crs
        layers = decoder.layers

        if not layers:
            raise InvalidParameterException("No layers specified", "layers")

        srid = crss.parseEPSGCode(
            crs, (crss.fromShortCode, crss.fromURN, crss.fromURL)
        )
        if srid is None:
            raise InvalidCRS(crs, "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        subsets = Subsets((
            Trim("x", minx, maxx),
            Trim("y", miny, maxy),
        ), crs=crs)
        if time:
            subsets.append(time)

        renderer = self.renderer
        root_group = lookup_layers(layers, subsets, renderer.suffixes)

        result, _ = renderer.render(
            root_group, request.GET.items(),
            width=int(decoder.width), height=int(decoder.height),
            time=decoder.time, bands=decoder.dim_bands, subsets=subsets,
            elevation=decoder.elevation,
            dimensions=dict(
                (key[4:], values) for key, values in decoder.dimensions
            )
        )

        return to_http_response(result)
Ejemplo n.º 4
0
    def encode_rectified_grid(self, grid, coverage, name):
        axis_names = [axis.name for axis in grid]
        offsets = [axis.offset for axis in grid]
        origin = coverage.origin

        sr = SpatialReference(grid.coordinate_reference_system)
        url = sr.url

        frmt = "%.3f" if sr.IsProjected() else "%.8f"
        offset_vectors = [
            GML("offsetVector",
                " ".join([frmt % 0.0] * i + [frmt % offset] + [frmt % 0.0] *
                         (len(offsets) - i - 1)),
                srsName=url) for i, offset in enumerate(offsets)
        ]

        if crss.hasSwappedAxes(sr.srid):
            axis_names[0:2] = [axis_names[1], axis_names[0]]
            # offset_vectors[0:2] = [offset_vectors[1], offset_vectors[0]]
            for offset_vector in offset_vectors[0:2]:
                parts = offset_vector.text.split(" ")
                parts[0:2] = reversed(parts[0:2])
                offset_vector.text = " ".join(parts)

            origin[0:2] = [origin[1], origin[0]]

        origin_str = " ".join(["%.3f" if sr.IsProjected() else "%.8f"] *
                              len(origin)) % tuple(origin)

        return GML(
            "RectifiedGrid",
            GML("limits", self.encode_grid_envelope(coverage.size)),
            GML("axisLabels", " ".join(axis_names)),
            GML(
                "origin",
                GML(
                    "Point", GML("pos", origin_str), **{
                        ns_gml("id"): self.get_gml_id("%s_origin" % name),
                        "srsName": url
                    })), *offset_vectors, **{
                        ns_gml("id"): self.get_gml_id(name),
                        "dimension": "2"
                    })
Ejemplo n.º 5
0
def parse_mask(mask_elem):
    nsmap = {k: v for k, v in iteritems(mask_elem.nsmap) if k}
    # name = mask_elem.xpath('gml:name/text()', namespaces=nsmap)[0]
    try:
        crs = mask_elem.xpath('gml:boundedBy/gml:Envelope/@srsName',
                              namespaces=nsmap)[0]
    except IndexError:
        # just return an empty polygon when no mask available
        return MultiPolygon()

    srid = crss.parseEPSGCode(crs, [crss.fromURN])
    swap = crss.hasSwappedAxes(srid)

    mask_features = [
        parse_polygon(polygon_elem, nsmap, swap)
        for polygon_elem in mask_elem.xpath(
            'eop:maskMembers/eop:MaskFeature/eop:extentOf/gml:Polygon',
            namespaces=nsmap)
    ]
    return MultiPolygon(mask_features, srid=srid)
Ejemplo n.º 6
0
    def handle(self, request):
        decoder = WMS13GetFeatureInfoDecoder(request.GET)

        bbox = decoder.bbox
        time = decoder.time
        crs = decoder.crs
        layers = decoder.layers

        if not layers:
            raise InvalidParameterException("No layers specified", "layers")

        srid = crss.parseEPSGCode(
            crs, (crss.fromShortCode, crss.fromURN, crss.fromURL))
        if srid is None:
            raise InvalidParameterException("Invalid CRS specifier.", "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        subsets = Subsets((
            Trim("x", minx, maxx),
            Trim("y", miny, maxy),
        ),
                          crs=crs)
        if time:
            subsets.append(time)

        renderer = self.renderer
        root_group = lookup_layers(layers, subsets, renderer.suffixes)

        result, _ = renderer.render(root_group,
                                    request.GET.items(),
                                    request,
                                    time=decoder.time,
                                    bands=decoder.dim_bands)
        return to_http_response(result)
Ejemplo n.º 7
0
    def handle(self, request):
        decoder = WMS13GetMapDecoder(request.GET)

        bbox = decoder.bbox
        time = decoder.time
        crs = decoder.crs
        layers = decoder.layers
        elevation = decoder.elevation

        if not layers:
            raise InvalidParameterException("No layers specified", "layers")

        srid = crss.parseEPSGCode(
            crs, (crss.fromShortCode, crss.fromURN, crss.fromURL)
        )
        if srid is None:
            raise InvalidCRS(crs, "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        subsets = Subsets((
            Trim("x", minx, maxx, crs),
            Trim("y", miny, maxy, crs),
        ))
        if time:
            subsets.append(time)
        
        renderer = self.renderer

        result, _ = renderer.render(
            layers, (minx, miny, maxx, maxy), crs, 
            (decoder.width, decoder.height), decoder.format, time, elevation, decoder.styles
        )

        return to_http_response(result)
Ejemplo n.º 8
0
    def handle(self, request):
        decoder = WMS13GetFeatureInfoDecoder(request.GET)

        bbox = decoder.bbox
        time = decoder.time
        crs = decoder.crs
        layers = decoder.layers

        if not layers:
            raise InvalidParameterException("No layers specified", "layers")

        srid = crss.parseEPSGCode(
            crs, (crss.fromShortCode, crss.fromURN, crss.fromURL)
        )
        if srid is None:
            raise InvalidParameterException("Invalid CRS specifier.", "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        subsets = Subsets((
            Trim("x", minx, maxx),
            Trim("y", miny, maxy),
        ), crs=crs)
        if time: 
            subsets.append(time)
        
        renderer = self.renderer
        root_group = lookup_layers(layers, subsets, renderer.suffixes)

        result, _ = renderer.render(
            root_group, request.GET.items(), 
            time=decoder.time, bands=decoder.dim_bands
        )
        return to_http_response(result)
Ejemplo n.º 9
0
    def handle(self, request):
        decoder = WMS13GetMapDecoder(request.GET)

        bbox = decoder.bbox
        time = decoder.time
        crs = decoder.crs
        layers = decoder.layers
        elevation = decoder.elevation

        if not layers:
            raise InvalidParameterException("No layers specified", "layers")

        srid = crss.parseEPSGCode(
            crs, (crss.fromShortCode, crss.fromURN, crss.fromURL))
        if srid is None:
            raise InvalidCRS(crs, "crs")

        if crss.hasSwappedAxes(srid):
            miny, minx, maxy, maxx = bbox
        else:
            minx, miny, maxx, maxy = bbox

        subsets = Subsets((
            Trim("x", minx, maxx, crs),
            Trim("y", miny, maxy, crs),
        ))
        if time:
            subsets.append(time)

        renderer = self.renderer

        result, _ = renderer.render(layers, (minx, miny, maxx, maxy), crs,
                                    (decoder.width, decoder.height),
                                    decoder.format, time, elevation,
                                    decoder.styles)

        return to_http_response(result)
Ejemplo n.º 10
0
def _georef_from_parsed(parsed_browse, clipping=None):
    srid = fromShortCode(parsed_browse.reference_system_identifier)

    if parsed_browse.reference_system_identifier == "RAW" and parsed_browse.geo_type != "modelInGeotiffBrowse":
        raise IngestionException(
            "Given referenceSystemIdentifier '%s' not "
            "valid for a '%s'." % (parsed_browse.reference_system_identifier, parsed_browse.geo_type)
        )

    if srid is None and parsed_browse.reference_system_identifier != "RAW":
        raise IngestionException(
            "Given referenceSystemIdentifier '%s' not valid." % parsed_browse.reference_system_identifier
        )

    swap_axes = hasSwappedAxes(srid)

    if parsed_browse.geo_type == "rectifiedBrowse":
        coords = decode_coord_list(parsed_browse.coord_list, swap_axes)
        # values are for bottom/left and top/right pixel
        coords = [coord for pair in coords for coord in pair]
        assert len(coords) == 4
        return Extent(*coords, srid=srid)

    elif parsed_browse.geo_type == "footprintBrowse":
        # Generate GCPs from footprint coordinates
        pixels = decode_coord_list(parsed_browse.col_row_list)
        coord_list = decode_coord_list(parsed_browse.coord_list, swap_axes)

        if _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid]):
            logger.info("Footprint crosses the dateline. Normalizing it.")
            coord_list = _unwrap_coord_list(coord_list, CRS_BOUNDS[srid])

        assert len(pixels) == len(coord_list)
        gcps = [(x, y, pixel, line) for (x, y), (pixel, line) in zip(coord_list, pixels)]

        # check that the last point of the footprint is the first
        if not gcps[0] == gcps[-1]:
            raise IngestionException("The last value of the footprint is not " "equal to the first.")
        gcps.pop()

        return GCPList(gcps, srid)

    elif parsed_browse.geo_type == "regularGridBrowse":
        # calculate a list of pixel coordinates according to the values of the
        # parsed browse report (col_node_number * row_node_number)
        range_x = arange(0.0, parsed_browse.row_node_number * parsed_browse.row_step, parsed_browse.row_step)
        range_y = arange(0.0, parsed_browse.col_node_number * parsed_browse.col_step, parsed_browse.col_step)
        pixels = [(x, y) for x in range_x for y in range_y]

        # apply clipping
        if clipping:
            clip_x, clip_y = clipping
            pixels[:] = [(min(clip_x, x), min(clip_y, y)) for x, y in pixels]

        # decode coordinate lists and check if any crosses the dateline
        coord_lists = []
        crosses_dateline = False
        for coord_list in parsed_browse.coord_lists:
            coord_list = decode_coord_list(coord_list, swap_axes)

            crosses_dateline = crosses_dateline or _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid])
            coord_lists.append(coord_list)

        # if any coordinate list was crossing the dateline, unwrap all
        # coordinate lists
        if crosses_dateline:
            logger.info("Regular grid crosses the dateline. Normalizing it.")
            coord_lists = [_unwrap_coord_list(coord_list, CRS_BOUNDS[srid]) for coord_list in coord_lists]

        coords = []
        for coord_list in coord_lists:
            coords.extend(coord_list)

        # check validity of regularGrid
        if len(parsed_browse.coord_lists) != parsed_browse.row_node_number:
            raise IngestionException(
                "Invalid regularGrid: number of coordinate " "lists is not equal to the given row node " "number."
            )

        elif len(coords) / len(parsed_browse.coord_lists) != parsed_browse.col_node_number:
            raise IngestionException("Invalid regularGrid: number of coordinates " "does not fit given columns number.")

        gcps = [(x, y, pixel, line) for (x, y), (pixel, line) in zip(coords, pixels)]
        return GCPList(gcps, srid)

    elif parsed_browse.geo_type == "modelInGeotiffBrowse":
        return None

    else:
        raise NotImplementedError("Invalid geo-reference type '%s'." % parsed_browse.geo_type)
Ejemplo n.º 11
0
    def encode_bounded_by(self, coverage, grid=None, subset_extent=None):
        # if grid is None:
        footprint = coverage.footprint

        if grid and not grid.is_referenceable:
            sr = SpatialReference(grid.coordinate_reference_system)
            labels = grid.names
            axis_units = " ".join(["m" if sr.IsProjected() else "deg"] *
                                  len(labels))
            extent = list(subset_extent) if subset_extent else list(
                coverage.extent)

            lc = extent[:len(extent) // 2]
            uc = extent[len(extent) // 2:]

            if crss.hasSwappedAxes(sr.srid):
                labels[0:2] = labels[1], labels[0]
                lc[0:2] = lc[1], lc[0]
                uc[0:2] = uc[1], uc[0]

            frmt = " ".join(["%.3f" if sr.IsProjected() else "%.8f"] *
                            len(labels))

            lower_corner = frmt % tuple(lc)
            upper_corner = frmt % tuple(uc)
            axis_labels = " ".join(labels)
            srs_name = sr.url

        elif footprint:
            minx, miny, maxx, maxy = subset_extent or footprint.extent
            sr = SpatialReference(4326)
            swap = crss.getAxesSwapper(sr.srid)
            labels = ("x", "y") if sr.IsProjected() else ("long", "lat")
            axis_labels = " ".join(swap(*labels))
            axis_units = "m m" if sr.IsProjected() else "deg deg"
            frmt = "%.3f %.3f" if sr.IsProjected() else "%.8f %.8f"

            # Make sure values are outside of actual extent
            if sr.IsProjected():
                minx -= 0.0005
                miny -= 0.0005
                maxx += 0.0005
                maxy += 0.0005
            else:
                minx -= 0.000000005
                miny -= 0.000000005
                maxx += 0.000000005
                maxy += 0.000000005

            lower_corner = frmt % swap(minx, miny)
            upper_corner = frmt % swap(maxx, maxy)
            srs_name = sr.url

        else:
            lower_corner = ""
            upper_corner = ""
            srs_name = ""
            axis_labels = ""
            axis_units = ""

        return GML(
            "boundedBy",
            GML("Envelope",
                GML("lowerCorner", lower_corner),
                GML("upperCorner", upper_corner),
                srsName=srs_name,
                axisLabels=axis_labels,
                uomLabels=axis_units,
                srsDimension="2"))
Ejemplo n.º 12
0
def _georef_from_parsed(parsed_browse, clipping=None):
    srid = fromShortCode(parsed_browse.reference_system_identifier)

    if (parsed_browse.reference_system_identifier == "RAW" and
        parsed_browse.geo_type != "modelInGeotiffBrowse"):
        raise IngestionException("Given referenceSystemIdentifier '%s' not "
                                 "valid for a '%s'."
                                 % (parsed_browse.reference_system_identifier,
                                    parsed_browse.geo_type))

    if srid is None and parsed_browse.reference_system_identifier != "RAW":
        raise IngestionException("Given referenceSystemIdentifier '%s' not valid."
                                 % parsed_browse.reference_system_identifier)

    swap_axes = hasSwappedAxes(srid)

    if parsed_browse.geo_type == "rectifiedBrowse":
        coords = decode_coord_list(parsed_browse.coord_list, swap_axes)
        # values are for bottom/left and top/right pixel
        coords = [coord for pair in coords for coord in pair]
        assert(len(coords) == 4)
        return Extent(*coords, srid=srid)

    elif parsed_browse.geo_type == "footprintBrowse":
        # Generate GCPs from footprint coordinates
        pixels = decode_coord_list(parsed_browse.col_row_list)
        # substitute ncol and nrow with image size
        if clipping:
            clip_x, clip_y = clipping
            pixels[:] = [(clip_x if x == "ncol" else x, clip_y if y == "nrow"
                         else y) for x, y in pixels]
        coord_list = decode_coord_list(parsed_browse.coord_list, swap_axes)

        if _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid]):
            logger.info("Footprint crosses the dateline. Normalizing it.")
            coord_list = _unwrap_coord_list(coord_list, CRS_BOUNDS[srid])

        assert(len(pixels) == len(coord_list))
        gcps = [(x, y, pixel, line)
                for (x, y), (pixel, line) in zip(coord_list, pixels)]


        # check that the last point of the footprint is the first
        if not gcps[0] == gcps[-1]:
            raise IngestionException("The last value of the footprint is not "
                                     "equal to the first.")
        gcps.pop()

        return GCPList(gcps, srid)

    elif parsed_browse.geo_type == "regularGridBrowse":
        # calculate a list of pixel coordinates according to the values of the
        # parsed browse report (col_node_number * row_node_number)
        range_x = arange(
            0.0, parsed_browse.row_node_number * parsed_browse.row_step,
            parsed_browse.row_step
        )
        range_y = arange(
            0.0, parsed_browse.col_node_number * parsed_browse.col_step,
            parsed_browse.col_step
        )
        pixels = [(x, y) for x in range_x for y in range_y]

        # apply clipping
        if clipping:
            clip_x, clip_y = clipping
            pixels[:] = [
                (min(clip_x, x), min(clip_y, y)) for x, y in pixels
            ]

        # decode coordinate lists and check if any crosses the dateline
        coord_lists = []
        crosses_dateline = False
        for coord_list in parsed_browse.coord_lists:
            coord_list = decode_coord_list(coord_list, swap_axes)

            crosses_dateline = crosses_dateline or \
                _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid])
            coord_lists.append(coord_list)

        # if any coordinate list was crossing the dateline, unwrap all
        # coordinate lists
        if crosses_dateline:
            logger.info("Regular grid crosses the dateline. Normalizing it.")
            coord_lists = [
                _unwrap_coord_list(coord_list, CRS_BOUNDS[srid])
                for coord_list in coord_lists
            ]

        coords = []
        for coord_list in coord_lists:
            coords.extend(coord_list)

        # check validity of regularGrid
        if len(parsed_browse.coord_lists) != parsed_browse.row_node_number:
            raise IngestionException("Invalid regularGrid: number of coordinate "
                                     "lists is not equal to the given row node "
                                     "number.")

        elif len(coords) / len(parsed_browse.coord_lists) != parsed_browse.col_node_number:
            raise IngestionException("Invalid regularGrid: number of coordinates "
                                     "does not fit given columns number.")

        gcps = [(x, y, pixel, line)
                for (x, y), (pixel, line) in zip(coords, pixels)]
        return GCPList(gcps, srid)

    elif parsed_browse.geo_type == "modelInGeotiffBrowse":
        return None

    else:
        raise NotImplementedError("Invalid geo-reference type '%s'."
                                  % parsed_browse.geo_type)
Ejemplo n.º 13
0
def _georef_from_parsed(parsed_browse):
    srid = fromShortCode(parsed_browse.reference_system_identifier)
    
    if (parsed_browse.reference_system_identifier == "RAW" and
        parsed_browse.geo_type != "modelInGeotiffBrowse"):
        raise IngestionException("Given referenceSystemIdentifier '%s' not "
                                 "valid for a '%s'."
                                 % (parsed_browse.reference_system_identifier,
                                    parsed_browse.geo_type))
    
    if srid is None and parsed_browse.reference_system_identifier != "RAW":
        raise IngestionException("Given referenceSystemIdentifier '%s' not valid."
                                 % parsed_browse.reference_system_identifier)
    
    swap_axes = hasSwappedAxes(srid)
    
    if parsed_browse.geo_type == "rectifiedBrowse":
        coords = decode_coord_list(parsed_browse.coord_list, swap_axes)
        # values are for bottom/left and top/right pixel
        coords = [coord for pair in coords for coord in pair]
        assert(len(coords) == 4)
        return Extent(*coords, srid=srid)
        
    elif parsed_browse.geo_type == "footprintBrowse":
        # Generate GCPs from footprint coordinates
        pixels = decode_coord_list(parsed_browse.col_row_list)
        coord_list = decode_coord_list(parsed_browse.coord_list, swap_axes)
        
        if _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid]):
            logger.info("Footprint crosses the dateline. Normalizing it.")
            coord_list = _unwrap_coord_list(coord_list, CRS_BOUNDS[srid])
        
        assert(len(pixels) == len(coord_list))
        gcps = [(x, y, pixel, line) 
                for (x, y), (pixel, line) in zip(coord_list, pixels)]
        
        
        # check that the last point of the footprint is the first
        if not gcps[0] == gcps[-1]:
            raise IngestionException("The last value of the footprint is not "
                                     "equal to the first.")
        gcps.pop()
        
        return GCPList(gcps, srid)
        
        
    elif parsed_browse.geo_type == "regularGridBrowse":
        # calculate a list of pixel coordinates according to the values of the
        # parsed browse report (col_node_number * row_node_number)
        range_x = arange(
            0.0, parsed_browse.row_node_number * parsed_browse.row_step,
            parsed_browse.row_step
        )
        range_y = arange(
            0.0, parsed_browse.col_node_number * parsed_browse.col_step,
            parsed_browse.col_step
        )
        pixels = [(x, y) for x in range_x for y in range_y]
        
        # get the lat-lon coordinates as tuple-lists
        # TODO: normalize if dateline is crossed
        
        coord_lists = []
        for coord_list in parsed_browse.coord_lists:
            coord_list = decode_coord_list(coord_list, swap_axes)
            
            # TODO: iterate over every coord pair. if a dateline cross occurred
            # move all the negative values to the positive space
            if _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid]):
                logger.info("Regular grid crosses the dateline. Normalizing it.")
                coord_list = _unwrap_coord_list(coord_list, CRS_BOUNDS[srid])
            
            coord_lists.append(coord_list)
        
        coords = []
        for coord_list in coord_lists:
            coords.extend(coord_list)
        
        # check validity of regularGrid
        if len(parsed_browse.coord_lists) != parsed_browse.row_node_number:
            raise IngestionException("Invalid regularGrid: number of coordinate "
                                     "lists is not equal to the given row node "
                                     "number.")
        
        elif len(coords) / len(parsed_browse.coord_lists) != parsed_browse.col_node_number:
            raise IngestionException("Invalid regularGrid: number of coordinates "
                                     "does not fit given columns number.") 
            
        
        gcps = [(x, y, pixel, line) 
                for (x, y), (pixel, line) in zip(coords, pixels)]
        return GCPList(gcps, srid)
    
    elif parsed_browse.geo_type == "modelInGeotiffBrowse":
        return None
    
    elif parsed_browse.geo_type == "verticalCurtainBrowse":
        pixels = decode_coord_list(parsed_browse.col_row_list)
        coord_list = decode_coord_list(parsed_browse.coord_list, swap_axes)

        if _coord_list_crosses_dateline(coord_list, CRS_BOUNDS[srid]):
            logger.info("Vertical curtain footprint crosses the dateline. Normalizing it.")
            coord_list = _unwrap_coord_list(coord_list, CRS_BOUNDS[srid])

        gcps = [(x, y, pixel, line) 
                for (x, y), (pixel, line) in zip(coord_list, pixels)]

        return VerticalCurtainGeoReference(gcps, srid)

    else:
        raise NotImplementedError("Invalid geo-reference type '%s'."
                                  % parsed_browse.geo_type)