GeoScript Spatial Capabilities for Scripting Languages Justin Deolivera and Jared Erickson.
-
Upload
crystal-ross -
Category
Documents
-
view
226 -
download
3
Transcript of GeoScript Spatial Capabilities for Scripting Languages Justin Deolivera and Jared Erickson.
GeoScriptSpatial Capabilities for Scripting Languages
Justin Deolivera and Jared Erickson
Scripting Platform for JVM Languages
Similar API Respect languages differences Python GeoScript should be PythonicMake easy things easy, Make hard things possible
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
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 typed???o 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...
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
GeoScript Modules
GeoScript Modules
• Geometry• Projection• Feature• Layer• Workspace• Style• Renderer
Geometry
• Convenient constructors• I/O
o WKT/WKBo JSONo GML
• Plotting• Transforms
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
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
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
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
Projection
• Parse/encode WKT• Full GeoTools EPSG
database• Re-projection
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
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
Data Access
• Read and Write Layers• Query Layers using CQL• I/O
o GeoJSONo GML
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
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
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
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
Styling and Rendering
• Taming SLDo Symbolizerso Scale dependenceo Thematics
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
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
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
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
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
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
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
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()
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]))
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
Road Map• Rendering Module• Raster Module• WPS/GeoServer plugin(s)• 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!