def lookup_coverage(self, decoder, subsets): """ Default implementation of the coverage lookup. Returns the coverage model for the given request decoder or raises an exception if it is not found. """ coverage_id = decoder.coverage_id try: obj = models.EOObject.objects.select_subclasses( models.Coverage, models.Mosaic).get( Q(identifier=coverage_id) & (Q(coverage__isnull=False) | Q(mosaic__isnull=False))) except models.EOObject.DoesNotExist: raise NoSuchCoverageException((coverage_id, )) if isinstance(obj, models.Coverage): return Coverage.from_model(obj) else: coverages = obj.coverages.all().order_by("begin_time") if subsets: subset_polygon = subsets.bounding_polygon( Mosaic.from_model(obj, [])) coverages = coverages.filter( footprint__intersects=subset_polygon) return Mosaic.from_model(obj, coverages)
def from_coverage_models(cls, band_expressions_and_ranges, fields_and_coverage_models, product_model): band_expressions, ranges = zip(*band_expressions_and_ranges) fields_and_coverages = { field_name: [ Coverage.from_model(coverage) for coverage in coverages ] for field_name, coverages in fields_and_coverage_models.items() } return cls( product_model.identifier, band_expressions, ranges, fields_and_coverages, [ fields_and_coverages[field_name][0].range_type.get_field( field_name ) for field_name in fields_and_coverages.keys() ], product_model.footprint )
def lookup_coverages(self, decoder): """ Default implementation of the coverage lookup. Returns a sorted list of coverage models according to the decoders `coverage_ids` attribute. Raises a `NoSuchCoverageException` if any of the given IDs was not found in the database. """ ids = decoder.coverage_ids # qs = models.Coverage.objects.filter(identifier__in=ids) qs = models.EOObject.objects.filter(identifier__in=ids, ).filter( Q(coverage__isnull=False) | Q(mosaic__isnull=False)).select_subclasses() objects = sorted(qs, key=(lambda coverage: ids.index(coverage.identifier))) # check correct number if len(objects) < len(ids): available_ids = set([coverage.identifier for coverage in objects]) raise NoSuchCoverageException(set(ids) - available_ids) return [ Coverage.from_model(obj) if isinstance(obj, models.Coverage) else Mosaic.from_model(obj) for obj in objects ]
def get_coverage_object(svc_cfg, product): crs = svc_cfg.published_CRSs[product.native_CRS] bbox = product.ranges["bboxes"][product.native_CRS] return Coverage( identifier=product.name, eo_metadata=None, range_type=RangeType('%s__range_type' % product.name, [ Field( index=i, identifier=band_label, description=band_label, definition='', unit_of_measure='', wavelength=None, significant_figures=None, allowed_values=None, nil_values=[(str(product.band_idx.nodata_val(band_label)), 'nodata')], data_type=None, data_type_range=None, ) for i, band_label in enumerate(product.band_idx.band_labels()) ]), grid=Grid( product.native_CRS, [ Axis( crs['horizontal_coord'], 0, product.resolution_x, 'm' if crs['geographic'] else 'deg' ), Axis( crs['vertical_coord'], 0, product.resolution_y, 'm' if crs['geographic'] else 'deg' ), IrregularAxis('time', 2, product.ranges['times'], 's') ] ), origin=Origin([ min(bbox["left"], bbox["right"]), min(bbox["top"], bbox["bottom"]) ]), size=[product.grid_high_x, product.grid_high_y], arraydata_locations=[], metadata_locations=[], native_format=svc_cfg.wcs_formats[svc_cfg.native_wcs_format]['mime'], )
def dispatch_wcs_get_capabilities(request, ows_url, config_client): if request.method == 'GET': decoder = WCS20GetCapabilitiesKVPDecoder(request.query) else: decoder = WCS20GetCapabilitiesXMLDecoder(request.body) encoder = WCS20GetCapabilitiesXMLEncoderExtended(ows_url) datasets = config_client.get_datasets() untimed_datasets = [ dataset for dataset in datasets if 'timeextent' not in dataset ] timed_datasets = [ dataset for dataset in datasets if 'timeextent' in dataset ] coverages = [ Coverage( dataset['id'], EOMetadata( None, None, None # TODO: whole world? ), get_range_type_from_dataset(dataset), *(get_grid(dataset) + ([], []))) for dataset in untimed_datasets ] dataset_series_set = [ DatasetSeries( dataset['id'], None, make_aware(datetime.combine(dataset['timeextent'][0], time.min), utc), make_aware( datetime.combine(dataset['timeextent'][1] or date.today(), time.min), utc), ) for dataset in timed_datasets ] return encoder.serialize( encoder.encode_capabilities(decoder.sections, DummyConfig(), coverages, dataset_series_set)), encoder.content_type
def get_coverage(config_client, coverage_id, dataset_name, datestr): dataset = config_client.get_dataset(dataset_name) try: date = datetime.strptime(datestr, '%Y-%m-%d') except: # TODO catch exact exception raise Exception(f'No such coverage {coverage_id}') grid, origin, size = get_grid(dataset) return Coverage( coverage_id, EOMetadata( date, date + timedelta(days=1), None # TODO: whole world? ), get_range_type_from_dataset(dataset), grid, origin, size, [], [])
def render(self, params): conf = CapabilitiesConfigReader(get_eoxserver_config()) http_service_url = get_http_service_url(params.http_request) map_ = Map() map_.setMetaData( { "enable_request": "*", "onlineresource": http_service_url, "service_onlineresource": conf.onlineresource, "updateSequence": conf.update_sequence, "name": conf.name, "title": conf.title, "label": conf.title, "abstract": conf.abstract, "accessconstraints": conf.access_constraints, "addresstype": "", "address": conf.delivery_point, "stateorprovince": conf.administrative_area, "city": conf.city, "postcode": conf.postal_code, "country": conf.country, "contactelectronicmailaddress": conf.electronic_mail_address, "contactfacsimiletelephone": conf.phone_facsimile, "contactvoicetelephone": conf.phone_voice, "contactperson": conf.individual_name, "contactorganization": conf.provider_name, "contactposition": conf.position_name, "role": conf.role, "hoursofservice": conf.hours_of_service, "contactinstructions": conf.contact_instructions, "fees": conf.fees, "keywordlist": ",".join(conf.keywords), "formats": " ".join([f.wcs10name for f in self.get_wcs_formats()]), "srs": " ".join( crss.getSupportedCRS_WCS( format_function=crss.asShortCode)), }, namespace="ows") map_.setProjection("EPSG:4326") for outputformat in self.get_all_outputformats(False): map_.appendOutputFormat(outputformat) for coverage in params.coverages: layer = Layer(coverage.identifier) render_coverage = Coverage.from_model(coverage) layer.setProjection(render_coverage.grid.spatial_reference.proj) extent = render_coverage.extent size = render_coverage.size resolution = ((extent[2] - extent[0]) / float(size[0]), (extent[1] - extent[3]) / float(size[1])) layer.setExtent(*extent) layer.setMetaData( { "title": coverage.identifier, "label": coverage.identifier, "extent": "%.10g %.10g %.10g %.10g" % extent, "resolution": "%.10g %.10g" % resolution, "size": "%d %d" % size, "formats": " ".join([f.wcs10name for f in self.get_wcs_formats()]), "srs": " ".join( crss.getSupportedCRS_WCS( format_function=crss.asShortCode)), }, namespace="wcs") map_.insertLayer(layer) request = create_request(params) request.setParameter("version", params.version) raw_result = map_.dispatch(request) result = result_set_from_raw_data(raw_result) xml_result = etree.fromstring(result[0].data) for elem in xml_result.xpath('//*[local-name() = "metadataLink"]'): elem.getparent().remove(elem) # Add CQL parameter to GetCapabilities operation for elem in xml_result.xpath( '//*[local-name() = "Operation"][@name = "GetCapabilities"]'): ows = elem.nsmap['ows'] param = etree.SubElement(elem, '{%s}Parameter' % ows) param.attrib['name'] = 'cql' etree.SubElement(param, '{%s}AnyValue' % ows) xml_result_data = etree.tostring(xml_result, pretty_print=True, encoding='UTF-8', xml_declaration=True) result[0] = ResultBuffer(xml_result_data, result[0].content_type) return result
def get_layer_description(self, eo_object, raster_styles, geometry_styles): if isinstance(eo_object, models.Coverage): coverage = RenderCoverage.from_model(eo_object) return LayerDescription.from_coverage(coverage, raster_styles) elif isinstance(eo_object, models.Mosaic): coverage = RenderCoverage.from_model(eo_object) return LayerDescription.from_mosaic(coverage, raster_styles) elif isinstance(eo_object, (models.Product, models.Collection)): if getattr(eo_object, "product_type", None): browse_type_qs = eo_object.product_type.browse_types.all() mask_type_qs = eo_object.product_type.mask_types.all() elif getattr(eo_object, "collection_type", None): browse_type_qs = models.BrowseType.objects.filter( product_type__allowed_collection_types__collections= eo_object) mask_type_qs = models.MaskType.objects.filter( product_type__allowed_collection_types__collections= eo_object) else: browse_type_qs = models.BrowseType.objects.none() mask_type_qs = models.MaskType.objects.none() browse_types_name_and_is_gray = browse_type_qs.annotate( is_gray=Case(When(green_expression__isnull=True, then=Value(True)), default=Value(False), output_field=BooleanField())).values_list( 'name', 'is_gray').distinct() mask_type_names = mask_type_qs.values_list('name', flat=True).distinct() sub_layers = [ LayerDescription("%s%soutlines" % (eo_object.identifier, self.suffix_separator), styles=geometry_styles, queryable=True), LayerDescription("%s%soutlined" % (eo_object.identifier, self.suffix_separator), styles=geometry_styles, queryable=True) ] for name, is_gray in browse_types_name_and_is_gray: sub_layers.append( LayerDescription( "%s%s%s" % (eo_object.identifier, self.suffix_separator, name) if name else eo_object.identifier, styles=raster_styles if is_gray else [])) for mask_type_name in mask_type_names: sub_layers.append( LayerDescription("%s%s%s" % (eo_object.identifier, self.suffix_separator, mask_type_name), styles=geometry_styles)) sub_layers.append( LayerDescription("%s%smasked_%s" % (eo_object.identifier, self.suffix_separator, mask_type_name))) dimensions = {} if eo_object.begin_time and eo_object.end_time: dimensions["time"] = { 'min': isoformat(eo_object.begin_time), 'max': isoformat(eo_object.end_time), 'step': 'PT1S', 'default': isoformat(eo_object.end_time), 'units': 'ISO8601' } return LayerDescription(name=eo_object.identifier, bbox=eo_object.footprint.extent if eo_object.footprint else None, dimensions=dimensions, sub_layers=sub_layers) raise UnsupportedObject("Object %r cannot be mapped to a layer." % eo_object)
def lookup_layer(self, layer_name, suffix, style, filters_expressions, sort_by, time, ranges, bands, wavelengths, elevation, zoom): """ Lookup the layer from the registered objects. """ reader = LayerMapperConfigReader(get_eoxserver_config()) limit_products = (reader.limit_products if reader.limit_mode == 'hide' else None) min_render_zoom = reader.min_render_zoom full_name = '%s%s%s' % (layer_name, self.suffix_separator, suffix) try: eo_object = models.EOObject.objects.select_subclasses( models.Collection, models.Product, models.Coverage, models.Mosaic).get(identifier=layer_name) except models.EOObject.DoesNotExist: raise NoSuchLayer('Layer %r does not exist' % layer_name) if isinstance(eo_object, models.Coverage): if suffix in ('', 'bands'): return CoverageLayer(full_name, style, RenderCoverage.from_model(eo_object), bands, wavelengths, time, elevation, ranges) elif suffix == 'outlines': return OutlinesLayer(name=full_name, style=style, fill=None, footprints=[eo_object.footprint]) # TODO: masked coverages, when using the coverages product else: raise NoSuchLayer('Invalid layer suffix %r' % suffix) # TODO: deprecated elif isinstance(eo_object, models.Mosaic): if suffix == 'outlines': return OutlinesLayer( name=full_name, style=style, fill=None, footprints=[ coverage.footprint for coverage in self.iter_coverages( eo_object, filters_expressions, sort_by) ]) else: return MosaicLayer( full_name, style, RenderMosaic.from_model(eo_object), [ RenderCoverage.from_model(coverage) for coverage in self.iter_coverages( eo_object, filters_expressions, sort_by) ], bands, wavelengths, time, elevation, ranges) elif isinstance(eo_object, (models.Collection, models.Product)): if suffix == '' or suffix == 'outlined' or suffix == 'bands': browses = [] product_browses = self.iter_products_browses( eo_object, filters_expressions, sort_by, None, style, limit=limit_products) has_products = False for product, browse, _ in product_browses: # When bands/wavelengths are specifically requested, make a # generated browse if bands or wavelengths: browse = _generate_browse_from_bands( product, bands, wavelengths, ranges) if browse: browses.append(browse) has_products = True # When available use the default browse elif browse: browses.append(Browse.from_model(product, browse)) has_products = True # As fallback use the default browse type (with empty name) # to generate a browse from the specified bands else: browse_type = product.product_type.browse_types.filter( name='').first() if browse_type: browse = _generate_browse_from_browse_type( product, browse_type) if browse: browses.append(browse) has_products = True if not has_products: coverages = self.iter_coverages(eo_object, filters_expressions, sort_by) if suffix == '': return CoveragesLayer(full_name, style, [ RenderCoverage.from_model(coverage) for coverage in coverages ], bands, wavelengths, time, elevation, ranges) else: return OutlinedCoveragesLayer(full_name, style, [ RenderCoverage.from_model(coverage) for coverage in coverages ], bands, wavelengths, time, elevation, ranges) # detect whether we are below the zoom limit if min_render_zoom is None or zoom >= min_render_zoom: # either return the simple browse layer or the outlined one if suffix == '': return BrowseLayer(name=full_name, style=style, browses=browses, ranges=ranges) else: return OutlinedBrowseLayer(name=full_name, style=style, browses=browses, ranges=ranges) # render outlines when we are below the zoom limit else: return OutlinesLayer(name=full_name, style=reader.color, fill=reader.fill_opacity, footprints=[ product.footprint for product in self.iter_products( eo_object, filters_expressions, sort_by, limit=limit_products) ]) elif suffix == 'outlines': return OutlinesLayer( name=full_name, style=style, fill=None, footprints=[ product.footprint for product in self.iter_products(eo_object, filters_expressions, sort_by, limit=limit_products) ]) elif suffix.startswith('outlines_masked_'): post_suffix = suffix[len('outlines_masked_'):] product_browses_mask = self.iter_products_browses_masks( eo_object, filters_expressions, sort_by, post_suffix, limit=limit_products) footprints = [] masks = [] for product, browse, mask, mask_type in product_browses_mask: footprints.append(product.footprint) masks.append(Mask.from_model(mask, mask_type)) return OutlinesLayer( name=full_name, style=style, fill=None, footprints=footprints, masks=masks, ) elif suffix.startswith('masked_'): post_suffix = suffix[len('masked_'):] mask_type = self.get_mask_type(eo_object, post_suffix) if not mask_type: raise NoSuchLayer('No such mask type %r' % post_suffix) masked_browses = [] product_browses_mask = self.iter_products_browses_masks( eo_object, filters_expressions, sort_by, post_suffix, limit=limit_products) for product, browse, mask, mask_type in product_browses_mask: # When bands/wavelengths are specifically requested, make a # generated browse if bands or wavelengths: masked_browses.append( MaskedBrowse(browse=_generate_browse_from_bands( product, bands, wavelengths, ranges), mask=Mask.from_model(mask, mask_type))) # When available use the default browse elif browse: masked_browses.append( MaskedBrowse.from_models(product, browse, mask, mask_type)) # As fallback use the default browse type (with empty name) # to generate a browse from the specified bands else: browse_type = product.product_type.browse_types.filter( name='').first() if browse_type: masked_browses.append( MaskedBrowse( browse=_generate_browse_from_browse_type( product, browse_type), mask=Mask.from_model(mask, mask_type))) return MaskedBrowseLayer(name=full_name, style=style, masked_browses=masked_browses) else: # either browse type or mask type browse_type = self.get_browse_type(eo_object, suffix) if browse_type: browses = [] product_browses = self.iter_products_browses( eo_object, filters_expressions, sort_by, suffix, style, limit=limit_products) for product, browse, browse_type in product_browses: # check if a browse is already available for that # browse type. if browse: browses.append(Browse.from_model(product, browse)) # if no browse is available for that browse type, # generate a new browse with the instructions of that # browse type else: browse = _generate_browse_from_browse_type( product, browse_type) if browse: browses.append(browse) return BrowseLayer(name=full_name, style=style, ranges=ranges, browses=browses) mask_type = self.get_mask_type(eo_object, suffix) if mask_type: return MaskLayer( name=full_name, style=style, masks=[ Mask.from_model(mask_model, mask_type) for _, mask_model in self.iter_products_masks( eo_object, filters_expressions, sort_by, suffix, limit=limit_products) ]) raise NoSuchLayer('Invalid layer suffix %r' % suffix)