""" Copyright (C) 2006 Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ """ $URL$ $Revision$ $Date$ """ """ Generate KML Convenience functions to generate KML fragments. """ import kml.genxml import os import time def Point(lon,lat,attrname=None,attrval=None): """ Args: lon,lat: decimal degrees, float attrname: id or targetId attrval: string Returns: KML: ... """ point = kml.genxml.Point() point.coordinates = '%f,%f' % (lon,lat) return point.xml() def Placemark(geometry,name=None,styleurl=None,attrname=None,attrval=None): """... Args: geometry: string: ,,, name: string: style: string: Helper function to create the appropriate KML to hide the children of either a Document, Folder or NetworkLink. NOTE: In a Folder or NetworkLink this is an inline style. In a Document this is a shared style and the Document must also use a to reference this Style for the ListStyle to take effect. Args: id: unique string Returns: KML: """ style = kml.genxml.Style() if id: style.id = id style.ListStyle = ListStyle('checkHideChildren') return style.xml() def PolygonBox(n,s,e,w,alt): """... Polygon with corners at nw,ne,se,sw Returns: KML: ... """ coordinates = Coordinates() coordinates.AddPoint(w,n,alt) coordinates.AddPoint(e,n,alt) coordinates.AddPoint(e,s,alt) coordinates.AddPoint(w,s,alt) coordinates.AddPoint(w,n,alt) linearring = kml.genxml.LinearRing() linearring.coordinates = coordinates.Coordinates() outer = kml.genxml.outerBoundaryIs() outer.LinearRing = linearring.xml() polygon = kml.genxml.Polygon() polygon.outerBoundaryIs = outer.xml() return polygon.xml() def LineStringBox(n,s,e,w): """ LineString between nw,ne,se,sw,nw. Tessellated to follow terrain and curvature of the earth. Returns: KML: ... """ c = Coordinates() c.AddPoint2(w,n) c.AddPoint2(e,n) c.AddPoint2(e,s) c.AddPoint2(w,s) c.AddPoint2(w,n) linestring = kml.genxml.LineString() linestring.coordinates = c.Coordinates() linestring.tessellate = 1 return linestring.xml() def LineStringAltBox(n,s,e,w,alt,altMode='relativeToGround'): """ LineString between nw,ne,se,sw,nw at altitude alt. Args: n,s,e,w: float alt: altitude altMode: relativeToGround (default) or absolute Returns: KML: ... """ c = Coordinates() c.AddPoint(w,n,alt) c.AddPoint(e,n,alt) c.AddPoint(e,s,alt) c.AddPoint(w,s,alt) c.AddPoint(w,n,alt) linestring = kml.genxml.LineString() linestring.coordinates = c.Coordinates() linestring.altitudeMode = altMode return linestring.xml() def SimpleLineString(a_lon, a_lat, b_lon, b_lat): """ Create a LineString from point a to point b Args: a_lon, a_lat: point at one end b_lon, b_lat: point at the other Returns: kml: '...' """ coordinates = kml.genkml.Coordinates() coordinates.AddPoint2(a_lon, a_lat) coordinates.AddPoint2(b_lon, b_lat) linestring = kml.genxml.LineString() linestring.coordinates = coordinates.Coordinates() linestring.tessellate = 1 return linestring.xml() def Box(n,s,e,w,name,styleurl=None,alt=None,altMode='relativeToGround'): """... Returns a Placemark with a LineString box between the corners of the given bounding box. Args: n,s,e,w: float name: Placemark name styleurl: xml string alt: altitude altMode: relativeToGround or absolute (only if alt != 0) Returns: KML: ... """ placemark = kml.genxml.Placemark() placemark.name = name if styleurl: placemark.styleUrl = styleurl if alt: placemark.Geometry = LineStringAltBox(n,s,e,w,alt,altMode) else: placemark.Geometry = LineStringBox(n,s,e,w) return placemark.xml() def RegionBox(name,n,s,e,w,minpx,maxpx): """ ...... Args: n,s,e,w: float minpx,maxpx: minLodPixels, maxLodPixels Returns: KML: ...... """ placemark = kml.genxml.Placemark() placemark.name = name regionxml = kml.genkml.Region(n,s,e,w,minpx=minpx,maxpx=maxpx) boxxml = kml.genkml.LineStringBox(n,s,e,w) placemark.Geometry = boxxml placemark.Region = regionxml return placemark.xml() def LatLonOutline(n,s,e,w,name): """ Generate a lat-lon-aligned box A filled Polygon with 0 opacity with outline enabled traces the lat-lon-aligned border of the given bounding box. (A KML LineString with corner coordinates using pairings of n,s,e,w has line segments which trace the shortest distance between the two corners -- this does not follow a longitude line). NOTE: The object will be not be visible if a GroundOverlay covers the same area because the draw order of this filled polygon is less than any GroundOverlay. Args: n,s,e,w: lat-lon-aligned bounding box name: string used in for this object Returns: KML Placemark """ style = kml.genxml.Style() style.PolyStyle = PolyStyle(0,0,0,0,1,1) style.LineStyle = LineStyle(255,255,255,255,2.0) placemark = kml.genxml.Placemark() placemark.name = name placemark.Add_Style(style.xml()) placemark.Geometry = PolygonBox(n,s,e,w,0) return placemark.xml() def LatLonBox(n,s,e,w): """... """ latlonbox = kml.genxml.LatLonBox() latlonbox.Set_NSEW(n,s,e,w) return latlonbox.xml() def Region(n,s,e,w, minalt=0,maxalt=0,altmode=None, minpx=128,minfade=0,maxpx=1024,maxfade=0): """... Args: NOTE: all args are _string_ representations of the floating point values n,s,e,w: geographic bounding box minalt,maxalt: minAltitude,maxAltitude altmode: altitudeMode minpx,maxpx: minLodPixels,maxLodPixels minfade,maxfade: minFadePixels,maxFadePixels """ latlonaltbox = kml.genxml.LatLonAltBox() latlonaltbox.north = n latlonaltbox.south = s latlonaltbox.east = e latlonaltbox.west = w if minalt: latlonaltbox.minAltitude = minalt if maxalt: latlonaltbox.maxAltitude = maxalt if altmode: latlonaltbox.altitudeMode = altmode lod = kml.genxml.Lod() lod.minLodPixels = minpx lod.maxLodPixels = maxpx if minfade: lod.minFadeExtent = minfade if maxfade: lod.maxFadeExtent = maxfade region = kml.genxml.Region() region.LatLonAltBox = latlonaltbox.xml() region.Lod = lod.xml() return region.xml() def RegionLod(n,s,e,w,minpx,maxpx): """... Region with default min/maxAltitude and no fade extents """ return Region(n,s,e,w,0,0,None,minpx,0,maxpx,0) def RegionNetworkLink(n,s,e,w,name,href,minpx,maxpx, minalt=None,maxalt=None,altmode=None): """... Region-based NetworkLink, onRegion viewRefreshMode. """ regionxml = Region(n,s,e,w,minpx=minpx,maxpx=maxpx,altmode=altmode) link = kml.genxml.Link() link.href = href link.viewRefreshMode = 'onRegion' networklink = kml.genxml.NetworkLink() networklink.name = name networklink.Link = link.xml() networklink.Region = regionxml return networklink.xml() def GroundOverlay(n,s,e,w,href,draworder,region=None): """... """ icon = kml.genxml.Icon() icon.href = href latlonboxkml = LatLonBox(n,s,e,w) groundoverlay = kml.genxml.GroundOverlay() groundoverlay.drawOrder = draworder groundoverlay.Icon = icon.xml() groundoverlay.LatLonBox = latlonboxkml if region: groundoverlay.Region = region return groundoverlay.xml() def RegionGroundoverlay(n,s,e,w,minpx,maxpx,href,draworder): """ """ region = Region(n,s,e,w,minpx=minpx,maxpx=maxpx) return GroundOverlay(n,s,e,w,href,draworder,region) def NetworkLink(href,visibility=1): """... """ networklink = kml.genxml.NetworkLink() networklink.name = href if visibility == 0: networklink.visibility = 0 link = kml.genxml.Link() link.href = href networklink.Link = link.xml() return networklink.xml() def overlayXY(x, y, xunits, yunits): overlayxy = kml.genxml.overlayXY() overlayxy.x = x overlayxy.y = y overlayxy.xunits = 'pixels' overlayxy.yunits = 'pixels' return overlayxy.xml() def screenXY(x, y, xunits, yunits): screenxy = kml.genxml.screenXY() screenxy.x = x screenxy.y = y screenxy.xunits = 'pixels' screenxy.yunits = 'pixels' return screenxy.xml() def ScreenOverlay(name,href,draworder,x,y,wid,ht,color=None,region=None): """... Draw the given image at the given location and size on the screen. Args: name: string for href: url/filename for draworder: int for x,y: screen coord relative to lower-left wid,ht: screen dimensions of image region: Returns: KML: ... """ screenoverlay = kml.genxml.ScreenOverlay() screenoverlay.name = name if color: screenoverlay.color = color if region: screenoverlay.Region = region screenoverlay.drawOrder = draworder if href: icon = kml.genxml.Icon() icon.href = href screenoverlay.Icon = icon.xml() screenoverlay.overlayXY = overlayXY(x, y, 'pixels', 'pixels') screenoverlay.screenXY = screenXY(x, y, 'pixels', 'pixels') size = kml.genxml.size() size.x = wid size.y = ht screenoverlay.size = size.xml() return screenoverlay.xml() def ScreenOverlayRect(name,color,draworder,x,y,wid,ht,region=None): """... A ScreenOverlay with no Icon draws a rectangle on the screen. Args: name: string for color: hex abgr for draworder: int for x,y: screen coord relative to lower-left wid,ht: screen dimensions of image region: Returns: KML: '...' """ return ScreenOverlay(name,None,draworder,x,y,wid,ht,color=color,region=region) def TimeSpan(b, e): """... Args: begin: string end: string Returns: KML: ... """ timespan = kml.genxml.TimeSpan() timespan.begin = b timespan.end = e return timespan.xml() def TimeStamp(when): """... Args: when: string Returns: KML: ... """ timestamp = kml.genxml.TimeStamp() timestamp.when = when return timestamp.xml() def Update(update,targethref): """ Args: update: ... /> targethref: value Returns: KML: ...... """ u = [] u.append('\n') u.append('%s\n' % targethref) u.append(update) u.append('\n') return "".join(u) def NetworkLinkControl(cookie=None,expires=None,update=None,targethref=None): """ [Other NLC tags not used here include: , ,,] Args: expires: value, ISO 8601 cookie: value, must be name=value targethref: value update: body of (targetHref must be supplied) Returns: KML: """ nlc = kml.genxml.NetworkLinkControl() if nlc: nlc.cookie = cookie if expires: nlc.expires = expires if update and targethref: nlc.Update = Update(update,targethref) return nlc.xml() def LookAt(lon,lat,range,tilt,heading,attrname=None,attrval=None): """ Args: lon: float lat: float range: float tilt: float heading: float attrname: attribute name ('id' or 'targetId') attrval: attribute value string Returns: KML: ... """ lookat = kml.genxml.LookAt() if attrname == 'id': lookat.id = attrval elif attrname == 'targetId': lookat.targetId = attrval if lon: lookat.longitude = '%f' % lon if lat: lookat.latitude = '%f' % lat if range: lookat.range = '%f' % range if tilt: lookat.tilt = '%f' % tilt if heading: lookat.heading = '%f' % heading return lookat.xml() def Camera(lon,lat,alt,heading,tilt,roll,altmode,attrname=None,attrval=None): """ Args: lon: float lat: float alt: float heading: float tilt: float roll: float altmode: attrname: attribute name ('id' or 'targetId') attrval: attribute value string Returns: KML: ... """ camera = kml.genxml.Camera() if attrname == 'id': camera.id = attrval elif attrname == 'targetId': camera.targetId = attrval if lon: camera.longitude = '%f' % lon if lat: camera.latitude = '%f' % lat if alt: camera.altitude = '%f' % alt if heading: camera.heading = '%f' % heading if tilt: camera.tilt = '%f' % tilt if roll: camera.roll = '%f' % roll if altmode: camera.altitudeMode = altmode return camera.xml() class Coordinates: """Create data 1) create Coordinates() 2) SetPoint() or N x AddPoint() 3) Coordinates() returns data """ def __init__(self): self.__coordinates = [] def SetPoint2(self, lon, lat): """ Args: lon,lat: float """ self.AddPoint2(lon, lat) def SetPoint(self, lon, lat, alt): """ Args: lon,lat,alt: float """ self.AddPoint(lon, lat, alt) def AddPoint2(self, lon, lat): """ Args: lon,lat: float """ if self.__coordinates: nl = ' ' # whitespace as separator else: nl = '' cstr = '%s%f,%f' % (nl, lon, lat) self.__coordinates.append(cstr) def AddPoint(self, lon, lat, alt): """ Args: lon,lat,alt: float """ if self.__coordinates: nl = ' ' # whitespace as separator else: nl = '' cstr = '%s%f,%f,%f' % (nl, lon, lat, alt) self.__coordinates.append(cstr) def Coordinates(self): """ Returns the set of coordinates as a string Returns: string: """ return "".join(self.__coordinates) def CreateISO8601(gm_seconds): """ Create an ISO-8601 format string Args: gm_seconds: seconds in UTC (GMT) Returns: string: YYYY-MM-DDTHH:MM:SSZ """ return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(gm_seconds)) def Data(name, displayName, value): data = kml.genxml.Data() data.name = name if displayName: data.displayName = displayName data.value = value return data.xml()