source: TI05-delivery/ows_framework/branches/ows_framework-refactor/ows_common/ows_common/service/imps/wms_csmllayer.py @ 3620

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/branches/ows_framework-refactor/ows_common/ows_common/service/imps/wms_csmllayer.py@3620
Revision 3620, 8.5 KB checked in by domlowe, 12 years ago (diff)

csml wms working with correct bbox behaviour

Line 
1"""
2implementation of ILayerMapper, ILayer, IDimension, ILayerSlab interfaces, as defined in wms_iface.py
3
4"""
5import csml
6import cdms
7import Image
8from copy import copy
9from pywms.render_imp import RGBARenderer
10from matplotlib import cm
11import genutil
12
13class CSMLLayerMapper(object):
14    """
15    Map keyword arguments to a collection of layers.
16    Supports the retrieval of sets of layers according to arbitary
17    keyword/value pairs.
18    Implements  ILayerMapper
19   
20    """
21   
22    def _getInfo(self, feature):
23        ''' given a csml feature, return info about the layer/feature
24        @return:   title, abstract, dimensions, units, crss '''
25
26        try:
27            title=feature.name.CONTENT
28        except:
29            title=''
30        try:
31            abstract=feature.description.CONTENT
32        except:
33            abstract=title
34       
35        units=feature.getDomainUnits()
36        dimensions={}
37        tmpunits=copy(units)
38        tmpunits.reverse()
39        domain = feature.getDomain()
40        for dim in feature.getAxisLabels():
41            nextdim=CSMLDimension(domain, dim, tmpunits.pop())
42            if dim not in ['latitude', 'longitude']:
43                dimensions[dim]=nextdim
44        crs=feature.getNativeCRS()
45        crss=[self._crscat.getCRS(crs).twoD]
46        return title, abstract, dimensions, units, crss
47   
48    def map(self, **kwargs):
49        """
50        Given csml.parser.Dataset object list the names of
51        all layers available.
52       
53        @return: A mapping of layer names to ILayer implementations.
54        @raise ValueError: If no layers are available for these keywords.
55        """
56        fileoruri=kwargs['fileoruri']
57       
58        #TODO - handle file paths/directories URIs in config
59        #For testing purposes...:
60        filename='/home/dom/hadgem/%s.csml'%fileoruri
61        ds=csml.parser.Dataset(filename)
62       
63       
64        layermap={}
65        self._crscat=csml.csmllibs.csmlcrs.CRSCatalogue()
66        for feature in csml.csmllibs.csmlextra.listify(ds.featureCollection.featureMembers):
67            title, abstract, dimensions, units, crss=self._getInfo(feature)
68            layermap[feature.id]=CSMLLayer(title,abstract, dimensions, units, crss, feature)
69        if len(layermap) > 0:
70            return layermap
71        else:
72            raise ValueError
73
74
75class CSMLLayer(object):
76    """
77     representing a WMS layer.    Implements ILayer
78
79    @ivar title: The layer title.  As seen in the Capabilities document.
80    @ivar abstract:  Abstract as seen in the Capabilities document.
81    @ivar dimensions: A dictionary of IDimension objects.
82    @ivar units: A string describing the units.
83    @ivar crss: A sequence of SRS/CRSs supported by this layer.
84
85    @todo: Do we need minValue/maxValue?
86
87    """
88
89    def __init__(self, title, abstract, dimensions, units, crss, feature):
90        self.title=title
91        self.abstract=abstract
92        self.dimensions=dimensions
93        self.units=units
94        self.crss=crss
95        self._feature=feature
96        self.legendSize=(30,100)
97
98    def getBBox(self, crs):
99        """
100        @return: A 4-typle of the bounding box in the given coordinate
101            reference system.
102        """
103        bb= self._feature.getCSMLBoundingBox().getBox()
104        #convert 0 - 360 to -180, 180 as per common WMS convention
105        if abs(bb[2]-bb[0]) >= 359 and abs(bb[2]-bb[0]) < 361:
106            bb[0], bb[2]=-180, 180
107        return bb
108        #raise NotImplementedError
109       
110    def getSlab(self, crs, dimValues=None, renderOpts={}):
111        """
112        Creates a slab of the layer in a particular CRS and set of
113        dimensions.
114
115        @param crs: The coordinate reference system.
116        @param dimValues: A mapping of dimension names to dimension values
117            as specified in the IDimension.extent
118        @param renderOpts: A generic mapping object for passing rendering
119            options
120        @return: An object implementing ILayerSlab
121        #create netcdf for whole lat/lon for given dimValues, use to init slab
122        """
123        if type(self._feature) == csml.parser.GridSeriesFeature:
124            randomname='tmp' + csml.csmllibs.csmlextra.getRandomID() + '.nc'
125            result= self._feature.subsetToGridSeries(outputdir='./', ncname=randomname, **dimValues)
126            #for now have to read netcdf back from disk.
127            netcdf=cdms.open(result[1])
128            bbox=self.getBBox(crs)
129            return CSMLLayerSlab(netcdf, self, crs, dimValues, renderOpts, bbox)
130        else:
131            raise NotImplementedError
132       
133    def getCacheKey(self, crs, dimValues=None, renderOpts={}):
134        """
135        Create a unique key for use in caching a slab.
136
137        The intention here is that most of the work should be done when
138        instantiating an ILayerSlab object.  These can be cached by the
139        server for future use.  The server will first call getCacheKey()
140        for the slab creation arguments and if the key is in it's cache
141        it will use a pre-generated ILayerSlab object.
142
143        """
144        return None
145        #raise NotImplementedError
146
147
148
149class CSMLDimension(object):
150    """
151    implements IDimension
152    @ivar units: The units string.
153    @ivar extent: Sequence of extent values.
154
155    """
156   
157    def __init__(self, domain, dimname, unit):
158        self.units = unit
159        self.extent = []
160        for val in domain[dimname]:
161            self.extent.append(str(val))
162               
163       
164       
165       
166class CSMLLayerSlab(object):
167    """
168    Implements LayerSlab
169    Represents a particular horizontal slice of a WMS layer.
170
171    ILayerSlab objects are designed to be convenient to cache.
172    They should be pickleable to enable memcached support in the future.
173
174    @ivar layer: The source ILayer instance.
175    @ivar crs: The coordinate reference system.
176    @ivar dimValues: A mapping of dimension values of this view.
177    @ivar renderOpts: The renderOpts used to create this view.
178    @ivar bbox: The bounding box as a 4-tuple.
179    """
180   
181    def __init__(self, netcdf, layer, crs, dimValues, renderOpts, bbox):
182        self._netcdf=netcdf
183        self.layer = layer
184        self.crs = crs
185        self.dimValues = dimValues
186        self.renderOpts=renderOpts
187        self.bbox=bbox
188       
189       
190    def getImage(self, bbox, width, height):
191        """
192        Create an image of a sub-bbox of a given size.
193
194        @ivar bbox: A bbox 4-tuple.
195        @ivar width: width in pixels.
196        @ivar height: height in pixels.
197        @return: A PIL Image object.
198
199        """
200        cmap=cm.gist_rainbow_r # renderOpts is hook for colourmap. 
201        grid=Grid(self.layer, self._netcdf, bbox, width, height)
202        #how to handle varmin,varmax? ..read array?
203        #minval, maxval=genutil.minmax(grid.value)
204        minval=min(min(l) for l in grid.value)
205        maxval=max(max(l) for l in grid.value)
206        renderer=RGBARenderer(minval, maxval)         
207        return renderer.renderGrid(grid, bbox, width, height, cmap)
208   
209class Grid(object):
210    """A class encapsulating a simple regularly spaced, rectilinear
211    grid.  This is the only type of grid pywms is expected to
212    understand and adaptors should be provided to connect to
213    underlying implementations such as cdms or csml.
214
215    @cvar crs: Coordinate reference system
216
217    @ivar x0: coordinate of the lower left corner.
218    @ivar y0: coordinate of the lower left corner.
219    @ivar dx: The x grid spacing.
220    @ivar dy: The y grid spacing.
221    @ivar nx: The number of x grid points.
222    @ivar ny: The number of y grid points.
223    @ivar value: A masked array of the grid values.
224    @ivar ix: The dimension index of longidude in value
225    @ivar iy: The dimension index of latitude in value
226    @ivar long_name: The name of the field.
227    @ivar units: The units of the field.
228    """
229    def __init__(self, layer, netcdf, bbox, width, height):
230        #we know the axes are called latitude and longitude as the CSML code has written it:
231
232        v=netcdf(layer.title)
233        tvar=v(latitude=(bbox[1], bbox[3]), longitude=(bbox[0],bbox[2]),squeeze=1)
234        order=tvar.getOrder()
235        #array of data
236        self.value=tvar.getValue()
237        #order of axes
238        if order == 'xy':
239            self.ix=0
240            self.iy=1
241        else:
242            self.ix=1
243            self.iy=0
244        lat = tvar.getLatitude()
245        lon = tvar.getLongitude()
246        self.x0=lon[0]
247        self.y0=lat[0]
248        self.dx=abs(lon[0]-lon[1])
249        self.dy=abs(lat[0]-lat[1])
250        self.nx=len(lon)
251        self.ny=len(lat)
252        self.long_name=tvar.id  #TODO, get long name from feature
253        self.units=tvar.units
Note: See TracBrowser for help on using the repository browser.