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

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

Made changes to MIDAS stations output.

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