#!/usr/bin/env python """ We take a Well-Known Text string and a KML file as parameters. The WKT string is converted into a polygon (hopefully), and the KML file is parsed for a linestring, which defines a path. We then drag the polygon along the linestring, and return the resulting polygon as KML. """ import pgdb import os import site import sys # Basically, add '../src' to our path. # Needed for the imports that follow. site.addsitedir(os.path.dirname(os.path.abspath(sys.argv[0])) + '/../src') import CLI import Configuration.Defaults import ExitCodes import Geometry import KML usage = '%prog [options] ' # -h (help) Conflicts with -h HOSTNAME parser = CLI.default_option_parser(usage) # Use this module's docstring as the description. parser.description = __doc__ parser.add_option('-o', '--outfile', help='Optional output file path. Defaults to stdout.') parser.add_option('-n', '--name', help='Name to give the geometry object in the KML document.', default='WKT Object') parser.add_option('-s', '--srid', type="int", help="SRID of the input geometry. Defaults to %s." % Configuration.Defaults.SRID, default=Configuration.Defaults.SRID) (options, args) = parser.parse_args() if len(args) < 2: print """ ERROR: You must supply both a Well-Known Text string, and a KML file containing a linestring. """ parser.print_help() print '' # Print a newline raise SystemExit(ExitCodes.NOT_ENOUGH_ARGS) wkt_string = args[0] kml_filename = args[1] f = open(kml_filename, 'r') kml = f.read() f.close() coords = KML.LineString.tuples_from_kml(kml) p = Geometry.Polygon.from_wkt(wkt_string) death_tube = None for i in range(len(coords) - 1): # For each coordinate (except the last), we want to: # a) Translate our polygon to the coordinate. # b) Drag the polygon to the next coordinate. this_coord = Geometry.TwoVector(coords[i][0], coords[i][1]) next_coord = Geometry.TwoVector(coords[i+1][0], coords[i+1][1]) drag_vector = (next_coord - this_coord) tp = p.translate(this_coord) if (death_tube == None): death_tube = tp.drag(drag_vector) else: death_tube = death_tube.union(tp.drag(drag_vector)) conn = pgdb.connect(host=options.host, database=options.database, user=options.username) # We'll use this cursor for all of our queries. cursor = conn.cursor() # We use one query that basically just imports the WKT string and # immediately exports it as KML. The geometry must have an SRID when # ST_AsKml is called, so we provide one to ST_GeomFromText. kml_query = "SELECT ST_AsKml(ST_GeomFromText('%s', %s))" % (death_tube.wkt(), options.srid) cursor.execute(kml_query) rows = cursor.fetchall() kml_representation = rows[0][0] conn.close() doc = KML.Document() # Create a semi-transparent blue polygon style, and add it to the # document. hex_value = "b0ff0000" s = KML.Style(initial_id=('default')) poly_style = KML.PolyStyle() color = KML.Color(hex_value) poly_style.children.append(color) s.children.append(poly_style) doc.styles.append(s) # We're only going to have one placemark -- the object defined by our # input WKT. placemark = KML.Placemark() name = KML.Name(options.name) placemark.children.append(name) # This applies the red polygon style defined earlier to our placemark. styleurl = KML.StyleUrl('default') placemark.children.append(styleurl) # The database query is going to give us raw KML. For example, if our # input WKT represents a polygon, the output of ST_AsKml will contain # ... and everything therein. rawkml = KML.RawText(kml_representation) placemark.children.append(rawkml) doc.children.append(placemark) # Default the output file to sys.stdout. If we were passed an outfile # as an argument, use that instead. output_file = sys.stdout if (options.outfile != None): output_file = open(options.outfile, 'w') # Write the KML and get out of here. output_file.write(doc.to_kml()) output_file.close()