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

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

Updated csmlGrapher and StationConvertor? to allow dynamic display of a list of CSML features per station, and per-feature graphing.

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, 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.geoServerUrl = 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 KML.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        '''
118
119        # Get a collection of stations from a GeoServer, and put the stations into a list
120        geoServerResponse = wget(self.geoServerUrl)
121        wfsStationsCollection = WFSStationCollection()
122        wfsStationsCollection.parseString(geoServerResponse)
123        npStations = wfsStationsCollection.stations
124
125        # Create a KML document and attach the stations, either directly or using KML regions
126        kmlDocument = KMLDocument(self.documentName, [self.placemarkKmlStyle])
127        if self.useSections:
128            kmlDocument = self._buildKmlDocumentUsingSections(kmlDocument, npStations)
129        else:
130            kmlDocument = self._buildKmlDocumentDirectly(kmlDocument, npStations)
131
132        # Save the KML document
133        kmlDocument.save(self.kmlFilename)
Note: See TracBrowser for help on using the repository browser.