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

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

changes to kid template

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.lib.decorators import *
13from ows_server.lib import grid_util, render
14from ows_server.lib.csml_cache import csmlCache, extractCache
15import ows_server.lib.validators as V
16
17from elementtree import ElementTree as ET
18
19from ows_common import exceptions as OWS_E
20from ows_common.wms import *
21from ows_common.common import BoundingBox
22from ows_common.domain import ValuesUnit, PossibleValues
23
24import cdms
25import os, sys
26from cStringIO import StringIO
27import MA
28
29class CsmlWmsController(OwsController):
30
31    _ows_parameters = {
32        'Format': make_domain(['text/xml']),
33        'ExceptionFormat': make_domain(['text/xml']),
34        }
35
36    #_ows_constraints = {
37        # MaximumLayerLevels
38        # MaximumWidth
39        # MaximumWidth
40    #    }
41
42
43    def _iterDimensions(self, feature):
44        """
45        Retrieve the non-geospatial dimensions of a feature.
46
47        @return: generator of dimension names
48
49        """
50        # Waiting for this feature to be implemented
51        #lat = feature.getLatitude()
52        #lon = feature.getLongitude()
53        lat = 'latitude'; lon = 'longitude'
54       
55        for axis_name in feature.getDomain():
56            if axis_name not in [lat, lon]:
57                yield axis_name
58
59    def _loadFeatureDimensions(self, feature):
60        dims = {}
61        domain = feature.getDomain()
62        for axis_name in self._iterDimensions(feature):
63            axis = domain[axis_name]
64            dims[axis_name] = Dimension(possibleValues=PossibleValues.fromAllowedValues(axis),
65                                        #!TODO: see ticket:770 for how to populate this
66                                        valuesUnit=ValuesUnit(uoms=[''],
67                                                              referenceSystems=['']))
68        return dims
69
70    def _loadFeatureSummary(self, feature):
71        dims = self._loadFeatureDimensions(feature)
72       
73        return WmsDatasetSummary(identifier=feature.id,
74                                 titles=[feature.description.CONTENT],
75                                 boundingBoxes=[BoundingBox([-180,-90], [180,90],
76                                                            crs='CRS:84')],
77                                 dimensions=dims,               
78                                 )
79
80    def _loadCapabilities(self):
81        """
82        Overriding subclass to add layer capabilities
83
84        """
85        # Get default capabilities from superclass
86        sm = super(CsmlWmsController, self)._loadCapabilities()
87
88        # For WMS 1.3.0 compatibility we need a single root DatasetSummary
89        ds = WmsDatasetSummary(titles=['Root Dataset'], datasetSummaries=[],
90                               CRSs=['CRS:84'])
91        # Add a DatasetSummary for each feature       
92        for f_n in c.dataset.getFeatureList():
93            feature_ds = self._loadFeatureSummary(c.dataset.getFeature(f_n))
94            ds.datasetSummaries.append(feature_ds)
95
96        sm.contents = Contents(datasetSummaries=[ds])
97        return sm
98
99   
100    @operation
101    @parameter('Format', possibleValues=['text/xml'])
102    @parameter('Service', possibleValues=['WMS'], required=True)
103    @parameter('Version', possibleValues=['1.3.0'])
104    def GetCapabilities(self, file, service=None, version=None):
105        """
106        @note: format and updatesequence parameters are not supported
107            by this WMS.
108
109        """
110        # Populate the context object with information required by the template
111        c.dataset = csmlCache[file]
112
113        return self._renderCapabilities('ows/wms_capabilities')
114
115
116    @operation
117    @parameter('Version', possibleValues=['1.3.0'], required=True)
118    @parameter('Layers', required=True, validator=V.single_layer)
119    @parameter('Styles', required=True)
120    @parameter('CRS', possibleValues=['CRS:84'], required=True)
121    @parameter('Bbox', required=True, validator=V.bbox_2d)
122    @parameter('Width', required=True, validator=V.integer('Width'))
123    @parameter('Height', required=True, validator=V.integer('Height'))
124    @parameter('Format', required=True)
125    @parameter('Transparent', validator=V.boolean('Transparent'))
126    @parameter('Bgcolor')
127    @parameter('Exceptions')
128    # Dimension parameters Time, Elevation, etc. are handled separately
129    def GetMap(self, file, version, layers, styles, crs, bbox, width, height, format,
130               transparent=False, bgcolor=None, exceptions=None):
131
132        # Retrieve dataset and selected feature
133        dataset = csmlCache[file]
134        feature = dataset.getFeature(layers)
135        if feature is None:
136            raise OWS_E.InvalidParameterValue('Layer not found', 'layers')
137
138        # Clean up bbox.  Openlayers can request some very strange bboxes.  It is trimmed
139        # here and the implications for the image's aspect ratio is calculated in
140        # render.render_variable()
141        #!TODO: This could be done better.
142        #x1 = max(-180., min(180., bbox[0]))
143        #x2 = max(-180., min(180., bbox[2]))
144        #y1 = max(-90., min(90., bbox[1]))
145        #y2 = max(-90., min(90., bbox[3]))
146
147        # Define the extraction selector
148        #sel = dict(latitude=(y1, y2), longitude=(x1, x2))
149
150        # Parse dimensions.
151        sel = {}
152        for dim in self._iterDimensions(feature):
153            # For the moment hard-code time in.  We don't support any other dimension yet.
154            if dim.lower() != 'time':
155                raise ValueError('Only lat, lon and time are supported domain axes')
156           
157            try:
158                sel[dim] = self.ows_params[dim]
159            except KeyError:
160                raise OWS_E.MissingParameterValue('%s dimension not specified' % dim, dim)
161
162        # Get the entire lat/lon slice from the extractCache
163        var = extractCache[feature, sel]
164
165        # Do geographical subsetting in cdms
166        var = var(latitude=(bbox[1], bbox[3]), longitude=(bbox[0], bbox[2]), squeeze=1)
167
168        # Deduce min and max
169        #!TODO: How do we get the min/max?
170        #varmin = MA.minimum(var, None)
171        #varmax = MA.maximum(var, None)
172        varmin=0; varmax=100
173
174        # Render variable to a PIL image
175        img = render.render_variable(var, bbox, width, height, varmin, varmax)
176
177        # Serialise it to PNG
178        buf = StringIO()
179        img.save(buf, 'PNG')
180
181        return Response(content=buf.getvalue(), mimetype='image/png')
Note: See TracBrowser for help on using the repository browser.