GeoScript

45
GeoScript Spatial Capabilities for Scripting Languages Justin Deolivera and Jared Erickson

description

GeoScript. Spatial Capabilities for Scripting Languages Justin Deolivera and Jared Erickson. Scripting Platform for JVM Languages. Similar API  Respect languages differences     Python GeoScript should be Pythonic Make easy things easy, Make hard things possible. Groovy. Groovy  - PowerPoint PPT Presentation

Transcript of GeoScript

Page 1: GeoScript

GeoScriptSpatial Capabilities for Scripting Languages

Justin Deolivera and Jared Erickson

Page 2: GeoScript

Scripting Platform for JVM Languages

Similar API Respect languages differences    Python GeoScript should be PythonicMake easy things easy, Make hard things possible

Page 3: GeoScript

Groovy

• Groovy o Dynamic languageo Easy for Java programmers to learn o Closures, DSLso REPL, GUI Consoleo Compiles to Java Byte Codeo Full access to Java libraries

• http://geoscript.org/groovy• https://github.com/jericks/geoscript-groovy

Page 4: GeoScript

JavaScript

 

Page 5: GeoScript

Python

• Jython o Java implementation of Python o Jython 2.5 = CPython 2.5o Full access to Java libraries

• http://geoscript.org/py• https://github.com/jdeolive/geoscript-py

Page 6: GeoScript

• Scalao Combine functional and object-oriented

programmingo Statically typed???o REPLo Compiles to Java bytecodeo Full access to Java libraries

• http://geoscript.org/scala/• https://github.com/dwins/geoscript.scala/

Scala

Page 7: GeoScript

On the shoulders of giants...

Page 8: GeoScript

On the shoulders of giants...

• Java Topology Suite (JTS)o Geometry API and Algorithms

• GeoToolso DataStoreso Features o Coverages/Rasters o Referencingo Renderering

• Java Tribe Base librarieso GeoServero uDigo Geomajas

Page 9: GeoScript

GeoScript Modules

Page 10: GeoScript

GeoScript Modules

• Geometry• Projection• Feature• Layer• Workspace• Style• Renderer

Page 11: GeoScript

Geometry

• Convenient constructors• I/O

o WKT/WKBo JSONo GML

• Plotting• Transforms

Page 12: GeoScript

Geometry

>>> from geoscript import geom

>>> geom.Point(30, 10)POINT(30 10)

>>> geom.LineString((30,10), (10,20), (20,40), (40,40), (30,10))  LINESTRING (30 10, 10 20, 20 40, 40 40, 30 10)

>>> geom.Polygon([(35,10), (10,20), (15,40), (45,45), (35,10)], [(20,30), (35,35), (30,20), (20,30)])POLYGON ((35 10, 10 20, ... 30 20, 20 30))

>>> geom.MultiLineString([(10,10), (20,20), (10,40)], [(40,40), (30,30), (40,20), (30,10)])MULTILINESTRING ((10 10, 20 20, ... 40 20, 30 10))

Constructors

Page 13: GeoScript

Geometry

>>> from geoscript import geom

>>> point = geom.Point(30, 10)>>> geom.writeGML(point)<gml:Point xmlns:gml="http://www.opengis.net/gml"> <gml:coord>  <gml:X>30.0</gml:X>  <gml:Y>10.0</gml:Y> </gml:coord></gml:Point>

>>> geom.readJSON('{"type":"Point","coordinates":[30,10]}')POINT(30 10)

>>> geom.writeWKB(point)array('b', [0, 0, 0, 0, 1, 64, 62, ... 64, 36, 0, 0, 0, 0, 0, 0])

Input/Output

Page 14: GeoScript

Geometry

>>> from geoscript.render import plot>>> from geoscript import geom

>>> poly = geom.Polygon([(35,10), (10,20), (15,40), (45,45), (35,10)], [(20,30), (35,35), (30,20), (20,30)])

>>> plot(poly)

Plotting

Page 15: GeoScript

Geometry

>>> from geoscript.geom import Point, transform>>> from geoscript.render import draw

>>> c = geom.Point(0, 0).buffer(10)>>> d = transform(c, dx=5) # translate>>> draw([c,d])

>>> e,f = transform(c, shx=0.5), transform(c, shx=-0.5) # shear>>> g = transform(c, sx=0.7) # scale>>> draw([e,f,g])

Transforms

Page 16: GeoScript

Projection

• Parse/encode WKT• Full GeoTools EPSG

database• Re-projection

Page 17: GeoScript

Projection

>>> from geoscript.proj import Projection

>>> Projection('EPSG:4326')GEOGCS["WGS 84",   DATUM["World Geodetic System 1984",     SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],     AUTHORITY["EPSG","6326"]],   PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],   UNIT["degree", 0.017453292519943295],   AXIS["Geodetic longitude", EAST],   AXIS["Geodetic latitude", NORTH],   AUTHORITY["EPSG","4326"]]

>>> p = Projection('GEOGCS[..."Degree",0.017453292519943295]]') >>> p.id'EPSG:4326'

Constructors

Page 18: GeoScript

Projection

>>> from geoscript import geom, render>>> from geoscript.proj import Projection

>>> p = Projection('epsg:4326')>>> p.transform((-111, 45.7), 'epsg:26912')(500000.0, 5060716.313515949)

>>> g = geom.Point(0, 0).buffer(4)>>> g = reduce(lambda x,y:x.union(y),[geom.transform(g,dx=x,dy=y)      for x,y in [(3,0),(0,3),(-3,0),(0,-3)]])>>> render.draw(g)>>> render.draw(p.transform(g, 'epsg:26912'))>>> render.draw(p.transform(g, 'epsg:3005'))

Reprojection

WGS 84 UTM Albers

Page 19: GeoScript

Data Access

• Read and Write Layers• Query Layers using CQL• I/O 

o GeoJSONo GML

Page 20: GeoScript

Data Access

>>> from geoscript.workspace import PostGIS>>> from geoscript import geom

>>> pg = PostGIS('spearfish')>>> pg.layers()['archsites', 'bugsites', 'railroads', 'restricted', 'roads', 'streams']>>> l = pg['bugsites']>>> l.schemabugsites [cat: long, str1: str, the_geom: Point]

>>> l = Layer('foo')>>> l.add([geom.Point(0,0)]) >>> l = pg.add(l) 

>>> l = pg.create('bar', [('geom',geom.Point),('name',str)])

Workspaces

Page 21: GeoScript

Data Access

>>> from geoscript.layer import Shapefile

>>> shp = Shapefile('states.shp')>>> shp.count()49>>> shp.count('CARPOOL/PERSONS > 0.06')26

>>> shp.bounds()(-124.731422, 24.955967, -66.969849, 49.371735, EPSG:4326)

>>> shp.bounds("STATE_NAME = 'Colorado'")(-109.055199, 36.988972, -102.036758, 41.00341, EPSG:4326)

>>> for f in shp.features():...   print '%s has %f people' % (f['STATE_NAME'],f['PERSONS'])

>>> for f in shp.features('CARPOOL/PERSONS > 0.06'):...   print '%s likes to carpool' % f['STATE_NAME']

Layers

Page 22: GeoScript

Data Access

>>> from geoscript.feature import Schema, Feature>>> from geoscript.geom import *

>>> schema = Schema('shapes', [('geom',Polygon), ('name',str)]) 

>>> square = Feature([LineString((0,0),(1,1)).bounds().toPolygon(),      'square'], 0, schema)>>> square.id0>>> square['name']'square'>>> square.geomPOLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))

>>> square.geom = LineString((0,0),(2,1)).bounds().toPolygon()>>> square['name'] = 'rectangle'

>>> circle = Feature({'geom':Point(0,0).buffer(1),'name':'circle'})

Features

Page 23: GeoScript

Data Access

>>> from geoscript.feature import *>>> from geoscript.geom import Polygon

>>> triangle = Feature({'geom':Polygon([(0,0),(1,1),(2,0),(0,0)])})>>> writeGML(triangle)<gsf:feature fid="fid--272f9bd3_1322c34ca2d_-8000" xmlns:gml="http://www.opengis.net/gml" xmlns:gsf="http://geoscript.org/feature"> <gsf:geom>  <gml:Polygon>...</gml:Polygon> </gsf:geom></gsf:feature>

>>> writeGML(triangle, version=3.2)...

>>> writeJSON(triangle){"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[0.0,0.0],[1,1],[2,0.0],[0.0,0.0]]]},"properties":{},"id":"fid--272f9bd3_1322c34ca2d_-8000"}

>>> f = readJSON('{"type":"Feature", "geometry":{"type":"Point", "coordinates":[1.0, 2.0]}}')feature.fid--709b2d80_1322c512876_-8000 {geometry: POINT (1 2)}

Input/Output

Page 24: GeoScript

Styling and Rendering

• Taming SLDo Symbolizerso Scale dependenceo Thematics

Page 25: GeoScript

Styling

>>> from geoscript.style import Stroke>>> from geoscript.render import draw>>> from geoscript.geom import *

>>> line = LineString((0,0), (1,1))

>>> draw(line, Stroke('#000000', width=2)) # normal>>> draw(line, Stroke('black', width=2, dash=[5,5])) # dash>>> draw(line, Stroke((0,0,0), width=2).hatch('vertline')) # hatch

Stroke

Page 26: GeoScript

Styling

>>> from geoscript.style import Fill, Stroke>>> from geoscript.render import draw>>> from geoscript.geom import *

>>> poly = Point(0,0).buffer(1)

>>> draw(poly, Fill('gray')) # normal>>> draw(poly, Fill('gray', opacity=0.5)) # transparent>>> draw(poly, Fill('gray').hatch('backslash')) # hatch

>>> draw(poly, Stroke('red',2) + Fill().hatch('times'))

Fill

Page 27: GeoScript

Styling

>>> from geoscript.style import Shape>>> from geoscript.render import draw>>> from geoscript.geom import *

>>> mpoint = MultiPoint((0,0), (0,1), (1,1), (1,0), (0.5,0.5))

>>> draw(mpoint, Shape('black', 10))>>> draw(mpoint, Shape('yellow', 20, 'star'))>>> draw(mpoint, Shape('red', 20, 'x'))

Shape

Page 28: GeoScript

Styling

>>> from geoscript.style import Icon>>> from geoscript.render import draw>>> from geoscript.geom import *

>>> mpoint = MultiPoint((0,0), (0,1), (1,1), (1,0), (0.5,0.5))

>>> draw(mpoint, Icon('hospital.png'))>>> draw(mpoint, Icon('rainy.svg'))

Icon

Page 29: GeoScript

Styling

>>> from geoscript.style import Label, Stroke, Fill, Shape>>> from geoscript.feature import Feature>>> from geoscript.render import draw>>> from geoscript.geom import *

>>> font = 'bold 16px Arial'>>> f = Feature({'geom': Point(0,0), 'name': 'foo'})>>> draw(f, Shape() + Label('name', font).point(displace=(20,0)))

>>> f = Feature({'geom': LineString((0,0), (1,1)), 'name': 'bar'})>>> draw(f, Stroke() + Label('name', font).linear(offset=10))

>>> f = Feature({'geom': Point(0,0).buffer(1), 'name': 'baz'})>>> draw(f, Fill() + Label('name', font).halo('white', 2))

Labels

Page 30: GeoScript

Styling

>>> from geoscript.style Shape, Icon, Label>>> from geoscript.render import draw>>> from geoscript.feature import Feature>>> from geoscript.geom import *

>>> school = Feature({'loc': Point(0,0), 'name': 'J.L. Crowe'})

>>> style = Shape('#004d96', 5).range(min=3000) >>> style += Icon('school20.png').range(max=3000, min=1500)>>> style += Icon('school40.png').range(max=1500)

>>> bounds = Bounds(-100, -100, 100, 100, 'epsg:404000') >>> draw(school, style, bounds)>>> draw(school, style, bounds.scale(0.5))>>> draw(school, style, bounds.scale(0.1))

Scale

Page 31: GeoScript

Styling

>>> from geoscript.style Stroke, Fill, Label>>> from geoscript.render import draw>>> from geoscript.layer import Shapefile

>>> states = Shapefile('states.shp')

>>> style = Stroke() + Label('STATE_ABBR', '14 "Times New Roman"')>>> style += Fill('#4DFF4D', 0.7).where('PERSONS < 2000000')>>> style += Fill('#FF4D4D', 0.7).where('PERSONS BETWEEN 2000000 AND 4000000')>>> style += Fill('#4D4DFF', 0.7).where('PERSONS > 4000000')>>> draw(states, style)

Theming

Page 32: GeoScript

Centroidsimport geoscript.layer.*import geoscript.feature.*import geoscript.geom.*

Shapefile shp = new Shapefile('states.shp')Schema schema = shp.schema.changeGeometryType('Point','states_centroids')Layer centroidLayer = shp.workspace.create(schema) Cursor cursor = shp.cursorwhile(cursor.hasNext()) {   Feature f = cursor.next()   Map attributes = [:]   f.attributes.each{k,v ->      if (v instanceof Geometry) {          attributes[k] = v.centroid      }      else {         attributes[k] = v      }   }   Feature feature = schema.feature(attributes, f.id)   centroidLayer.add(feature)}

cursor.close() 

Page 33: GeoScript

Voronoi Diagramimport geoscript.layer.*import geoscript.feature.*import geoscript.geom.*

Shapefile shp = new Shapefile('states.shp')Schema schema = new Schema('states_voronoi',           [['the_geom','MultiPolygon','EPSG:4326']])

Layer diagramLayer = shp.workspace.create(schema)List geoms = shp.features.collect{f->    f.geom.centroid}GeometryCollection geomCol = new GeometryCollection(geoms)Geometry voronoiGeom = geomCol.voronoiDiagramdiagramLayer.add(schema.feature([voronoiGeom]))

Page 34: GeoScript

Shapefiles to PostGIS

import geoscript.workspace.*import geoscript.layer.*

def dir = new Directory("/Users/jericks/Downloads/wash")println("Shapefiles: ${dir.layers}")

def postgis = new PostGIS('postgres','localhost','5432','public','postgres', 'postgres')println("PostGIS Layers: ${postgis.layers}")

dir.layers.each{name->    def layer = dir.get(name)    println("Adding ${layer.name}...")    postgis.add(layer)}

Page 35: GeoScript

USGS Earth Quakes

Read RSS Feed to a Shapefile

Page 36: GeoScript

import geoscript.geom.*import geoscript.feature.*import geoscript.layer.Layerimport geoscript.workspace.Directory

Schema s = new Schema('earthquakes'[['the_geom', 'Point', 'EPSG:4326'], ['title','String'], ['date', 'java.util.Date'], ['elevation', 'Double']])Directory dir = new Directory('.')Layer layer = dir.create(s)

def url = "http://earthquake.usgs.gov/earthquakes/catalogs/1day-M2.5.xml"def rss = new XmlParser().parse(url)int c = 0String dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"rss.entry.each{e ->    def title = e.title.text()    def date = Date.parse(dateFormat, e.updated.text())    def coordinate = e."georss:point".text().split(" ")    double x = coordinate[1] as Double    double y = coordinate[0] as Double    def point = new Point(x,y)    def elev = e."georss:elev".text() as Double    Feature f = s.feature(['title':title,'date':date,      'elevation': elev, 'the_geom': point],"earthquake_${c}")    layer.add(f)    c++}

Page 37: GeoScript

Web Applications

@GrabResolver(name="graffiti", root="http://simple-dm.googlecode.com/svn/repository")@Grab("com.goodercode:graffiti:1.0-SNAPSHOT")import graffiti.*import geoscript.geom.Geometry

@Get("/buffer")def buffer() {    Geometry.fromWKT(params.geom).buffer(params.distance as double).wkt}@Get("/centroid")def centroid() {    Geometry.fromWKT(params.geom).centroid.wkt}@Get("/convexHull")def convexHull() {    Geometry.fromWKT(params.geom).convexHull.wkt}

Graffiti.root 'graffiti'Graffiti.serve thisGraffiti.start()    

Graffiti Micro Web Framework

Page 38: GeoScript

Geometry Web Services 

Page 39: GeoScript

Geometry Web ServicesOpen Layers

function centroid() {   var features = vectorLayer.features;   if (features.length == 0) {      alert("Please add some features!");   } else {      OpenLayers.loadURL('centroid', {            geom: wktFormat.write(features)         },          this,          function(request) {            var wkt = request.responseText;            var features = wktFormat.read(wkt);            if (features) vectorLayer.addFeatures(features);         },          function() {            alert("Error calculating centroids!");         }      );   }}

Page 40: GeoScript

WMS Serverimport com.sun.grizzly.http.embed.GrizzlyWebServerimport com.sun.grizzly.http.servlet.ServletAdapterimport groovy.servlet.GroovySerlvet

@Grab(group='com.sun.grizzly',module='grizzly-servlet-webserver',  version='1.9.10')def start() {    def server = new GrizzlyWebServer(8080, "web")    def servlet = new ServletAdapter()    servlet.contextPath = "/geoscript"    servlet.servletInstance = new GroovyServlet()    server.addGrizzlyAdapter(servlet, ["/geoscript"] as String[])    server.start()}start()

Page 41: GeoScript

WMS Server...import geoscript.map.Mapimport geoscript.style.*import geoscript.layer.Shapefileimport geoscript.geom.Bounds

def file = new File("states.shp")def shp = new Shapefile(file)shp.style = new Fill("steelblue") + new Stroke("wheat", 0.1)

def map = new Map(    width: 256,     height: 256,     layers: [shp],    proj: shp.proj,    fixAspectRatio: false)

def bbox = request.getParameter("BBOX").split(",")def bounds = new Bounds(bbox[0] as double, bbox[1] as double, bbox[2] as double, bbox[3] as double)

map.bounds = boundsresponse.contentType = "image/png"map.render(response.outputStream)map.close()

Page 42: GeoScript

Geometry Command line echo "POINT (1 1)" | geoscript-groovy geom_buffer.groovy -d 10 | geoscript-groovy geom_envelope.groovy

def cli = new CliBuilder(usage: 'geoscript-groovy geom_buffer.groovy -d')cli.d(longOpt: 'distance', 'buffer distance', args:1)cli.h(longOpt: 'help', 'Show usage information and quit')def opt = cli.parse(args)if(!opt) returnif (opt.h || !opt.d) cli.usage()else println geoscript.geom.Geometry.fromWKT(System.in.text).buffer(opt.d as double).wkt

def cli = new CliBuilder(usage: 'geoscript-groovy geom_envelope.groovy')cli.h(longOpt: 'help', 'Show usage information and quit')def opt = cli.parse(args)if(!opt) returnif (opt.h) cli.usage()else println geoscript.geom.Geometry.fromWKT(System.in.text).bounds.geometry.wkt

geom_buffer.groovy

geom_envelope.groovy

Page 43: GeoScript

Road Map• Rendering Module• Raster Module• WPS/GeoServer plugin(s)• Map Printing

Page 44: GeoScript

Resources

Web Site    http://geoscript.org

Google Group    http://groups.google.com/group/geoscript

Blog    http://geoscriptblog.blogspot.com

GitHub    https://github.com/jdeolive/geoscript-py    https://github.com/tschaub/geoscript-js    https://github.com/dwins/geoscript.scala    https://github.com/jericks/geoscript-groovy    

Page 45: GeoScript

Thank you!