2004-04-26 23:05:20 +00:00
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "access/gist.h"
|
|
|
|
#include "access/itup.h"
|
|
|
|
#include "access/rtree.h"
|
|
|
|
|
|
|
|
#include "fmgr.h"
|
|
|
|
#include "utils/elog.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "lwgeom.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define DEBUG
|
|
|
|
|
|
|
|
#include "wktparse.h"
|
|
|
|
|
2004-08-17 15:27:47 +00:00
|
|
|
Datum combine_box2d(PG_FUNCTION_ARGS);
|
2004-08-24 10:01:16 +00:00
|
|
|
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_summary(PG_FUNCTION_ARGS);
|
|
|
|
Datum LWGEOM_npoints(PG_FUNCTION_ARGS);
|
2004-08-25 07:29:32 +00:00
|
|
|
Datum LWGEOM_area2d(PG_FUNCTION_ARGS);
|
2004-08-23 15:37:16 +00:00
|
|
|
Datum postgis_uses_stats(PG_FUNCTION_ARGS);
|
|
|
|
Datum postgis_scripts_released(PG_FUNCTION_ARGS);
|
|
|
|
Datum postgis_lib_version(PG_FUNCTION_ARGS);
|
2004-04-26 23:05:20 +00:00
|
|
|
|
2004-08-24 10:01:16 +00:00
|
|
|
|
|
|
|
// internal
|
2004-08-24 06:59:14 +00:00
|
|
|
char * lwgeom_summary_recursive(char *serialized, int offset);
|
2004-08-24 09:34:33 +00:00
|
|
|
int32 lwgeom_npoints_recursive(char *serialized);
|
2004-08-25 07:29:32 +00:00
|
|
|
double lwgeom_polygon_area2d(LWPOLY *poly);
|
2004-08-20 14:08:41 +00:00
|
|
|
|
2004-08-24 10:01:16 +00:00
|
|
|
/*------------------------------------------------------------------*/
|
2004-08-17 15:27:47 +00:00
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(combine_box2d);
|
|
|
|
Datum combine_box2d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Pointer box2d_ptr = PG_GETARG_POINTER(0);
|
|
|
|
Pointer geom_ptr = PG_GETARG_POINTER(1);
|
|
|
|
BOX2DFLOAT4 *a,*b;
|
|
|
|
char *lwgeom;
|
|
|
|
BOX2DFLOAT4 box, *result;
|
|
|
|
|
|
|
|
if ( (box2d_ptr == NULL) && (geom_ptr == NULL) )
|
|
|
|
{
|
|
|
|
PG_RETURN_NULL(); // combine_box2d(null,null) => null
|
|
|
|
}
|
|
|
|
|
|
|
|
result = (BOX2DFLOAT4 *)palloc(sizeof(BOX2DFLOAT4));
|
|
|
|
|
|
|
|
if (box2d_ptr == NULL)
|
|
|
|
{
|
|
|
|
lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
|
|
|
|
|
|
|
box = getbox2d(lwgeom+4);
|
|
|
|
memcpy(result, &box, sizeof(BOX2DFLOAT4));
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
// combine_bbox(BOX3D, null) => BOX3D
|
|
|
|
if (geom_ptr == NULL)
|
|
|
|
{
|
|
|
|
memcpy(result, (char *)PG_GETARG_DATUM(0), sizeof(BOX2DFLOAT4));
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
//combine_bbox(BOX3D, geometry) => union(BOX3D, geometry->bvol)
|
|
|
|
|
|
|
|
lwgeom = (char *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
|
|
|
box = getbox2d(lwgeom+4);
|
|
|
|
|
|
|
|
a = (BOX2DFLOAT4 *)PG_GETARG_DATUM(0);
|
|
|
|
b = &box;
|
|
|
|
|
|
|
|
result->xmax = LWGEOM_Maxf(a->xmax, b->xmax);
|
|
|
|
result->ymax = LWGEOM_Maxf(a->ymax, b->ymax);
|
|
|
|
result->xmin = LWGEOM_Minf(a->xmin, b->xmin);
|
|
|
|
result->ymin = LWGEOM_Minf(a->ymin, b->ymin);
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
2004-08-19 13:56:30 +00:00
|
|
|
|
|
|
|
//find the size of geometry
|
2004-08-24 10:01:16 +00:00
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_mem_size);
|
|
|
|
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
|
2004-08-19 13:56:30 +00:00
|
|
|
{
|
2004-08-23 10:49:08 +00:00
|
|
|
LWGEOM *geom = (LWGEOM *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
int32 size = geom->size;
|
|
|
|
int32 computed_size = lwgeom_seralizedformlength_simple(SERIALIZED_FORM(geom));
|
|
|
|
computed_size += 4; // varlena size
|
|
|
|
if ( size != computed_size )
|
|
|
|
{
|
|
|
|
elog(NOTICE, "varlena size (%d) != computed size+4 (%d)",
|
|
|
|
size, computed_size);
|
|
|
|
}
|
|
|
|
|
2004-08-20 09:31:32 +00:00
|
|
|
PG_FREE_IF_COPY(geom,0);
|
|
|
|
PG_RETURN_INT32(size);
|
2004-08-19 13:56:30 +00:00
|
|
|
}
|
2004-08-23 08:32:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns a palloced string containing summary for the serialized
|
|
|
|
* LWGEOM object
|
|
|
|
*/
|
|
|
|
char *
|
2004-08-23 10:49:08 +00:00
|
|
|
lwgeom_summary_recursive(char *serialized, int offset)
|
2004-08-23 08:32:14 +00:00
|
|
|
{
|
2004-08-23 10:49:08 +00:00
|
|
|
static int idx = 0;
|
2004-08-23 08:32:14 +00:00
|
|
|
LWGEOM_INSPECTED *inspected;
|
|
|
|
char *result;
|
|
|
|
char *ptr;
|
|
|
|
char tmp[100];
|
|
|
|
int size;
|
|
|
|
int32 j,i;
|
|
|
|
|
|
|
|
size = 1;
|
|
|
|
result = palloc(1);
|
|
|
|
result[0] = '\0';
|
|
|
|
|
2004-08-23 10:49:08 +00:00
|
|
|
if ( offset == 0 ) idx = 0;
|
|
|
|
|
2004-08-23 08:32:14 +00:00
|
|
|
inspected = lwgeom_inspect(serialized);
|
2004-08-23 10:49:08 +00:00
|
|
|
|
2004-08-23 08:32:14 +00:00
|
|
|
//now have to do a scan of each object
|
|
|
|
for (j=0; j<inspected->ngeometries; j++)
|
|
|
|
{
|
|
|
|
LWLINE *line=NULL;
|
|
|
|
LWPOINT *point=NULL;
|
|
|
|
LWPOLY *poly=NULL;
|
2004-08-23 10:49:08 +00:00
|
|
|
char *subgeom=NULL;
|
2004-08-23 08:32:14 +00:00
|
|
|
|
|
|
|
point = lwgeom_getpoint_inspected(inspected,j);
|
|
|
|
if (point !=NULL)
|
|
|
|
{
|
|
|
|
size += 30;
|
|
|
|
result = repalloc(result,size);
|
2004-08-23 10:49:08 +00:00
|
|
|
sprintf(tmp,"Object %i is a POINT()\n",
|
|
|
|
idx++);
|
2004-08-23 08:32:14 +00:00
|
|
|
strcat(result,tmp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
poly = lwgeom_getpoly_inspected(inspected, j);
|
|
|
|
if (poly !=NULL)
|
|
|
|
{
|
|
|
|
size += 57*(poly->nrings+1);
|
|
|
|
result = repalloc(result,size);
|
2004-08-23 10:49:08 +00:00
|
|
|
sprintf(tmp,"Object %i is a POLYGON() with %i rings\n",
|
|
|
|
idx++, poly->nrings);
|
2004-08-23 08:32:14 +00:00
|
|
|
strcat(result,tmp);
|
|
|
|
for (i=0; i<poly->nrings;i++)
|
|
|
|
{
|
|
|
|
sprintf(tmp," + ring %i has %i points\n",
|
|
|
|
i, poly->rings[i]->npoints);
|
|
|
|
strcat(result,tmp);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = lwgeom_getline_inspected(inspected, j);
|
|
|
|
if (line != NULL)
|
|
|
|
{
|
|
|
|
size += 57;
|
|
|
|
result = repalloc(result,size);
|
|
|
|
sprintf(tmp,
|
|
|
|
"Object %i is a LINESTRING() with %i points\n",
|
2004-08-23 10:49:08 +00:00
|
|
|
idx++, line->points->npoints);
|
2004-08-23 08:32:14 +00:00
|
|
|
strcat(result,tmp);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
subgeom = lwgeom_getsubgeometry_inspected(inspected, j);
|
|
|
|
if ( subgeom != NULL )
|
|
|
|
{
|
2004-08-23 10:49:08 +00:00
|
|
|
ptr = lwgeom_summary_recursive(subgeom, 1);
|
2004-08-23 08:32:14 +00:00
|
|
|
size += strlen(ptr);
|
|
|
|
result = repalloc(result,size);
|
|
|
|
strcat(result, ptr);
|
|
|
|
pfree(ptr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
elog(ERROR, "What ? lwgeom_getsubgeometry_inspected returned NULL??");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 10:49:08 +00:00
|
|
|
pfree_inspected(inspected);
|
2004-08-23 08:32:14 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//get summary info on a GEOMETRY
|
2004-08-24 10:01:16 +00:00
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_summary);
|
|
|
|
Datum LWGEOM_summary(PG_FUNCTION_ARGS)
|
2004-08-23 08:32:14 +00:00
|
|
|
{
|
|
|
|
LWGEOM *geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
char *result;
|
|
|
|
text *mytext;
|
|
|
|
|
2004-08-23 10:49:08 +00:00
|
|
|
result = lwgeom_summary_recursive(SERIALIZED_FORM(geom), 0);
|
2004-08-23 08:32:14 +00:00
|
|
|
|
|
|
|
// create a text obj to return
|
|
|
|
mytext = (text *) palloc(VARHDRSZ + strlen(result) );
|
|
|
|
VARATT_SIZEP(mytext) = VARHDRSZ + strlen(result) ;
|
|
|
|
memcpy(VARDATA(mytext) , result, strlen(result) );
|
|
|
|
pfree(result);
|
|
|
|
PG_RETURN_POINTER(mytext);
|
|
|
|
}
|
2004-08-23 15:37:16 +00:00
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(postgis_lib_version);
|
|
|
|
Datum postgis_lib_version(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *ver = POSTGIS_LIB_VERSION;
|
|
|
|
text *result;
|
|
|
|
result = (text *) palloc(VARHDRSZ + strlen(ver));
|
|
|
|
VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ;
|
|
|
|
memcpy(VARDATA(result), ver, strlen(ver));
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(postgis_scripts_released);
|
|
|
|
Datum postgis_scripts_released(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *ver = POSTGIS_SCRIPTS_VERSION;
|
|
|
|
text *result;
|
|
|
|
result = (text *) palloc(VARHDRSZ + strlen(ver));
|
|
|
|
VARATT_SIZEP(result) = VARHDRSZ + strlen(ver) ;
|
|
|
|
memcpy(VARDATA(result), ver, strlen(ver));
|
|
|
|
PG_RETURN_POINTER(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_FUNCTION_INFO_V1(postgis_uses_stats);
|
|
|
|
Datum postgis_uses_stats(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
#ifdef USE_STATS
|
|
|
|
PG_RETURN_BOOL(TRUE);
|
|
|
|
#else
|
|
|
|
PG_RETURN_BOOL(FALSE);
|
|
|
|
#endif
|
|
|
|
}
|
2004-08-24 09:34:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Recursively count points in a SERIALIZED lwgeom
|
|
|
|
*/
|
|
|
|
int32
|
|
|
|
lwgeom_npoints_recursive(char *serialized)
|
|
|
|
{
|
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(serialized);
|
|
|
|
int i, j;
|
|
|
|
int npoints=0;
|
|
|
|
|
|
|
|
//now have to do a scan of each object
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
LWLINE *line=NULL;
|
|
|
|
LWPOINT *point=NULL;
|
|
|
|
LWPOLY *poly=NULL;
|
|
|
|
char *subgeom=NULL;
|
|
|
|
|
|
|
|
point = lwgeom_getpoint_inspected(inspected, i);
|
|
|
|
if (point !=NULL)
|
|
|
|
{
|
|
|
|
npoints++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if (poly !=NULL)
|
|
|
|
{
|
|
|
|
for (j=0; j<poly->nrings; j++)
|
|
|
|
{
|
|
|
|
npoints += poly->rings[j]->npoints;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = lwgeom_getline_inspected(inspected, i);
|
|
|
|
if (line != NULL)
|
|
|
|
{
|
|
|
|
npoints += line->points->npoints;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
subgeom = lwgeom_getsubgeometry_inspected(inspected, i);
|
|
|
|
if ( subgeom != NULL )
|
|
|
|
{
|
|
|
|
npoints += lwgeom_npoints_recursive(subgeom);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
elog(ERROR, "What ? lwgeom_getsubgeometry_inspected returned NULL??");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return npoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
//number of points in an object
|
2004-08-24 10:01:16 +00:00
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_npoints);
|
|
|
|
Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
|
2004-08-24 09:34:33 +00:00
|
|
|
{
|
|
|
|
LWGEOM *geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
int32 npoints = 0;
|
|
|
|
|
|
|
|
npoints = lwgeom_npoints_recursive(SERIALIZED_FORM(geom));
|
|
|
|
|
|
|
|
PG_RETURN_INT32(npoints);
|
|
|
|
}
|
|
|
|
|
2004-08-25 07:29:32 +00:00
|
|
|
//find the 2d area of the outer ring - sum (area 2d of inner rings)
|
|
|
|
// Could use a more numerically stable calculator...
|
|
|
|
double lwgeom_polygon_area2d(LWPOLY *poly)
|
|
|
|
{
|
|
|
|
double poly_area=0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//elog(NOTICE,"in lwgeom_polygon_area2d (%d rings)", poly->nrings);
|
|
|
|
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
POINTARRAY *ring = poly->rings[i];
|
|
|
|
double ringarea = 0.0;
|
|
|
|
|
|
|
|
//elog(NOTICE," rings %d has %d points", i, ring->npoints);
|
|
|
|
for (j=0; j<ring->npoints-1; j++)
|
|
|
|
{
|
|
|
|
POINT2D *p1 = (POINT2D *)getPoint(ring, j);
|
|
|
|
POINT2D *p2 = (POINT2D *)getPoint(ring, j+1);
|
|
|
|
ringarea += ( p1->x * p2->y ) - ( p1->y * p2->x );
|
|
|
|
}
|
|
|
|
|
|
|
|
ringarea /= 2.0;
|
|
|
|
//elog(NOTICE," ring 1 has area %lf",ringarea);
|
|
|
|
ringarea = fabs(ringarea );
|
|
|
|
if (i != 0) //outer
|
|
|
|
ringarea = -1.0*ringarea ; // its a hole
|
|
|
|
|
|
|
|
poly_area += ringarea;
|
|
|
|
}
|
|
|
|
|
|
|
|
return poly_area;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the area of all the subobj in a polygon
|
|
|
|
// area(point) = 0
|
|
|
|
// area (line) = 0
|
|
|
|
// area(polygon) = find its 2d area
|
|
|
|
PG_FUNCTION_INFO_V1(LWGEOM_area2d);
|
|
|
|
Datum LWGEOM_area2d(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
LWGEOM *geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
|
|
|
LWGEOM_INSPECTED *inspected = lwgeom_inspect(SERIALIZED_FORM(geom));
|
|
|
|
LWPOLY *poly;
|
|
|
|
double area = 0.0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
//elog(NOTICE, "in LWGEOM_area2d");
|
|
|
|
|
|
|
|
for (i=0; i<inspected->ngeometries; i++)
|
|
|
|
{
|
|
|
|
poly = lwgeom_getpoly_inspected(inspected, i);
|
|
|
|
if ( poly == NULL ) continue;
|
|
|
|
area += lwgeom_polygon_area2d(poly);
|
|
|
|
//elog(NOTICE, " LWGEOM_area2d found a poly (%f)", area);
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree_inspected(inspected);
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(area);
|
|
|
|
}
|