Commits

sgillies  committed f62f6ac

'ruffgeo' app.

  • Participants

Comments (0)

Files changed (7)

+application: ruffgeo
+version: 4
+runtime: python
+api_version: 1
+
+handlers:
+- url: /stylesheets
+  static_dir: stylesheets
+
+- url: .*
+  script: main.py
+

File geouri_template.kml

+<?xml version="1.0" encoding="UTF-8"?>
+<kml xmlns="http://www.opengis.net/kml/2.2"
+  xmlns:atom="http://www.w3.org/2005/Atom"
+  xmlns:x="http://example.com/x">
+
+<Document>
+  <name>{{ doc_name }}</name>
+  <atom:link href="http://sgillies.net/files/rough.kml"/>
+
+  <open>1</open>
+
+  <Style id="roughStyle">
+    <PolyStyle>
+      <color>330000ff</color>
+    </PolyStyle>
+  </Style>
+
+  <!-- Roughly located place -->
+  <Folder>
+    <name>{{ geo_uri }}</name>
+    <atom:link href="{{ geo_uri }}"/>
+    <description><![CDATA[A possibility indeterminate point location]]></description>
+    
+    <Placemark>
+      <name>Indeterminate location</name>
+      <description><![CDATA[Location is within {{ u }} meters of {{ latlon }}]]></description>
+
+    <styleUrl>#roughStyle</styleUrl>
+    
+    <MultiGeometry> 
+      <!-- representation of indeterminate region -->
+      
+      <MultiGeometry>
+        <!-- core -->
+        <x:relation>Contains/hasProperPart</x:relation>
+        {{ core_point }}
+      </MultiGeometry>
+
+      <MultiGeometry>
+        <!-- wide-boundary -->
+        <x:relation>Within/properPartOf</x:relation>
+      	{{ wide_polygon }}
+      </MultiGeometry>
+
+      <MultiGeometry>
+        <!-- exterior -->
+        <x:relation>Disjoint</x:relation>
+        <!-- no geometry -->
+      </MultiGeometry>
+
+    </MultiGeometry>
+
+    </Placemark>
+      
+  </Folder>
+
+</Document>
+</kml>
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd"> 
+<html> 
+<head> 
+  <title>KML rough location for 'geo' URIs</title> 
+  <link rel="stylesheet" href="/stylesheets/main.css" type="text/css"> 
+</head> 
+<body> 
+<div id="doc" class="yui-t7"> 
+  <div id="hd" role="banner"><h1>KML rough location for 'geo' URIs</h1></div> 
+  <div id="bd" role="main"> 
+    <div class="yui-g"> 
+      <p>Enter a 'geo' URI (see <a href="http://tools.ietf.org/html/rfc5870">RFC 5870</a>) and get a KML document designed to represent the possibly indeterminate nature of that location (see <a href="http://sgillies.net/blog/1034/representing-rough-locations-in-kml-3">rough locations in KML</a>).</p>
+      <form id="kml" method="get" action="/kml"> 
+        <label for="g">geo: URI</label> 
+        <input type="text" name="q" size="60" value="geo:43.70131168124085,3.898388489973128;u=10"/> 
+        <input type="submit" name="submit" value="Submit"/> 
+      </form> 
+    </div> 
+  
+  <div id="ft" role="contentinfo"><p>Some rights reserved 2010 by Sean Gillies.</p></div> 
+</div> 
+</body> 
+</html>
+
+indexes:
+
+# AUTOGENERATED
+
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run.  If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED").  If you want to manage some indexes
+# manually, move them above the marker line.  The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
+#!/usr/bin/env python
+#
+# Copyright 2007 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.
+#
+
+import math
+import os
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template, util
+
+from geouri import parse
+
+def circle_coords(lon, lat, r, n=32):
+    a = 2.0*math.pi/360.0
+    b = math.cos(lat*a)
+    dt = 2.0*math.pi/n
+    f = 360.0/40075000.16
+    coords = []
+    for i in range(n):
+        t = i*dt
+        x = lon + f*r*math.sin(t)/b
+        y = lat + f*r*math.cos(t)
+        coords.append('%s,%s,0' % (x, y))
+    coords.append(coords[0])
+    return ' '.join(coords)
+
+def wide_polygon(coords):
+    return """
+        <Polygon>
+		    <outerBoundaryIs>
+			    <LinearRing>
+				    <coordinates>%s</coordinates>
+			    </LinearRing>
+		    </outerBoundaryIs>
+	    </Polygon>
+    """ % coords
+
+def core_point(lon, lat):
+    return '<Point><coordinates>%s,%s,0</coordinates></Point>' % (lon, lat)
+
+class MainHandler(webapp.RequestHandler):
+    def get(self):
+        path = os.path.join(os.path.dirname(__file__), 'index.html')
+        data = {}
+        self.response.headers['Content-Type'] = 'text/html'
+        self.response.out.write(template.render(path, data))
+
+class KMLHandler(webapp.RequestHandler):
+    def get(self):
+        q = self.request.get('q')
+        r = parse(q)
+        slug = '%s,%s' % tuple(r.coords)
+        if r.u:
+            slug += ',%s' % r.u
+        data = {
+            'doc_name': slug,
+            'geo_uri': q,
+            'u': r.u,
+            'latlon': r.coords
+            }
+        if r.u is None:
+            data['core_point'] = core_point(r.coords[1], r.coords[0])
+            data['wide_polygon'] = '<!-- no geometry -->'
+        else:
+            data['core_point'] = '<!-- no geometry -->'
+            data['wide_polygon'] = wide_polygon(circle_coords(r.coords[1], r.coords[0], r.u))
+
+        path = os.path.join(os.path.dirname(__file__), 'geouri_template.kml')
+
+        self.response.headers['Content-Type'] = 'application/vnd.google-earth.kml+xml'
+        self.response.headers['Content-Disposition'] = 'attachment; filename=ruffgeo-%s.kml' % slug
+        self.response.out.write(template.render(path, data))
+
+def main():
+    application = webapp.WSGIApplication([('/', MainHandler), ('/kml', KMLHandler)],
+                                         debug=True)
+    util.run_wsgi_app(application)
+
+
+if __name__ == '__main__':
+    main()

File stylesheets/main.css

+@import url("reset-fonts-grids.css");
+
+html {
+  font-size: 62.5%;
+}
+
+body {
+  font-family: "Georgia", serif;
+  font-size: 1.4em;
+  color: #333;
+  background-color: #fff;
+  margin: 3em 6em;
+}
+
+h1, h2, h3, h4, h5 {
+  font-family: "Verdana", sans-serif;
+}
+
+h1 {
+  letter-spacing: 0.12em;
+}
+
+h2 {
+  letter-spacing: 0.08em;
+}
+
+h1 + h5, h2 + h5, h3 + h5 {
+  margin-top: -1em;
+}
+
+#hd {
+  text-align: center;
+}
+
+p {
+  margin: 1em auto;
+}
+
+label {
+  font-weight: bold;
+}
+
+a:link {
+    color: #222;
+}
+
+a:visited {
+    color: #555;
+}
+
+a:hover {
+    color: #000;
+}
+
+a:active {
+}
+
+a:focus {
+}
+
+.path {
+  font-family: "Tahoma";
+  font-size: 1.2em;
+  color: #333;
+}
+
+ul.path {
+  text-align: left;
+  margin: 1em 0em;
+}
+
+ul.path > li {
+  display: inline;
+  list-style-type: none;
+}
+
+ul.path > li:after {
+  content: "\00BB";
+  font-family: "Tahoma", serif;
+  font-size: 14px;
+  padding-left: 6px;
+}
+
+ul.path > li.current:after {
+  content: "";
+}
+
+dt {
+  font-weight: bold;
+}
+
+dd {
+  margin-bottom: 1em;
+}
+
+div.yui-g {
+  margin-bottom: 4em;
+}

File stylesheets/reset-font-grids.css

+/*
+Copyright (c) 2008, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.6.0
+*/
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:text-top;}sub{vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}del,ins{text-decoration:none;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#ft{clear:both;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;min-width:750px;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;} .yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#bd:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#bd,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}