Commits

Anonymous committed 967296d

added the possibility to insert geometries with a different srid than the one used for the geometry column

Comments (0)

Files changed (6)

 This tutorial requires a working PostGIS installation. The PostGIS
 Documentation has extensive `installation instructions
 <http://postgis.refractions.net/docs/ch02.html#PGInstall>`_. Create a
-spatially enabled database called `gis` as per instructions given
-`here <http://postgis.refractions.net/docs/ch02.html#id2532099>`_. Also
+spatially enabled database called `gis` as per instructions given in the
+`PostGIS documentation <http://postgis.refractions.net/docs/ch02.html#id2532099>`_. Also
 create a new user and grant it permissions on this database.
 
 On Ubuntu the following steps have to executed to create the database.
 the tables using mapper configuration, or they can be defined
 declaratively using the new declarative extension. In this example we
 use the SQLAlchemy declarative extension to define the model. Notes on how to use
-GeoAlchemy with a non-declarative mapping can be found `here
+GeoAlchemy with a non-declarative mapping are stated `below
 <#notes-on-non-declarative-mapping>`_. We also
 create a metadata object that holds the schema information of all
 database objects and will thus be useful for creating the objects in
     session.add_all([spot1, spot2, road1, road2, lake1, lake2])
     session.commit()
 
+If you want to insert a geometry that has a different spatial reference system than your
+geometry column, a transformation is added automatically.
+
+.. code-block:: python
+
+    geom_spot3 = WKTSpatialElement('POINT(30250865 -610981)', 2249)
+    spot3 = Spot(name="Park", height=53.2, geom=geom_spot3)
+    session.add(spot3)
+    session.commit()
+
 Scripts for creating sample gis objects as shown above are available
 in the `examples directory
 <http://bitbucket.org/sanjiv/geoalchemy/src/tip/examples/>`_. You could run those scripts to create the

examples/tutorial.py

 session.add_all([spot1, spot2, road1, road2, lake1, lake2])
 session.commit()
 
+# Insert a geometry with a different SRID
+geom_spot3 = WKTSpatialElement('POINT(30250865 -610981)', 2249)
+spot3 = Spot(name="Park", height=53.2, geom=geom_spot3)
+session.add(spot3)
+session.commit()

geoalchemy/base.py

 
 # ORM integration
 
-def _to_gis(value):
+def _to_gis(value, srid_db):
     """Interpret a value as a GIS-compatible construct."""
 
     if hasattr(value, '__clause_element__'):
         return value.__clause_element__()
+    elif isinstance(value, SpatialElement):
+        if isinstance(value.desc, (WKBSpatialElement, WKTSpatialElement)):
+            return _check_srid(value.desc, srid_db)
+        return _check_srid(value, srid_db)
+    elif isinstance(value, basestring):
+        return _check_srid(WKTSpatialElement(value), srid_db)
     elif isinstance(value, expression.ClauseElement):
         return value
-    elif isinstance(value, SpatialElement):
-        if isinstance(value.desc, (WKBSpatialElement, WKTSpatialElement)):
-            return value.desc
-        return value
-    elif isinstance(value, basestring):
-        return WKTSpatialElement(value)
     elif value is None:
         return None
     else:
         raise Exception("Invalid type")
+    
+def _check_srid(spatial_element, srid_db):
+    """Check if the SRID of the spatial element which we are about to insert
+    into the database equals the SRID used for the geometry column.
+    If not, a transformation is added.
+    """
+    if srid_db is None or not hasattr(spatial_element, 'srid'):
+        return spatial_element
+    
+    if spatial_element.srid == srid_db:
+        return spatial_element
+    else:
+        return functions.transform(spatial_element, srid_db)
 
 class SpatialComparator(ColumnProperty.ColumnComparator):
     """Intercepts standard Column operators on mapped class attributes

geoalchemy/geometry.py

     """
     
     def set(self, state, value, oldvalue, initiator):
-        return _to_gis(value)
+        return _to_gis(value, self.__get_srid(initiator))
+ 
+    def __get_srid(self, initiator):
+        """Returns the SRID used for the geometry column that is connected
+        to this SpatialAttribute instance."""
+        try:
+            return initiator.parent_token.columns[0].type.srid
+        except Exception:
+            return None
  
 class GeometryExtensionColumn(Column):
     pass

geoalchemy/tests/test_postgis.py

     def test_persistent(self):
         eq_(session.scalar(functions.wkt(func.GeomFromWKB(self.r.road_geom.wkb, 4326))), 
             u'LINESTRING(-88.6748409363057 43.1035032292994,-88.6464173694267 42.9981688343949,-88.607961955414 42.9680732929936,-88.5160033566879 42.9363057770701,-88.4390925286624 43.0031847579618)')
-
+        
+        geom = WKTSpatialElement('POINT(30250865.9714116 -610981.481754275)', 2249)
+        spot = Spot(spot_height=102.34, spot_location=geom)
+        session.add(spot)
+        session.commit();
+        assert_almost_equal(session.scalar(spot.spot_location.x), 0)
+        assert_almost_equal(session.scalar(spot.spot_location.y), 0)
+        
     def test_eq(self):
         r1 = session.query(Road).filter(Road.road_name=='Graeme Ave').one()
         r2 = session.query(Road).filter(Road.road_geom == 'LINESTRING(-88.5477708726115 42.6988853949045,-88.6096339299363 42.9697452675159,-88.6029460318471 43.0884554585987,-88.5912422101911 43.187101955414)').one()

geoalchemy/tests/test_spatialite.py

         eq_(session.scalar(functions.wkt(func.GeomFromWKB(self.r.road_geom.wkb, 4326))), 
             u'LINESTRING(-88.674841 43.103503, -88.646417 42.998169, -88.607962 42.968073, -88.516003 42.936306, -88.439093 43.003185)')
 
+        geom = WKTSpatialElement('POINT(30250865.9714116 -610981.481754275)', 2249)
+        spot = Spot(spot_height=102.34, spot_location=geom)
+        session.add(spot)
+        session.commit();
+        assert_almost_equal(session.scalar(spot.spot_location.x), 0)
+        assert_almost_equal(session.scalar(spot.spot_location.y), 0)
+
     def test_svg(self):
         eq_(session.scalar(self.r.road_geom.svg), 'M -88.674841 -43.103503 -88.646417 -42.998169 -88.607962 -42.968073 -88.516003 -42.936306 -88.439093 -43.003185 ')