Soporte GIS / Espacial en DAL (trunk)
=====================
Patrocinado por AidIQ para ser usado en Sahana Eden
Disponible para (por ahora)
++++++++++++++++++++++
1) Postgres + PostGIS
http://postgis.refractions.net/docs/
2) MS SQL
http://msdn.microsoft.com/en-us/library/ff848797.aspx
SQLite + Spatialite pronto.
Soporte para campos geometry y geography.
Funciones (por ahora)
++++++++++++++++++++++++++++
st_asgeojson (solo PostGIS)
st_astext
st_contained
st_contains
st_distance
st_equals
st_intersects
st_overlaps
st_simplify (solo PostGIS)
st_touches
st_within
Algunos ejemplos con MS SQL
++++++++++++++++++++
dbm = DAL(r"mssql://user:pass@host:db")
sp = dbm.define_table('spatial',
Field('geo1','geometry()')
)
# un punto
sp.insert(geo1="POINT (1 2)")
1
# una linea
sp.insert(geo1="LINESTRING (100 100, 20 180, 180 180)")
2
# un poligono (un cuadrado en este caso)
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,
# porque no muestra el campo geo1?
# porque geo1 tiene una representacion interna binaria en MS SQL
# e.g. el punto del primer registro se guarda como
# 0x00000000010C000000000000F03F0000000000000040
# para visualizarlo use la funcion 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))"
# o usando un 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))
# otras funciones
# 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))"
Algunos ejemplos PostGIS
+++++++++++++++++++++
#pg es la conexion a la BD PostGres
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()'),
)
# los parametros para campos geometry son:
# schema, srid y dimension
# e.g. Field('geom', 'geometry('',4326,2)')
# los valores por defecto son: srid=4326, dimension=2
# la migracion funciona, los campos se agregan o
# eliminan segun sea requerido.
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
# resultado nulo, no hay ninguna sobreposicion
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))"
# ejemplo geografico
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
# los resultados vienen en metros
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]}
Continuara...
Denes Lengyel