source: qesdi/wms_ddc_vis/trunk/lib/wms_ddc_vis/controllers/coastwms.py @ 5701

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/qesdi/wms_ddc_vis/trunk/lib/wms_ddc_vis/controllers/coastwms.py@5701
Revision 5701, 12.4 KB checked in by pnorton, 10 years ago (diff)

Added the 'auto' layer to the coastwms.

Fixed a bug in the wms getFigure code.

Added some additional getFigure options to the wms3 code.

RevLine 
[5403]1import logging
2import Image
3import thread
4import re
[5535]5import simplejson as json
6
[5403]7from StringIO import StringIO
8from sets import Set
9from matplotlib.cm import get_cmap
10from pylons import request, response, c
11from routes import url_for
12from routes.util import GenerationException
13from genshi.template import NewTextTemplate
14from cows.pylons.wms_controller import WMSController
15from cows.model.wms import WmsDatasetSummary, Dimension, DataURL
16from cows.model import PossibleValues, WGS84BoundingBox, BoundingBox, Contents
17from cows.pylons import ows_controller
18from cows.exceptions import *
19from cows import bbox_util
[5647]20import time
[5403]21
[5479]22from geoplot.layer_drawer_coastline import LayerDrawerCoastlines
[5403]23
[5535]24from cows.model.wms import Style, LegendURL, FormattedURL, MetadataURL
25from cows.xml.iso19115_subset import OnlineResource
26
[5403]27log = logging.getLogger(__name__)
28
29class CoastwmsController(ows_controller.OWSController):
30
31    #layers = {}   
32    _pilImageFormats = {
33        'image/png': 'PNG',
34        'image/jpg': 'JPEG',
35        'image/gif': 'GIF',
36        'image/tiff': 'TIFF'
37        }
38   
39    _layerSlabCache = {}
40
41    #-------------------------------------------------------------------------
42    # Attributes required by OWSController
43
44    service = 'WMS'
45    owsOperations = (ows_controller.OWSController.owsOperations +
[5535]46        ['GetMap', 'GetContext', 'GetLegend', 'GetFeatureInfo', 'GetInfo', 'GetDisplayOptions'])
47   
[5403]48    validVersions = ['1.1.1', '1.3.0']
49
50
51
52    def _renderCapabilities(self, version, format):
53        if format == 'application/json':
54            t = ows_controller.templateLoader.load('wms_capabilities_json.txt',
55                                                   cls=NewTextTemplate)
56        elif version == '1.1.1':
57            t = ows_controller.templateLoader.load('wms_capabilities_1_1_1.xml')
58        elif version == '1.3.0':
59            t = ows_controller.templateLoader.load('wms_capabilities_1_3_0.xml')
60        else:
61            # We should never get here!  The framework should raise an exception before now.
62            raise RuntimeError("Version %s not supported" % version)
63       
64        return t.generate(c=c).render()
65
66    def _loadCapabilities(self):
67        """
68        @note: Assumes self.layers has already been created by __before__().
69
70        """
71        #!TODO: Add json format to GetCapabilities operation
72
73        ows_controller.addOperation('GetMap', formats=self._pilImageFormats.keys())
74        ows_controller.addOperation('GetContext', formats=['text/xml', 'application/json'])
[5479]75
[5403]76       
77        featureInfoFormats = Set()
78
79        log.debug('Loading capabilities contents')
80        c.capabilities.contents = Contents()
[5535]81       
82       
83        layers = ( ('c', 'coarse', 'coarse detail'), 
84                   ('l', 'low', 'low detail'), 
85                   ('i', 'intermediate', 'intermediate detail'),
86                   ('h', 'high', 'high detail'),
[5701]87                   ('f', 'full', 'full detail'),
88                   ('auto', 'auto', 'automatic detail'),)
[5535]89       
90       
91        for layerName, title,  abstract in layers:
[5403]92            log.debug('LayerName: %s' % layerName)
93            log.debug('Loading layer %s' % layerName)
94
[5535]95            wgs84BBox = WGS84BoundingBox((-180,-90), (180,90))
96
[5403]97            # Get CRS/BBOX pairs
98            bboxObjs = []
[5535]99            for crs in ('EPSG:4326', 'CRS:84', 'WGS84'):
100                bbox = [-180,-90,180,90]
[5403]101                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
102               
[5535]103
104               
[5403]105            #URL to WCS - uses named route 'wcsroute'
106            #TODO: Allow for a WCS blacklist to opt out of providing dataurls for certain datasets?
107            #TODO: How to make this more configurable - what if WCS is not coupled with WMS?
[5535]108#            try:
109#                version='1.0.0' #wcs version
110#                wcsbaseurl=url_for('wcsroute', fileoruri=c.fileoruri,qualified=True)+'?'
111#                dataURLs=[DataURL(format='WCS:CoverageDescription', onlineResource='%sService=WCS&Request=DescribeCoverage&Coverage=%s&Version=%s'%(wcsbaseurl, layerName, version))]
112#            except GenerationException:
113#                log.info("dataURLs not populated: could not generate WCS url with url_for('wcsroute', filedoruri=%s,qualified=True)"%c.fileoruri)
114#                dataURLs=[]
115           
116            onlineRes = OnlineResource(url_for(qualified=True, action='index') +\
117                                    "?request=GetDisplayOptions&layers=%s" % layerName)
118            metadataURL = MetadataURL(metadataType='display_options', format='application/json', onlineResource=onlineRes)
119       
[5403]120            # Create the cows object
121            ds = WmsDatasetSummary(identifier=layerName,
[5535]122                                   titles=[title],
123                                   CRSs=('EPSG:4326', 'CRS:84', 'WGS84'),
[5403]124                                   wgs84BoundingBoxes=[wgs84BBox],
125                                   boundingBoxes=bboxObjs,
[5535]126                                   abstracts=[abstract],
127                                   dimensions={},
128                                   queryable=False,
129                                   dataURLs=[],
130                                   styles=[],
131                                   metadataURLs=[metadataURL])
[5403]132
133            # Stuff that should go in the capabilities tree eventually
[5535]134            ds.legendSize = (630,80)
[5403]135            ds.legendFormats = ['image/png']
136
137            c.capabilities.contents.datasetSummaries.append(ds)
138
139        # Add this operation here after we have found all formats
140        ows_controller.addOperation('GetFeatureInfo',
141                                    formats = list(featureInfoFormats))
142
143
144    _escapedDimNames = ['width', 'height', 'version', 'request',
145                        'layers', 'styles', 'crs', 'srs', 'bbox',
146                        'format', 'transparent', 'bgcolor',
147                        'exceptions']
148
149
150    def _mapDimToParam(self, dimName):
151        """
152        Dimension names might clash with WMS parameter names, making
153        them inaccessible in WMS requests.  This method maps a
154        dimension name to a parameter name that appears in the
155        capabilities document and WMS requests.
156
157        """
158        if dimName.lower() in self._escapedDimNames:
159            return dimName+'_dim'
160        else:
161            return dimName
162       
163   
[5647]164    def GetMap(self):       
165        st = time.time()
[5403]166
[5647]167       
[5403]168        # Housekeeping
169        version = self.getOwsParam('version', default=self.validVersions[0])
170        if version not in self.validVersions:
171            raise InvalidParameterValue('Version %s not supported' % version,
172                                        'version')
173        styles = self.getOwsParam('styles', default='')
174        transparent = self.getOwsParam('transparent', default='FALSE')
175        bgcolor = self.getOwsParam('bgcolor', default='0xFFFFFF')
176
177        # Layer handling
178        layerName = self.getOwsParam('layers')
179       
180        transparent = self.getOwsParam('transparent').lower() == 'true'
181       
182       
183        # Coordinate parameters
184        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
185        width = int(self.getOwsParam('width'))
186        height = int(self.getOwsParam('height'))
187
188        if version == '1.1.1':
189            srs = self.getOwsParam('srs')
190        else:
191            srs = self.getOwsParam('crs')
192
[5479]193       # Get format
[5403]194        format = self.getOwsParam('format')
195        if format not in self._pilImageFormats:
196            raise InvalidParameterValue(
197                'Format %s not supported' % format, 'format')
198
[5647]199        if layerName == 'auto':
200            layerName = None
201       
[5479]202        ldg = LayerDrawerCoastlines(transparent=transparent,
203                                    resolution=layerName)
[5403]204
205        xLimits = (bbox[0], bbox[2])
206        yLimits = (bbox[1], bbox[3])       
[5479]207        finalImg = ldg.makeImage(xLimits, yLimits, width, height)     
[5647]208
[5403]209       
210        # IE < 7 doesn't display the alpha layer right.  Here we sniff the
211        # user agent and remove the alpha layer if necessary.
212        try:
213            ua = request.headers['User-Agent']
214        except:
215            pass
216        else:
217            if 'MSIE' in ua and 'MSIE 7' not in ua:
218                finalImg = finalImg.convert('RGB')
219
220        buf = StringIO()
221        finalImg.save(buf, self._pilImageFormats[format])
222
223        response.headers['Content-Type'] = format
224        response.write(buf.getvalue())
225
[5647]226       
227        log.debug("got coastline in %s" % (time.time() - st,))
[5403]228
229    def GetContext(self):
230        """
231        Return a WebMap Context document for a given set of layers.
232
233        """
234        # Parameters
235        layers = self.getOwsParam('layers', default=None)
236        format = self.getOwsParam('format', default='text/xml')
237
238        # Filter self.layers for selected layers
239        if layers is not None:
240            newLayerMap = {}
241            for layerName in layers.split(','):
242                try:
243                    newLayerMap[layerName] = self.layers[layerName]
244                except KeyError:
245                    raise InvalidParameterValue('Layer %s not found' % layerName,
246                                                'layers')
247                   
248            self.layers = newLayerMap
249
250        # Automatically select the first bbox/crs for the first layer
251        aLayer = self.layers.values()[0]
252        crs = aLayer.crss[0]
253        bb = aLayer.getBBox(crs)
254        c.bbox = BoundingBox(bb[:2], bb[2:], crs)
255
256        # Initialise as if doing GetCapabilities
257        ows_controller.initCapabilities()
258        self._loadCapabilities()
259
260        if format == 'text/xml':
[5479]261           
[5403]262            response.headers['Content-Type'] = format
263            t = ows_controller.templateLoader.load('wms_context_1_1_1.xml')
264            return t.generate(c=c).render()
[5479]265       
[5403]266        elif format == 'application/json':
[5479]267           
[5403]268            response.headers['Content-Type'] = format
269            t = ows_controller.templateLoader.load('wms_context_json.txt',
270                                                   cls=NewTextTemplate)
271            return t.generate(c=c).render()
[5479]272       
[5403]273        else:
274            raise InvalidParameterValue('Format %s not supported' % format)
275
[5535]276
277    def GetDisplayOptions(self):
278           
279        displayOptions = {
280#          "common": [
281#                        {
282#                            "type":"select",
283#                            "name":"cmap",
284#                            "options":["bone","jet", "copper", "gray", "winter"],
285#                            "title":"Colour Scheme",
286#                            "defaultVal":"jet",
287#                        },
288#                        {
289#                            "type":"value",
290#                            "name":"cmap_min",
291#                            "title":"Legend Min",
292#                            "defaultVal":None,
293#                        },
294#                        {
295#                            "type":"value",
296#                            "name":"cmap_max",
297#                            "title":"Legend Max",
298#                            "defaultVal":None,
299#                        },         
300#                     ],
301#          "grid": [
302#                        {
303#                            "type":"bool",
304#                            "name":"show_grid_lines",
305#                            "title":"Draw Grid Boxes",
306#                            "defaultVal":"False",
307#                        },   
308#                  ],
309#          "contour":[
310#                        {
311#                            "type":"value",
312#                            "name":"num_contour_lines",
313#                            "title":"Number of Contour Lines",
314#                            "defaultVal":10,
315#                        },
316#                        {
317#                            "type":"select",
318#                            "name":"contour_font_size",
319#                            "title":"Contour Label Size",
320#                            "options":["small","medium", "large",],
321#                            "defaultVal":"medium",
322#                        },   
323#                        {
324#                            "type":"value",
325#                            "name":"contour_label_interval",
326#                            "title":"Interval Between Labels",
327#                            "defaultVal":1,
328#                        },             
329#                    ],
330        }
331       
332       
333        request.headers['Content-Type'] = 'application/json'
334        response.write( json.dumps(displayOptions) )
335
Note: See TracBrowser for help on using the repository browser.