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

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

Prepared file hierarchy for creating an egg "csml2kml"

RevLine 
[3304]1from cElementTree import ElementTree, Element, SubElement, XML
2from pylab import *
3from datetime import datetime, timedelta
4import re
5import csml
6import urllib
[3363]7from KML import *
[3312]8from QuadTree import *
[3304]9from utils import wget
[3362]10from Station import NPStation, WFSStationCollection
[3304]11
[3323]12class StationConvertor:
[3315]13    '''
[3323]14    Converter from GML+CSML to KML.
15    Contains functionality for converting GML containing a collection of Station elements into KML.
[3315]16    '''
[3304]17   
18    def __init__(self, config, kmlFilename):
[3362]19        '''Initialize the convertor and set it up according to the config file.'''
20       
[3304]21        self.config = config
22        self.kmlFilename = kmlFilename
23
[3362]24        # Read config document name
25        self.documentName = self.config.find('name').text
26
27        # URL of GeoServer to get a <wfs:StationCollection> from
[3434]28        self.geoServerUrl = self.config.find('GeoServerRequest/URL').text
[3362]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
[3434]48        self.grapherUrl = self.config.find('GrapherRequest/URL').text
49
[3362]50    def _npStationToKmlPlacemark(self, npStation):
[3363]51        '''Converts a Station.NPStation object into it's KML.KMLPlacemark representation'''
[3434]52        featuresHtml = ''
53        for featureId in npStation.csmlFeatureIds:
54            featuresHtml = featuresHtml + '<img src="' + self.grapherUrl + '?feature_id=' + featureId + '"><br>'
55        return KMLPlacemark(npStation.id, npStation.desc, npStation.lon, npStation.lat, featuresHtml,
[3362]56                            styleID = self.placemarkKmlStyle.id, data = self.stationData
57                            )
58
59    def _buildKmlDocumentDirectly(self, kmlDocument, npStations):
[3304]60        '''
[3362]61        Returns an object of the KMLDocument class, kmlDocument, which will contain each station
62        represented by a placemark directly contained in the document (i.e. no intermediate folders).
[3304]63        '''
[3362]64        for npStation in npStations:
65            kmlDocument.elements.append( self._npStationToKmlPlacemark(npStation) )
66        return kmlDocument
[3304]67
[3362]68    def _buildKmlDocumentUsingSections(self, kmlDocument, npStations):
69        '''
70        Returns an object of the KMLDocument class, kmlDocument, which contains the stations
71        organized into a hierarchy of folders, each containing ever smaller section of land.
72        The root of this hierarchy, a KMLFolder object, gets attached to the document,
73        and is "closed" i.e. it is not possible to open it in Google Earth's list view.
74        '''
[3306]75
[3362]76        def _quadTreeToKMLFolder(t):
[3315]77            '''
[3362]78            Convert the quad-tree into a KMLElement instance being a folder hierarchy with placemark leaves.
[3315]79            '''
[3362]80            if isinstance(t, NilLeaf):                      # Do nothing
81                pass
82            elif isinstance(t, LocLeaf):                    # Create a folder with an embedded region and placemarks
83                kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
84                kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
85                for location in t.locations:
86                    npStation = location.obj
87                    kmlPlacemark = self._npStationToKmlPlacemark(npStation)
88                    kmlFolder.children.append(kmlPlacemark)
89                return kmlFolder
90            elif isinstance(t, Node):                       # Create a folder containing nested elements
91                kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
92                kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
93                for i in t.children:
94                    kmlChild = _quadTreeToKMLFolder(i)
95                    if kmlChild:
96                        kmlFolder.children.append(kmlChild)
97                return kmlFolder
[3312]98
[3362]99        # Create a list of locations (that is, of QuadTree.Location objects), associated with the stations;
100        # each location will also hold the npStation object it refers to.
101        locations = []
102        for npStation in npStations:
103            locations.append( Location(npStation.lon, npStation.lat, npStation) )
[3312]104
[3362]105        # Build a quad-tree from the locations, and convert it into a KMLFolder object.
106        quadTree = build_quadtree(locations)
107        kmlFolder = _quadTreeToKMLFolder(quadTree)
[3312]108
[3362]109        # Add kmlFolder to the current document
110        kmlDocument.elements.append(kmlFolder)
[3312]111
[3362]112        # Make the folder follow the "locked folder" style
113        kmlDocument.styles.append(self.lockedFolderStyle)
114        kmlFolder.styleID = self.lockedFolderStyle.id
[3312]115
[3362]116        return kmlDocument
[3312]117
[3362]118    def convert(self):
119        '''
120        Convert GML input from GeoServer (containing the <Station> tags with station information)
121        to the KML representation.
122        [NOTE] At the moment, since the <Station> GML-feature element does not contain a list of CSML features,
123               the output of this code is not entirely correct. In particular, the HTTP reference to the grapher web-service
124               cannot be correctly determined.
125        '''
[3304]126
[3362]127        # Get a collection of stations from a GeoServer, and put the stations into a list
[3434]128        geoServerResponse = wget(self.geoServerUrl)
[3362]129        wfsStationsCollection = WFSStationCollection()
130        wfsStationsCollection.parseString(geoServerResponse)
131        npStations = wfsStationsCollection.stations
[3315]132
[3362]133        # Create a KML document and attach the stations, either directly or using KML regions
134        kmlDocument = KMLDocument(self.documentName, [self.placemarkKmlStyle])
135        if self.useSections:
136            kmlDocument = self._buildKmlDocumentUsingSections(kmlDocument, npStations)
[3312]137        else:
[3362]138            kmlDocument = self._buildKmlDocumentDirectly(kmlDocument, npStations)
[3304]139
140        # Save the KML document
141        kmlDocument.save(self.kmlFilename)
Note: See TracBrowser for help on using the repository browser.