source: cows/trunk/cows/service/imps/wms_layers.py @ 4106

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/trunk/cows/service/imps/wms_layers.py@4106
Revision 4106, 11.1 KB checked in by spascoe, 11 years ago (diff)

Moving wms_gdal.py to imps folder. This implementation is broken anyway (probably permanently as I never managed to get GDAL to work satisfactorily).

Line 
1"""
2implementation of ILayerMapper, ILayer, IDimension, ILayerSlab interfaces, as defined in wms_iface.py
3
4"""
5import os
6import cdms2 as cdms
7import Image
8from copy import copy
9from pointrenderer import PointRenderer
10from matplotlib import cm
11import genutil
12from pylons import config  #config must have tmpfilebuffer and csmlstore values
13from layers import LayerParser
14from csml2kml.utils import wget
15from StationCollection import StationCollection
16from xml.etree.ElementTree import ElementTree, Element, SubElement, XML
17import urllib
18from matplotlib import dates
19
20
21class WMSLayerMapper(object):
22    """
23    Map keyword arguments to a collection of layers.
24    Supports the retrieval of sets of layers according to arbitary
25    keyword/value pairs.
26    Implements  ILayerMapper
27   
28    """
29    def __init__(self):
30   
31        """
32        Lists the names of all layers available as listed in the configuration file specified by the 'layer_config' parameter in the development.ini file.
33
34        @return: A mapping of layer names to ILayer implementations.
35        @raise ValueError: If no layers are available for these keywords.
36        """
37       
38        filename=config['layer_config']
39        if not os.path.exists(filename):
40            raise Exception(str('Config File could not be found: %s')%filename)
41        print filename
42       
43        #instantiate LayerParser class with the value of 'layer_config' as parameter to read layer infromation
44        layerparser = LayerParser(filename)
45
46        layermap={}
47        layers = layerparser.getLayers()
48        for feature in layers:
49            # read information necessary to create a StationLayer object
50            title, abstract, crss,formats, serverURL, icon, featureName, dataSet, bbox, dataSetURL =self._getInfo(feature)
51            # URL required to query the relevant WFS server to acquire a list of station for the current layer in the loop
52            geoServerUrl =serverURL+'/wfs?request=getfeature&service=wfs&version=1.1.0&typename='+featureName+'&maxfeatures=100'
53            print geoServerUrl
54            geoServerResponse = wget(geoServerUrl)
55            stationCollection=StationCollection(geoServerResponse)
56            # specify the filepath for the static image to be used for representing each station in the GetMap image
57            icon =config['csml_config']+'/img/'+icon
58            print icon
59            #instantiate a StationLayer object and store that in the layermap dictionary with the name of the layer as the key
60            layermap[feature.findtext("Name")]=StationLayer(title,abstract, crss, stationCollection,bbox, formats, icon, dataSet, dataSetURL)
61        if len(layermap) > 0:
62            self.layermap = layermap
63        else:
64            raise ValueError
65
66   
67    def _getInfo(self, feature):
68        ''' given a Station feature, return info about the layer/feature
69        @return:    title, abstract, crss, formats, serverURL, icon, featureName,dataSet, bbox, dataSetURL  '''
70
71        try:
72            title=feature.findtext("Title")
73        except:
74            title=''
75        try:
76            abstract=feature.findtext("Abstract")
77        except:
78            abstract=title
79       
80        crs=feature.findtext("SRS")
81        crss=[crs]
82        print crss
83        formats = []
84       
85        #read supported getFeatureInfo formats from the "SupportedFormats" element
86        sFElem = feature.getchildren()[4]
87        for format in sFElem.getchildren():
88                formats.append(format.text)
89       
90        # read orignal bbox info
91        bboxElem = feature.getchildren()[5]
92        bbox=[int(bboxElem.getchildren()[0].text),int(bboxElem.getchildren()[1].text),int(bboxElem.getchildren()[2].text),int(bboxElem.getchildren()[3].text)]
93        #static image to be used for GetMap response
94        icon = feature.getchildren()[6].text
95        #read WFS server information
96        wfsElem = feature.getchildren()[7]
97        serverURL = wfsElem.getchildren()[0].text
98        featureName = wfsElem.getchildren()[1].text
99        dataSet = wfsElem.getchildren()[2].text
100        dataSetURL =  wfsElem.getchildren()[3].text
101        return title, abstract, crss, formats, serverURL, icon, featureName,dataSet, bbox, dataSetURL
102
103
104
105   
106    def map(self, **kwargs):
107        '''this function is called by the wms_controller class to acquire information about all available layers'''
108        return self.layermap
109
110
111class StationLayer(object):
112    """
113    representing a WMS layer for MIDAS/ECN Stations.    Implements ILayer
114
115    @ivar title: The layer title.  As seen in the Capabilities document.
116    @ivar abstract:  Abstract as seen in the Capabilities document.
117    @ivar crss: A sequence of SRS/CRSs supported by this layer.
118    @ivar stationCollection: A list of NPStation objects to be rendered as part of GetMap response
119    @ivar formats: A list of output formats supported by the layer in question for GetFeatureInfo response
120    @ivar icon: A static image to be used for representing each station in the stationCollection in the GetMap response
121    @ivar dataSet: Name of the dataset to be used to construct an URL for the GetFeatureInfo response
122    @ivar dataSetURL: Server address part of the URL to be returned as a part of the GetFeatureInfo response
123
124    """
125
126    def __init__(self, title, abstract, crss, stationCollection, wgs84BBox, formats, icon,dataSet, dataSetURL):       
127        self.title=title
128        self.abstract=abstract
129        self.crss=crss
130        self.legendSize=(300,60)
131        self.dimensions ={}
132        self.stationCollection = stationCollection
133        self.featureInfoFormats= formats
134        self.wgs84BBox=wgs84BBox
135        self.dataSet = dataSet
136        self.dataSetURL = dataSetURL
137        self.icon = icon
138    def getBBox(self, crs):
139        """
140        @return: A 4-tuple of the bounding box in the given coordinate
141            reference system.
142        """
143        bb= self.wgs84BBox
144        #convert 0 - 360 to -180, 180 as per common WMS convention
145        if abs(bb[2]-bb[0]) >= 359 and abs(bb[2]-bb[0]) < 361:
146            bb[0], bb[2]=-180, 180
147        return bb
148        #raise NotImplementedError
149       
150    def getSlab(self, crs, dimValues=None, renderOpts={}):
151        """
152        Creates a slab of the layer in a particular CRS and set of
153        dimensions.
154
155        @param crs: The coordinate reference system.
156        @param dimValues: A mapping of dimension names to dimension values
157            as specified in the IDimension.extent
158        @param renderOpts: A generic mapping object for passing rendering
159            options
160        @return: An object implementing ILayerSlab
161       
162        """
163        bbox=self.getBBox(crs)
164        return StationLayerSlab(self, crs, dimValues, renderOpts, bbox,self.icon, self.stationCollection)
165               
166    def getCacheKey(self, crs, dimValues=None, renderOpts={}):
167        """
168        Create a unique key for use in caching a slab.
169
170        The intention here is that most of the work should be done when
171        instantiating an ILayerSlab object.  These can be cached by the
172        server for future use.  The server will first call getCacheKey()
173        for the slab creation arguments and if the key is in it's cache
174        it will use a pre-generated ILayerSlab object.
175
176        """
177        return None
178        #raise NotImplementedError
179       
180    def getFeatureInfo(self, format, crs, point, dimValues):
181        """
182        Return a response string descibing the feature at a given
183        point in a given CRS.
184       
185        Currently only "html" is supported as output format
186
187        @param format: One of self.featureInfoFormats.  Defines which
188            format the response will be in.
189        @param crs: One of self.crss
190        @param point: a tuple (x, y) in the supplied crs of the point
191            being selected.
192        @param dimValues: A mapping of dimension names to dimansion values.
193        @return: A string containing the response.
194       
195        """
196        print point
197        nearestStation = self.stationCollection.getNearestStation(point[1], point[0])
198       
199        print nearestStation.desc
200       
201       
202        responseURL = self.dataSetURL+'/list?dataset_id='+self.dataSet+'&station_name='+nearestStation.desc
203        # replace space characters in the URL with %20 to avoid any URL validation error on the client side
204        responseURL = responseURL.replace(' ', '%20')
205        print responseURL
206        #finally construct the response, in this case it is in HTML with the responseURL represented as a hyperlink in it
207        response = "Description: <em>"+nearestStation.desc+"</em><br /><a href='"+responseURL+"'>"+responseURL+"</a>"
208        return response
209
210    def getLegendImage(self, orientation='vertical', renderOpts={}):
211        """
212        Create an image of the colourbar for this layer.
213
214        @param orientation: Either 'vertical' or 'horizontal'
215        @return: A PIL image
216
217        """
218        width = self.legendSize[0]
219        height = self.legendSize[1]
220        # if width and height specified in the GetLegend request parameters
221        # then use them instead of the default values
222        if 'width' in renderOpts:
223                width = renderOpts['width']
224        if 'height' in renderOpts:
225                height = renderOpts['height']
226        renderer=PointRenderer()
227        legImage = Image.new('RGBA', (width, height), (0,0,0,0))
228        # legend for stations without any associated dataset
229        withoutData = Image.open(self.icon)
230        # legend for stations that contain datasets
231        withData= Image.open(self.icon+'1')
232        legImage.paste(withoutData, (0,0))
233        legImage.paste(renderer.txt2img(self.title+' without dataset', "helvB08.pil"),(30, 5) )
234        legImage.paste(withData, (0, 30))
235        legImage.paste(renderer.txt2img(self.title+' with dataset', "helvB08.pil"),(30, 35) )       
236        return legImage
237
238class StationDimension(object):
239    """
240    implements IDimension
241    @ivar units: The units string.
242    @ivar extent: Sequence of extent values.
243
244    """
245   
246    def __init__(self, domain, dimname, unit):
247        self.units = unit
248        self.extent = []
249        for val in domain[dimname]:
250            self.extent.append(str(val))
251               
252       
253       
254       
255class StationLayerSlab(object):
256    """
257    Implements LayerSlab
258    Represents a particular horizontal slice of a WMS layer.
259
260    ILayerSlab objects are designed to be convenient to cache.
261    They should be pickleable to enable memcached support in the future.
262
263    @ivar layer: The source ILayer instance.
264    @ivar crs: The coordinate reference system.
265    @ivar dimValues: A mapping of dimension values of this view.
266    @ivar renderOpts: The renderOpts used to create this view.
267    @ivar bbox: The bounding box as a 4-tuple.
268    """
269   
270    def __init__(self,  layer, crs, dimValues, renderOpts, bbox, icon,stationCollection):
271        self.layer = layer
272        self.crs = crs
273        self.dimValues = dimValues
274        self.renderOpts=renderOpts
275        self.bbox=bbox
276        self.stationCollection = stationCollection
277        self.icon = icon
278    def getImage(self, bbox, width, height):
279        """
280        Create an image of a sub-bbox of a given size.
281
282        @ivar bbox: A bbox 4-tuple.
283        @ivar width: width in pixels.` 
284        @ivar height: height in pixels.
285        @return: A PIL Image object.
286
287        """
288        print bbox
289        stationsInBbox = self.stationCollection.getStationsInBBox(bbox[1],bbox[0],bbox[3], bbox[2])
290       
291       
292        cmap=eval(config['colourmap']) 
293        renderer=PointRenderer()         
294        return renderer.renderPoint(bbox, stationsInBbox, width, height, cmap,self.icon)
Note: See TracBrowser for help on using the repository browser.