[postgis-users] C question, PG_RETURN_POINTER
Nicolas Ribot
nicolas.ribot at scot.cnes.fr
Thu Apr 25 06:52:44 PDT 2002
Mr ONO, thank you for your answer,
Here is, attached to this mail, the file containing the c code I use,
and header file, with the 2 functions scot_gpc_read_polygon and
scot_gpc_write_polygon.
Nicolas Ribot.
Hisaji ONO wrote:
> Hello. Until last February, I've tackled with GPC library with
> shapelib for triangulation of polygons to create VRML files. I've
> tried to compile you code in Cygwin on NT 4.0 Sp6a, commneting out
> some functions. Could you show me two your "original" functions
> codes, "scot_gpc_read_polygon" and
> "scot_gpc_write_polygon"? Regards.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/postgis-users/attachments/20020425/81e8d78d/attachment.html>
-------------- next part --------------
/*************************************************************
First attempt to integrate GPC into postgis, by scot
*************************************************************/
#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 "utils/elog.h"
#include "scot_gpc.h"
PG_FUNCTION_INFO_V1(test_geo);
Datum test_geo(PG_FUNCTION_ARGS) {
GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
int32 *offsets1;
char *o1;
int32 type1,j,i;
POLYGON3D *poly;
LINE3D *line;
int32 numb_points = 0;
offsets1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;
//now have to do a scan of each object
for (j=0; j< geom1->nobjs; j++) //for each object in geom1
{
o1 = (char *) geom1 +offsets1[j] ;
type1= geom1->objType[j];
if (type1 == POINTTYPE) //point
{
numb_points ++;
}
if (type1 == LINETYPE) //line
{
line = (LINE3D *) o1;
numb_points += line->npoints;
}
if (type1 == POLYGONTYPE) //POLYGON
{
poly = (POLYGON3D *) o1;
for (i=0; i<poly->nrings;i++)
{
numb_points += poly->npoints[i];
}
}
}
PG_RETURN_INT32(numb_points);
}
/*
tests
very first gpc operation on 2 geometries
Works only on 2 real POLYGON object,
*/
PG_FUNCTION_INFO_V1(test_geogpc);
Datum test_geogpc(PG_FUNCTION_ARGS) {
GEOMETRY *geom1 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
GEOMETRY *geom2 = (GEOMETRY *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
GEOMETRY *result = (GEOMETRY *) palloc(sizeof(GEOMETRY) );
POLYGON3D *poly1;
POLYGON3D *poly2;
POLYGON3D *poly_res;
int32 *offset1;
int32 *offset2;
int poly_res_size;
char *o1;
char *o2;
// for debug only
int toto = 666;
/* gpc types */
gpc_polygon gpcsubject, gpcclip, gpcresult;
elog(NOTICE,"Entering test_geogpc. Int: %d", toto);
// looks at the input geometries type
if (geom1->type != POLYGONTYPE || geom2->type != POLYGONTYPE) {
elog(ERROR,"Incompatible types for 2 geometries (expected POLYGON)");
PG_RETURN_NULL();
}
elog(NOTICE,"geom type is polygon ");
if (geom1->SRID != geom2->SRID) {
elog(ERROR,"Operation on two GEOMETRIES with different SRIDs");
PG_RETURN_NULL();
}
elog(NOTICE,"SRID's are equals ");
// creates the 2 polygons and 2 gpc polygons on which operations will be done
offset1 = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs );
offset2 = (int32 *) ( ((char *) &(geom2->objType[0] ))+ sizeof(int32) * geom2->nobjs );
elog(NOTICE,"offsets set, hihi");
o1 = (char *) geom1 +offset1[0];
o2 = (char *) geom2 +offset2[0];
poly1 = (POLYGON3D *)o1;
poly2 = (POLYGON3D *)o2;
elog(NOTICE,"postgis polygon cast");
// creates gpc polygon from postgis polygons:
scot_gpc_read_polygon(poly1, &gpcsubject);
elog(NOTICE,"read first poly into gpcsubject");
scot_gpc_read_polygon(poly2, &gpcclip);
elog(NOTICE,"read first poly into gpcclip");
// perform the clipping operation (union geom1-geom2 for test)
gpc_polygon_clip(GPC_UNION, &gpcsubject, &gpcclip, &gpcresult);
elog(NOTICE,"clipping performed by gcp...");
//Convert result to opengis polygon:
poly_res = scot_gpc_write_polygon(&gpcresult, &poly_res_size);
elog(NOTICE,"poly_res written... poly_res_size: %d", poly_res_size);
result = make_oneobj_geometry(poly_res_size,
(char *)poly_res,
POLYGONTYPE,
FALSE,
geom1->SRID,
geom1->scale,
geom1->offsetX,
geom1->offsetY
);
elog(NOTICE,"result geometry made...");
elog(NOTICE,"result size: %d, SRID: %d, type: %d, nobjs: %d", result->size, result->SRID, result->type, result->nobjs);
// free memory for gpc polygons.
gpc_free_polygon(&gpcsubject);
gpc_free_polygon(&gpcclip);
gpc_free_polygon(&gpcresult);
elog(NOTICE,"gpc objects (3 polygons) freed.");
// free memory for postgis polygons ?
PG_FREE_IF_COPY(geom1, 0);
PG_FREE_IF_COPY(geom2, 1);
elog(NOTICE,"before return");
PG_RETURN_POINTER(result);
//PG_RETURN_NULL();
}
/*
add-on to GPC to allow the construction of a polygon from an array of coordinates instead of file
method should allow the construction of a GPC polygon from a postgis POLYGON or MULTIPOLYGON
// original method from gpc.c
void gpc_read_polygon(FILE *fp, int read_hole_flags, gpc_polygon *p) {
int c, v;
fscanf(fp, "%d", &(p->num_contours));
MALLOC(p->hole, p->num_contours * sizeof(int),
"hole flag array creation");
MALLOC(p->contour, p->num_contours
* sizeof(gpc_vertex_list), "contour creation");
for (c= 0; c < p->num_contours; c++)
{
fscanf(fp, "%d", &(p->contour[c].num_vertices));
if (read_hole_flags)
fscanf(fp, "%d", &(p->hole[c]));
else
p->hole[c]= FALSE;
MALLOC(p->contour[c].vertex, p->contour[c].num_vertices
* sizeof(gpc_vertex), "vertex creation");
for (v= 0; v < p->contour[c].num_vertices; v++)
fscanf(fp, "%lf %lf", &(p->contour[c].vertex[v].x),
&(p->contour[c].vertex[v].y));
}
}
No control is made on the input polygon3d geometry. Use this function with caution
Convention: when referening to gpc polygons, contour is the ring
for opengis poly, ring is a contour, first one is exterior, all other are holes.
CAUTION: postgis polygons have their last ring point = first one, must deal with this
when building gpc polygons.
*/
void scot_gpc_read_polygon(POLYGON3D *ppoly, gpc_polygon *p) {
int c, v;
// is the current polygon ring a hole ?
int isHole;
// the position of the current point in the array of points for the poly
int point_offset;
// the array of points for each ring
POINT3D *pts;
// First ring is always exterior for OpenGIS polygon
isHole = 0;
// copy the number of rings of the input polygon
p->num_contours = ppoly->nrings;
elog(NOTICE,"gpc_read_polygon: num rings to convert: %d", ppoly->nrings);
// allocates rings
MALLOC(p->hole, p->num_contours * sizeof(int), "hole flag array creation");
MALLOC(p->contour, p->num_contours * sizeof(gpc_vertex_list), "contour creation");
// gets the array of points for all the rings forming the polygon:
pts = (POINT3D *) ( (char *)&(ppoly->npoints[ppoly->nrings] ) );
pts = (POINT3D *) MAXALIGN(pts);
point_offset = 0;
// loop for each ring, num_countours is the number of rings in ppoly
for (c= 0; c < p->num_contours; c++) {
// num vertices for this ring: 1 less thant postgis polygon
p->contour[c].num_vertices = ppoly->npoints[c] - 1;
// set hole feature of this poly
p->hole[c] = isHole;
if (c == 0) {
// now first ring is treated, all other rings are holes
isHole = 1;
}
// allocates vertex for this ring
MALLOC(p->contour[c].vertex, p->contour[c].num_vertices * sizeof(gpc_vertex), "vertex creation");
// copies each vertex coordinates from opengis poly to gpc poly
for (v= 0; v < p->contour[c].num_vertices; v++) {
p->contour[c].vertex[v].x = pts[v].x;
p->contour[c].vertex[v].y = pts[v].y;
elog(NOTICE,"gpc_read_polygon: vertex read from ring %d: %f %f", c, p->contour[c].vertex[v].x, p->contour[c].vertex[v].y);
}
elog(NOTICE,"gpc_read_polygon: read %d vertices for ring %d", v, c);
//increments current ring offset: must go forward in the array of points to the next ring's first point,
// be careful that postgis polygons contain 1 more vertex than gpc polygon do
point_offset += ppoly->npoints[c];
}
}
/*
Write function, from GPC code
// original method from gpc.c
void gpc_write_polygon(FILE *fp, int write_hole_flags, gpc_polygon *p)
{
int c, v;
fprintf(fp, "%d\n", p->num_contours);
for (c= 0; c < p->num_contours; c++)
{
fprintf(fp, "%d\n", p->contour[c].num_vertices);
if (write_hole_flags)
fprintf(fp, "%d\n", p->hole[c]);
for (v= 0; v < p->contour[c].num_vertices; v++)
fprintf(fp, "% .*lf % .*lf\n",
DBL_DIG, p->contour[c].vertex[v].x,
DBL_DIG, p->contour[c].vertex[v].y);
}
}
Writes an existing gpc polygon into a newly created postgis polygon
No control is made on the input gpc polygon geometry. Use this function with caution
Convention: when referening to gpc polygons, contour is the ring
for opengis poly, ring is a contour, first one is exterior, all other are holes.
caution: the number of vertices in each gpc polygon is 1 less than the number in
postgis polygon, as OpenGIS says a ring must have its last point=first point.
Force this point in this code.
*/
POLYGON3D * scot_gpc_write_polygon(gpc_polygon *p, int *ppoly_size) {
int c, v;
// The array of points: total number of points for all rings
POINT3D *pts;
POLYGON3D *ppoly; /*the result*/
int num_vertices = 0;
// array of points per ring
int *pts_per_ring;
elog(NOTICE,"gpc_write_polygon: num rings to write: %d", p->num_contours);
// first, creates a new polygon from scratch.
pts_per_ring = malloc(p->num_contours * sizeof(int));
for (c = 0; c < p->num_contours; c++) {
num_vertices += p->contour[c].num_vertices + 1; /* reserve an extra point */
pts_per_ring[c] = p->contour[c].num_vertices + 1;
}
pts = malloc(num_vertices * sizeof(POINT3D));
//loop for all contours to take their vertices
// no holes to take into account as postgis will treat them correctly
// adds the first point at the end to close the postgis ring
for (c= 0; c < p->num_contours; c++) {
for (v = 0; v < p->contour[c].num_vertices; v++) {
set_point( &pts[c+v], p->contour[c].vertex[v].x, p->contour[c].vertex[v].y, 0.0);
elog(NOTICE,"gpc_write_polygon: coord written: %f %f", p->contour[c].vertex[v].x, p->contour[c].vertex[v].y);
}
// adds the first point at the end to close the postgis ring
set_point( &pts[c+v+1], p->contour[c].vertex[0].x, p->contour[c].vertex[0].y, 0.0);
elog(NOTICE,"gpc_write_polygon: coord written: %f %f", p->contour[c].vertex[0].x, p->contour[c].vertex[0].y);
elog(NOTICE,"gpc_write_polygon: written %d vertices for ring: %d", v+1, c);
}
//make the polygon
ppoly = make_polygon(p->num_contours, pts_per_ring, pts, num_vertices, ppoly_size);
// checks the produced postgis polygon.
elog(NOTICE,"num rings in res: %d", ppoly->nrings);
elog(NOTICE,"num vertices for exterior: %d", ppoly->npoints[0]);
elog(NOTICE,"size of this object %d", size_subobject ((char*)ppoly, POLYGONTYPE));
elog(NOTICE,"pointer value: %d", (int)ppoly);
return ppoly;
}
-------------- next part --------------
#include "utils/geo_decls.h"
#include "postgis.h"
#include "gpc.h"
// taken from gpc.c to avoid inclusion:
#define MALLOC(p, b, s) {if ((b) > 0) { \
p= malloc(b); if (!(p)) { \
fprintf(stderr, "gpc malloc failure: %s\n", s); \
exit(0);}} else p= NULL;}
// geo functions
Datum test_geo(PG_FUNCTION_ARGS);
Datum test_geo_2(PG_FUNCTION_ARGS);
Datum test_geogpc(PG_FUNCTION_ARGS);
// transformation functions:
void scot_gpc_read_polygon(POLYGON3D *ppoly, gpc_polygon *p);
//void scot_gpc_write_polygon(gpc_polygon *p, POLYGON3D *ppoly, int *ppoly_size);
POLYGON3D * scot_gpc_write_polygon(gpc_polygon *p, int *ppoly_size);
More information about the postgis-users
mailing list