]> granicus.if.org Git - postgis/commitdiff
Add casts from geometry::path, geometry::point, geometry::polygon, polygon::geometry...
authorPaul Ramsey <pramsey@cleverelephant.ca>
Fri, 28 Sep 2012 17:03:46 +0000 (17:03 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Fri, 28 Sep 2012 17:03:46 +0000 (17:03 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@10336 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
postgis/Makefile.in
postgis/geometry_inout.c
postgis/postgis.sql.in.c
regress/out_geometry.sql
regress/out_geometry_expected

diff --git a/NEWS b/NEWS
index 3239521f3026174bbd1818fb97a9a0244ee6f87a..55b42c4d63bf31430242b7fb9e5ec0d87213f017 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -24,10 +24,11 @@ PostGIS 2.1.0
     (Bborie Park / UC Davis)
   - Added array variants of ST_SetValues() to set many pixel values of a band
     in one call (Bborie Park / UC Davis)
-  - #1643, Tiger Geocoder - Tiger 2011 loader (Regina Obe / Paragon Corporation) 
-    Funded by Hunter Systems Group
+  - #1643, Tiger Geocoder - Tiger 2011 loader 
+    (Regina Obe / Paragon Corporation) Funded by Hunter Systems Group
   - GEOMETRYCOLLECTION support for ST_MakeValid (Sandro Santilli / Vizzuality)
   - ST_PixelOfValue (Bborie Park / UC Davis)
+  - Casts to/from PostgreSQL geotypes (point/path/polygon).
 
 * Enhancements *
   - #823, tiger geocoder: Make loader_generate_script download portion less greedy
index a0f4312b192ccd75dc86fa2987faaa6d189b101e..805a903f49ae90b8affd2e69bac4d36e64c80247 100644 (file)
@@ -59,7 +59,8 @@ PG_OBJS= \
        geography_estimate.o \
        geography_measurement.o \
        geography_measurement_trees.o \
-       geometry_estimate.o 
+       geometry_estimate.o \
+       geometry_inout.o
 
 # Objects to build using PGXS
 OBJS=$(PG_OBJS)
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..26a994fed040280e39728bf106f7cd1af88dc079 100644 (file)
@@ -0,0 +1,269 @@
+#include "postgres.h"
+#include "utils/geo_decls.h"
+
+#include "../postgis_config.h"
+
+#include "liblwgeom.h"         /* For standard geometry types. */
+#include "lwgeom_pg.h"       /* For debugging macros. */
+
+
+Datum geometry_to_point(PG_FUNCTION_ARGS);
+Datum point_to_geometry(PG_FUNCTION_ARGS);
+Datum geometry_to_path(PG_FUNCTION_ARGS);
+Datum path_to_geometry(PG_FUNCTION_ARGS);
+Datum geometry_to_polygon(PG_FUNCTION_ARGS);
+Datum polygon_to_geometry(PG_FUNCTION_ARGS);
+
+/**
+* Cast a PostgreSQL Point to a PostGIS geometry
+*/
+PG_FUNCTION_INFO_V1(point_to_geometry);
+Datum point_to_geometry(PG_FUNCTION_ARGS)
+{
+       Point *point;
+       LWPOINT *lwpoint;
+       GSERIALIZED *geom;
+
+       POSTGIS_DEBUG(2, "point_to_geometry called");
+
+       if ( PG_ARGISNULL(0) )
+               PG_RETURN_NULL();
+               
+       point = PG_GETARG_POINT_P(0);
+       
+       if ( ! point )
+               PG_RETURN_NULL();
+               
+       lwpoint = lwpoint_make2d(SRID_UNKNOWN, point->x, point->y);
+       geom = geometry_serialize(lwpoint_as_lwgeom(lwpoint));
+       lwpoint_free(lwpoint);
+       
+       PG_RETURN_POINTER(geom);
+}
+
+/**
+* Cast a PostGIS geometry to a PostgreSQL Point
+*/
+PG_FUNCTION_INFO_V1(geometry_to_point);
+Datum geometry_to_point(PG_FUNCTION_ARGS)
+{
+       Point *point;
+       LWGEOM *lwgeom;
+       LWPOINT *lwpoint;
+       GSERIALIZED *geom;
+
+       POSTGIS_DEBUG(2, "geometry_to_point called");
+
+       if ( PG_ARGISNULL(0) )
+               PG_RETURN_NULL();
+       
+       geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       
+       if ( gserialized_get_type(geom) != POINTTYPE )
+               elog(ERROR, "geometry_to_point only accepts Points");
+       
+       lwgeom = lwgeom_from_gserialized(geom);
+       
+       if ( lwgeom_is_empty(lwgeom) )
+               PG_RETURN_NULL();
+       
+       lwpoint = lwgeom_as_lwpoint(lwgeom);
+       
+       point = (Point*)palloc(sizeof(Point));
+       point->x = lwpoint_get_x(lwpoint);
+       point->y = lwpoint_get_y(lwpoint);
+       
+       lwpoint_free(lwpoint);
+       PG_FREE_IF_COPY(geom,0);
+       
+       PG_RETURN_POINT_P(point);
+}
+
+PG_FUNCTION_INFO_V1(geometry_to_path);
+Datum geometry_to_path(PG_FUNCTION_ARGS)
+{
+       PATH *path;
+       LWLINE *lwline;
+       LWGEOM *lwgeom;
+       GSERIALIZED *geom;
+       POINTARRAY *pa;
+       int i;
+       POINT2D pt;
+       size_t size;
+
+       POSTGIS_DEBUG(2, "geometry_to_path called");
+
+       if ( PG_ARGISNULL(0) )
+               PG_RETURN_NULL();
+               
+       geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       
+       if ( gserialized_get_type(geom) != LINETYPE )
+               elog(ERROR, "geometry_to_path only accepts LineStrings");
+       
+       lwgeom = lwgeom_from_gserialized(geom);
+       if ( lwgeom_is_empty(lwgeom) )
+               PG_RETURN_NULL();       
+       lwline = lwgeom_as_lwline(lwgeom);
+       
+       pa = lwline->points;
+    size = offsetof(PATH, p[0]) + sizeof(path->p[0]) * pa->npoints;
+    path = (PATH*)palloc(size);
+       SET_VARSIZE(path, size);
+       path->npts = pa->npoints;
+       path->closed = 0;
+       path->dummy = 0;
+
+       for ( i = 0; i < pa->npoints; i++ )
+       {
+               getPoint2d_p(pa, i, &pt);
+               (path->p[i]).x = pt.x;
+               (path->p[i]).y = pt.y;
+       }
+       
+       lwgeom_free(lwgeom);
+       PG_FREE_IF_COPY(geom,0);
+       
+       PG_RETURN_PATH_P(path);
+}
+
+
+PG_FUNCTION_INFO_V1(path_to_geometry);
+Datum path_to_geometry(PG_FUNCTION_ARGS)
+{
+       PATH *path;
+       LWLINE *lwline;
+       POINTARRAY *pa;
+       GSERIALIZED *geom;
+       POINT4D pt;
+       Point p;
+       int i;
+
+       POSTGIS_DEBUG(2, "path_to_geometry called");
+
+       if ( PG_ARGISNULL(0) )
+               PG_RETURN_NULL();
+               
+       path = PG_GETARG_PATH_P(0);
+
+       if ( ! path )
+               PG_RETURN_NULL();
+       
+       pa = ptarray_construct_empty(0, 0, path->npts);
+       for ( i = 0; i < path->npts; i++ )
+       {
+               p = path->p[i];
+               pt.x = p.x; 
+               pt.y = p.y;
+               ptarray_append_point(pa, &pt, LW_FALSE);
+       }
+       lwline = lwline_construct(SRID_UNKNOWN, NULL, pa);
+       geom = geometry_serialize(lwline_as_lwgeom(lwline));
+       lwline_free(lwline);
+       
+       PG_RETURN_POINTER(geom);
+}
+
+PG_FUNCTION_INFO_V1(geometry_to_polygon);
+Datum geometry_to_polygon(PG_FUNCTION_ARGS)
+{
+       POLYGON *polygon;
+       LWPOLY *lwpoly;
+       LWGEOM *lwgeom;
+       GSERIALIZED *geom;
+       POINTARRAY *pa;
+       GBOX gbox;
+       int i;
+       size_t size;
+
+       POSTGIS_DEBUG(2, "geometry_to_polygon called");
+
+       if ( PG_ARGISNULL(0) )
+               PG_RETURN_NULL();
+               
+       geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       
+       if ( gserialized_get_type(geom) != POLYGONTYPE )
+               elog(ERROR, "geometry_to_polygon only accepts Polygons");
+       
+       lwgeom = lwgeom_from_gserialized(geom);
+       if ( lwgeom_is_empty(lwgeom) )
+               PG_RETURN_NULL();       
+       lwpoly = lwgeom_as_lwpoly(lwgeom);
+       
+       pa = lwpoly->rings[0];
+
+    size = offsetof(POLYGON, p[0]) + sizeof(polygon->p[0]) * pa->npoints;
+    polygon = (POLYGON*)palloc0(size); /* zero any holes */
+       SET_VARSIZE(polygon, size);
+
+       polygon->npts = pa->npoints;    
+
+       lwgeom_calculate_gbox(lwgeom, &gbox);
+       polygon->boundbox.low.x = gbox.xmin;
+       polygon->boundbox.low.y = gbox.ymin;
+       polygon->boundbox.high.x = gbox.xmax;
+       polygon->boundbox.high.y = gbox.ymax;
+               
+       for ( i = 0; i < pa->npoints; i++ )
+       {
+               POINT2D pt;
+               getPoint2d_p(pa, i, &pt);
+               (polygon->p[i]).x = pt.x;
+               (polygon->p[i]).y = pt.y;
+       }
+
+       lwgeom_free(lwgeom);
+       PG_FREE_IF_COPY(geom,0);
+       
+       PG_RETURN_POLYGON_P(polygon);
+}
+
+
+PG_FUNCTION_INFO_V1(polygon_to_geometry);
+Datum polygon_to_geometry(PG_FUNCTION_ARGS)
+{
+       POLYGON *polygon;
+       LWPOLY *lwpoly;
+       POINTARRAY *pa;
+       POINTARRAY **ppa;
+       GSERIALIZED *geom;
+       Point p;
+       int i = 0, unclosed = 0;
+
+       POSTGIS_DEBUG(2, "polygon_to_geometry called");
+
+       if ( PG_ARGISNULL(0) )
+               PG_RETURN_NULL();
+               
+       polygon = PG_GETARG_POLYGON_P(0);
+
+       if ( ! polygon )
+               PG_RETURN_NULL();
+
+       /* Are first and last points different? If so we need to close this ring */
+       if ( memcmp( polygon->p, polygon->p + polygon->npts - 1, sizeof(Point) ) )
+       {
+               unclosed = 1;
+       }
+       
+       pa = ptarray_construct_empty(0, 0, polygon->npts + unclosed);
+               
+       for ( i = 0; i < (polygon->npts+unclosed); i++ )
+       {
+               POINT4D pt;
+               p = polygon->p[i % polygon->npts];
+               pt.x = p.x; 
+               pt.y = p.y;
+               ptarray_append_point(pa, &pt, LW_FALSE);
+       }
+       
+       ppa = palloc(sizeof(POINTARRAY*));
+       ppa[0] = pa;
+       lwpoly = lwpoly_construct(SRID_UNKNOWN, NULL, 1, ppa);  
+       geom = geometry_serialize(lwpoly_as_lwgeom(lwpoly));
+       lwpoly_free(lwpoly);
+       
+       PG_RETURN_POINTER(geom);
+}
+
index 5494a01edaf1037c76d84b7e91a814983fada36b..7887780740fc74d1b37f388cab4a6486b100f513 100644 (file)
@@ -113,6 +113,49 @@ CREATE OR REPLACE FUNCTION geometry(geometry, integer, boolean)
 CREATE CAST (geometry AS geometry) WITH FUNCTION geometry(geometry, integer, boolean) AS IMPLICIT;
 
 
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION geometry(point)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','point_to_geometry'
+       LANGUAGE 'c' IMMUTABLE STRICT; 
+
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION point(geometry)
+       RETURNS point
+       AS 'MODULE_PATHNAME','geometry_to_point'
+       LANGUAGE 'c' IMMUTABLE STRICT; 
+
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION geometry(path)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','path_to_geometry'
+       LANGUAGE 'c' IMMUTABLE STRICT; 
+
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION path(geometry)
+       RETURNS path
+       AS 'MODULE_PATHNAME','geometry_to_path'
+       LANGUAGE 'c' IMMUTABLE STRICT; 
+
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION geometry(polygon)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','polygon_to_geometry'
+       LANGUAGE 'c' IMMUTABLE STRICT; 
+
+-- Availability: 2.1.0
+CREATE OR REPLACE FUNCTION polygon(geometry)
+       RETURNS polygon
+       AS 'MODULE_PATHNAME','geometry_to_polygon'
+       LANGUAGE 'c' IMMUTABLE STRICT; 
+
+CREATE CAST (geometry AS point) WITH FUNCTION point(geometry);
+CREATE CAST (point AS geometry) WITH FUNCTION geometry(point);
+CREATE CAST (geometry AS path) WITH FUNCTION path(geometry);
+CREATE CAST (path AS geometry) WITH FUNCTION geometry(path);
+CREATE CAST (geometry AS polygon) WITH FUNCTION polygon(geometry);
+CREATE CAST (polygon AS geometry) WITH FUNCTION geometry(polygon);
+
 -------------------------------------------------------------------
 --  BOX3D TYPE
 -- Point coordinate data access
index c9789ad62799b6f2a4ae9c0c830d6e6bbb792041..f3fa4af66b785b8edcf80776dfe4bae4eacdade1 100644 (file)
@@ -145,6 +145,17 @@ SELECT 'geojson_options_14', ST_AsGeoJson(GeomFromEWKT('SRID=4326;LINESTRING(1 1
 SELECT 'geojson_options_15', ST_AsGeoJson(GeomFromEWKT('SRID=0;LINESTRING(1 1, 2 2, 3 3, 4 4)'), 0, 7);
 SELECT 'geojson_options_16', ST_AsGeoJson(GeomFromEWKT('SRID=4326;LINESTRING(1 1, 2 2, 3 3, 4 4)'), 0, 7);
 
+-- Out and in to PostgreSQL native geometric types
+WITH p AS ( SELECT '((0,0),(0,1),(1,1),(1,0),(0,0))'::text AS p ) 
+  SELECT 'pgcast_01', p = p::polygon::geometry::polygon::text FROM p;
+WITH p AS ( SELECT '[(0,0),(1,1)]'::text AS p ) 
+  SELECT 'pgcast_02', p = p::path::geometry::path::text FROM p;
+WITH p AS ( SELECT '(1,1)'::text AS p ) 
+  SELECT 'pgcast_03', p = p::point::geometry::point::text FROM p;
+SELECT 'pgcast_03','POLYGON EMPTY'::geometry::polygon IS NULL;
+SELECT 'pgcast_04','LINESTRING EMPTY'::geometry::path IS NULL;
+SELECT 'pgcast_05','POINT EMPTY'::geometry::point IS NULL;
+SELECT 'pgcast_06',ST_AsText('((0,0),(0,1),(1,1),(1,0))'::polygon::geometry);
 
 --
 -- Delete inserted spatial data
index 6e9d6ddf2b052516ffcf96b7c05aa3f0f39006f2..82b1a207c9043e5071e17c548397e541a9609c8f 100644 (file)
@@ -72,3 +72,10 @@ geojson_options_13|{"type":"LineString","coordinates":[[1,1],[2,2],[3,3],[4,4]]}
 geojson_options_14|{"type":"LineString","crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:EPSG::4326"}},"coordinates":[[1,1],[2,2],[3,3],[4,4]]}
 geojson_options_15|{"type":"LineString","bbox":[1,1,4,4],"coordinates":[[1,1],[2,2],[3,3],[4,4]]}
 geojson_options_16|{"type":"LineString","crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:EPSG::4326"}},"bbox":[1,1,4,4],"coordinates":[[1,1],[2,2],[3,3],[4,4]]}
+pgcast_01|t
+pgcast_02|t
+pgcast_03|t
+pgcast_03|t
+pgcast_04|t
+pgcast_05|t
+pgcast_06|POLYGON((0 0,0 1,1 1,1 0,0 0))