Spatial / GIS support (in latest trunk) ===================== Sponsored by AidIQ for use by Sahana Eden
available for (so far) ++++++++++++++++++++++ 1) Postgres + PostGIS http://postgis.refractions.net/docs/ 2) MS SQL http://msdn.microsoft.com/en-us/library/ff848797.aspx SQLite + Spatialite next. Both geometry and geography fields are supported. supported functions (so far) ++++++++++++++++++++++++++++ st_asgeojson (PostGIS only) st_astext st_contained st_contains st_distance st_equals st_intersects st_overlaps st_simplify (PostGIS only) st_touches st_within Some MS SQL examples ++++++++++++++++++++ dbm = DAL(r"mssql://user:pass@host:db") sp = dbm.define_table('spatial', Field('geo1','geometry()') ) # a point sp.insert(geo1="POINT (1 2)") 1 # a line sp.insert(geo1="LINESTRING (100 100, 20 180, 180 180)") 2 # a polygon (a square in this case) sp.insert(geo1="POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))") 3 rr=dbm(sp.id>0).select() print rr spatial.id,spatial.geo1 1, 2, 3, # why doesn't it display geo1? # field geo1 has an undisplayable internal representation in MS SQL # e.g. the first record's POINT(1 2) is stored as # 0x00000000010C000000000000F03F0000000000000040 # to visualize as WKT use function st_astext rr=dbm(sp.id>0).select(sp.id, sp.geo1.st_astext()) print rr spatial.id,spatial.geo1.STAsText() 1,POINT (1 2) 2,"LINESTRING (100 100, 20 180, 180 180)" 3,"POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))" # or using an alias rr=dbm(sp.id>0).select(sp.id, sp.geo1.st_astext().with_alias('g1')) for r in rr: print r.spatial.id, r.g1 ... 1 POINT (1 2) 2 LINESTRING (100 100, 20 180, 180 180) 3 POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0)) # other functions # STContains rr=dbm(sp.geo1.st_contains("POINT(1 1)")).select(sp.id,sp.geo1.st_astext()) print rr spatial.id,spatial.geo1.STAsText() 3,"POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))" # STDistance rr=dbm(sp.id>0).select(sp.id, sp.geo1.st_distance("POINT(-1 2)").with_alias('d')) for r in rr: print r.spatial.id, r.d ... 1 2.0 2 140.714249456 3 1.0 # STIntersects rr=dbm(sp.geo1.st_intersects("LINESTRING(20 120,60 160)")).select(sp.id,sp.geo1.st_astext()) print rr spatial.id,spatial.geo1.STAsText() 2,"LINESTRING (100 100, 20 180, 180 180)" 3,"POLYGON ((0 0, 150 0, 150 150, 0 150, 0 0))" Some PostGIS examples +++++++++++++++++++++ #pg is the postgres db connection pg.define_table('franchise', Field('code', 'string', length=1), Field('name'), ) pg.define_table('fastfood', Field('franchise', 'reference franchise'), Field('lat', 'double'), Field('lon', 'double'), Field('geom', 'geometry()'), ) # parameters for geom fields are: schema, srid and dimension # e.g. Field('geom', 'geometry('',4326,2)') # hard-coded defaults: srid=4326, dimension=2 # migration works, fields are added/dropped as required. pg.franchise.insert(code='b', name='Burger Joint') pg.fastfood.insert(franchise=1,lat=25.8092,lon=-80.24,geom='POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))') pg.commit() ff=pg.fastfood q=ff.geom.st_overlaps('POLYGON((1 1,5 1,5 5,1 5,1 1))') print pg(q).select() fastfood.id,fastfood.franchise,fastfood.lat,fastfood.lon,fastfood.geom # no records, there are no overlaps q=ff.geom.st_overlaps('POLYGON((1 1,11 1,11 11,11 1,1 1))') print pg(q).select() fastfood.id,fastfood.franchise,fastfood.lat,fastfood.lon,fastfood.geom 1,1,25.8092,-80.24,0103000020E61000000100000005000000000000000000000000000000000 00000000000000000244000000000000000000000000000002440000000000000244000000000000 00000000000000000244000000000000000000000000000000000 print pg(ff.id>0).select(ff.id,ff.franchise,ff.lat,ff.lon,ff.geom.st_simplify(1).st_astext()) fastfood2.id,fastfood2.franchise,fastfood2.lat,fastfood2.lon,"ST_AsText(ST_Simplify(fastfood2.geom, 1.0))" 1,1,25.8092,-80.24,"POLYGON((0 0,10 0,10 10,0 10,0 0))" # geography example pg.define_table('airport', Field('code','string',3), Field('geog','geography()'), ) a=pg.airport a.insert(code='LAX', geog='POINT(-118.4079 33.9434)') 1 a.insert(code='CDG', geog='POINT(2.5559 49.0083)') 2 a.insert(code='REK', geog='POINT(-21.8628 64.1286)') 3 lax="POINT(-118.4079 33.9434)" rr=pg(a.id>0).select(a.code,a.geog.st_distance(lax).with_alias('from_lax')) for r in rr: print r.airport.code, r.from_lax ... LAX,0.0 CDG,9124665.26917 REK,6969660.54628 # results are in meters rr=pg(a.id>0).select(a.code,a.geog.st_asgeojson().with_alias('geojson')) for r in rr: print r.airport.code, r.geojson ... LAX {"type":"Point","coordinates":[-118.4079,33.943399999999997]} CDG {"type":"Point","coordinates":[2.5559,49.008299999999998]} REK {"type":"Point","coordinates":[-21.8628,64.128600000000006]} More to come... Denes Lengyel.