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

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

'testing organise imports'

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