+#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);
+}
+
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
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