2004-09-29 10:50:30 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2004-09-29 15:25:21 +00:00
|
|
|
#include <string.h>
|
2004-09-29 10:50:30 +00:00
|
|
|
#include "liblwgeom.h"
|
|
|
|
|
2004-10-03 15:52:23 +00:00
|
|
|
//#define DEBUG_CALLS 1
|
|
|
|
|
2004-10-07 10:03:23 +00:00
|
|
|
#define CHECK_LWGEOM_ZM 1
|
|
|
|
|
|
|
|
LWCOLLECTION *
|
2004-10-08 13:20:55 +00:00
|
|
|
lwcollection_construct(unsigned int type, int SRID, BOX2DFLOAT4 *bbox,
|
2004-10-07 10:03:23 +00:00
|
|
|
unsigned int ngeoms, LWGEOM **geoms)
|
|
|
|
{
|
|
|
|
LWCOLLECTION *ret;
|
|
|
|
int hasz, hasm;
|
|
|
|
#ifdef CHECK_LWGEOM_ZM
|
|
|
|
char zm;
|
|
|
|
unsigned int i;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
hasz = 0;
|
|
|
|
hasm = 0;
|
|
|
|
if ( ngeoms > 0 )
|
|
|
|
{
|
|
|
|
hasz = TYPE_HASZ(geoms[0]->type);
|
|
|
|
hasm = TYPE_HASM(geoms[0]->type);
|
|
|
|
#ifdef CHECK_LWGEOM_ZM
|
2004-10-21 19:46:36 +00:00
|
|
|
zm = TYPE_GETZM(geoms[0]->type);
|
|
|
|
for (i=1; i<ngeoms; i++)
|
|
|
|
{
|
|
|
|
if ( zm != TYPE_GETZM(geoms[i]->type) )
|
|
|
|
lwerror("lwcollection_construct: mixed dimension geometries");
|
|
|
|
}
|
2004-10-07 10:03:23 +00:00
|
|
|
#endif
|
2004-10-21 19:46:36 +00:00
|
|
|
}
|
|
|
|
|
2004-10-07 10:03:23 +00:00
|
|
|
|
|
|
|
ret = lwalloc(sizeof(LWCOLLECTION));
|
|
|
|
ret->type = lwgeom_makeType_full(hasz, hasm, (SRID!=-1),
|
2004-10-08 13:20:55 +00:00
|
|
|
type, 0);
|
2004-10-07 10:03:23 +00:00
|
|
|
ret->SRID = SRID;
|
|
|
|
ret->ngeoms = ngeoms;
|
|
|
|
ret->geoms = geoms;
|
2004-10-08 13:20:55 +00:00
|
|
|
ret->bbox = bbox;
|
|
|
|
|
2004-10-07 10:03:23 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2004-10-11 09:32:44 +00:00
|
|
|
LWCOLLECTION *
|
2004-10-11 09:46:42 +00:00
|
|
|
lwcollection_construct_empty(int SRID, char hasz, char hasm)
|
2004-10-11 09:32:44 +00:00
|
|
|
{
|
|
|
|
LWCOLLECTION *ret;
|
|
|
|
|
|
|
|
ret = lwalloc(sizeof(LWCOLLECTION));
|
|
|
|
ret->type = lwgeom_makeType_full(hasz, hasm, (SRID!=-1),
|
|
|
|
COLLECTIONTYPE, 0);
|
|
|
|
ret->SRID = SRID;
|
|
|
|
ret->ngeoms = 0;
|
|
|
|
ret->geoms = NULL;
|
2004-10-11 09:46:42 +00:00
|
|
|
ret->bbox = NULL;
|
2004-10-11 09:32:44 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2004-10-07 10:03:23 +00:00
|
|
|
|
2004-09-29 10:50:30 +00:00
|
|
|
LWCOLLECTION *
|
|
|
|
lwcollection_deserialize(char *srl)
|
|
|
|
{
|
|
|
|
LWCOLLECTION *result;
|
|
|
|
LWGEOM_INSPECTED *insp;
|
2004-09-30 11:45:40 +00:00
|
|
|
char typefl = srl[0];
|
|
|
|
int type = lwgeom_getType(typefl);
|
2004-09-29 10:50:30 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( type != COLLECTIONTYPE )
|
|
|
|
{
|
2005-01-07 09:56:33 +00:00
|
|
|
lwerror("lwcollection_deserialize called on NON geometrycollection: %d", type);
|
2004-09-29 10:50:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
insp = lwgeom_inspect(srl);
|
|
|
|
|
|
|
|
result = lwalloc(sizeof(LWCOLLECTION));
|
2004-10-04 13:53:42 +00:00
|
|
|
result->type = typefl;
|
2004-09-29 10:50:30 +00:00
|
|
|
result->SRID = insp->SRID;
|
|
|
|
result->ngeoms = insp->ngeometries;
|
|
|
|
result->geoms = lwalloc(sizeof(LWGEOM *)*insp->ngeometries);
|
|
|
|
|
2004-10-08 13:20:55 +00:00
|
|
|
if (lwgeom_hasBBOX(srl[0]))
|
|
|
|
result->bbox = (BOX2DFLOAT4 *)(srl+1);
|
|
|
|
else result->bbox = NULL;
|
|
|
|
|
|
|
|
|
2004-09-29 10:50:30 +00:00
|
|
|
for (i=0; i<insp->ngeometries; i++)
|
|
|
|
{
|
2004-09-29 15:25:21 +00:00
|
|
|
result->geoms[i] = lwgeom_deserialize(insp->sub_geoms[i]);
|
2004-09-29 10:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
LWGEOM *
|
|
|
|
lwcollection_getsubgeom(LWCOLLECTION *col, int gnum)
|
|
|
|
{
|
|
|
|
return (LWGEOM *)col->geoms[gnum];
|
|
|
|
}
|
|
|
|
|
|
|
|
// find serialized size of this collection
|
|
|
|
size_t
|
|
|
|
lwcollection_serialize_size(LWCOLLECTION *col)
|
|
|
|
{
|
|
|
|
size_t size = 5; // type + nsubgeoms
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if ( col->SRID != -1 ) size += 4; // SRID
|
2004-10-08 13:20:55 +00:00
|
|
|
if ( col->bbox ) size += sizeof(BOX2DFLOAT4);
|
2004-09-29 15:25:21 +00:00
|
|
|
|
2004-10-03 15:52:23 +00:00
|
|
|
#ifdef DEBUG_CALLS
|
|
|
|
lwnotice("lwcollection_serialize_size[%p]: start size: %d", col, size);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
for (i=0; i<col->ngeoms; i++)
|
2004-10-03 15:52:23 +00:00
|
|
|
{
|
2004-12-14 09:37:47 +00:00
|
|
|
size += lwgeom_serialize_size(col->geoms[i]);
|
2004-10-03 15:52:23 +00:00
|
|
|
#ifdef DEBUG_CALLS
|
|
|
|
lwnotice("lwcollection_serialize_size[%p]: with geom%d: %d", col, i, size);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_CALLS
|
|
|
|
lwnotice("lwcollection_serialize_size[%p]: returning %d", col, size);
|
|
|
|
#endif
|
2004-09-29 15:25:21 +00:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert this collectoin into its serialize form writing it into
|
|
|
|
// the given buffer, and returning number of bytes written into
|
|
|
|
// the given int pointer.
|
|
|
|
void
|
2004-10-03 15:52:23 +00:00
|
|
|
lwcollection_serialize_buf(LWCOLLECTION *coll, char *buf, size_t *retsize)
|
2004-09-29 15:25:21 +00:00
|
|
|
{
|
|
|
|
int size=1; // type
|
|
|
|
int subsize=0;
|
|
|
|
char hasSRID;
|
|
|
|
char *loc;
|
|
|
|
int i;
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
#ifdef DEBUG_CALLS
|
|
|
|
lwnotice("lwcollection_serialize_buf called (%d with %d elems)",
|
|
|
|
lwgeom_typename(TYPE_GETTYPE(coll->type)), coll->ngeoms);
|
|
|
|
#endif
|
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
hasSRID = (coll->SRID != -1);
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
buf[0] = (unsigned char) lwgeom_makeType_full(
|
|
|
|
TYPE_HASZ(coll->type), TYPE_HASM(coll->type),
|
2004-10-08 13:20:55 +00:00
|
|
|
hasSRID, TYPE_GETTYPE(coll->type), coll->bbox ? 1 : 0);
|
2004-09-29 15:25:21 +00:00
|
|
|
loc = buf+1;
|
|
|
|
|
2004-09-30 15:42:28 +00:00
|
|
|
// Add BBOX if requested
|
2004-10-08 13:20:55 +00:00
|
|
|
if ( coll->bbox )
|
2004-09-30 15:42:28 +00:00
|
|
|
{
|
2004-10-08 13:20:55 +00:00
|
|
|
memcpy(loc, coll->bbox, sizeof(BOX2DFLOAT4));
|
2004-09-30 15:42:28 +00:00
|
|
|
size += sizeof(BOX2DFLOAT4);
|
|
|
|
loc += sizeof(BOX2DFLOAT4);
|
|
|
|
}
|
|
|
|
|
2004-09-29 15:25:21 +00:00
|
|
|
// Add SRID if requested
|
|
|
|
if (hasSRID)
|
|
|
|
{
|
|
|
|
memcpy(loc, &coll->SRID, 4);
|
|
|
|
size += 4;
|
|
|
|
loc += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write number of subgeoms
|
|
|
|
memcpy(loc, &coll->ngeoms, 4);
|
|
|
|
size += 4;
|
|
|
|
loc += 4;
|
|
|
|
|
|
|
|
// Serialize subgeoms
|
|
|
|
for (i=0; i<coll->ngeoms; i++)
|
|
|
|
{
|
|
|
|
lwgeom_serialize_buf(coll->geoms[i], loc, &subsize);
|
|
|
|
size += subsize;
|
2004-10-03 15:52:23 +00:00
|
|
|
loc += subsize;
|
2004-09-29 15:25:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (retsize) *retsize = size;
|
2004-10-05 16:28:34 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_CALLS
|
|
|
|
lwnotice("lwcollection_serialize_buf returning");
|
|
|
|
#endif
|
2004-09-29 15:25:21 +00:00
|
|
|
}
|
2004-09-30 15:42:28 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
lwcollection_compute_bbox_p(LWCOLLECTION *col, BOX2DFLOAT4 *box)
|
|
|
|
{
|
|
|
|
BOX2DFLOAT4 boxbuf;
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
if ( ! col->ngeoms ) return 0;
|
|
|
|
if ( ! lwgeom_compute_bbox_p(col->geoms[0], box) ) return 0;
|
|
|
|
for (i=1; i<col->ngeoms; i++)
|
|
|
|
{
|
|
|
|
if ( ! lwgeom_compute_bbox_p(col->geoms[i], &boxbuf) ) return 0;
|
|
|
|
if ( ! box2d_union_p(box, &boxbuf, box) ) return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2004-10-01 14:49:34 +00:00
|
|
|
|
|
|
|
// Clone LWCOLLECTION object. POINTARRAY are not copied.
|
|
|
|
LWCOLLECTION *
|
|
|
|
lwcollection_clone(const LWCOLLECTION *g)
|
|
|
|
{
|
|
|
|
uint32 i;
|
|
|
|
LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION));
|
|
|
|
memcpy(ret, g, sizeof(LWCOLLECTION));
|
|
|
|
for (i=0; i<g->ngeoms; i++)
|
|
|
|
{
|
|
|
|
ret->geoms[i] = lwgeom_clone(g->geoms[i]);
|
|
|
|
}
|
2004-10-08 13:20:55 +00:00
|
|
|
if ( g->bbox && ! TYPE_HASBBOX(g->type) )
|
|
|
|
ret->bbox = box2d_clone(g->bbox);
|
2004-10-01 14:49:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add 'what' to this collection at position 'where'.
|
|
|
|
// where=0 == prepend
|
|
|
|
// where=-1 == append
|
|
|
|
// Returns a GEOMETRYCOLLECTION
|
|
|
|
LWGEOM *
|
|
|
|
lwcollection_add(const LWCOLLECTION *to, uint32 where, const LWGEOM *what)
|
|
|
|
{
|
|
|
|
LWCOLLECTION *col;
|
|
|
|
LWGEOM **geoms;
|
|
|
|
uint32 i;
|
|
|
|
|
|
|
|
if ( where == -1 ) where = to->ngeoms;
|
|
|
|
else if ( where < -1 || where > to->ngeoms )
|
|
|
|
{
|
|
|
|
lwerror("lwcollection_add: add position out of range %d..%d",
|
|
|
|
-1, to->ngeoms);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// dimensions compatibility are checked by caller
|
|
|
|
|
|
|
|
// Construct geoms array
|
|
|
|
geoms = lwalloc(sizeof(LWGEOM *)*(to->ngeoms+1));
|
|
|
|
for (i=0; i<where; i++)
|
|
|
|
{
|
|
|
|
geoms[i] = lwgeom_clone(to->geoms[i]);
|
2004-10-08 13:20:55 +00:00
|
|
|
lwgeom_dropSRID(geoms[i]);
|
|
|
|
lwgeom_dropBBOX(geoms[i]);
|
2004-10-01 14:49:34 +00:00
|
|
|
}
|
|
|
|
geoms[where] = lwgeom_clone(what);
|
2004-10-08 13:20:55 +00:00
|
|
|
lwgeom_dropSRID(geoms[where]);
|
|
|
|
lwgeom_dropBBOX(geoms[where]);
|
2004-10-01 14:49:34 +00:00
|
|
|
for (i=where; i<to->ngeoms; i++)
|
|
|
|
{
|
|
|
|
geoms[i+1] = lwgeom_clone(to->geoms[i]);
|
2004-10-08 13:20:55 +00:00
|
|
|
lwgeom_dropSRID(geoms[i+1]);
|
|
|
|
lwgeom_dropBBOX(geoms[i+1]);
|
2004-10-01 14:49:34 +00:00
|
|
|
}
|
|
|
|
|
2004-10-05 16:28:34 +00:00
|
|
|
col = lwcollection_construct(COLLECTIONTYPE,
|
2004-10-08 13:20:55 +00:00
|
|
|
to->SRID, NULL,
|
2004-10-04 13:53:42 +00:00
|
|
|
to->ngeoms+1, geoms);
|
2004-10-01 14:49:34 +00:00
|
|
|
|
|
|
|
return (LWGEOM *)col;
|
|
|
|
|
|
|
|
}
|
2004-10-10 20:31:23 +00:00
|
|
|
|
|
|
|
LWCOLLECTION *
|
|
|
|
lwcollection_segmentize2d(LWCOLLECTION *col, double dist)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
LWGEOM **newgeoms;
|
|
|
|
|
|
|
|
if ( ! col->ngeoms ) return col;
|
|
|
|
|
|
|
|
newgeoms = lwalloc(sizeof(LWGEOM *)*col->ngeoms);
|
|
|
|
for (i=0; i<col->ngeoms; i++)
|
|
|
|
newgeoms[i] = lwgeom_segmentize2d(col->geoms[i], dist);
|
|
|
|
|
|
|
|
return lwcollection_construct(col->type, col->SRID, col->bbox,
|
|
|
|
col->ngeoms, newgeoms);
|
|
|
|
}
|
2004-10-11 07:15:20 +00:00
|
|
|
|
|
|
|
// check for same geometry composition
|
|
|
|
char
|
|
|
|
lwcollection_same(const LWCOLLECTION *c1, const LWCOLLECTION *c2)
|
|
|
|
{
|
2004-11-26 15:06:08 +00:00
|
|
|
unsigned int i, j;
|
|
|
|
char *hit;
|
2004-10-11 07:15:20 +00:00
|
|
|
|
2004-11-26 14:56:13 +00:00
|
|
|
#if DEBUG_CALLS
|
|
|
|
lwnotice("lwcollection_same called");
|
|
|
|
#endif // DEBUG_CALLS
|
|
|
|
|
2004-10-11 07:15:20 +00:00
|
|
|
if ( TYPE_GETTYPE(c1->type) != TYPE_GETTYPE(c2->type) ) return 0;
|
|
|
|
if ( c1->ngeoms != c2->ngeoms ) return 0;
|
|
|
|
|
2004-11-26 15:06:08 +00:00
|
|
|
hit = (char *)lwalloc(sizeof(char)*c1->ngeoms);
|
|
|
|
memset(hit, 0, sizeof(char)*c1->ngeoms);
|
|
|
|
|
2004-10-11 07:15:20 +00:00
|
|
|
for (i=0; i<c1->ngeoms; i++)
|
|
|
|
{
|
2004-11-26 15:06:08 +00:00
|
|
|
char found=0;
|
|
|
|
for (j=0; j<c2->ngeoms; j++)
|
|
|
|
{
|
|
|
|
if ( hit[j] ) continue;
|
|
|
|
if ( lwgeom_same(c1->geoms[i], c2->geoms[j]) )
|
|
|
|
{
|
|
|
|
hit[j] = 1;
|
|
|
|
found=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( ! found ) return 0;
|
2004-10-11 07:15:20 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|