source: DPPP/kml/csml2kml/python/csml2kml/StationConvertor.py @ 3323

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/DPPP/kml/csml2kml/python/csml2kml/StationConvertor.py@3323
Revision 3323, 6.9 KB checked in by mkochan, 12 years ago (diff)

Changed PointSeriesConvertor? into StationConvertor?

Line 
1from cElementTree import ElementTree, Element, SubElement, XML
2from pylab import *
3from datetime import datetime, timedelta
4import re
5import csml
6import urllib
7from KMLDocument import *
8from QuadTree import *
9from utils import wget
10
11class Station:
12    '''Represents a ground meteorological station, identified by id, with description, desc, at (lon,lat) '''
13    def __init__(self, id, desc, lon, lat):
14        self.id = id
15        self.desc = desc
16        self.lon = lon; self.lat = lat
17
18    def __repr__(self):
19        return 'Station %s ("%s")' % (self.id, self.desc)
20
21class StationConvertor:
22    '''
23    Converter from GML+CSML to KML.
24    Contains functionality for converting GML containing a collection of Station elements into KML.
25    '''
26   
27    def __init__(self, config, kmlFilename):
28        self.config = config
29        self.kmlFilename = kmlFilename
30
31    def convert(self):
32        '''
33        Convert GML input from GeoServer (containing the <Station> tags with station information)
34        to the KML representation.
35        [NOTE] At the moment, since the <Station> GML-feature element does not contain a list of CSML features,
36               the output of this code is not entirely correct. In particular, the HTTP reference to the grapher web-service
37               cannot be correctly determined.
38        '''
39
40        def _parseGMLStationsCollection(textGml):
41            '''
42            Parse the GML returned from GeoServer and yield Station objects with info about each station.
43            '''
44            root = XML(textGml)
45            featureCollectionElement = root
46            for featureMember in featureCollectionElement.getchildren():
47                stationElement = featureMember.getchildren()[0]
48                (stationNameElement, stationIDElement, locationElement) = stationElement.getchildren()
49                pointElement = locationElement.getchildren()[0]
50                posElement = pointElement.getchildren()[0]
51                (lon,lat) = map(float, posElement.text.split())
52                yield Station(stationElement.get('{http://www.opengis.net/gml}id'), stationNameElement.text, lon, lat)
53
54        def _buildKmlDocumentDirectly(kmlDocument, stations, placemarkKmlStyle, stationData):
55            '''
56            Returns an object of the KMLDocument class, kmlDocument, which will contain each station
57            represented by a placemark directly contained in the document (i.e. no intermediate folders).
58            '''
59            for station in stations:
60                kmlStation = KMLPlacemark(station.id, station.desc, station.lon, station.lat,
61                                          styleID = placemarkKmlStyle.id, data = stationData
62                                          )
63                kmlDocument.elements.append(kmlStation)
64            return kmlDocument
65
66        def _buildKmlDocumentUsingSections(kmlDocument, stations, placemarkKmlStyle, stationData):
67            '''
68            Returns an object of the KMLDocument class, kmlDocument, which contains the stations
69            organized into a hierarchy of folders, each containing ever smaller section of land.
70            The root of this hierarchy, a KMLFolder object, gets attached to the document,
71            and is "closed" i.e. it is not possible to open it in Google Earth's list view.
72            '''
73
74            def _quadTreeToKMLFolder(t):
75                '''
76                Convert the quad-tree into a KMLElement instance being a folder hierarchy with placemark leaves.
77                '''
78                if isinstance(t, NilLeaf):                      # Do nothing
79                    pass
80                elif isinstance(t, LocLeaf):                    # Create a folder with an embedded region and placemarks
81                    kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
82                    kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
83                    for location in t.locations:
84                        station = location.obj
85                        kmlPlacemark = KMLPlacemark(
86                            station.desc, station.desc, station.lon, station.lat,
87                            styleID = placemarkKmlStyle.id, data = stationData
88                            )
89                        kmlFolder.children.append(kmlPlacemark)
90                    return kmlFolder
91                elif isinstance(t, Node):                       # Create a folder containing nested elements
92                    kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
93                    kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
94                    for i in t.children:
95                        kmlChild = _quadTreeToKMLFolder(i)
96                        if kmlChild:
97                            kmlFolder.children.append(kmlChild)
98                    return kmlFolder
99           
100            locations = []
101            for station in stations:
102                locations.append( Location(station.lon, station.lat, station) )
103            quadTree = build_quadtree(locations)
104            kmlFolder = _quadTreeToKMLFolder(quadTree)
105
106            lockedFolderStyle = KMLStyle('locked_folder_style', listItemType = 'checkHideChildren')
107            kmlFolder.styleID = lockedFolderStyle.id
108            kmlDocument.styles.append(lockedFolderStyle)
109
110            kmlDocument.elements.append(kmlFolder)
111            return kmlDocument
112
113        #-----------------------------------------------------------------------------
114
115        # Read conversion configuration
116        documentName = self.config.find('name').text
117        url = self.config.find('GeoServerRequest/URL').text
118        balloonTemplate = self.config.find('GeoServerRequest/BalloonTemplate').text
119        stationData = {}
120        data = self.config.findall('GeoServerRequest/StationData/Datum')
121        for datum in data:
122            datumName = datum.get('name')
123            datumValue = datum.text
124            stationData[datumName] = datumValue
125        useSections = self.config.find('UseRegions').text == 'yes'
126
127        # Read in GML containing the stations, and extract them into a list of Station objects
128        textGml = wget(url)
129        stations = _parseGMLStationsCollection(textGml)
130
131        # Create a KML style for each station/placemark -- can contain appropriate HTML balloon template
132        placemarkKmlStyle = createDefaultPlacemarKMLStyle(balloonTemplate = balloonTemplate)
133
134        # Create a KML document and attach the stations either directly to it, or using a folder hierarchy
135        # of KML sections (derived by means of quad-tree)
136        kmlDocument = KMLDocument(documentName, [placemarkKmlStyle])
137        if useSections:
138            kmlDocument = _buildKmlDocumentUsingSections(kmlDocument, stations, placemarkKmlStyle, stationData)
139        else:
140            kmlDocument = _buildKmlDocumentDirectly(kmlDocument, stations, placemarkKmlStyle, stationData)
141
142        # Save the KML document
143        kmlDocument.save(self.kmlFilename)
Note: See TracBrowser for help on using the repository browser.