source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/csml_wms.py @ 2586

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/csml_wms.py@2586
Revision 2586, 6.5 KB checked in by spascoe, 12 years ago (diff)

First WMS GetMap? request working.

Line 
1# Copyright (C) 2007 STFC & NERC (Science and Technology Facilities Council).
2# This software may be distributed under the terms of the
3# Q Public License, version 1.0 or later.
4# http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
5"""
6Example WMS controller driven by CSML.
7
8@author: Stephen Pascoe
9
10"""
11from ows_server.lib.base import *
12from ows_server.controllers.csml_api import get_csml_doc
13from ows_server.lib.decorators import *
14from ows_server.lib import grid_util, render
15from ows_server.lib.csml_util import get_csml_doc
16import ows_server.lib.validators as V
17
18from elementtree import ElementTree as ET
19
20from ows_common import exceptions as OWS_E
21from ows_common.wms import *
22from ows_common.common import BoundingBox
23from ows_common.domain import ValuesUnit, PossibleValues
24
25import cdms
26import tempfile, os
27from cStringIO import StringIO
28import MA
29
30class CsmlWmsController(OwsController):
31
32    _ows_parameters = {
33        'Format': make_domain(['text/xml']),
34        'ExceptionFormat': make_domain(['text/xml']),
35        }
36
37    #_ows_constraints = {
38        # MaximumLayerLevels
39        # MaximumWidth
40        # MaximumWidth
41    #    }
42
43
44    def _iterDimensions(self, feature):
45        """
46        Retrieve the non-geospatial dimensions of a feature.
47
48        @return: generator of dimension names
49
50        """
51        # Waiting for this feature to be implemented
52        #lat = feature.getLatitude()
53        #lon = feature.getLongitude()
54        lat = 'latitude'; lon = 'longitude'
55       
56        for axis_name in feature.getDomain():
57            if axis_name not in [lat, lon]:
58                yield axis_name
59
60    def _loadFeatureDimensions(self, feature):
61        dims = {}
62        domain = feature.getDomain()
63        for axis_name in self._iterDimensions(feature):
64            axis = domain[axis_name]
65            dims[axis_name] = Dimension(possibleValues=PossibleValues.fromAllowedValues(axis),
66                                        #!TODO: see ticket:770 for how to populate this
67                                        valuesUnit=ValuesUnit(uoms=[''],
68                                                              referenceSystems=['']))
69        return dims
70
71    def _loadFeatureSummary(self, feature):
72        dims = self._loadFeatureDimensions(feature)
73       
74        return WmsDatasetSummary(identifier=feature.id,
75                                 titles=[feature.description.CONTENT],
76                                 boundingBoxes=[BoundingBox([-180,-90], [180,90],
77                                                            crs='CRS:84')],
78                                 dimensions=dims,               
79                                 )
80
81    def _loadCapabilities(self):
82        """
83        Overriding subclass to add layer capabilities
84
85        """
86        # Get default capabilities from superclass
87        sm = super(CsmlWmsController, self)._loadCapabilities()
88
89        # For WMS 1.3.0 compatibility we need a single root DatasetSummary
90        ds = WmsDatasetSummary(titles=['Root Dataset'], datasetSummaries=[],
91                               CRSs=['CRS:84'])
92        # Add a DatasetSummary for each feature       
93        for f_n in c.dataset.getFeatureList():
94            feature_ds = self._loadFeatureSummary(c.dataset.getFeature(f_n))
95            ds.datasetSummaries.append(feature_ds)
96
97        sm.contents = Contents(datasetSummaries=[ds])
98        return sm
99
100   
101    @operation
102    @parameter('Format', possibleValues=['text/xml'])
103    @parameter('Service', possibleValues=['WMS'], required=True)
104    @parameter('Version', possibleValues=['1.3.0'])
105    def GetCapabilities(self, file, service=None, version=None):
106        """
107        @note: format and updatesequence parameters are not supported
108            by this WMS.
109
110        """
111       
112        # Populate the context object with information required by the template
113        c.dataset = get_csml_doc(file)
114
115        return self._renderCapabilities('ows/wms_capabilities')
116
117
118    @operation
119    @parameter('Version', possibleValues=['1.3.0'], required=True)
120    @parameter('Layers', required=True, validator=V.single_layer)
121    @parameter('Styles', required=True)
122    @parameter('CRS', possibleValues=['CRS:84'], required=True)
123    @parameter('Bbox', required=True, validator=V.bbox_2d)
124    @parameter('Width', required=True, validator=V.integer('Width', 0, 640))
125    @parameter('Height', required=True, validator=V.integer('Height', 0, 320))
126    @parameter('Format', required=True)
127    @parameter('Transparent', validator=V.boolean('Transparent'))
128    @parameter('Bgcolor')
129    @parameter('Exceptions')
130    # Dimension parameters Time, Elevation, etc. are handled separately
131    def GetMap(self, file, version, layers, styles, crs, bbox, width, height, format,
132               transparent=False, bgcolor=None, exceptions=None):
133
134        # Retrieve dataset and selected feature
135        dataset = get_csml_doc(file)
136        feature = dataset.getFeature(layers)
137        if feature is None:
138            raise OWS_E.InvalidParameterValue('Layer not found', 'layers')
139
140        # Define the extraction selector
141        sel = dict(latitude=(bbox[1], bbox[3]), longitude=(bbox[0], bbox[2]))
142
143        # Parse dimensions.
144        for dim in self._iterDimensions(feature):
145            # For the moment hard-code time in.  We don't support any other dimension yet.
146            if dim.lower() != 'time':
147                raise ValueError('Only lat, lon and time are supported domain axes')
148           
149            try:
150                sel[dim] = request.params[dim]
151            except KeyError:
152                raise OWS_E.MissingParameterValue('%s dimension not specified' % dim, dim)
153           
154        # Subset the feature
155        (fd, filename) = tempfile.mkstemp('.nc', 'csml_wms_'); os.close(fd)
156        feature.subsetToGridSeries(ncname=os.path.basename(filename),
157                                   outputdir=os.path.dirname(filename),
158                                   time=sel['time'] # workarround for CSML bug
159                                   #**sel
160                                   )
161        d = cdms.open(filename)
162        #var = d(feature.name.CONTENT, squeeze=1)
163        var = d(feature.name.CONTENT, longitude=sel['longitude'], latitude=sel['latitude'],
164                squeeze=1)
165       
166        # Deduce min and max
167        varmin = MA.minimum(var, None)
168        varmax = MA.maximum(var, None)
169
170        # Render variable to a PIL image
171        img = render.render_variable(var, bbox, width, height, varmin, varmax)
172
173        # Serialise it to PNG
174        buf = StringIO()
175        img.save(buf, 'PNG')
176
177        return Response(content=buf.getvalue(), mimetype='image/png')
Note: See TracBrowser for help on using the repository browser.