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

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

Added Epydoc fields to comments.

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