Changeset 3291 for DPPP/kml


Ignore:
Timestamp:
01/02/08 15:24:40 (12 years ago)
Author:
mkochan
Message:

Made other prototypes use KMLDocument-encapsulated functionality. Tested using these prototypes.

Location:
DPPP/kml/csml2kml/python
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • DPPP/kml/csml2kml/python/notes.txt

    r3290 r3291  
     1[x] long term task 
    12[.] minor issue 
    23[o] important but can wait 
     
    56---------------------------------------------------------------------------------------------------------------------------- 
    67 
     8[O] Add comments: KMLDocument.py 
    79[o] Resolve outstanding issues in pylons controllers 
    810[O] Make quadrize_stations.py work with the KMLDocument module -- by wrapping the functionality for creating 
     
    1012    * test the new KMLDocument classes 
    1113    * make quadrize_stations.py use KMLDocument for all KML generation 
    12      
     14[.] Consider issues with visibility and open tags for elements -- how should they be set? 
     15[x] Possibility of clicking on a globe and getting info for a certain feature (i.e. the value profile for that 
     16    location) -- Dominic said there is a function in the CSML API which allows doing that -- investigate 
     17[x] Superimposing PointSeries locations onto WMS-generated grid 
     18 
  • DPPP/kml/csml2kml/python/prototypes/KMLDocument.py

    r3290 r3291  
    33class KMLDocument: 
    44 
    5     def __init__(self, name, basicKMLStyle = None): 
     5    def __init__(self, name, styles): 
    66 
    77        self.name = name 
    8  
    9         self.documentElement = Element('Document') 
    10         SubElement(self.documentElement, 'name').text = name 
    11         SubElement(self.documentElement, 'open').text = '0' 
    12  
    13         if basicKMLStyle: 
    14             self.styles = [basicKMLStyle] 
    15         else: 
    16             self.styles = [] 
    17         for style in self.styles: 
    18             self.documentElement.append(style.build()) 
    19  
    20     def appendElement(self, element): 
    21         '''Append directly to the <Document> element''' 
    22         self.documentElement.append(element) 
     8        self.styles = styles 
     9        self.elements = [] 
    2310 
    2411    def save(self, outputFilename): 
     
    4027                    elem.tail = i 
    4128 
     29        # Create an element to hold the document 
     30        self.documentElement = Element('Document') 
     31        SubElement(self.documentElement, 'name').text = self.name 
     32        SubElement(self.documentElement, 'open').text = '0' 
     33 
     34        # Build the associated styles 
     35        for style in self.styles: 
     36            self.documentElement.append( style.build() ) 
     37 
     38        # Build the sub-elements 
     39        for element in self.elements: 
     40            self.documentElement.append( element.build() ) 
     41 
    4242        # Attach the Document element as a subelement of a root 'kml' element 
    43         kmlElement=Element('kml', xmlns='http://earth.google.com/kml/2.2') 
    44         kmlElement.append(self.documentElement) 
    45         _indentXML(kmlElement) 
     43        rootElement=Element('kml', xmlns='http://earth.google.com/kml/2.2') 
     44        rootElement.append(self.documentElement) 
     45        _indentXML(rootElement) 
    4646 
    4747        # Write the KML document to a file 
    48         t = ElementTree(kmlElement)        
    49         f = open(outputFilename, 'w') 
    50         t.write(f) 
    51         f.close() 
     48        elementTree = ElementTree(rootElement)        
     49        kmlFile = open(outputFilename, 'w') 
     50        elementTree.write(kmlFile) 
     51        kmlFile.close() 
    5252 
    5353# Abstract class 
     
    5858class KMLStyle(KMLElement): 
    5959 
    60     def __init__(self, id, iconURL, balloonTemplate): 
     60    def __init__(self, id, iconURL = None, balloonTemplate = None, listItemType = None): 
    6161        self.id = id 
    6262        self.iconURL = iconURL 
    6363        self.balloonTemplate = balloonTemplate 
     64        if listItemType: 
     65            allowedValues =  ['check', 'checkOffOnly', 'checkHideChildren', 'radioFolder'] 
     66            if not listItemType in allowedValues: 
     67                raise ValueError('listItemType not among allowed values: ' + str(allowedValues)) 
     68        self.listItemType = listItemType 
    6469 
    6570    def build(self): 
     
    6873        styleElement.set('id', self.id) 
    6974 
    70         # Build the IconStyle element (for assigning an icon to station placemarks) 
    71         iconStyleElement = SubElement(styleElement, 'IconStyle') 
    72         SubElement(iconStyleElement, 'scale').text = '1.2' 
    73         iconElement = SubElement(iconStyleElement, 'Icon') 
    74         SubElement(iconElement, 'href').text = self.iconURL 
     75        # If specified, build the IconStyle element -- for assigning an icon to station placemarks 
     76        if self.iconURL: 
     77            iconStyleElement = SubElement(styleElement, 'IconStyle') 
     78            SubElement(iconStyleElement, 'scale').text = '1.2' 
     79            iconElement = SubElement(iconStyleElement, 'Icon') 
     80            SubElement(iconElement, 'href').text = self.iconURL 
    7581 
    76         # Build the BalloonStyle element -- an HTML template for the balloons 
    77         ballonStyleElement = SubElement(styleElement, 'BalloonStyle') 
    78         SubElement(ballonStyleElement, 'text').text = self.balloonTemplate 
     82        # If specified, build the BalloonStyle sub-element -- an HTML template for the balloons 
     83        if self.balloonTemplate: 
     84            balloonStyleElement = SubElement(styleElement, 'BalloonStyle') 
     85            SubElement(balloonStyleElement, 'text').text = self.balloonTemplate 
    7986 
     87        # If specified, build the ListStyle sub-element -- which determines how the associated lists 
     88        # in the left-hand side of the Google Earth screen are going to display/behave 
     89        if self.listItemType: 
     90            listStyleElement = SubElement(styleElement, 'ListStyle') 
     91            SubElement(listStyleElement, 'listItemType').text = self.listItemType 
     92         
    8093        return styleElement 
    8194 
    82 def getBasicKMLStyle(basicBalloonTemplate = ''): 
    83     basicIcon = 'http://maps.google.com/mapfiles/kml/shapes/target.png' 
    84     return KMLStyle('basic_style', basicIcon, basicBalloonTemplate) 
     95# Defined for convenience 
     96def createDefaultPlacemarKMLStyle(id = 'default_placemark_style', 
     97                                  iconURL = 'http://maps.google.com/mapfiles/kml/shapes/target.png', 
     98                                  balloonTemplate = ''): 
     99    return KMLStyle(id, iconURL, balloonTemplate) 
    85100 
    86101class KMLPlacemark(KMLElement): 
    87102     
    88     def __init__(self, id, name, lon, lat, style='basic_style', data=None): 
     103    def __init__(self, id, name, lon, lat, styleID = None, data=None): 
    89104        self.id = id 
    90105        self.name = name 
    91106        self.lon = lon 
    92107        self.lat = lat 
    93         self.style = style 
     108        self.styleID = styleID 
    94109        self.data = data 
    95110 
     
    98113        SubElement(placemarkElement, 'name').text = self.name 
    99114        SubElement(placemarkElement, 'open').text = '0' 
    100         SubElement(placemarkElement, 'visibility').text = '0' 
    101         SubElement(placemarkElement, 'styleUrl').text = '#' + self.style 
     115        if self.styleID: 
     116            SubElement(placemarkElement, 'styleUrl').text = '#' + self.styleID 
    102117 
    103118        lookAtElement = SubElement(placemarkElement, 'LookAt') 
     
    127142class KMLFolder(KMLElement): 
    128143 
    129     def __init__(self, name, children): 
     144    def __init__(self, name, children, styleID = None, region = None): 
    130145        self.name = name 
    131146        self.children = children 
    132          
     147        self.styleID = styleID 
     148        self.region = region 
     149 
    133150    def build(self): 
    134151        folderElement = Element('Folder') 
    135         SubElement(folderElement, 'name').text = name 
    136         for child in children: 
     152        if self.styleID: 
     153            SubElement(folderElement, 'styleUrl').text = '#' + self.styleID 
     154        SubElement(folderElement, 'name').text = self.name 
     155        if self.region: 
     156            if not isinstance(self.region, KMLRegion): 
     157                raise TypeError('Region not a KMLRegion') 
     158            folderElement.append( self.region.build() ) 
     159        for child in self.children: 
    137160            if not isinstance(child, KMLElement): 
    138                 raise TypeError('KMLFolder child does not have a KMLElement base class') 
     161                raise TypeError('Child does not have a KMLElement base class') 
    139162            folderElement.append( child.build() ) 
    140163        return folderElement 
     
    147170        self.east = east 
    148171        self.north = north 
    149         self.minLodPixels = minLodPixel 
    150         self.maxLodPixels = maxLodPixel 
     172        self.minLodPixels = minLodPixels 
     173        self.maxLodPixels = maxLodPixels 
    151174 
    152175    def build(self): 
    153176 
    154177        llabElement = Element('LatLonAltBox') 
    155         SubElement(llabElement, 'west').text = self.west 
    156         SubElement(llabElement, 'south').text = self.south 
    157         SubElement(llabElement, 'east').text = self.east 
    158         SubElement(llabElement, 'north').text = self.north 
     178        SubElement(llabElement, 'west').text = str(self.west) 
     179        SubElement(llabElement, 'south').text = str(self.south) 
     180        SubElement(llabElement, 'east').text = str(self.east) 
     181        SubElement(llabElement, 'north').text = str(self.north) 
    159182 
    160183        lodElement = Element('Lod') 
    161         SubElement(lodElement, 'minLodPixels').text = self.minLodPixels 
    162         SubElement(lodElement, 'maxLodPixels').text = self.maxLodPixels 
     184        SubElement(lodElement, 'minLodPixels').text = str(self.minLodPixels) 
     185        SubElement(lodElement, 'maxLodPixels').text = str(self.maxLodPixels) 
    163186 
    164187        regionElement = Element('Region') 
  • DPPP/kml/csml2kml/python/prototypes/buildPointSeriesWithReferencedPlotsUsingGeoServerOO.py

    r3289 r3291  
    66import urllib 
    77 
    8 from KMLDocument import KMLDocument, KMLStyle, KMLPlacemark, getBasicKMLStyle 
     8from KMLDocument import * 
    99 
    1010# -------------------------------------------------------------------------------------------------------------------------- 
     
    2727def parseGMLStationsCollection(textGml): 
    2828    ''' 
    29     A generator method. Parse the GML returned from GeoServer and yield tuples containing information 
    30     (gml_id, name, lon, lat) about each station. 
     29    Parse the GML returned from GeoServer and yield tuples containing information (gml_id, name, lon, lat) 
     30    about each station. 
    3131    ''' 
    3232    root = XML(textGml) 
     
    4141 
    4242# -------------------------------------------------------------------------------------------------------------------------- 
     43# 
     44# [NOTE] At the moment, since the <Station> GML-feature element does not contain a list of CSML features, 
     45#        the output of this code is not entirely correct. In particular, the HTTP reference to the grapher web-service 
     46#        cannot be correctly determined. 
    4347 
    4448url = 'http://bond.badc.rl.ac.uk:8089/dummyGeoServer/GetStationCSMLFeatures?gml_id=MIDAS_Stations' 
     
    4953eachStationData = {'feature_id': '#ID#'} 
    5054 
    51 basicKmlStyle = getBasicKMLStyle(balloonTemplate) 
    52 kmlDocument = KMLDocument('MIDAS stations (example)', basicKmlStyle) 
     55placemarkKmlStyle = createDefaultPlacemarKMLStyle(balloonTemplate = balloonTemplate) 
     56kmlDocument = KMLDocument('MIDAS stations (example)', [placemarkKmlStyle]) 
    5357 
    5458generator =  parseGMLStationsCollection(textGml) 
    5559for (gml_id, name, lon, lat) in generator: 
    5660    print 'Station %s ("%s"): @ (%f,%f)' %  (gml_id, name, lon, lat) 
    57     kmlStation = KMLPlacemark(gml_id, name, lon, lat, data=eachStationData) 
    58     kmlDocument.appendElement(kmlStation.build()) 
     61    kmlStation = KMLPlacemark(gml_id, name, lon, lat, styleID = placemarkKmlStyle.id, data = eachStationData) 
     62    kmlDocument.elements.append(kmlStation) 
     63 
    5964kmlDocument.save('./../../output/exampleps_stations.kml') 
  • DPPP/kml/csml2kml/python/prototypes/quadrize_stations_use_KMLDocument.py

    r3290 r3291  
    11''' 
    2 [CHANGE]("Prototype") for producing KML documents containing a quad-tree like <Folder> structure containing locations 
     2Prototype for producing KML documents containing a quad-tree like <Folder> structure containing locations 
    33in an effective way. See description of the build_quadtree() function to see what a "quad-tree" is. 
     4To generate KML, uses functionality encapsulated in the KMLDocument module's classes. 
    45''' 
    56 
     
    78from cElementTree import ElementTree, Element, SubElement 
    89from KMLDocument import * 
     10import sys 
    911 
    1012class Location: 
     
    137139#--------------------------------------------------------------------------------------------------------------------------- 
    138140 
    139 def kml_from_quadtree(t): 
    140     ''' 
    141     Convert the quad-tree into a KML element containing a <Folder> hierarchy with <Placemark> leaves. 
    142     ''' 
    143     def _buildRegionElement(bbox): 
    144         ''' 
    145         Convert a BBox object to a KML <Region> element 
    146         ''' 
    147         llabElement = Element('LatLonAltBox') 
    148         SubElement(llabElement, 'west').text = str(bbox.west) 
    149         SubElement(llabElement, 'south').text = str(bbox.south) 
    150         SubElement(llabElement, 'east').text = str(bbox.east) 
    151         SubElement(llabElement, 'north').text = str(bbox.north) 
    152  
    153         lodElement = Element('Lod') 
    154         SubElement(lodElement, 'minLodPixels').text = '64' 
    155         SubElement(lodElement, 'maxLodPixels').text = '-1' 
    156         SubElement(lodElement, 'minFadeExtent').text = '128' 
    157  
    158         regionElement = Element('Region') 
    159         regionElement.append(llabElement) 
    160         regionElement.append(lodElement) 
    161         return regionElement 
    162  
    163     def _buildPlacemarkElement(loc): 
    164         ''' 
    165         Convert a Location object to a KML <Placemark> element 
    166         ''' 
    167         pointElement = Element('Point') 
    168         SubElement(pointElement, 'coordinates').text = '%f,%f,%f' % (loc.lon,loc.lat,loc.alt) 
    169  
    170         placemarkElement = Element('Placemark') 
    171         SubElement(placemarkElement, 'name').text = loc.name 
    172         placemarkElement.append(pointElement) 
    173         return placemarkElement 
    174  
    175     if isinstance(t, NilLeaf):                      # Do nothing 
    176         pass 
    177     elif isinstance(t, LocLeaf):                    # Create a <Folder> with embedded <Region> and <Placemark>s 
    178         folderElement = Element('Folder') 
    179         SubElement(folderElement, 'name').text = repr(t.bbox) 
    180         folderElement.append(_buildRegionElement(t.bbox)) 
    181         for loc in t.locations: 
    182             folderElement.append(_buildPlacemarkElement(loc)) 
    183         return folderElement 
    184     elif isinstance(t, Node):                       # Create a <Folder> containing nested elements 
    185         folderElement = Element('Folder') 
    186         SubElement(folderElement, 'name').text = repr(t.bbox) 
    187         folderElement.append(_buildRegionElement(t.bbox)) 
    188         for i in t.children: 
    189             childElement = kml_from_quadtree(i)  # could be None 
    190             if childElement: 
    191                 folderElement.append(childElement) 
    192         return folderElement 
    193  
    194 #--------------------------------------------------------------------------------------------------------------------------- 
    195  
    196 def wrapRootFolderElement(rootFolderElement): 
    197     ''' 
    198     Create a full valid KML document containing the <Folder> element, rootFolderElement. 
    199     ''' 
    200     def _indentXML(elem, level=0):                     # Auxiliary function, indents XML 
    201         i = "\n" + level * "  " 
    202         if len(elem): 
    203             if not elem.text or not elem.text.strip(): 
    204                 elem.text = i + "  " 
    205             for child in elem: 
    206                 _indentXML(child, level+1) 
    207             if not child.tail or not child.tail.strip(): 
    208                 child.tail = i 
    209             if not elem.tail or not elem.tail.strip(): 
    210                 elem.tail = i 
    211         else: 
    212             if level and (not elem.tail or not elem.tail.strip()): 
    213                 elem.tail = i 
    214  
    215     # Auxiliary func, creates a list style that forces a <Folder> not to be "openable" in the Google Earth list view 
    216     def _buildCheckHideChildrenStyleElement():         
    217         listStyleElement = Element('ListStyle') 
    218         SubElement(listStyleElement, 'listItemType').text = 'checkHideChildren' 
    219         styleElement = Element('Style') 
    220         styleElement.set('id', 'checkHideChildrenStyle') 
    221         styleElement.append(listStyleElement) 
    222         return styleElement 
    223      
    224     SubElement(rootFolderElement, 'styleUrl').text = '#checkHideChildrenStyle' 
    225  
    226     kmlDocumentElement=Element('Document') 
    227     SubElement(kmlDocumentElement, 'name').text='Example quadrization run' 
    228     SubElement(kmlDocumentElement, 'open').text='1' 
    229     kmlDocumentElement.append(_buildCheckHideChildrenStyleElement()) 
    230     kmlDocumentElement.append(rootFolderElement) 
    231  
    232     kmlRootElement=Element('kml', xmlns='http://earth.google.com/kml/2.2') 
    233     kmlRootElement.append(kmlDocumentElement) 
    234     _indentXML(kmlRootElement, 0) 
    235     return kmlRootElement 
    236  
    237 #--------------------------------------------------------------------------------------------------------------------------- 
    238  
    239141def makeRandomStationsQuadTree(): 
    240142    ''' 
     
    250152def makeUKMOStationsQuadTree(): 
    251153    ''' 
    252     Parse the "ukmo.kml" file made by A.S.Harwood@rl.ac.uk (the MIDAS list of UK weather stations) 
     154    Parse the "ukmo.kml" file made by A.S.Harwood@rl.ac.uk (the MIDAS list of UK weather stations). 
     155    Create a quad-tree representation of that document. 
    253156    ''' 
    254157    tree = ElementTree() 
     
    276179#--------------------------------------------------------------------------------------------------------------------------- 
    277180 
     181def QuadTreeToKMLElement(t): 
     182    ''' 
     183    Convert the quad-tree into a KMLElement instance containing a folder hierarchy with placemark leaves. 
     184    ''' 
     185    if isinstance(t, NilLeaf):                      # Do nothing 
     186        pass 
     187    elif isinstance(t, LocLeaf):                    # Create a folder with an embedded region and placemarks 
     188        kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north) 
     189        kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion) 
     190        for loc in t.locations: 
     191            kmlFolder.children.append(KMLPlacemark(loc.name, loc.name, loc.lon, loc.lat)) 
     192        return kmlFolder 
     193    elif isinstance(t, Node):                       # Create a folder containing nested elements 
     194        kmlRegion = KMLRegion(t.bbox.west, t.bbox.south, t.bbox.east, t.bbox.north) 
     195        kmlFolder = KMLFolder(repr(t.bbox), [], region = kmlRegion) 
     196        for i in t.children: 
     197            kmlChild = QuadTreeToKMLElement(i) 
     198            if kmlChild: 
     199                kmlFolder.children.append(kmlChild) 
     200        return kmlFolder 
     201 
     202#--------------------------------------------------------------------------------------------------------------------------- 
     203 
    278204# Convert the MIDAS list of stations to a KML document 
    279205quadtree = makeUKMOStationsQuadTree() 
    280 rootFolderElement = kml_from_quadtree(quadtree) 
    281 kmlRootElement = wrapRootFolderElement(rootFolderElement) 
    282  
    283 # Write the KML document to a file 
    284 kmlTree = ElementTree(kmlRootElement) 
    285 kmlFile = open('../../output/quadrize_ukmo.kml', 'w') 
    286 kmlTree.write(kmlFile) 
    287 kmlFile.close() 
     206 
     207kmlLockedFolderStyle = KMLStyle('locked_folder_style', listItemType = 'checkHideChildren') 
     208kmlDocument = KMLDocument('MIDAS stations', [kmlLockedFolderStyle]) 
     209kmlFolder = QuadTreeToKMLElement(quadtree) 
     210kmlFolder.styleID = 'locked_folder_style' 
     211kmlDocument.elements.append(kmlFolder) 
     212kmlDocument.save('../../output/quadrize_ukmo.2.kml') 
Note: See TracChangeset for help on using the changeset viewer.