= GIS Storage = [[TOC]] For portability, the default storage for Features is the normal database via Web2Py's [http://web2py.com/books/default/chapter/29/6 DAL]. In order to support Lines & Polygons we store as [http://en.wikipedia.org/wiki/Well-known_text WKT] * UI for Points can hide this behind simple !Lat/Lon * [http://pypi.python.org/pypi/Shapely/ Shapely] used to do conversion An option should be provided to store in [http://postgis.refractions.net PostGIS], [http://www.gaia-gis.it/spatialite Spatialite] or even [http://gitorious.org/geocouch/ GeoCouch] instead, where available, as then can have spatial indexes for speed. We can extend DAL for spatial support: * adding if deployment_settings.gis.spatialdb == True and deployment_settings.database.db_type == "postgres" to routines inside S3GIS' spaital functions to use optimised routines where possible & falling back to the existing Shapely routines. We could [http://groups.google.com/group/web2py/browse_thread/thread/7551b50ef3ca72a8 bypass DAL completely] & use an ORM like [http://geoalchemy.org/ GeoAlchemy]: {{{ response.custom_commit = lambda: do_commit() }}} == PostGIS == Since we store features in !Lat/Lon then we need to use the geography_columns, which stay updated automatically :) {{{ geog GEOGRAPHY(Point) geog GEOGRAPHY(Polygon) ST_Distance(geography, geography) returns double ST_DWithin(geography, geography, float8) returns boolean ST_Area(geography) returns double ST_Length(geography) returns double ST_Covers(geography, geography) returns boolean ST_CoveredBy(geography, geography) returns boolean ST_Intersects(geography, geography) returns boolean ST_Centroid(geometry) returns a point that is approximately on the center of mass of the input argument. This simple calculation is very fast, but sometimes not desirable, because the returned point is not necessarily in the feature itself. If the input feature has a convexity (imagine the letter ā€˜Cā€™) the returned centroid might not be in the interior of the feature. ST_PointOnSurface(geometry) returns a point that is guaranteed to be inside the input argument. It is substantially more computationally expensive than the centroid operation }}} == Options == Q: integrate [http://featureserver.org FeatureServer]? Q: copy [http://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/ GeoDjango]? == Extend DAL to support Spatial Queries == We need to support some extra SQL queries in DAL. I guess we have a PostGIS Adapter which inherits from the PostgreSQL one & a Spatialite adapter which inherits from the Sqlite one. Both should inherit the OpenGIS set of SQL syntax: * http://www.opengeospatial.org/standards/sfs We need to be able to do spatial queries like this: * http://postgis.refractions.net/docs/ST_Overlaps.html This one is our key performance bottleneck currently as we do BBOX filters on GeoJSON feature layers like this: * https://github.com/flavour/eden/blob/master/modules/s3/s3rest.py#L4612 Instead of this query: {{{ bbox_filter = ((table.lon > minLon) & (table.lon < maxLon) & (table.lat > minLat) & (table.lat < maxLat)) }}} We want to: {{{ bbox_filter = (table.ST_Overlaps([minLon, minLat, maxLon, maxLat])) }}} Full list of possible commands are here, but I don't expect all these to be implemented immediately (we can add additional ones as/when we need them if the hooks are right): * http://postgis.refractions.net/documentation/manual-1.3/ch06.html#id2574404 We also want to be able to specify that a table is spatialised, so an option to db.define_table(spatial=True). If this is on then we should send [http://postgis.refractions.net/docs/AddGeometryColumn.html AddGeometryColumn()] to the SQL Adapter NB A normal system would commonly only have a single spatial table, so this could be easily done out of band using a script, as I do now: * wiki:InstallationGuidelinesPostgreSQL#AddGeometrycolumntogis_location There are also some new field types, but I don't think we need to worry about those right now. ---- [wiki:BluePrint/GIS GIS BluePrints]