GeoScript - Spatial Capabilities for Scripting Languages
-
Upload
justin-deoliveira -
Category
Technology
-
view
134 -
download
7
description
Transcript of GeoScript - Spatial Capabilities for Scripting Languages
GeoScriptSpatial Capabilities for Scripting Languages
Justin Deolivera, Tim Schaub, and Jared Erickson
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
Scripting Platform for JVM Languages
• Similar API • Respect languages differences
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
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/
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
• 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
On the shoulders of giants...
GeoScript Modules
Geometry
• Easy to use constructors• I/O
o WKT/WKBo JSONo GML
• Plotting• Transforms
Geometry
>>> from geoscript import geom>>> geom.Point(30, 10)POINT(30 10)
Geometry
>>> import geoscript.geom.*>>> line = new LineString([[111.0, -47], [123.0, -48], [110.0, -47]])
LINESTRING (111 -47, 123 -48, 110 -47)
Geometry
js> var poly = geom.Point([10, 30]). > buffer(5)js> poly<Polygon [[[15, 30], [14.90...>
js> poly.area78.03612880645133
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>
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>
Geometry - I/O
js> var geom = require("geoscript/geom");
js> var point = geom.Point([1, 2])js> point.json{"type":"Point","coordinates":[1,2]}
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)
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...>
Projection
• Parse/encode WKT• Full GeoTools EPSG
database• Re-projection
Projection
js> var proj = require("geoscript/proj");js> var p = proj.Projection("epsg:4326");js> p.wktGEOGCS["WGS 84", DATUM["World Geodetic System 1984", ...
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
Data Access
• Read and Write Layers• Query Layers using CQL• I/O
o GeoJSONo GML
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>
Data Access - Workspace
>> from geoscript.workspace import PostGIS
>> pg = PostGIS('spearfish')>> pg.layers()['archsites', 'bugsites', ..., 'streams']>> l = pg['archsites']
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"])
Data Access - Layers
>>> from geoscript.layer import Shapefile
>>> states = Shapefile('states.shp')>>> states = states.reproject('epsg:3005')
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
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...
Styling and Rendering
• Taming SLDo Symbolizerso Scale dependenceo Thematics
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')
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")
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'>
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)
Styling - Scale
>>> new Shape('#004d96', 5).range(3000) + new Icon('school20.png').range(1500, 3000)+ new Icon('school40.png').range(-1, 1500)
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')
Demos
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]))
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"});
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
Road Map
• Raster• Rendering• WPS/GeoServer• Map Printing
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
Thank you!
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()
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)}
USGS Earth Quakes
Read RSS Feed to a Shapefile
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++}
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
Geometry Web Services
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!"); } ); }}
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()
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()
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