Package eoxserver :: Package services :: Package ows :: Package wms :: Module common
[hide private]
[frames] | no frames]

Source Code for Module eoxserver.services.ows.wms.common

  1  #------------------------------------------------------------------------------- 
  2  # $Id: common.py 2476 2013-05-14 09:58:42Z meissls $ 
  3  # 
  4  # Project: EOxServer <http://eoxserver.org> 
  5  # Authors: Stephan Krause <stephan.krause@eox.at> 
  6  #          Stephan Meissl <stephan.meissl@eox.at> 
  7  #          Martin Paces <martin.paces@eox.at> 
  8  # 
  9  #------------------------------------------------------------------------------- 
 10  # Copyright (C) 2011 EOX IT Services GmbH 
 11  # 
 12  # Permission is hereby granted, free of charge, to any person obtaining a copy 
 13  # of this software and associated documentation files (the "Software"), to deal 
 14  # in the Software without restriction, including without limitation the rights 
 15  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
 16  # copies of the Software, and to permit persons to whom the Software is  
 17  # furnished to do so, subject to the following conditions: 
 18  # 
 19  # The above copyright notice and this permission notice shall be included in all 
 20  # copies of this Software or works derived from this Software. 
 21  # 
 22  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 23  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 24  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 25  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 26  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 27  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 28  # THE SOFTWARE. 
 29  #------------------------------------------------------------------------------- 
 30   
 31  import logging 
 32  import os 
 33  from uuid import uuid4 
 34   
 35  import mapscript 
 36   
 37  from eoxserver.core.system import System 
 38  from eoxserver.core.util.timetools import ( 
 39      isotime, getDateTime 
 40  ) 
 41  from eoxserver.core.exceptions import InternalError, InvalidParameterException 
 42  from eoxserver.contrib import gdal 
 43  from eoxserver.resources.coverages.filters import ( 
 44      BoundedArea, TimeInterval 
 45  ) 
 46  from eoxserver.resources.coverages.formats import getFormatRegistry 
 47  from eoxserver.resources.coverages import crss 
 48  from eoxserver.resources.coverages.dateline import ( 
 49      extent_crosses_dateline, wrap_extent_around_dateline 
 50  ) 
 51   
 52  from eoxserver.processing.gdal.reftools import create_temporary_vrt 
 53  from eoxserver.services.owscommon import OWSCommonConfigReader 
 54  from eoxserver.services.mapserver import MapServerOperationHandler 
 55  from eoxserver.services.exceptions import InvalidRequestException 
 56  from eoxserver.processing.gdal.vrt import create_simple_vrt 
 57   
 58   
 59  logger = logging.getLogger(__name__) 
 60   
 61  _stripDot = lambda s : s[1:] if s[0] == '.' else s  
 62   
63 -def getMSWMSSRSMD():
64 """ get the space separated list of CRS EPSG codes to be passed 65 to MapScript setMedata("wms_srs",...) method 66 """ 67 return " ".join(crss.getSupportedCRS_WMS(format_function=crss.asShortCode)) 68
69 -class WMSLayer(object):
70 - def __init__(self):
71 self.group_name = None 72 73 self.temp_files = []
74
75 - def getName(self):
76 raise NotImplementedError
77
78 - def setGroup(self, group_name):
79 self.group_name = group_name
80
81 - def getGroup(self):
82 return self.group_name
83
84 - def getMapServerLayer(self, req):
85 layer = mapscript.layerObj() 86 87 layer.name = self.getName() 88 layer.setMetaData("ows_title", self.getName()) 89 layer.setMetaData("wms_label", self.getName()) 90 layer.addProcessing("CLOSE_CONNECTION=CLOSE") 91 92 if self.group_name: 93 layer.group = self.group_name 94 layer.setMetaData("wms_group_title", self.group_name) 95 96 return layer
97
98 - def cleanup(self):
99 for temp_file in self.temp_files: 100 try: 101 os.remove(temp_file) 102 except: 103 logger.warning("Could not remove temporary file '%s'" % temp_file)
104
105 -class WMSEmptyLayer(WMSLayer):
106 - def __init__(self, layer_name):
107 super(WMSEmptyLayer, self).__init__() 108 109 self.layer_name = layer_name
110
111 - def getName(self):
112 return self.layer_name
113
114 - def getMapServerLayer(self, req):
115 layer = super(WMSEmptyLayer, self).getMapServerLayer(req) 116 117 layer.setMetaData("wms_enable_request", "getmap") 118 119 return layer
120
121 -class WMSCoverageLayer(WMSLayer):
122 - def __init__(self, coverage):
123 super(WMSCoverageLayer, self).__init__() 124 125 self.coverage = coverage 126 self.name = None
127
128 - def getName(self):
129 if self.name: 130 return self.name 131 else: 132 return self.coverage.getCoverageId()
133
134 - def isRGB(self):
135 return self.coverage.getRangeType().name == "RGB"
136
137 - def isRGBA(self):
138 return self.coverage.getRangeType().name == "RGBA"
139
140 - def isGrayscale(self):
141 return self.coverage.getRangeType().name == "Grayscale"
142
143 - def getBandIndices(self, req):
144 if len(self.coverage.getRangeType().bands) >= 3: 145 return [1, 2, 3] 146 else: 147 return [1, 1, 1]
148
149 - def getBandSelection(self, req):
150 bands = self.coverage.getRangeType().bands 151 152 if len(bands) in range(1, 5): # 1 to 4 153 return bands 154 else: 155 return bands[:3]
156
157 - def setOffsiteColor(self, layer, bands):
158 nil_values = [] 159 160 if len(bands) == 1: 161 if len(bands[0].nil_values) > 0: 162 nil_values = [ 163 int(bands[0].nil_values[0].value), 164 int(bands[0].nil_values[0].value), 165 int(bands[0].nil_values[0].value) 166 ] 167 168 layer.offsite = mapscript.colorObj(*nil_values) 169 170 if len(bands) == 3: 171 for band in bands: 172 if len(band.nil_values) > 0: 173 nil_values.append(int(band.nil_values[0].value)) 174 else: 175 return 176 177 layer.offsite = mapscript.colorObj(*nil_values)
178
179 - def setScale(self, layer):
180 if self.coverage.getRangeType().data_type != gdal.GDT_Byte: 181 layer.setProcessingKey("SCALE", "AUTO")
182
183 - def configureBands(self, layer, req):
184 bands = self.getBandSelection(req) 185 186 if not self.isRGB() and not self.isGrayscale() and not self.isRGBA(): 187 layer.setProcessingKey("BANDS", "%d,%d,%d" % tuple(self.getBandIndices(req))) 188 189 self.setOffsiteColor(layer, bands) 190 191 self.setScale(layer)
192
193 - def getMapServerLayer(self, req):
194 layer = super(WMSCoverageLayer, self).getMapServerLayer(req) 195 196 layer.setMetaData("wms_enable_request", "getcapabilities,getmap") 197 198 for key, value in self.coverage.getLayerMetadata(): 199 layer.setMetaData(key, value) 200 201 layer.type = mapscript.MS_LAYER_RASTER 202 layer.setConnectionType(mapscript.MS_RASTER, '') 203 204 self.configureBands(layer, req) 205 206 return layer
207
208 -class WMSRectifiedDatasetLayer(WMSCoverageLayer):
209
210 - def getMapServerLayer(self, req):
211 layer = super(WMSRectifiedDatasetLayer, self).getMapServerLayer(req) 212 213 # general rectified coverage metadata 214 srid = self.coverage.getSRID() 215 extent = self.coverage.getExtent() 216 217 layer.setProjection(crss.asProj4Str(srid)) 218 layer.setMetaData("ows_srs", crss.asShortCode(srid)) 219 layer.setMetaData("wms_srs", crss.asShortCode(srid)) 220 layer.setMetaData("wms_extent", "%.10g %.10g %.10g %.10g" % extent) 221 layer.setExtent(*extent) 222 223 # bind rectified dataset 224 connector = System.getRegistry().findAndBind( 225 intf_id = "services.mapserver.MapServerDataConnectorInterface", 226 params = { 227 "services.mapserver.data_structure_type": \ 228 self.coverage.getDataStructureType() 229 } 230 ) 231 232 layer = connector.configure(layer, self.coverage) 233 234 return layer
235
236 -class WMSWrappedRectifiedDatasetLayer(WMSRectifiedDatasetLayer):
237
238 - def __init__(self, coverage, vrt_path, extent=None):
239 super(WMSWrappedRectifiedDatasetLayer, self).__init__(coverage) 240 self.vrt_path = vrt_path
241 242
243 - def getMapServerLayer(self, req):
244 layer = super(WMSWrappedRectifiedDatasetLayer, self).getMapServerLayer(req) 245 246 e = wrap_extent_around_dateline(self.coverage.getExtent(), 247 self.coverage.getSRID()) 248 249 layer.setMetaData("wms_extent", "%.10g %.10g %.10g %.10g" % e) 250 layer.setExtent(*e) 251 252 data_package = self.coverage.getData() 253 data_package.prepareAccess() 254 ds = gdal.Open(data_package.getGDALDatasetIdentifier()) 255 256 vrt_ds = create_simple_vrt(ds, self.vrt_path) 257 258 259 size_x = ds.RasterXSize 260 size_y = ds.RasterYSize 261 262 dx = abs(e[0] - e[2]) / size_x 263 dy = abs(e[1] - e[3]) / size_y 264 265 vrt_ds.SetGeoTransform([e[0], dx, 0, e[3], 0, -dy]) 266 267 vrt_ds = None 268 269 layer.data = self.vrt_path 270 271 return layer
272 273
274 - def cleanup(self):
275 super(WMSWrappedRectifiedDatasetLayer, self).cleanup() 276 gdal.Unlink(str(self.vrt_path))
277 278 279
280 -class WMSReferenceableDatasetLayer(WMSCoverageLayer):
281 - def setScale(self, layer):
282 layer.setProcessingKey("SCALE", "1,2000") # TODO: make this configurable
283
284 - def getMapServerLayer(self, req):
285 layer = super(WMSReferenceableDatasetLayer, self).getMapServerLayer(req) 286 287 # general rectified coverage metadata 288 srid = self.coverage.getSRID() 289 layer.setProjection( crss.asProj4Str( srid ) ) 290 layer.setMetaData("ows_srs", crss.asShortCode( srid ) ) 291 layer.setMetaData("wms_srs", crss.asShortCode( srid ) ) 292 layer.setMetaData("wms_extent", "%.10g %.10g %.10g %.10g" \ 293 % self.coverage.getExtent()) 294 layer.setExtent(*self.coverage.getExtent()) 295 296 # project the dataset 297 vrt_path = self.rectify() 298 layer.data = vrt_path 299 self.temp_files.append(vrt_path) 300 301 return layer
302
303 - def rectify(self):
307
308 -class WMSRectifiedStitchedMosaicLayer(WMSCoverageLayer):
309 - def getMapServerLayer(self, req):
310 layer = super(WMSRectifiedStitchedMosaicLayer, self).getMapServerLayer(req) 311 312 connector = System.getRegistry().findAndBind( 313 intf_id = "services.mapserver.MapServerDataConnectorInterface", 314 params = { 315 "services.mapserver.data_structure_type": \ 316 self.coverage.getDataStructureType() 317 } 318 ) 319 320 layer = connector.configure(layer, self.coverage) 321 322 extent = self.coverage.getExtent() 323 srid = self.coverage.getSRID() 324 size = self.coverage.getSize() 325 resolution = ((extent[2]-extent[0]) / float(size[0]), 326 (extent[1]-extent[3]) / float(size[1])) 327 328 layer.setProjection( crss.asProj4Str( srid ) ) 329 layer.setMetaData("ows_srs", crss.asShortCode( srid ) ) 330 layer.setMetaData("wms_srs", crss.asShortCode( srid ) ) 331 332 layer.setExtent(*self.coverage.getExtent()) 333 layer.setMetaData("wms_extent", "%.10g %.10g %.10g %.10g" % extent) 334 layer.setMetaData("wms_resolution", "%.10g %.10g" % resolution) 335 layer.setMetaData("wms_size", "%d %d" % size) 336 337 layer.type = mapscript.MS_LAYER_RASTER 338 layer.setConnectionType(mapscript.MS_RASTER, '') 339 340 return layer
341
342 -class WMSDatasetSeriesLayer(WMSLayer):
343 - def __init__(self, dataset_series):
344 super(WMSDatasetSeriesLayer, self).__init__() 345 346 self.dataset_series = dataset_series
347
348 - def getName(self):
349 return self.dataset_series.getEOID()
350
351 - def getMapServerLayer(self, req):
352 layer = super(WMSDatasetSeriesLayer, self).getMapServerLayer(req) 353 354 coverages = self.dataset_series.getEOCoverages() 355 356 layer.setMetaData("wms_extent", "%.10g %.10g %.10g %.10g" \ 357 % self.dataset_series.getWGS84Extent()) 358 layer.setExtent(*self.dataset_series.getWGS84Extent()) 359 360 time_extent = ",".join( 361 sorted(set(isotime(coverage.getBeginTime()) for coverage in coverages)) 362 ) 363 layer.setMetaData("wms_timeextent", time_extent) 364 365 srid = 4326 # TODO: source CRS of dataset series 366 layer.setProjection( crss.asProj4Str( srid ) ) 367 layer.setMetaData("ows_srs", crss.asShortCode( srid ) ) 368 layer.setMetaData("wms_srs", crss.asShortCode( srid ) ) 369 370 371 layer.type = mapscript.MS_LAYER_RASTER 372 373 layer.setConnectionType(mapscript.MS_RASTER, '') 374 layer.setMetaData("wms_enable_request", "*") 375 layer.status = mapscript.MS_ON 376 377 for key, value in self.dataset_series.getLayerMetadata(): 378 layer.setMetaData(key, value) 379 380 # use a dummy coverage to connect to 381 382 connector = System.getRegistry().findAndBind( 383 intf_id = "services.mapserver.MapServerDataConnectorInterface", 384 params = { 385 "services.mapserver.data_structure_type": \ 386 coverages[0].getDataStructureType() 387 } 388 ) 389 390 layer = connector.configure(layer, coverages[0]) 391 392 return layer
393
394 -class WMSCommonHandler(MapServerOperationHandler):
395 PARAM_SCHEMA = { 396 "service": {"xml_location": "/@service", "xml_type": "string", "kvp_key": "service", "kvp_type": "string"}, 397 "version": {"xml_location": "/@version", "xml_type": "string", "kvp_key": "version", "kvp_type": "string"}, 398 "operation": {"xml_location": "/", "xml_type": "localName", "kvp_key": "request", "kvp_type": "string"} 399 } 400
401 - def __init__(self):
402 super(WMSCommonHandler, self).__init__() 403 404 self.req = None 405 406 self.layers = [] 407 408 self.temp_files = []
409
410 - def _processRequest(self, req):
411 self.req = req 412 self.req.setSchema(self.PARAM_SCHEMA) 413 414 try: 415 self.validateParams() 416 self.configureRequest() 417 self.configureMapObj() 418 self.createLayers() 419 self.addMapServerLayers() 420 response = self.postprocess(self.dispatch()) 421 finally: 422 self.cleanup() 423 424 return response
425
426 - def validateParams(self):
427 pass
428
429 - def _setMapProjection(self):
430 # set the default EPSG:4326 projection 431 # TODO: check whether this is really correct 432 self.map.setProjection( crss.asProj4Str( 4326 ) )
433
434 - def configureMapObj(self):
435 """ 436 This method configures the ``ms_req.map`` object (an 437 instance of ``mapscript.mapObj``) with parameters from the 438 config. This method can be overridden in order to implement more 439 sophisticated behaviour. 440 441 @param ms_req An :class:`MapServerRequest` object 442 443 @return None 444 """ 445 446 self.map.setMetaData("ows_onlineresource", OWSCommonConfigReader().getHTTPServiceURL() + "?") 447 448 # set (per-service) map projection 449 self._setMapProjection() 450 451 # set the (global) list of supported CRSes 452 self.map.setMetaData("ows_srs", getMSWMSSRSMD()) 453 self.map.setMetaData("wms_srs", getMSWMSSRSMD()) 454 455 # set all supported output formats 456 457 # retrieve the format registry 458 FormatRegistry = getFormatRegistry() 459 460 # define the supported formats 461 for sf in FormatRegistry.getSupportedFormatsWMS(): 462 # output format definition 463 of = mapscript.outputFormatObj( sf.driver, "custom" ) 464 of.name = sf.mimeType 465 of.mimetype = sf.mimeType 466 of.extension = _stripDot(sf.defaultExt) 467 #of.imagemode = mapscript.MS_IMAGEMODE_BYTE 468 of.imagemode = mapscript.MS_IMAGEMODE_RGBA 469 470 #add the format 471 self.map.appendOutputFormat( of ) 472 473 # set the formats supported by getMap WMS operation 474 self.map.setMetaData("wms_getmap_formatlist", 475 ",".join( 476 map(lambda f: f.mimeType, 477 FormatRegistry.getSupportedFormatsWMS()) 478 ) 479 )
480 481
482 - def createLayers(self):
483 pass
484
485 - def createCoverageLayer(self, coverage):
486 logger.debug("Adding WMS coverage layer for coverage '%s'." 487 % coverage.getCoverageId()) 488 489 if coverage.getType() == "plain": 490 raise InternalError( 491 "Plain coverage WMS views are not yet implemented." 492 ) 493 elif coverage.getType() == "eo.rect_dataset": 494 return WMSRectifiedDatasetLayer(coverage) 495 elif coverage.getType() == "eo.ref_dataset": 496 return WMSReferenceableDatasetLayer(coverage) 497 elif coverage.getType() == "eo.rect_stitched_mosaic": 498 return WMSRectifiedStitchedMosaicLayer(coverage)
499
500 - def addLayer(self, layer):
501 self.layers.append(layer)
502
503 - def addMapServerLayers(self):
504 for layer in self.layers: 505 self.map.insertLayer(self.getMapServerLayer(layer))
506
507 - def getMapServerLayer(self, layer):
508 return layer.getMapServerLayer(self.req)
509
510 - def postprocess(self, resp):
511 return resp
512
513 - def cleanup(self):
514 super(WMSCommonHandler, self).cleanup() 515 516 for layer in self.layers: 517 layer.cleanup()
518
519 -class WMS1XGetCapabilitiesHandler(WMSCommonHandler):
520
521 - def configureMapObj(self):
523 524 525
526 - def createLayers(self):
527 visible_expr = System.getRegistry().getFromFactory( 528 "resources.coverages.filters.CoverageExpressionFactory", 529 {"op_name": "attr", "operands": ("visible", "=", True)} 530 ) 531 532 cov_factory = System.getRegistry().bind("resources.coverages.wrappers.EOCoverageFactory") 533 534 for coverage in cov_factory.find(filter_exprs=[visible_expr]): 535 self.addLayer(self.createCoverageLayer(coverage)) 536 537 dss_factory = System.getRegistry().bind("resources.coverages.wrappers.DatasetSeriesFactory") 538 539 # TODO: find a more efficient way to do this check 540 for dataset_series in dss_factory.find(): 541 if len(dataset_series.getEOCoverages()) > 0: 542 self.layers.append(WMSDatasetSeriesLayer(dataset_series))
543
544 - def getMapServerLayer(self, layer):
545 ms_layer = super(WMS1XGetCapabilitiesHandler, self).getMapServerLayer(layer) 546 547 ms_layer.status = mapscript.MS_ON 548 549 return ms_layer
550
551 -class WMS1XGetMapHandler(WMSCommonHandler):
552
553 - def _setMapProjection(self):
554 self.map.setProjection( crss.asProj4Str( self.getSRID() ) )
555
556 - def getSRSParameterName(self):
557 raise NotImplementedError()
558
559 - def getBoundedArea(self, srid, bbox):
560 return BoundedArea(srid, *bbox)
561
562 - def getTimeFilterExpr(self, time_param):
563 timestamps = time_param.split("/") 564 565 if len(timestamps) == 1: 566 try: 567 timestamp = getDateTime(timestamps[0]) 568 except InvalidParameterException: 569 raise InvalidRequestException( 570 "Invalid 'TIME' parameter format.", 571 "InvalidParameterValue", 572 "time" 573 ) 574 575 return System.getRegistry().getFromFactory( 576 "resources.coverages.filters.CoverageExpressionFactory", 577 { 578 "op_name": "time_slice", 579 "operands": (timestamp,) 580 } 581 ) 582 583 elif len(timestamps) == 2: 584 try: 585 time_intv = TimeInterval( 586 getDateTime(timestamps[0]), 587 getDateTime(timestamps[1]) 588 ) 589 except InvalidParameterException: 590 raise InvalidRequestException( 591 "Invalid 'TIME' parameter format.", 592 "InvalidParameterValue", 593 "time" 594 ) 595 596 return System.getRegistry().getFromFactory( 597 "resources.coverages.filters.CoverageExpressionFactory", 598 { 599 "op_name": "time_intersects", 600 "operands": (time_intv,) 601 } 602 ) 603 else: 604 raise InvalidRequestException( 605 "Invalid 'TIME' parameter format.", 606 "InvalidParameterValue", 607 "time" 608 )
609
610 - def getFilterExpressions(self):
611 try: 612 bbox = self.req.getParamValue("bbox") 613 except InvalidParameterException: 614 raise InvalidRequestException( 615 "Invalid BBOX parameter value", 616 "InvalidParameterValue", 617 "bbox" 618 ) 619 620 if len(bbox) != 4: 621 raise InvalidRequestException( 622 "Wrong number of arguments for 'BBOX' parameter", 623 "InvalidParameterValue", 624 "bbox" 625 ) 626 627 srid = self.getSRID() 628 629 area = self.getBoundedArea(srid, bbox) 630 631 filter_exprs = [] 632 633 # TODO sqlite assert ahead `GEOSCoordSeq_setOrdinate_r` 634 filter_exprs.append( 635 System.getRegistry().getFromFactory( 636 "resources.coverages.filters.CoverageExpressionFactory", 637 { 638 "op_name": "footprint_intersects_area", 639 "operands": (area,) 640 } 641 ) 642 ) 643 644 time_param = self.req.getParamValue("time") 645 646 if time_param is not None: 647 filter_exprs.append(self.getTimeFilterExpr(time_param)) 648 649 return filter_exprs
650
651 - def createLayers(self):
652 layer_names = self.req.getParamValue("layers") 653 654 if layer_names is None: 655 raise InvalidRequestException( 656 "Missing 'LAYERS' parameter", 657 "MissingParameterValue", 658 "layers" 659 ) 660 661 filter_exprs = self.getFilterExpressions() 662 663 for layer_name in layer_names: 664 self.createLayersForName(layer_name, filter_exprs)
665
666 - def createLayersForName(self, layer_name, filter_exprs):
667 dataset_series = System.getRegistry().getFromFactory( 668 "resources.coverages.wrappers.DatasetSeriesFactory", 669 {"obj_id": layer_name} 670 ) 671 if dataset_series is not None: 672 self.createDatasetSeriesLayers(dataset_series, filter_exprs) 673 else: 674 coverage = System.getRegistry().getFromFactory( 675 "resources.coverages.wrappers.EOCoverageFactory", 676 {"obj_id": layer_name} 677 ) 678 if coverage is not None: 679 if coverage.matches(filter_exprs): 680 # TODO: check if the coverage crosses the dateline 681 # if yes, add multiple layers 682 683 if extent_crosses_dateline(coverage.getExtent(), coverage.getSRID()): 684 logger.debug("Coverage %s crosses the dateline. Special layer setup." % coverage.getCoverageId()) 685 if coverage.getType() == "eo.rect_dataset": 686 coverage_id = coverage.getCoverageId() 687 688 unwrapped_coverage_layer = WMSRectifiedDatasetLayer(coverage) 689 unwrapped_coverage_layer.name = coverage_id + "_unwrapped" 690 691 wrapped_extent = wrap_extent_around_dateline( 692 coverage.getExtent(), coverage.getSRID() 693 ) 694 vrt_path = str("/vsimem/%s/%s.vrt" % (str(uuid4()), coverage_id)) # str to avoid unicode issues 695 wrapped_coverage_layer = WMSWrappedRectifiedDatasetLayer(coverage, vrt_path, wrapped_extent) 696 wrapped_coverage_layer.name = coverage_id + "_wrapped" 697 698 unwrapped_coverage_layer.setGroup(coverage_id) 699 wrapped_coverage_layer.setGroup(coverage_id) 700 701 self.addLayer(unwrapped_coverage_layer) 702 self.addLayer(wrapped_coverage_layer) 703 else: 704 raise NotImplementedError( 705 "WMS for dateline crossing datasets are not " 706 "implemented." 707 ) 708 else: 709 self.addLayer(self.createCoverageLayer(coverage)) 710 else: 711 self.addLayer(WMSEmptyLayer(coverage.getCoverageId())) 712 else: 713 raise InvalidRequestException( 714 "No coverage or dataset series with EO ID '%s' found" % layer_name, 715 "LayerNotDefined", "layers" 716 )
717
718 - def createDatasetSeriesLayers(self, dataset_series, filter_exprs):
719 def _get_begin_time(coverage): 720 return coverage.getBeginTime()
721 722 coverages = dataset_series.getEOCoverages(filter_exprs) 723 eoid = dataset_series.getEOID() 724 725 if len(coverages) == 0: 726 layer = WMSEmptyLayer(eoid) 727 728 self.addLayer(layer) 729 730 coverages.sort(key=_get_begin_time) 731 732 for coverage in coverages: 733 if extent_crosses_dateline(coverage.getExtent(), coverage.getSRID()): 734 logger.debug("Coverage %s crosses the dateline. Special layer setup." % coverage.getCoverageId()) 735 if coverage.getType() == "eo.rect_dataset": 736 coverage_id = coverage.getCoverageId() 737 738 unwrapped_coverage_layer = WMSRectifiedDatasetLayer(coverage) 739 unwrapped_coverage_layer.name = coverage_id + "_unwrapped" 740 741 wrapped_extent = wrap_extent_around_dateline( 742 coverage.getExtent(), coverage.getSRID() 743 ) 744 vrt_path = str("/vsimem/%s/%s.vrt" % (str(uuid4()), coverage_id)) # str to avoid unicode issues 745 wrapped_coverage_layer = WMSWrappedRectifiedDatasetLayer(coverage, vrt_path, wrapped_extent) 746 wrapped_coverage_layer.name = coverage_id + "_wrapped" 747 748 unwrapped_coverage_layer.setGroup(eoid) 749 wrapped_coverage_layer.setGroup(eoid) 750 751 self.addLayer(unwrapped_coverage_layer) 752 self.addLayer(wrapped_coverage_layer) 753 else: 754 raise NotImplementedError( 755 "WMS for dateline crossing datasets are not " 756 "implemented." 757 ) 758 759 else: 760 layer = self.createCoverageLayer(coverage) 761 layer.setGroup(eoid) 762 self.addLayer(layer)
763 764
765 - def addLayer(self, layer):
766 # TODO: more performant solution based on hashes 767 for other_layer in self.layers: 768 if other_layer.getName() == layer.getName(): 769 return 770 771 self.layers.append(layer)
772
773 - def getSRID(self):
774 775 srs = self.req.getParamValue(self.getSRSParameterName()) 776 777 if srs is None: 778 raise InvalidRequestException("Missing '%s' parameter" 779 % self.getSRSParameterName().upper(), "MissingParameterValue", 780 self.getSRSParameterName()) 781 782 srid = crss.parseEPSGCode(srs,(crss.fromURL,crss.fromURN, 783 crss.fromShortCode)) 784 785 if srid is None: 786 raise InvalidRequestException("Invalid '%s' parameter value" 787 % self.getSRSParameterName().upper(), "InvalidCRS" , 788 self.getSRSParameterName()) 789 790 return srid
791
792 - def getMapServerLayer(self, layer):
793 ms_layer = super(WMS1XGetMapHandler, self).getMapServerLayer(layer) 794 795 ms_layer.status = mapscript.MS_DEFAULT 796 797 return ms_layer
798