Fixed bug in box3d computation.

Dropped obsoleted LWGEOM_EXPLODED structure and associated functions.


git-svn-id: http://svn.osgeo.org/postgis/trunk@1555 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
Sandro Santilli 2005-03-23 16:23:45 +00:00
parent 7b327f64f2
commit 5115b8221c
3 changed files with 27 additions and 671 deletions

View file

@ -596,49 +596,6 @@ typedef struct
extern int lwgeom_size_inspected(const LWGEOM_INSPECTED *inspected, int geom_number);
/*
* This structure is intended to be used for geometry collection construction.
* Does not allow specification of collection structure
* (serialization chooses the simpler form)
*/
typedef struct
{
int SRID;
uchar dims;
uint32 npoints;
uchar **points;
uint32 nlines;
uchar **lines;
uint32 npolys;
uchar **polys;
} LWGEOM_EXPLODED;
void pfree_exploded(LWGEOM_EXPLODED *exploded);
// Returns a 'palloced' union of the two input exploded geoms.
// Returns NULL if SRID or ndims do not match.
LWGEOM_EXPLODED * lwexploded_sum(LWGEOM_EXPLODED *exp1, LWGEOM_EXPLODED *exp2);
/*
* This function recursively scan the given serialized geometry
* and returns a list of _all_ subgeoms in it (deep-first)
*/
extern LWGEOM_EXPLODED *lwgeom_explode(uchar *serialized);
/*
* Return the length of the serialized form corresponding
* to this exploded structure.
*/
extern size_t lwexploded_findlength(LWGEOM_EXPLODED *exp, int wantbbox);
// Serialize an LWGEOM_EXPLODED object.
// SRID and ndims will be taken from exploded structure.
// wantbbox will determine result bbox.
extern uchar *lwexploded_serialize(LWGEOM_EXPLODED *exploded, int wantbbox);
// Same as lwexploded_serialize but writing to pre-allocated space
extern void lwexploded_serialize_buf(LWGEOM_EXPLODED *exploded, int wantbbox, uchar *buf, size_t *retsize);
// note - for a simple type (ie. point), this will have sub_geom[0] = serialized_form.
// for multi-geomtries sub_geom[0] will be a few bytes into the serialized form
// This function just computes the length of each sub-object and pre-caches this info.
@ -777,6 +734,7 @@ extern void pfree_POINTARRAY(POINTARRAY *pa);
extern uint32 get_uint32(const uchar *loc);
extern int32 get_int32(const uchar *loc);
extern void printBOX3D(BOX3D *b);
extern void printPA(POINTARRAY *pa);
extern void printLWPOINT(LWPOINT *point);
extern void printLWLINE(LWLINE *line);
@ -1042,7 +1000,6 @@ extern POINTARRAY *ptarray_addPoint(POINTARRAY *pa, uchar *p, size_t pdims, unsi
extern int ptarray_isclosed2d(const POINTARRAY *pa);
extern int32 lwgeom_nrings_recursive(uchar *serialized);
extern void dump_lwexploded(LWGEOM_EXPLODED *exploded);
extern void ptarray_reverse(POINTARRAY *pa);
// Ensure every segment is at most 'dist' long.

View file

@ -8,14 +8,10 @@
#include "liblwgeom.h"
//#define PGIS_DEBUG 1
//#define PGIS_DEBUG_EXPLODED 1
// This is an implementation of the functions defined in lwgeom.h
//forward decs
#ifdef PGIS_DEBUG_EXPLODED
void checkexplodedsize(uchar *srl, LWGEOM_EXPLODED *exploded, int alloced, char wantbbox);
#endif
extern uchar *parse_lwg(const char* geometry, lwallocator allocfunc, lwreporter errfunc);
//*********************************************************************
@ -1469,11 +1465,20 @@ lwnotice("compute_serialized_box3d: bbox found");
result = NULL;
for (t=0; t<ngeoms; t++)
{
if ( ! compute_serialized_box3d_p(loc, &b1) ) continue;
if (result) nboxes += box3d_union_p(result, &b1, result);
else {
result = lwalloc(sizeof(BOX3D));
memcpy(result, &b1, sizeof(BOX3D));
if ( compute_serialized_box3d_p(loc, &b1) )
{
#ifdef PGIS_DEBUG
lwnotice("Geom %d have box:"); printBOX3D(&b1);
#endif
if (result)
{
nboxes += box3d_union_p(result, &b1, result);
}
else
{
result = lwalloc(sizeof(BOX3D));
memcpy(result, &b1, sizeof(BOX3D));
}
}
sub_size = lwgeom_size(loc);
@ -1510,6 +1515,12 @@ void pfree_POINTARRAY(POINTARRAY *pa)
//** debugging routines
void printBOX3D(BOX3D *box)
{
lwnotice("BOX3D: %g %g, %g %g", box->xmin, box->ymin,
box->xmax, box->ymax);
}
void printPA(POINTARRAY *pa)
{
int t;
@ -1733,622 +1744,6 @@ pglwgeom_setSRID(PG_LWGEOM *lwgeom, int32 newSRID)
return result;
}
void
pfree_exploded(LWGEOM_EXPLODED *exploded)
{
if ( exploded->npoints )
lwfree(exploded->points);
if ( exploded->nlines )
lwfree(exploded->lines);
if ( exploded->npolys )
lwfree(exploded->polys);
lwfree(exploded);
};
/*
* This function recursively scan the given serialized geometry
* and returns a list of _all_ subgeoms in it (deep-first)
*/
LWGEOM_EXPLODED *
lwgeom_explode(uchar *serialized)
{
LWGEOM_INSPECTED *inspected;
LWGEOM_EXPLODED *subexploded, *result;
int i;
#ifdef PGIS_DEBUG
lwnotice("lwgeom_explode called");
#endif
inspected = lwgeom_inspect(serialized);
#ifdef PGIS_DEBUG
lwnotice("lwgeom_explode: serialized inspected");
#endif
result = lwalloc(sizeof(LWGEOM_EXPLODED));
result->points = lwalloc(1);
result->lines = lwalloc(1);
result->polys = lwalloc(1);
result->npoints = 0;
result->nlines = 0;
result->npolys = 0;
if ( ! inspected->ngeometries )
{
lwfree(result->points);
lwfree(result->lines);
lwfree(result->polys);
result->SRID = -1;
result->dims = inspected->type;
pfree_inspected(inspected);
//lwnotice("lwgeom_explode: no geometries");
return result;
}
result->SRID = lwgeom_getsrid(serialized);
result->dims = inspected->type; // will use ZM only
for (i=0; i<inspected->ngeometries; i++)
{
uchar *subgeom = inspected->sub_geoms[i];
int type = lwgeom_getType(subgeom[0]);
if ( type == POINTTYPE )
{
#ifdef PGIS_DEBUG
lwnotice("lwgeom_explode: it's a point");
#endif
result->points = lwrealloc(result->points,
(result->npoints+1)*sizeof(uchar *));
result->points[result->npoints] = subgeom;
result->npoints++;
continue;
}
if ( type == LINETYPE )
{
#ifdef PGIS_DEBUG
lwnotice("lwgeom_explode: it's a line");
#endif
result->lines = lwrealloc(result->lines,
(result->nlines+1)*sizeof(uchar *));
result->lines[result->nlines] = subgeom;
result->nlines++;
continue;
}
if ( type == POLYGONTYPE )
{
#ifdef PGIS_DEBUG
lwnotice("lwgeom_explode: it's a polygon");
#endif
result->polys = lwrealloc(result->polys,
(result->npolys+1)*sizeof(uchar *));
result->polys[result->npolys] = subgeom;
result->npolys++;
continue;
}
#ifdef PGIS_DEBUG
lwnotice("type of subgeom %d is %d, recursing", i, type);
#endif
// it's a multi geometry, recurse
subexploded = lwgeom_explode(subgeom);
#ifdef PGIS_DEBUG
lwnotice("subgeom %d, exploded: %d point, %d lines, %d polys", i, subexploded->npoints, subexploded->nlines, subexploded->npolys);
#endif
// Re-allocate adding space for new exploded geoms
// (-1 because 1 was already allocated for the collection)
// Copy subgeom pointers from subexploded to current
// exploded.
if ( subexploded->npoints )
{
result->points = lwrealloc(result->points,
sizeof(uchar *)*(result->npoints+subexploded->npoints-1));
if ( ! result )
lwerror("Out of virtual memory");
#ifdef PGIS_DEBUG
lwnotice("lwrealloc'ed exploded->points");
#endif
memcpy(&(result->points[result->npoints]),
subexploded->points,
subexploded->npoints*sizeof(uchar *));
#ifdef PGIS_DEBUG
lwnotice("memcpied exploded->points");
#endif
result->npoints += subexploded->npoints;
#ifdef PGIS_DEBUG
lwnotice("memcopied %d points from subexploded (exploded points: %d", subexploded->npoints, result->npoints);
#endif
}
if ( subexploded->nlines )
{
result->lines = lwrealloc(result->lines,
sizeof(uchar *)*
(result->nlines+subexploded->nlines-1));
memcpy(&(result->lines[result->nlines]),
subexploded->lines,
subexploded->nlines*sizeof(uchar *));
result->nlines += subexploded->nlines;
}
if ( subexploded->npolys )
{
result->polys = lwrealloc(result->polys,
sizeof(uchar *)*
(result->npolys+subexploded->npolys-1));
memcpy(&(result->polys[result->npolys]),
subexploded->polys,
subexploded->npolys*sizeof(uchar *));
result->npolys += subexploded->npolys;
}
// release subexploded memory
pfree_exploded(subexploded);
}
pfree_inspected(inspected);
#ifdef PGIS_DEBUG
lwnotice("lwgeom_explode: returning");
#endif
return result;
}
// Returns a 'lwalloced' union of the two input exploded geoms
// Returns NULL if SRID or ndims do not match.
LWGEOM_EXPLODED *
lwexploded_sum(LWGEOM_EXPLODED *exp1, LWGEOM_EXPLODED *exp2)
{
LWGEOM_EXPLODED *expcoll;
uchar *loc;
if ( TYPE_GETZM(exp1->dims) != TYPE_GETZM(exp2->dims) )
{
lwerror("lwexploded_sum: can't sum mixed DIMS geoms (%d/%d)",
TYPE_GETZM(exp1->dims), TYPE_GETZM(exp2->dims));
return NULL;
}
if ( exp1->SRID != exp2->SRID )
{
lwerror("lwexploded_sum: can't sum mixed SRID geoms (%d/%d)",
exp1->SRID, exp2->SRID);
return NULL;
}
expcoll = lwalloc(sizeof(LWGEOM_EXPLODED));
expcoll->npoints = exp1->npoints + exp2->npoints;
if ( expcoll->npoints ) {
expcoll->points = lwalloc(expcoll->npoints*sizeof(char *));
loc = (char *)&(expcoll->points[0]);
if ( exp1->npoints ) {
memcpy(loc, exp1->points,
exp1->npoints*sizeof(char *));
loc += exp1->npoints*sizeof(char *);
}
if ( exp2->npoints ) {
memcpy(loc, exp2->points,
exp2->npoints*sizeof(char *));
}
}
expcoll->nlines = exp1->nlines + exp2->nlines;
if ( expcoll->nlines ) {
expcoll->lines = lwalloc(expcoll->nlines*sizeof(char *));
loc = (char *)&(expcoll->lines[0]);
if ( exp1->nlines ) {
memcpy(loc, exp1->lines,
exp1->nlines*sizeof(char *));
loc += exp1->nlines*sizeof(char *);
}
if ( exp2->nlines ) {
memcpy(loc, exp2->lines,
exp2->nlines*sizeof(char *));
}
}
expcoll->npolys = exp1->npolys + exp2->npolys;
if ( expcoll->npolys ) {
expcoll->polys = lwalloc(expcoll->npolys*sizeof(char *));
loc = (char *)&(expcoll->polys[0]);
if ( exp1->npolys ) {
memcpy(loc, exp1->polys,
exp1->npolys*sizeof(char *));
loc += exp1->npolys*sizeof(char *);
}
if ( exp2->npolys ) {
memcpy(loc, exp2->polys,
exp2->npolys*sizeof(char *));
}
}
expcoll->dims = exp1->dims;
expcoll->SRID = exp1->SRID;
return expcoll;
}
/*
* Serialized a LWGEOM_EXPLODED structure
*/
uchar *
lwexploded_serialize(LWGEOM_EXPLODED *exploded, int wantbbox)
{
size_t sizecom = 0;
size_t size;
uchar *result;
size = lwexploded_findlength(exploded, wantbbox);
result = lwalloc(size);
lwexploded_serialize_buf(exploded, wantbbox, result, &sizecom);
#ifdef PGIS_DEBUG
lwnotice("lwexploded_serialize: findlength:%d, serialize_buf:%d", size, sizecom);
#endif
return result;
}
/*
* Serialized a LWGEOM_EXPLODED structure into a
* pre-allocated memory space.
* Use lwexploded_findlength to know the required size
* of the provided buffer.
*/
void
lwexploded_serialize_buf(LWGEOM_EXPLODED *exploded, int wantbbox,
uchar *buf, size_t *retsize)
{
size_t size=0;
int i;
int ntypes = 0;
int ngeoms = 0;
uchar *loc;
int outtype = 0;
LWPOLY *poly;
LWLINE *line;
LWPOINT *point;
BOX2DFLOAT4 *box2d;
BOX3D *box3d;
ngeoms = exploded->npoints + exploded->nlines + exploded->npolys;
if ( ngeoms == 0 )
{
lwgeom_constructempty_buf(exploded->SRID,
TYPE_HASZ(exploded->dims), TYPE_HASM(exploded->dims),
buf, retsize);
return;
}
// For a single geometry just set SRID and BBOX (if requested)
if ( ngeoms == 1 )
{
loc = buf;
if ( exploded->npoints ) {
if ( wantbbox && !
lwgeom_hasBBOX(exploded->points[0][0]) )
{
loc += sizeof(BOX2DFLOAT4);
}
point = lwpoint_deserialize(exploded->points[0]);
point->SRID = exploded->SRID;
lwpoint_serialize_buf(point, loc, &size);
pfree_point(point);
}
else if ( exploded->nlines ) {
if ( wantbbox && !
lwgeom_hasBBOX(exploded->lines[0][0]) )
{
loc += sizeof(BOX2DFLOAT4);
}
line = lwline_deserialize(exploded->lines[0]);
line->SRID = exploded->SRID;
lwline_serialize_buf(line, loc, &size);
pfree_line(line);
}
else if ( exploded->npolys ) {
if ( wantbbox && !
lwgeom_hasBBOX(exploded->polys[0][0]) )
{
loc += sizeof(BOX2DFLOAT4);
}
poly = lwpoly_deserialize(exploded->polys[0]);
poly->SRID = exploded->SRID;
lwpoly_serialize_buf(poly, loc, &size);
pfree_polygon(poly);
}
else {
if ( retsize ) *retsize = 0;
return; // ERROR !!
}
// Now compute the bounding box and write it
if ( wantbbox && ! lwgeom_hasBBOX(loc[0]) )
{
buf[0] = loc[0];
TYPE_SETHASBBOX(buf[0], 1);
box3d = compute_serialized_box3d(loc);
box2d = box3d_to_box2df(box3d);
loc = buf+1;
memcpy(loc, box2d, sizeof(BOX2DFLOAT4));
size += sizeof(BOX2DFLOAT4);
}
if (retsize) *retsize = size;
return;
}
if ( exploded->npoints ) {
ntypes++;
outtype = (exploded->npoints>1) ? MULTIPOINTTYPE : POINTTYPE;
}
if ( exploded->nlines ) {
ntypes++;
if ( outtype ) outtype = COLLECTIONTYPE;
else outtype = (exploded->nlines>1) ? MULTILINETYPE : LINETYPE;
}
if ( exploded->npolys ) {
ntypes++;
if ( outtype ) outtype = COLLECTIONTYPE;
else outtype = (exploded->npolys>1) ? MULTIPOLYGONTYPE : POLYGONTYPE;
}
#ifdef PGIS_DEBUG
lwnotice(" computed outtype: %d, ngeoms: %d", outtype, ngeoms);
#endif
loc = buf+1; // skip type
if ( wantbbox ) loc += sizeof(BOX2DFLOAT4); // skip box
if ( exploded->SRID != -1 ) loc += 4; // skip SRID
// If we have more then one type of geom
// write that number in the 'ngeoms' field of the
// output serialized form (internal geoms would be multi themself).
// Else rewind location pointer so to overwrite result type.
if ( ntypes > 1 ) {
memcpy(loc, &ntypes, 4);
loc += 4;
} else {
loc--; // let the type be specified later.
}
if ( exploded->npoints > 1 )
{
loc[0] = lwgeom_makeType_full(
TYPE_HASZ(exploded->dims), TYPE_HASM(exploded->dims),
0, MULTIPOINTTYPE, 0);
loc++;
memcpy(loc, &exploded->npoints, 4); // numpoints
loc += 4;
}
// Serialize points stripping BBOX and SRID if any
for (i=0; i<exploded->npoints; i++)
{
size_t subsize;
point = lwpoint_deserialize(exploded->points[i]);
point->SRID = -1;
lwpoint_serialize_buf(point, loc, &subsize);
pfree_point(point);
loc += subsize;
}
if ( exploded->nlines > 1 )
{
loc[0] = lwgeom_makeType_full(
TYPE_HASZ(exploded->dims),
TYPE_HASM(exploded->dims),
0, MULTILINETYPE, 0);
loc++;
memcpy(loc, &exploded->nlines, 4); // numlines
loc += 4;
}
// Serialize lines stripping BBOX and SRID if any
for (i=0; i<exploded->nlines; i++)
{
size_t subsize;
line = lwline_deserialize(exploded->lines[i]);
if ( line == NULL )
{
lwerror("Error deserializing %dnt line from exploded geom", i);
return;
}
line->SRID = -1;
lwline_serialize_buf(line, loc, &subsize);
pfree_line(line);
loc += subsize;
}
if ( exploded->npolys > 1 )
{
loc[0] = lwgeom_makeType_full(
TYPE_HASZ(exploded->dims),
TYPE_HASM(exploded->dims),
0, MULTIPOLYGONTYPE, 0);
loc++;
memcpy(loc, &exploded->npolys, 4); // numpolys
loc += 4;
}
// Serialize polys stripping BBOX and SRID if any
for (i=0; i<exploded->npolys; i++)
{
size_t subsize;
poly = lwpoly_deserialize(exploded->polys[i]);
if ( poly == NULL )
{
lwerror("Error deserializing %dnt polygon from exploded geom", i);
return;
}
poly->SRID = -1;
lwpoly_serialize_buf(poly, loc, &subsize);
pfree_polygon(poly);
loc += subsize;
}
// Register now the number of written bytes
if (retsize) *retsize = (loc-buf);
// Ok. now we need to add type, SRID and bbox
buf[0] = lwgeom_makeType_full(
TYPE_HASZ(exploded->dims),
TYPE_HASM(exploded->dims),
(exploded->SRID!=-1), outtype, wantbbox);
loc = buf+1;
if ( wantbbox )
{
box3d = compute_serialized_box3d(buf);
box2d = box3d_to_box2df(box3d);
memcpy(loc, box2d, sizeof(BOX2DFLOAT4));
loc += sizeof(BOX2DFLOAT4);
}
if ( exploded->SRID != -1 )
{
memcpy(loc, &(exploded->SRID), 4);
loc += 4; // useless.. we've finished
}
#ifdef PGIS_DEBUG
lwnotice("lwexploded_serialize finished");
lwnotice(" type: %d", lwgeom_getType(buf[0]));
lwnotice(" SRID: %d", lwgeom_getsrid(buf));
if ( lwgeom_hasBBOX(buf[0]) )
{
{
BOX2DFLOAT4 boxbuf;
getbox2d_p(buf, &boxbuf);
lwnotice(" BBOX: %f,%f %f,%f",
boxbuf.xmin, boxbuf.ymin,
boxbuf.xmax, boxbuf.ymax);
}
}
lwnotice(" numgeoms: %d", lwgeom_getnumgeometries(buf));
#endif
return;
}
#ifdef PGIS_DEBUG_EXPLODED
void
checkexplodedsize(uchar *srl, LWGEOM_EXPLODED *exp, int alloced, char wantbbox)
{
lwnotice("exploded len: serialized:%d computed:%d alloced:%d",
lwgeom_size(srl), lwexploded_findlength(exp, wantbbox),
alloced);
}
#endif
size_t
lwexploded_findlength(LWGEOM_EXPLODED *exploded, int wantbbox)
{
size_t size=0;
char ntypes=0;
uint32 i;
// find sum of sizes of all geoms.
// substract size of eventually embedded SRID and BBOXes
if ( exploded->npoints )
{
ntypes++;
for (i=0; i<exploded->npoints; i++)
{
size += lwgeom_size_point(exploded->points[i]);
if ( lwgeom_hasBBOX(exploded->points[i][0]) )
size -= sizeof(BOX2DFLOAT4);
if ( lwgeom_hasSRID(exploded->points[i][0]) )
size -= 4;
}
// add multigeom header size
if ( exploded->npoints > 1 )
{
size += 1; // type
size += 4; // numgeometries
}
}
if ( exploded->nlines )
{
ntypes++;
for (i=0; i<exploded->nlines; i++)
{
size += lwgeom_size_line(exploded->lines[i]);
if ( lwgeom_hasBBOX(exploded->lines[i][0]) )
size -= sizeof(BOX2DFLOAT4);
if ( lwgeom_hasSRID(exploded->lines[i][0]) )
size -= 4;
}
// add multigeom header size
if ( exploded->nlines > 1 )
{
size += 1; // type
size += 4; // numgeometries
}
}
if ( exploded->npolys )
{
ntypes++;
for (i=0; i<exploded->npolys; i++)
{
size += lwgeom_size_poly(exploded->polys[i]);
if ( lwgeom_hasBBOX(exploded->polys[i][0]) )
size -= sizeof(BOX2DFLOAT4);
if ( lwgeom_hasSRID(exploded->polys[i][0]) )
size -= 4;
}
// add multigeom header size
if ( exploded->npolys > 1 )
{
size += 1; // type
size += 4; // numgeometries
}
}
/* structure is empty */
if ( ! ntypes ) return lwgeom_empty_length(exploded->SRID);
/* multi-typed geom (collection), add collection header */
if ( ntypes > 1 )
{
size += 1; // type
size += 4; // numgeometries
}
/*
* Add BBOX and SRID if required
*/
if ( exploded->SRID != -1 ) size += 4;
if ( wantbbox ) size += sizeof(BOX2DFLOAT4);
return size;
}
char
ptarray_isccw(const POINTARRAY *pa)

View file

@ -231,6 +231,7 @@ Datum LWGEOM_to_BOX3D(PG_FUNCTION_ARGS)
BOX3D *result;
result = compute_serialized_box3d(SERIALIZED_FORM(lwgeom));
if ( ! result ) PG_RETURN_NULL();
PG_RETURN_POINTER(result);
}
@ -369,7 +370,8 @@ Datum BOX3D_construct(PG_FUNCTION_ARGS)
}
//min(a,b)
double LWGEOM_Mind(double a, double b)
double
LWGEOM_Mind(double a, double b)
{
if (a<b)
return a;
@ -377,9 +379,11 @@ double LWGEOM_Mind(double a, double b)
}
//max(a,b)
double LWGEOM_Maxd(double a, double b)
double
LWGEOM_Maxd(double a, double b)
{
if (b>a)
return b;
return a;
}