geoscript - spatial capabilities for scripting languages

52
GeoScript Spatial Capabilities for Scripting Languages Justin Deolivera, Tim Schaub, and Jared Erickson

Upload: justin-deoliveira

Post on 26-Jan-2015

134 views

Category:

Technology


7 download

DESCRIPTION

GeoScript adds spatial capabilities to dynamic scripting languages. With implementations in Python, JavaScript, Scala, and Groovy, GeoScript provides an interface to the powerful geospatial data access, processing and rendering functionality of the GeoTools library.GeoScript provides concise and simple apis that allow developers to perform a variety of tasks quickly. Some include:Geoprocessing - Coordinate reference system transforms, geometry operations, and feature queries.Data Juggling - GeoScript allows you to read and write feature data in a variety of formats. Converting Shapefiles to PostGIS tables, and processing on the fly while converting formats.Mapping Services - Using a simple web framework in conjunction with GeoScript, it is possible to write custom geospatial services quickly and easily like a simple WMS or WFS implementation. GeoScript is a new project but is growing in the number of users and contributors. Come check this talk out if you are interested in learning about a new tool to add to your geospatial hacking toolbox. Maybe you have tried to use GeoTools but find it too difficult and complex to use. Or perhaps your java skills are not where you would like them to be. If that is the case this talk, and GeoScript, might be just what you are looking for.

TRANSCRIPT

Page 1: GeoScript - Spatial Capabilities for Scripting Languages

GeoScriptSpatial Capabilities for Scripting Languages

Justin Deolivera, Tim Schaub, and Jared Erickson

Page 2: GeoScript - Spatial Capabilities for Scripting Languages

Introduction• What is GeoScript?

o Overview of languages• Motivation

o GeoTools hard, scripting easyo Development turnaround

• GeoScript Modules/API Overviewo Geometryo Projectiono Data Accesso Styling

Page 3: GeoScript - Spatial Capabilities for Scripting Languages

Scripting Platform for JVM Languages

• Similar API • Respect languages differences

Page 4: GeoScript - Spatial Capabilities for Scripting Languages

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 5: GeoScript - Spatial Capabilities for Scripting Languages

JavaScript

Not just for the browser any more!

Common JS module loading with Rhino.

One language for client & server code.

Docs: http://geoscript.org/js/Source: https://github.com/tschaub/geoscript-js/

Page 6: GeoScript - Spatial Capabilities for Scripting Languages

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 7: GeoScript - Spatial Capabilities for Scripting Languages

• Scalao Combine functional and object-oriented

programmingo Statically typedo REPLo Compiles to Java bytecodeo Full access to Java libraries

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

Scala

Page 8: GeoScript - Spatial Capabilities for Scripting Languages

On the shoulders of giants...

Page 9: GeoScript - Spatial Capabilities for Scripting Languages

GeoScript Modules

Page 10: GeoScript - Spatial Capabilities for Scripting Languages

Geometry

• Easy to use constructors• I/O

o WKT/WKBo JSONo GML

• Plotting• Transforms

Page 11: GeoScript - Spatial Capabilities for Scripting Languages

Geometry

>>> from geoscript import geom>>> geom.Point(30, 10)POINT(30 10)

Page 12: GeoScript - Spatial Capabilities for Scripting Languages

Geometry

>>> import geoscript.geom.*>>> line = new LineString([[111.0, -47], [123.0, -48], [110.0, -47]])

LINESTRING (111 -47, 123 -48, 110 -47)

Page 13: GeoScript - Spatial Capabilities for Scripting Languages

Geometry

js> var poly = geom.Point([10, 30]).  >     buffer(5)js> poly<Polygon [[[15, 30], [14.90...>

js> poly.area78.03612880645133

Page 14: GeoScript - Spatial Capabilities for Scripting Languages

Geometry - I/O

>>> from geoscript import geom>>> point = geom.Point(30, 10)>>> geom.writeKML(point)<kml:Point xmlns:kml="http://earth.google.com/kml/2.1"> <kml:coordinates>0.0,0.0</kml:coordinates></kml:Point>

Page 15: GeoScript - Spatial Capabilities for Scripting Languages

Geometry - I/O

>>> import geoscript.geom.Point>>> import geoscript.geom.io.Gml2Writer

>>> p = new Point(111, -47)

>>> gml = new Gml2Writer()>>> gml.write(p)<gml:Point> <gml:coordinates>111.0,-47.0</gml:coordinates></gml:Point>

Page 16: GeoScript - Spatial Capabilities for Scripting Languages

Geometry - I/O

js> var geom = require("geoscript/geom");

js> var point = geom.Point([1, 2])js> point.json{"type":"Point","coordinates":[1,2]}

Page 17: GeoScript - Spatial Capabilities for Scripting Languages

Geometry - Visualization

>>> 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)

Page 18: GeoScript - Spatial Capabilities for Scripting Languages

Geometry - Visualization

js> var geom = require("geoscript/geom")js> require("geoscript/viewer").bind() js> var poly1 = geom.Point([0, 0]).buffer(1)js> var poly2 = poly1.transform({dx: 0.5, dy: 0.5})js> poly1.difference(poly2)<Polygon [[[0.9095298326166407, -0.409529...>

Page 19: GeoScript - Spatial Capabilities for Scripting Languages

Projection

• Parse/encode WKT• Full GeoTools EPSG

database• Re-projection

Page 20: GeoScript - Spatial Capabilities for Scripting Languages

Projection

js> var proj = require("geoscript/proj");js> var p = proj.Projection("epsg:4326");js> p.wktGEOGCS["WGS 84",   DATUM["World Geodetic System 1984",   ...

Page 21: GeoScript - Spatial Capabilities for Scripting Languages

Projection

>>> from geoscript import geom>>> 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)]])

>>> p.transform(g, 'epsg:26912')>>> p.transform(g, 'epsg:3005')

Reprojection

WGS 84 UTM Albers

Page 22: GeoScript - Spatial Capabilities for Scripting Languages

Data Access

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

o GeoJSONo GML

Page 23: GeoScript - Spatial Capabilities for Scripting Languages

Data Access - Workspace

js> var ws = require("geoscript/workspace");       js> var dir = ws.Directory("data");  js> dir          <Directory ["states"]>

js> var states = dir.get("states");js> states<Layer name: states, count: 49>

Page 24: GeoScript - Spatial Capabilities for Scripting Languages

Data Access - Workspace

>> from geoscript.workspace import PostGIS

>> pg = PostGIS('spearfish')>> pg.layers()['archsites', 'bugsites', ..., 'streams']>> l = pg['archsites']

Page 25: GeoScript - Spatial Capabilities for Scripting Languages

Data Access - Workspace

>>> import geoscript.workspace.H2>>> import geoscript.geom.Point>>> import geoscript.feature.Feature

>>> h2 = new H2("name", "path")

>>> layer = h2.create("points", [    new Field("geom","Point"),    new Field("name","String")])

>>> layer.add([new Point[1,1],"one"])

Page 26: GeoScript - Spatial Capabilities for Scripting Languages

Data Access - Layers

>>> from geoscript.layer import Shapefile

>>> states = Shapefile('states.shp')>>> states = states.reproject('epsg:3005')

Page 27: GeoScript - Spatial Capabilities for Scripting Languages

Data Access - Layer Info

>>> import geoscript.layer.Shapefile>>> shp = new Shapefile("states.shp")>>> shp.count49>>> shp.bounds(-124.73142200000001, 24.955967,-66.969849, 49.371735, EPSG:4326)

>>> shp.schema.fields.each {  fld -> println fld}the_geom: MultiPolygon(EPSG:4326)STATE_NAME: StringSTATE_FIPS: StringSUB_REGION: StringSTATE_ABBR: String

Page 28: GeoScript - Spatial Capabilities for Scripting Languages

Data Access - Layers

js> var ws = require("geoscript/workspace");      js> var dir = ws.Directory("data");  js> var states = dir.get("states");

js> states.query("STATE_ABBR like 'M%'").forEach(  >     function(feature) {  >         print(feature.get("STATE_NAME"));  >     }  > )MarylandMissouriMississippi...

Page 29: GeoScript - Spatial Capabilities for Scripting Languages

Styling and Rendering

• Taming SLDo Symbolizerso Scale dependenceo Thematics

Page 30: GeoScript - Spatial Capabilities for Scripting Languages

Styling - Stroke

>>> from geoscript.style import Stroke

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

Page 31: GeoScript - Spatial Capabilities for Scripting Languages

Styling - Fill

>>> import geoscript.style.Fill

>>> new Fill("gray")>>> new Fill("gray", 0.5))>>> new Fill("gray").hatch("backslash")>>> new Stroke("red",2) + new Fill("gray").hatch("times")

Page 32: GeoScript - Spatial Capabilities for Scripting Languages

Styling - Shape and Icon

js> var style = require("geoscript/style");

js> style.Shape({name: "star", fill: "yellow"})<Shape name: 'star', size: 6>

js> style.Icon("rainy.svg")<Icon url: 'rainy.svg'>

Page 33: GeoScript - Spatial Capabilities for Scripting Languages

Styling - Labels

>>> from geoscript.style import Label,Stroke,Fill,Shape

>>> font = 'bold 16px Arial'>>> Shape() + Label('name',font)     .point(displace=(20,0))

>>> Stroke() + Label('name',font)     .linear(offset=10)

>>> Fill() + Label('name',font).halo('white',2)

Page 34: GeoScript - Spatial Capabilities for Scripting Languages

Styling - Scale

>>> new Shape('#004d96', 5).range(3000) + new Icon('school20.png').range(1500, 3000)+ new Icon('school40.png').range(-1, 1500)

Page 35: GeoScript - Spatial Capabilities for Scripting Languages

Styling - Theming

>>> from geoscript.style Stroke, Fill, Label

>>> style = Stroke() + Label('STATE_ABBR', 14, 'Serif')>>> 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')

Page 36: GeoScript - Spatial Capabilities for Scripting Languages

Demos

Page 37: GeoScript - Spatial Capabilities for Scripting Languages

Voronoi Diagram Exampleimport geoscript.layer.*import geoscript.feature.*import geoscript.geom.*

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

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

Page 38: GeoScript - Spatial Capabilities for Scripting Languages

Gradient  Examplevar Directory = require("geoscript/workspace").Directory;var {Fill, gradient} = require("geoscript/style");var Map = require("geoscript/map").Map;

var states = Directory("data").get("states");

states.style = gradient({    expression: "PERSONS / LAND_KM",     values: [0, 200],     styles: [Fill("#000066"), Fill("red")],    classes: 10,     method: "exponential"}).and(    Fill("red").where("PERSONS / LAND_KM > 200"));

var map = Map([states]);

map.render({path: "states.png"});

Page 39: GeoScript - Spatial Capabilities for Scripting Languages

Shapefile to PostGISfrom geoscript.workspace import Directory, PostGISshps = Directory('shapefiles')shps.layers()

archsites = shps['archsites']archsites.proj.id

pg = PostGIS('demo')pg.layers()for layer in shps:  reprojected = shps[layer].reproject('epsg:4326')  pg.add(reprojected, name=layer)

pg.layers()archsites = pg['archsites']archsites.proj.id

Page 40: GeoScript - Spatial Capabilities for Scripting Languages

Road Map

• Raster• Rendering• WPS/GeoServer• Map Printing

Page 41: GeoScript - Spatial Capabilities for Scripting Languages

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 42: GeoScript - Spatial Capabilities for Scripting Languages

Thank you!

Page 43: GeoScript - Spatial Capabilities for Scripting Languages

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 44: GeoScript - Spatial Capabilities for Scripting Languages

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 45: GeoScript - Spatial Capabilities for Scripting Languages

USGS Earth Quakes

Read RSS Feed to a Shapefile

Page 46: GeoScript - Spatial Capabilities for Scripting Languages

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 47: GeoScript - Spatial Capabilities for Scripting Languages

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 48: GeoScript - Spatial Capabilities for Scripting Languages

Geometry Web Services 

Page 49: GeoScript - Spatial Capabilities for Scripting Languages

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 50: GeoScript - Spatial Capabilities for Scripting Languages

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 51: GeoScript - Spatial Capabilities for Scripting Languages

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 52: GeoScript - Spatial Capabilities for Scripting Languages

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