39adc44a3f
References #4676
282 lines
6.3 KiB
C
282 lines
6.3 KiB
C
/**********************************************************************
|
|
*
|
|
* PostGIS - Spatial Types for PostgreSQL
|
|
* http://postgis.net
|
|
*
|
|
* PostGIS is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* PostGIS is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
**********************************************************************
|
|
*
|
|
* ^copyright^
|
|
*
|
|
**********************************************************************/
|
|
|
|
#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;
|
|
POINT4D pt;
|
|
GSERIALIZED *geom;
|
|
|
|
if (PG_ARGISNULL(0))
|
|
PG_RETURN_NULL();
|
|
geom = PG_GETARG_GSERIALIZED_P(0);
|
|
|
|
if (gserialized_get_type(geom) != POINTTYPE)
|
|
elog(ERROR, "geometry_to_point only accepts Points");
|
|
|
|
if (gserialized_peek_first_point(geom, &pt) == LW_FAILURE)
|
|
PG_RETURN_NULL();
|
|
|
|
point = (Point *)palloc(sizeof(Point));
|
|
point->x = pt.x;
|
|
point->y = pt.y;
|
|
|
|
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;
|
|
uint32_t i;
|
|
const POINT2D *pt;
|
|
size_t size;
|
|
|
|
POSTGIS_DEBUG(2, "geometry_to_path called");
|
|
|
|
if ( PG_ARGISNULL(0) )
|
|
PG_RETURN_NULL();
|
|
|
|
geom = PG_GETARG_GSERIALIZED_P(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++ )
|
|
{
|
|
pt = getPoint2d_cp(pa, i);
|
|
(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;
|
|
uint32_t i;
|
|
size_t size;
|
|
|
|
POSTGIS_DEBUG(2, "geometry_to_polygon called");
|
|
|
|
if ( PG_ARGISNULL(0) )
|
|
PG_RETURN_NULL();
|
|
|
|
geom = PG_GETARG_GSERIALIZED_P(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++ )
|
|
{
|
|
const POINT2D *pt = getPoint2d_cp(pa, i);
|
|
(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);
|
|
}
|
|
|