source: TI02-CSML/trunk/csml/csmllibs/csmlextra.py @ 4048

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/csml/csmllibs/csmlextra.py@4048
Revision 4048, 11.8 KB checked in by domlowe, 12 years ago (diff)

Fixing bounding box code so that correct ISO representations are always used.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#Stuff with nowhere better to go
2import cdtime
3import csml.parser
4from csml.csmllibs.csmltime import UDtimeToCSMLtime
5import os
6import sys
7import random
8import string
9
10def getRandomID():
11    '''returns a random 8 character alphanumeric string that can be used as an internal identifier in a CSML document.
12    the ID only needs to be unique within the document that it occurs, so this is sufficiently random
13    to make a clash extremely unlikely. The string is alphanumeric but always begins with an upper case letter. 
14    Note: tested with 50000 ids and all were different'''
15    randomID=random.choice(string.letters)
16    randomID=string.upper(randomID)
17    for i in range(7):
18        randomID=randomID+random.choice(string.letters+string.digits)
19    return randomID
20
21def _locateByGmlId(elem, idtofind):
22    ''' look for child element with particular id'''
23    it=elem.getiterator()
24    for i in it:
25        if '{http://www.opengis.net/gml}id' in i.attrib:
26            if i.attrib['{http://www.opengis.net/gml}id'] == idtofind:
27                return i
28
29
30def _getEmptyCSMLobj(tag):
31    '''given an elementtree tag name, such as SpatialOrTemporalPositionList
32    return a parser object such as csml.parser.SpatialOrTemporalPosition()'''
33    csmlname=tag.split('}')[1]
34    return csml.parser.__dict__[csmlname]()       
35
36
37def getObjbyGMLID(elem,idtofind):
38    '''Given an element tree object and a gml:id return the fully parsed CSML object
39    that matches the id
40    useful for finding xlink matches'''
41    matchingelement= _locateByGmlId(elem, idtofind)
42    csmlobj=_getEmptyCSMLobj(matchingelement.tag)
43    csmlobj.fromXML(matchingelement)
44    return csmlobj
45
46def strToDate(ymd):
47    '''given a string in form '2006-01-01' returns a cdtime object'''
48    return cdtime.comptime(*map(int, ymd.split(' ')[0].split('-')))
49
50class EnvelopeAggregator(object):
51    def __init__(self,envelope):
52        '''start with aggregated envelope equal to the initialising envelope
53        envelope must be of type csml.parser.EnvelopeWithTimePeriod'''
54        self.minX=envelope.lowerCorner.CONTENT.split()[0]
55        self.minY=envelope.lowerCorner.CONTENT.split()[1]
56        self.maxX=envelope.upperCorner.CONTENT.split()[0]
57        self.maxY=envelope.upperCorner.CONTENT.split()[1]
58        self.t1= strToDate(envelope.beginPosition.CONTENT.split('T')[0])
59        self.t2= strToDate(envelope.endPosition.CONTENT.split('T')[0])
60 
61    def _compareLowerCorners(self,lowerCorner):
62        minX,minY=lowerCorner.CONTENT.split()[0],lowerCorner.CONTENT.split()[1]
63        if float(minX) < float(self.minX):
64            self.minX=minX
65        if float(minY) < float(self.minY):
66            self.minY=minY
67           
68    def _compareUpperCorners(self,upperCorner):
69        maxX,maxY=upperCorner.CONTENT.split()[0],upperCorner.CONTENT.split()[1]
70        if float(maxX) > float(self.maxX):
71            self.maxX=maxX
72        if float(maxY) > float(self.maxY):
73            self.maxY=maxY
74           
75    def _compareLowerTimes(self,timepos):
76        t=strToDate(timepos)
77        if t<self.t1:
78            self.t1=t
79       
80    def _compareUpperTimes(self,timepos):
81        t=strToDate(timepos)
82        if t>self.t2:
83            self.t2=t
84   
85    def compareEnvelope(self,envtocheck):
86        '''compares new envelope, and if necessary changes the aggregated envelope.'''
87        #if envtocheck.srsName!=self.envelope.srsName:
88            #print 'Skipping envelope with srs %s Can currently only perform aggregation within the same spatio-temporal reference system.'%envtocheck.srsName           
89        #else:
90        self._compareLowerCorners(envtocheck.lowerCorner)
91        self._compareUpperCorners(envtocheck.upperCorner)
92        self._compareLowerTimes(envtocheck.beginPosition.CONTENT.split('T')[0])
93        self._compareUpperTimes(envtocheck.endPosition.CONTENT.split('T')[0])
94   
95    def getAggregatedEnvelope(self):
96        ''' get aggregation of all envelopes in one aggregated envelope'''
97        newenvelope=csml.parser.EnvelopeWithTimePeriod()
98        newenvelope.beginPosition=csml.parser.csString(UDtimeToCSMLtime(self.t1)) #convert from datetime types to date only string
99        newenvelope.endPosition=csml.parser.csString(UDtimeToCSMLtime(self.t2)) 
100        newenvelope.lowerCorner=csml.parser.csString(str(self.minX +' '+ self.minY))
101        newenvelope.upperCorner=csml.parser.csString(str(self.maxX +' '+ self.maxY))
102        newenvelope.srsName='WGS84'
103        return newenvelope
104
105
106
107def getSeqRule(nDims):
108        '''returns a sequenceRule
109        *****************very simplified version*****************
110        This really needs more work to see if the +s and -s are correct. and the x/y/z s in right order
111        nDims = spatial dimensions + time dimension '''
112       
113        #TODO CSML2 - rewrite this
114        if nDims == 2:
115                seq = "Linear"
116        elif nDims ==3:
117                seq = "+x+y"
118        elif nDims ==4:
119                seq = "+x+y+z"
120        else:
121                seq="not sure"
122        return seq
123       
124       
125def getMappingRule(nDims):
126        #TODO CSML2 - rewrite this
127        if nDims == 2:
128                mr = "+ gridI + series"
129        elif nDims ==3:
130                mr = "+ gridI + gridJ +series"
131        elif nDims ==4:
132                mr = "+ gridI + gridJ +gridK +series"
133        else:
134                mr="not sure"
135        return mr
136       
137       
138def _getEnvelopeFromLimits(limits, axislabels):
139    env = csml.parser.EnvelopeWithTimePeriod()
140   
141    #simplistic reduction to remove time from CRS.
142    if limits['crs'][-1:] =='t':
143        env.srsName=limits['crs'][:-1]
144    else:
145        env.srsName=limits['crs']
146       
147    if env.srsName == 'ndg:crs:lonlat':
148        limits['crs'] ='WGS84'     
149        env.srsName = 'WGS84'     
150   
151    lowCorner= ''
152    upCorner=''
153    for axis in axislabels.split():
154        if axis != 'time':
155            try:
156                lowCorner = lowCorner + str(limits[axis][0]) + ' '
157                upCorner = upCorner + str(limits[axis][1]) + ' '
158            except:
159                pass
160        else:
161            env.beginPosition=csml.parser.csString(str(limits[axis][0]))
162            env.endPosition=csml.parser.csString(str(limits[axis][1]))
163#            env.beginPosition=csml.parser.csString(str(limits[axis][0].split()[0]))
164#            env.endPosition=csml.parser.csString(str(limits[axis][1].split()[0]))
165    env.lowerCorner  = csml.parser.csString(lowCorner)
166    env.upperCorner  = csml.parser.csString(upCorner)
167    return env
168
169def addBoundingBoxes(ds):
170    '''Adds envelope with timeperiod to each feature, currently only works on GridSeriesFeatures but extendable.'''
171    timename='time'
172    cat=csml.csmllibs.csmlcrs.CRSCatalogue()
173    xlinkresolver=csml.csmllibs.csmlxlink.XlinkResolver(ds)
174    for feature in ds.featureCollection.featureMembers:
175        limits={}
176        if type(feature) is csml.parser.GridSeriesFeature:   
177            crsName=feature.value.gridSeriesDomain.srsName
178            limits['crs']=crsName
179            crs=cat.getCRS(feature.value.gridSeriesDomain.srsName)
180            axislabels=feature.value.gridSeriesDomain.axisLabels
181         
182            #find the max and min bounds for all the axes of this feature:
183            for ord in feature.value.gridSeriesDomain.coordTransformTable.gridOrdinates:               
184                if ord.coordAxisLabel.CONTENT!=timename:
185                    #Deal with non-time axes:
186                    if hasattr(ord.coordAxisValues, 'href'):
187                        #deal with file extracts:
188                        if hasattr(ord.coordAxisValues, 'insertedExtract'):
189                            data=ord.coordAxisValues.insertedExtract.getData()[0].tolist()
190                        else:
191                            fileextract= xlinkresolver.resolveXlink(ord.coordAxisValues.href[1:])   
192                            data=fileextract.getData()[0].tolist()   
193                    else:
194                        #deal with inline content:
195                        data=ord.coordAxisValues.coordinateList.CONTENT.split()
196                    data.sort()
197                    minval,maxval=_getMaxMinBounds(ord.coordAxisLabel.CONTENT,data)
198                    limits[ord.coordAxisLabel.CONTENT]=[minval,maxval]
199                else:
200                    #Deal with time axis in similar way.       
201                    if hasattr(ord.coordAxisValues, 'href'):
202                        #fileextract #TODO
203                        if hasattr(ord.coordAxisValues, 'insertedExtract'):
204                            data=ord.coordAxisValues.insertedExtract.getData()[0].tolist()                         
205                        else:
206                            sptlist= xlinkresolver.resolveXlink(ord.coordAxisValues.href[1:])
207                            data=sptlist.timePositionList.CONTENT.split()
208                            tmin=str(data[0])
209                            tmax=str(data[len(data)-1]) 
210                    else:
211                        #inline content
212                        tmin= str(ord.coordAxisValues.timePositionList.CONTENT.split()[0])
213                        tmax=str(ord.coordAxisValues.timePositionList.CONTENT.split()[len(ord.coordAxisValues.timePositionList.CONTENT.split())-1])                       
214                    limits[timename]=[tmin,tmax]
215        feature.boundedBy=_getEnvelopeFromLimits(limits, axislabels)
216    return ds.featureCollection
217
218def _getMaxMinBounds(axisname,data):
219    if len(data) > 1:                   
220        halfcell=abs(0.5*(abs(data[1])-abs(data[0])))
221    else:
222        halfcell=0
223    minval=data[0] - halfcell
224    maxval=data[len(data)-1] + halfcell                   
225    if axisname=='longitude':
226        #deal with the case where the grid point is 0, so the grid goes from -x to +x e.g. -0.5 to 359.5
227        if minval < 0:
228            if maxval - minval > 359.0:
229                minval=0.0
230                maxval=360.0
231    if axisname=='latitude':
232        #deal with latitudes
233        if minval < -90:
234            minval=-90.0
235        if maxval > 90:
236            maxval=90.0
237    return minval,maxval
238
239def addEnvelope(fc):
240    '''adds EnvelopeWithTimePeriod to feature collection, based on the spatial extent of the features within.   '''
241    aggregator=None
242    for feature in fc.featureMembers:
243        env=feature.boundedBy
244        if aggregator is None:
245            aggregator=EnvelopeAggregator(env)
246        else:
247            aggregator.compareEnvelope(env)
248    fcEnvelope=aggregator.getAggregatedEnvelope()
249    fc.boundedBy=fcEnvelope
250    return fc
251       
252               
253       
254# a couple of string cleaning functions:
255#   don't think these are used now
256def cleanString1(messystring):
257        #removes outer brackets and changes commas to spaces
258        cleanstring = messystring[1:-1]
259        cleanstring = cleanstring.replace(',',' ')
260        #strip off first (time) dimension.
261        #note, this might need rethinking for other datasets
262        cleanstring = cleanstring[3:]
263        return cleanstring
264#       
265def cleanString(messystring):
266   # removes outer brackets and 's, but leaves commas.
267    cleanstring = messystring[1:-1]
268    cleanstring = cleanstring.replace("'",'')
269    #remove any carriage returns
270    cleanstring = cleanstring.replace("\n",'')
271    return cleanstring
272       
273def listify(item):
274    ''' listify checks if an item is a list, if it isn't it puts it inside a list and returns it. Always returns a list object'''
275    if type(item) is list:
276        return item
277    else:
278        return [item]       
279
280def stringify(inputlist):
281    '''stringify takes a list and returns a string containing the contents of the list separated by spaces'''
282    strreturn=''
283    for item in inputlist:
284        strreturn=strreturn + item +' '
285    return strreturn[:-1]
286
287def checkDirExists(dirpath):
288    if os.path.isdir(dirpath) != True:
289        try:
290            os.mkdir(dirpath)
291        except:
292            pass
293             
294
295
296def main():
297    #test to check randomness of getRandomID()
298    idlist=[]
299    for j in range (500):
300        for i in range(100):
301            newid= getRandomID()
302            if newid in idlist:
303                print 'ID matched!!!'               
304                sys.exit()
305            else:               
306                idlist.append(newid)
307        print i * j
308    print 'done'
309   
310if __name__=="__main__":
311    main()
Note: See TracBrowser for help on using the repository browser.