source: cows/trunk/cows/service/imps/data_reader_geoplot_backend/geoplot_slabs/geoplot_slab_base.py @ 5848

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/trunk/cows/service/imps/data_reader_geoplot_backend/geoplot_slabs/geoplot_slab_base.py@5848
Revision 5848, 5.6 KB checked in by pnorton, 11 years ago (diff)

First attempt at passing the axis config xml through to the metadata in the getcapabilities.

Line 
1import logging
2import time
3
4import numpy
5
6from geoplot.utils import isRangeInLimits
7
8from cows.service.wms_iface import IwmsLayerSlab
9from cows.service.imps.image_import import Image
10from cows.service.imps.data_reader_geoplot_backend.slab_options_parser import SlabOptionsParser
11   
12log = logging.getLogger(__name__)
13
14class GeoplotSlabBase(IwmsLayerSlab):
15    """
16    A layer slab that implements the IwmsLayerSlab interface and uses geoplot
17    to render the required images.
18   
19    This is an abstract base class and should not be used directly.
20    """
21
22    """
23    contstructor
24   
25    @param netcdf: the netcdf variable that contains the data for this slab
26    @param title: the title of the variable that is to be used
27    @param crs: the coordinate refrence system the data is stored in
28    @param dimValues: the dimension values for this slab
29    @param transparent: indicates if the produced image should be transparent or
30        not.
31    @param bbox: the bounds of the data in lat/lon
32    @param renderOpts: the additional parameters recieved by the WMS, may include
33        some custom rendering options.
34    """
35    def __init__(self, variable, title, crs, dimValues, transparent, bgcolour, bbox, renderOpts):
36
37        self.title = title
38        self.crs = crs
39        self.dimValues = dimValues
40        self.renderOpts = renderOpts
41        self.bgcolour = bgcolour
42        self.transparent = transparent
43        self.bbox=bbox
44        self.variable = variable
45               
46        #log.debug("renderOpts = %s" % (renderOpts,))
47       
48        self.parser = SlabOptionsParser(self.renderingOptions, renderOpts)
49        self.ld = self._setupLayerDrawer()
50   
51    """
52    Creates the layer drawer object so that it can be used in getImage
53    """
54    def _setupLayerDrawer(self):
55        raise NotImplementedError()
56   
57    """
58    returns an image of the data constructed using the layer drawer
59   
60    @param bbox: the limits of the image requested
61    @param width: the width in px of the image
62    @param height: the height in px of the image
63    """
64    def getImage(self, bbox, width, height):
65        """
66        Create an image of a sub-bbox of a given size.
67
68        @ivar bbox: A bbox 4-tuple.
69        @ivar width: width in pixels.` 
70        @ivar height: height in pixels.
71        @return: A PIL Image object.
72
73        """
74        #log.debug("GetImage called with bbox=%s, width=%s, height = %s" % (bbox, width, height,))
75       
76        xLimits = (bbox[0], bbox[2])
77        yLimits = (bbox[1], bbox[3])
78       
79        if sorted(self.variable.getAxisIds()) == sorted(['latitude','longitude']):
80           
81            if not self._areBoundsInLimits(bbox, xLimits, yLimits):
82               
83                img = numpy.zeros((height,width,4), numpy.uint8)
84                pilImage = Image.fromarray(img, 'RGBA')
85               
86                log.debug("empty image used as no data found for id=%s (%sx%s), lon=%s, lat=%s " % \
87                  (self.variable.id, width, height, xLimits, yLimits))
88           
89                return pilImage
90                       
91        st = time.time()
92        im = self.ld.makeImage(xLimits, yLimits, width, height)
93       
94        log.debug("generated contour image id=%s (%sx%s, lon=%s, lat=%s in %.2fs" % \
95                  (self.variable.id, width, height, xLimits, yLimits,  time.time() - st,))
96       
97        return im
98
99    def _areBoundsInLimits(self, bbox, xLimits, yLimits):
100       
101        if self.variable.getAxisIds()[0] == 'longitude':
102            lonAx, latAx = self.variable.getAxisList()
103        else:
104            latAx, lonAx = self.variable.getAxisList()
105           
106        xRange = [ lonAx.getBounds().min(), lonAx.getBounds().max()]
107        yRange = [ latAx.getBounds().min(), latAx.getBounds().max()]
108        log.debug("xLimits = %s" % (xLimits,))
109        log.debug("yLimits = %s" % (yLimits,))
110        log.debug("xRange = %s" % (xRange,))
111        log.debug("yRange = %s" % (yRange,))
112       
113        xRange = self._fixLongitudeRange(xLimits, xRange)
114       
115        isInLimits = isRangeInLimits(xRange, xLimits) and \
116                     isRangeInLimits(yRange, yLimits)
117                             
118        log.debug("isInLimits = %s" % (isInLimits,))
119       
120        return isInLimits
121   
122    def _fixLongitudeRange(self, xLimits, xRange):
123        """
124        Attemts to match the upper and lower bounds of the longiude range
125        to that of the xLimits (either -180,180 or 0,360)
126        """
127       
128        returnRange = xRange
129       
130        range_180to0 = False
131        range180to360 = False 
132             
133        #assuming the xLimits are given in range -180 to 180
134        for i in [0,1]:
135            if -180.0 <= xLimits[i] < 0.0:
136                range_180to0 = True
137           
138            elif 180 < xLimits[i] <= 360:
139                range180to360 = True
140       
141#        log.debug("range180to360 = %s, range_180to0 = %s" % (range180to360, range_180to0,))
142        assert not (range_180to0 and range180to360), "confusing bounds found on longitude range %s " % (xLimits,)
143       
144        if range_180to0:
145            #if the xRange is 0-360 need to adjust it
146            for x in returnRange:
147               
148                if x > 180.0:
149                    returnRange = [x - 180 for x in returnRange]
150                    break
151                   
152        if range180to360:
153            #if the range is -180-0 need to adjust it
154            for x in returnRange:
155                if x < 0.0:
156                    returnRange =  [x + 180 for x in returnRange]
157                    break
158               
159#        log.debug("returnRange = %s" % (returnRange,))
160        return returnRange
161       
Note: See TracBrowser for help on using the repository browser.