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

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

Extended documentation of Station and StationConvertor?.

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    Contains functionality for converting a collection of <np:Station>'s into a KML or a KMZ file.
15    '''
16   
17    def __init__(self, config):
18        '''
19        Initialize the convertor and set it up according to the configuration.
20        @param config: An element containing contents of a <NPStations2KML> element from a XML config file.
21        @type config: C{cElementTree.Element}
22        '''
23       
24        self.config = config
25
26        # Read the KMZ file name
27        self.kmlFilename = self.config.find('OutputKmzFilename').text
28
29        # Read the document name
30        self.documentName = self.config.find('DocumentName').text
31
32        # URL of GeoServer to get a <wfs:StationCollection> from
33        self.geoServerRequestUrl = self.config.find('GetAllStationsRequestURL').text
34
35        # Get template for placemark balloons; create a KML style for placemarks
36        self.balloonTemplate = self.config.find('BalloonTemplate').text
37        self.placemarkKmlStyle = createDefaultPlacemarKMLStyle(balloonTemplate = self.balloonTemplate)
38
39        # Initialize placemark data -- i.e. values to be substituted for placeholders in the balloon template
40        self.stationData = {}
41        data = self.config.findall('StationData/Datum')
42        for datum in data:
43            datumName = datum.get('name')
44            datumValue = datum.text
45            self.stationData[datumName] = datumValue
46
47        # Should we use KML regions? (recommended for high number of stations)
48        self.useSections = self.config.find('UseRegions').text == 'yes'
49
50        # Create a KML style to be used for holding a KML folder hierarchy in a folder that can't open
51        self.lockedFolderStyle = KMLStyle('locked_folder_style', listItemType = 'checkHideChildren')
52
53    def _npStationToKmlPlacemark(self, npStation):
54        '''Converts a C{Station.NPStation} object into it's C{KML.KMLPlacemark} representation'''
55        return KMLPlacemark(npStation.id, npStation.desc, npStation.lon, npStation.lat,
56                            styleID = self.placemarkKmlStyle.id, data = self.stationData
57                            )
58
59    def _buildKmlDocumentDirectly(self, kmlDocument, npStations):
60        '''
61        Returns a C{KMLDocument} object with stations represented by KML placemarks directly contained
62        in the document (i.e. without any intermediate folders).
63        @param kmlDocument: A document to which the folder hierarchy should be attached.
64        @type kmlDocument: C{KML.KMLDocument}
65        @param npStations: A list of stations to be contained in the hierarchy.
66        @type npStations: List of C{Station.NPStation} objects.
67        @return: A C{KML.KMLDocument} object.
68        '''
69        for npStation in npStations:
70            kmlDocument.elements.append( self._npStationToKmlPlacemark(npStation) )
71        return kmlDocument
72
73    def _buildKmlDocumentUsingSections(self, kmlDocument, npStations):
74        '''
75        Returns a C{KMLDocument} object containing stations as KML placemarks wrapped in a hierarchy
76        of C{KMLFolder}'s with associated C{KMLRegion}'s. The regions are recursively decreasing in size.
77        @param kmlDocument: A document to which the folder hierarchy should be attached.
78        @type kmlDocument: C{KML.KMLDocument}
79        @param npStations: A list of stations to be contained in the hierarchy.
80        @type npStations: List of C{Station.NPStation} objects.
81        @return: A C{KML.KMLDocument} object.
82        '''
83
84        def _quadTreeToKMLFolder(t):
85            '''
86            Convert the quad-tree into a KMLElement instance being a folder hierarchy with placemark leaves.
87            '''
88            if isinstance(t, NilLeaf):                      # Do nothing
89                pass
90            elif isinstance(t, LocLeaf):                    # Create a folder with an embedded region and placemarks
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 location in t.locations:
94                    npStation = location.obj
95                    kmlPlacemark = self._npStationToKmlPlacemark(npStation)
96                    kmlFolder.children.append(kmlPlacemark)
97                return kmlFolder
98            elif isinstance(t, Node):                       # Create a folder containing nested elements
99                kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north)
100                kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion)
101                for i in t.children:
102                    kmlChild = _quadTreeToKMLFolder(i)
103                    if kmlChild:
104                        kmlFolder.children.append(kmlChild)
105                return kmlFolder
106
107        # Create a list of locations (that is, of QuadTree.Location objects), associated with the stations;
108        # each location will also hold the npStation object it refers to.
109        locations = []
110        for npStation in npStations:
111            locations.append( Location(npStation.lon, npStation.lat, npStation) )
112
113        # Build a quad-tree from the locations, and convert it into a KMLFolder object.
114        quadTree = build_quadtree(locations)
115        kmlFolder = _quadTreeToKMLFolder(quadTree)
116
117        # Add kmlFolder to the current document
118        kmlDocument.elements.append(kmlFolder)
119
120        # Make the folder follow the "locked folder" style
121        kmlDocument.styles.append(self.lockedFolderStyle)
122        kmlFolder.styleID = self.lockedFolderStyle.id
123
124        return kmlDocument
125
126    def convert(self):
127        '''
128        Perform the conversion.
129        This will produce a KML or KMZ file, depending on the suffix of the output file as defined in the config file.
130
131        The stations will be organised depending on the C{UseRegions} setting in the config file:
132          - if C{UseRegions} is set to C{no},
133            stations will be included simply as a list of KML placemarks.
134          - if C{UseRegions} is set to C{yes},
135            stations will be divided into a hierarchy of KML regions, by recursively splitting
136            the the covered are into 4 smaller regions, starting with the whole globe.
137            The actual station KML placemarks will be placed at the bottom of the hierarchy.
138            Therefore, they will be visible only for closer zooms onto the ground.
139        '''
140
141        # Get a collection of stations from a GeoServer, and put the stations into a list
142        geoServerResponse = wget(self.geoServerRequestUrl)
143        wfsStationsCollection = WFSStationCollection()
144        wfsStationsCollection.parseString(geoServerResponse)
145        npStations = wfsStationsCollection.stations
146
147        # Create a KML document and attach the stations, either directly or using KML regions
148        kmlDocument = KMLDocument(self.documentName, [self.placemarkKmlStyle])
149        if self.useSections:
150            kmlDocument = self._buildKmlDocumentUsingSections(kmlDocument, npStations)
151        else:
152            kmlDocument = self._buildKmlDocumentDirectly(kmlDocument, npStations)
153
154        # Save the KML document
155        kmlDocument.save(self.kmlFilename)
Note: See TracBrowser for help on using the repository browser.