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

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

Created the script stations2kml.py runnable from command line.

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