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.

Line 
1import logging
2import Image
3import thread
4import re
5import simplejson as json
6
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
20import time
21
22from geoplot.layer_drawer_coastline import LayerDrawerCoastlines
23
24from cows.model.wms import Style, LegendURL, FormattedURL, MetadataURL
25from cows.xml.iso19115_subset import OnlineResource
26
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 +
46        ['GetMap', 'GetContext', 'GetLegend', 'GetFeatureInfo', 'GetInfo', 'GetDisplayOptions'])
47   
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'])
75
76       
77        featureInfoFormats = Set()
78
79        log.debug('Loading capabilities contents')
80        c.capabilities.contents = Contents()
81       
82       
83        layers = ( ('c', 'coarse', 'coarse detail'), 
84                   ('l', 'low', 'low detail'), 
85                   ('i', 'intermediate', 'intermediate detail'),
86                   ('h', 'high', 'high detail'),
87                   ('f', 'full', 'full detail'),
88                   ('auto', 'auto', 'automatic detail'),)
89       
90       
91        for layerName, title,  abstract in layers:
92            log.debug('LayerName: %s' % layerName)
93            log.debug('Loading layer %s' % layerName)
94
95            wgs84BBox = WGS84BoundingBox((-180,-90), (180,90))
96
97            # Get CRS/BBOX pairs
98            bboxObjs = []
99            for crs in ('EPSG:4326', 'CRS:84', 'WGS84'):
100                bbox = [-180,-90,180,90]
101                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
102               
103
104               
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?
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       
120            # Create the cows object
121            ds = WmsDatasetSummary(identifier=layerName,
122                                   titles=[title],
123                                   CRSs=('EPSG:4326', 'CRS:84', 'WGS84'),
124                                   wgs84BoundingBoxes=[wgs84BBox],
125                                   boundingBoxes=bboxObjs,
126                                   abstracts=[abstract],
127                                   dimensions={},
128                                   queryable=False,
129                                   dataURLs=[],
130                                   styles=[],
131                                   metadataURLs=[metadataURL])
132
133            # Stuff that should go in the capabilities tree eventually
134            ds.legendSize = (630,80)
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   
164    def GetMap(self):       
165        st = time.time()
166
167       
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
193       # Get format
194        format = self.getOwsParam('format')
195        if format not in self._pilImageFormats:
196            raise InvalidParameterValue(
197                'Format %s not supported' % format, 'format')
198
199        if layerName == 'auto':
200            layerName = None
201       
202        ldg = LayerDrawerCoastlines(transparent=transparent,
203                                    resolution=layerName)
204
205        xLimits = (bbox[0], bbox[2])
206        yLimits = (bbox[1], bbox[3])       
207        finalImg = ldg.makeImage(xLimits, yLimits, width, height)     
208
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
226       
227        log.debug("got coastline in %s" % (time.time() - st,))
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':
261           
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()
265       
266        elif format == 'application/json':
267           
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()
272       
273        else:
274            raise InvalidParameterValue('Format %s not supported' % format)
275
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.