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

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

Made StationConvertor? class use the Station.py module.

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
10from Station import NPStation, WFSStationCollection
11
12class StationConvertor:
13    '''
14    Converter from GML+CSML to KML.
15    Contains functionality for converting GML containing a collection of Station elements into KML.
16    '''
17   
18    def __init__(self, config, kmlFilename):
19        '''Initialize the convertor and set it up according to the config file.'''
20       
21        self.config = config
22        self.kmlFilename = kmlFilename
23
24        # Read config document name
25        self.documentName = self.config.find('name').text
26
27        # URL of GeoServer to get a <wfs:StationCollection> from
28        self.url = self.config.find('GeoServerRequest/URL').text
29
30        # Get template for placemark balloons; create a KML style for placemarks
31        self.balloonTemplate = self.config.find('GeoServerRequest/BalloonTemplate').text
32        self.placemarkKmlStyle = createDefaultPlacemarKMLStyle(balloonTemplate = self.balloonTemplate)
33
34        # Initialize placemark data -- i.e. values to be substituted for placeholders in the balloon template
35        self.stationData = {}
36        data = self.config.findall('GeoServerRequest/StationData/Datum')
37        for datum in data:
38            datumName = datum.get('name')
39            datumValue = datum.text
40            self.stationData[datumName] = datumValue
41
42        # Should we use KML regions? (recommended for high number of stations)
43        self.useSections = self.config.find('UseRegions').text == 'yes'
44
45        # Create a KML style to be used for holding a KML folder hierarchy in a folder that can't open
46        self.lockedFolderStyle = KMLStyle('locked_folder_style', listItemType = 'checkHideChildren')
47
48    def _npStationToKmlPlacemark(self, npStation):
49        '''Converts a Station.NPStation object into it's KMLDocument.KMLPlacemark representation'''
50        return KMLPlacemark(npStation.id, npStation.desc, npStation.lon, npStation.lat,
51                            styleID = self.placemarkKmlStyle.id, data = self.stationData
52                            )
53
54    def _buildKmlDocumentDirectly(self, kmlDocument, npStations):
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 npStation in npStations:
60            kmlDocument.elements.append( self._npStationToKmlPlacemark(npStation) )
61        return kmlDocument
62
63    def _buildKmlDocumentUsingSections(self, kmlDocument, npStations):
64        '''
65        Returns an object of the KMLDocument class, kmlDocument, which contains the stations
66        organized into a hierarchy of folders, each containing ever smaller section of land.
67        The root of this hierarchy, a KMLFolder object, gets attached to the document,
68        and is "closed" i.e. it is not possible to open it in Google Earth's list view.
69        '''
70
71        def _quadTreeToKMLFolder(t):
72            '''
73            Convert the quad-tree into a KMLElement instance being a folder hierarchy with placemark leaves.
74            '''
75            if isinstance(t, NilLeaf):                      # Do nothing
76                pass
77            elif isinstance(t, LocLeaf):                    # Create a folder with an embedded region and placemarks
78                kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
79                kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
80                for location in t.locations:
81                    npStation = location.obj
82                    kmlPlacemark = self._npStationToKmlPlacemark(npStation)
83                    kmlFolder.children.append(kmlPlacemark)
84                return kmlFolder
85            elif isinstance(t, Node):                       # Create a folder containing nested elements
86                kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
87                kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
88                for i in t.children:
89                    kmlChild = _quadTreeToKMLFolder(i)
90                    if kmlChild:
91                        kmlFolder.children.append(kmlChild)
92                return kmlFolder
93
94        # Create a list of locations (that is, of QuadTree.Location objects), associated with the stations;
95        # each location will also hold the npStation object it refers to.
96        locations = []
97        for npStation in npStations:
98            locations.append( Location(npStation.lon, npStation.lat, npStation) )
99
100        # Build a quad-tree from the locations, and convert it into a KMLFolder object.
101        quadTree = build_quadtree(locations)
102        kmlFolder = _quadTreeToKMLFolder(quadTree)
103
104        # Add kmlFolder to the current document
105        kmlDocument.elements.append(kmlFolder)
106
107        # Make the folder follow the "locked folder" style
108        kmlDocument.styles.append(self.lockedFolderStyle)
109        kmlFolder.styleID = self.lockedFolderStyle.id
110
111        return kmlDocument
112
113    def convert(self):
114        '''
115        Convert GML input from GeoServer (containing the <Station> tags with station information)
116        to the KML representation.
117        [NOTE] At the moment, since the <Station> GML-feature element does not contain a list of CSML features,
118               the output of this code is not entirely correct. In particular, the HTTP reference to the grapher web-service
119               cannot be correctly determined.
120        '''
121
122        # Get a collection of stations from a GeoServer, and put the stations into a list
123        geoServerResponse = wget(self.url)
124        wfsStationsCollection = WFSStationCollection()
125        wfsStationsCollection.parseString(geoServerResponse)
126        npStations = wfsStationsCollection.stations
127
128        # Create a KML document and attach the stations, either directly or using KML regions
129        kmlDocument = KMLDocument(self.documentName, [self.placemarkKmlStyle])
130        if self.useSections:
131            kmlDocument = self._buildKmlDocumentUsingSections(kmlDocument, npStations)
132        else:
133            kmlDocument = self._buildKmlDocumentDirectly(kmlDocument, npStations)
134
135        # Save the KML document
136        kmlDocument.save(self.kmlFilename)
Note: See TracBrowser for help on using the repository browser.