2006-05-30 08:47:00 +00:00
|
|
|
/**********************************************************************
|
|
|
|
*
|
|
|
|
* PostGIS - Spatial Types for PostgreSQL
|
|
|
|
* http://postgis.refractions.net
|
2011-09-28 10:05:36 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2001-2006 Refractions Research Inc.
|
2006-05-30 08:47:00 +00:00
|
|
|
*
|
|
|
|
* This is free software; you can redistribute and/or modify it under
|
|
|
|
* the terms of the GNU General Public Licence. See the COPYING file.
|
2009-05-03 03:58:20 +00:00
|
|
|
*
|
2006-05-30 08:47:00 +00:00
|
|
|
**********************************************************************/
|
|
|
|
|
2004-09-29 10:50:30 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
2009-09-14 20:30:35 +00:00
|
|
|
#include "liblwgeom_internal.h"
|
2011-09-28 10:05:36 +00:00
|
|
|
#include "lwgeom_log.h"
|
2010-10-31 02:31:34 +00:00
|
|
|
#include "libtgeom.h"
|
2004-09-29 10:50:30 +00:00
|
|
|
|
2004-10-03 15:52:23 +00:00
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/** Force Right-hand-rule on LWGEOM polygons **/
|
2004-09-30 08:18:06 +00:00
|
|
|
void
|
2010-10-03 18:14:35 +00:00
|
|
|
lwgeom_force_clockwise(LWGEOM *lwgeom)
|
2004-09-30 08:18:06 +00:00
|
|
|
{
|
|
|
|
LWCOLLECTION *coll;
|
|
|
|
int i;
|
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom->type)
|
2004-09-30 08:18:06 +00:00
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
case POLYGONTYPE:
|
2010-10-03 18:14:35 +00:00
|
|
|
lwpoly_force_clockwise((LWPOLY *)lwgeom);
|
2009-06-11 16:44:03 +00:00
|
|
|
return;
|
|
|
|
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
2010-10-03 18:14:35 +00:00
|
|
|
lwtriangle_force_clockwise((LWTRIANGLE *)lwgeom);
|
2010-08-13 17:29:29 +00:00
|
|
|
return;
|
|
|
|
|
2010-08-15 08:30:08 +00:00
|
|
|
/* Not handle POLYHEDRALSURFACE and TIN
|
2010-09-05 15:25:50 +00:00
|
|
|
as they are supposed to be well oriented */
|
|
|
|
case MULTIPOLYGONTYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
coll = (LWCOLLECTION *)lwgeom;
|
|
|
|
for (i=0; i<coll->ngeoms; i++)
|
2010-10-03 18:14:35 +00:00
|
|
|
lwgeom_force_clockwise(coll->geoms[i]);
|
2009-06-11 16:44:03 +00:00
|
|
|
return;
|
2004-09-30 08:18:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/** Reverse vertex order of LWGEOM **/
|
2004-09-30 08:18:06 +00:00
|
|
|
void
|
|
|
|
lwgeom_reverse(LWGEOM *lwgeom)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
LWCOLLECTION *col;
|
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom->type)
|
2004-09-30 08:18:06 +00:00
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
case LINETYPE:
|
|
|
|
lwline_reverse((LWLINE *)lwgeom);
|
|
|
|
return;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
lwpoly_reverse((LWPOLY *)lwgeom);
|
|
|
|
return;
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
lwtriangle_reverse((LWTRIANGLE *)lwgeom);
|
|
|
|
return;
|
2009-06-11 16:44:03 +00:00
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
col = (LWCOLLECTION *)lwgeom;
|
|
|
|
for (i=0; i<col->ngeoms; i++)
|
|
|
|
lwgeom_reverse(col->geoms[i]);
|
|
|
|
return;
|
2004-09-30 08:18:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-10-01 07:51:00 +00:00
|
|
|
LWPOINT *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwpoint(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == POINTTYPE )
|
2005-12-13 18:19:34 +00:00
|
|
|
return (LWPOINT *)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWLINE *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwline(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == LINETYPE )
|
2005-12-13 18:19:34 +00:00
|
|
|
return (LWLINE *)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
2009-01-13 12:27:39 +00:00
|
|
|
LWCIRCSTRING *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
|
2006-12-01 22:16:44 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == CIRCSTRINGTYPE )
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWCIRCSTRING *)lwgeom;
|
|
|
|
else return NULL;
|
2006-12-01 22:16:44 +00:00
|
|
|
}
|
|
|
|
|
2010-10-23 23:48:37 +00:00
|
|
|
LWCOMPOUND *
|
|
|
|
lwgeom_as_lwcompound(const LWGEOM *lwgeom)
|
|
|
|
{
|
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == COMPOUNDTYPE )
|
2010-10-23 23:48:37 +00:00
|
|
|
return (LWCOMPOUND *)lwgeom;
|
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWCURVEPOLY *
|
|
|
|
lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
|
|
|
|
{
|
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == CURVEPOLYTYPE )
|
2010-10-23 23:48:37 +00:00
|
|
|
return (LWCURVEPOLY *)lwgeom;
|
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
2004-10-01 07:51:00 +00:00
|
|
|
LWPOLY *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwpoly(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == POLYGONTYPE )
|
2005-12-13 18:19:34 +00:00
|
|
|
return (LWPOLY *)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-13 17:29:29 +00:00
|
|
|
LWTRIANGLE *
|
|
|
|
lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
|
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == TRIANGLETYPE )
|
2010-08-13 17:29:29 +00:00
|
|
|
return (LWTRIANGLE *)lwgeom;
|
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
2004-10-01 07:51:00 +00:00
|
|
|
LWCOLLECTION *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwcollection(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-02 06:20:22 +00:00
|
|
|
if ( lwgeom_is_collection(lwgeom) )
|
2010-03-16 03:13:33 +00:00
|
|
|
return (LWCOLLECTION*)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWMPOINT *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == MULTIPOINTTYPE )
|
2005-12-13 18:19:34 +00:00
|
|
|
return (LWMPOINT *)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWMLINE *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwmline(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == MULTILINETYPE )
|
2005-12-13 18:19:34 +00:00
|
|
|
return (LWMLINE *)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWMPOLY *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_lwmpoly(const LWGEOM *lwgeom)
|
2004-10-01 07:51:00 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( lwgeom == NULL ) return NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == MULTIPOLYGONTYPE )
|
2005-12-13 18:19:34 +00:00
|
|
|
return (LWMPOLY *)lwgeom;
|
2004-10-01 07:51:00 +00:00
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-25 21:20:09 +00:00
|
|
|
LWPSURFACE *
|
2010-08-13 17:29:29 +00:00
|
|
|
lwgeom_as_lwpsurface(const LWGEOM *lwgeom)
|
2010-07-25 21:20:09 +00:00
|
|
|
{
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == POLYHEDRALSURFACETYPE )
|
2010-07-25 21:20:09 +00:00
|
|
|
return (LWPSURFACE *)lwgeom;
|
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
2010-08-13 17:29:29 +00:00
|
|
|
LWTIN *
|
|
|
|
lwgeom_as_lwtin(const LWGEOM *lwgeom)
|
|
|
|
{
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom->type == TINTYPE )
|
2010-08-13 17:29:29 +00:00
|
|
|
return (LWTIN *)lwgeom;
|
|
|
|
else return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWGEOM *lwtin_as_lwgeom(const LWTIN *obj)
|
|
|
|
{
|
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
LWGEOM *lwpsurface_as_lwgeom(const LWPSURFACE *obj)
|
2010-07-25 21:20:09 +00:00
|
|
|
{
|
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
|
|
|
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwmpoly_as_lwgeom(const LWMPOLY *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwmline_as_lwgeom(const LWMLINE *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwmpoint_as_lwgeom(const LWMPOINT *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwcollection_as_lwgeom(const LWCOLLECTION *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwcircstring_as_lwgeom(const LWCIRCSTRING *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-10-23 23:48:37 +00:00
|
|
|
LWGEOM *lwcurvepoly_as_lwgeom(const LWCURVEPOLY *obj)
|
|
|
|
{
|
|
|
|
if ( obj == NULL ) return NULL;
|
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
|
|
|
LWGEOM *lwcompound_as_lwgeom(const LWCOMPOUND *obj)
|
|
|
|
{
|
|
|
|
if ( obj == NULL ) return NULL;
|
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwpoly_as_lwgeom(const LWPOLY *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-08-13 17:29:29 +00:00
|
|
|
LWGEOM *lwtriangle_as_lwgeom(const LWTRIANGLE *obj)
|
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2010-08-13 17:29:29 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwline_as_lwgeom(const LWLINE *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2010-03-16 03:13:33 +00:00
|
|
|
LWGEOM *lwpoint_as_lwgeom(const LWPOINT *obj)
|
2009-06-11 16:44:03 +00:00
|
|
|
{
|
2010-08-15 08:30:08 +00:00
|
|
|
if ( obj == NULL ) return NULL;
|
2009-06-11 16:44:03 +00:00
|
|
|
return (LWGEOM *)obj;
|
|
|
|
}
|
2004-10-01 14:49:34 +00:00
|
|
|
|
2009-03-09 18:40:23 +00:00
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/**
|
|
|
|
** Look-up for the correct MULTI* type promotion for singleton types.
|
2009-03-09 18:40:23 +00:00
|
|
|
*/
|
2011-08-19 09:34:58 +00:00
|
|
|
static uint8_t MULTITYPE[16] =
|
2010-02-01 17:35:55 +00:00
|
|
|
{
|
|
|
|
0,
|
|
|
|
MULTIPOINTTYPE,
|
|
|
|
MULTILINETYPE,
|
|
|
|
MULTIPOLYGONTYPE,
|
|
|
|
0,0,0,0,
|
|
|
|
MULTICURVETYPE,
|
|
|
|
MULTICURVETYPE,
|
|
|
|
MULTISURFACETYPE,
|
2010-07-25 21:20:09 +00:00
|
|
|
POLYHEDRALSURFACETYPE,
|
2010-08-13 17:29:29 +00:00
|
|
|
0,
|
|
|
|
TINTYPE,
|
|
|
|
0,0
|
2010-02-01 17:35:55 +00:00
|
|
|
};
|
2009-03-09 18:40:23 +00:00
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/**
|
|
|
|
* Create a new LWGEOM of the appropriate MULTI* type.
|
2009-03-09 18:40:23 +00:00
|
|
|
*/
|
|
|
|
LWGEOM *
|
2010-03-16 03:13:33 +00:00
|
|
|
lwgeom_as_multi(const LWGEOM *lwgeom)
|
2009-03-09 18:40:23 +00:00
|
|
|
{
|
|
|
|
LWGEOM **ogeoms;
|
|
|
|
LWGEOM *ogeom = NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
GBOX *box = NULL;
|
2009-03-09 18:40:23 +00:00
|
|
|
int type;
|
|
|
|
|
|
|
|
ogeoms = lwalloc(sizeof(LWGEOM*));
|
|
|
|
|
|
|
|
/*
|
|
|
|
** This funx is a no-op only if a bbox cache is already present
|
2009-05-03 03:58:20 +00:00
|
|
|
** in input.
|
2009-03-09 18:40:23 +00:00
|
|
|
*/
|
2010-11-02 06:20:22 +00:00
|
|
|
if ( lwgeom_is_collection(lwgeom) )
|
2009-03-09 18:40:23 +00:00
|
|
|
{
|
|
|
|
return lwgeom_clone(lwgeom);
|
|
|
|
}
|
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
type = lwgeom->type;
|
2009-03-09 18:40:23 +00:00
|
|
|
|
|
|
|
if ( MULTITYPE[type] )
|
|
|
|
{
|
|
|
|
ogeoms[0] = lwgeom_clone(lwgeom);
|
|
|
|
|
|
|
|
/* Sub-geometries are not allowed to have bboxes or SRIDs, move the bbox to the collection */
|
|
|
|
box = ogeoms[0]->bbox;
|
|
|
|
ogeoms[0]->bbox = NULL;
|
2010-12-13 19:25:15 +00:00
|
|
|
ogeoms[0]->srid = SRID_UNKNOWN;
|
2009-05-03 03:58:20 +00:00
|
|
|
|
2010-11-25 17:34:21 +00:00
|
|
|
ogeom = (LWGEOM *)lwcollection_construct(MULTITYPE[type], lwgeom->srid, box, 1, ogeoms);
|
2009-03-09 18:40:23 +00:00
|
|
|
}
|
2009-05-03 03:58:20 +00:00
|
|
|
else
|
2009-03-09 18:40:23 +00:00
|
|
|
{
|
|
|
|
return lwgeom_clone(lwgeom);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ogeom;
|
|
|
|
}
|
|
|
|
|
2004-10-01 14:49:34 +00:00
|
|
|
void
|
|
|
|
lwgeom_release(LWGEOM *lwgeom)
|
|
|
|
{
|
2011-08-19 09:34:58 +00:00
|
|
|
uint32_t i;
|
2004-10-01 14:49:34 +00:00
|
|
|
LWCOLLECTION *col;
|
|
|
|
|
2004-10-08 13:20:55 +00:00
|
|
|
if ( ! lwgeom )
|
|
|
|
lwerror("lwgeom_release: someone called on 0x0");
|
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
LWDEBUGF(3, "releasing type %s", lwtype_name(lwgeom->type));
|
2010-03-16 03:13:33 +00:00
|
|
|
|
2005-12-30 17:40:37 +00:00
|
|
|
/* Drop bounding box (always a copy) */
|
2009-06-11 16:44:03 +00:00
|
|
|
if ( lwgeom->bbox )
|
|
|
|
{
|
2010-03-16 03:13:33 +00:00
|
|
|
LWDEBUGF(3, "lwgeom_release: releasing bbox. %p", lwgeom->bbox);
|
2008-05-31 09:56:44 +00:00
|
|
|
|
2009-06-11 16:44:03 +00:00
|
|
|
lwfree(lwgeom->bbox);
|
|
|
|
}
|
2005-11-14 09:01:15 +00:00
|
|
|
|
2005-12-30 17:40:37 +00:00
|
|
|
/* Collection */
|
2004-10-01 14:49:34 +00:00
|
|
|
if ( (col=lwgeom_as_lwcollection(lwgeom)) )
|
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
LWDEBUG(3, "lwgeom_release: Releasing collection.");
|
2006-12-01 22:16:44 +00:00
|
|
|
|
2004-10-01 14:49:34 +00:00
|
|
|
for (i=0; i<col->ngeoms; i++)
|
|
|
|
{
|
|
|
|
lwgeom_release(col->geoms[i]);
|
|
|
|
}
|
|
|
|
lwfree(lwgeom);
|
|
|
|
}
|
|
|
|
|
2005-12-30 17:40:37 +00:00
|
|
|
/* Single element */
|
2004-10-01 14:49:34 +00:00
|
|
|
else lwfree(lwgeom);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-12-18 20:22:07 +00:00
|
|
|
|
2011-07-06 14:29:26 +00:00
|
|
|
/* @brief Clone LWGEOM object. Serialized point lists are not copied.
|
|
|
|
*
|
|
|
|
* @see ptarray_clone
|
|
|
|
*/
|
2004-10-01 14:49:34 +00:00
|
|
|
LWGEOM *
|
|
|
|
lwgeom_clone(const LWGEOM *lwgeom)
|
|
|
|
{
|
2010-02-26 00:16:25 +00:00
|
|
|
LWDEBUGF(2, "lwgeom_clone called with %p, %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwgeom, lwtype_name(lwgeom->type));
|
2008-05-31 09:56:44 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom->type)
|
2004-10-01 14:49:34 +00:00
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
case POINTTYPE:
|
|
|
|
return (LWGEOM *)lwpoint_clone((LWPOINT *)lwgeom);
|
|
|
|
case LINETYPE:
|
|
|
|
return (LWGEOM *)lwline_clone((LWLINE *)lwgeom);
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
return (LWGEOM *)lwcircstring_clone((LWCIRCSTRING *)lwgeom);
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return (LWGEOM *)lwpoly_clone((LWPOLY *)lwgeom);
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
return (LWGEOM *)lwtriangle_clone((LWTRIANGLE *)lwgeom);
|
2009-06-11 16:44:03 +00:00
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case CURVEPOLYTYPE:
|
2010-11-18 05:28:19 +00:00
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return (LWGEOM *)lwcollection_clone((LWCOLLECTION *)lwgeom);
|
|
|
|
default:
|
2010-12-23 18:03:30 +00:00
|
|
|
lwerror("lwgeom_clone: Unknown geometry type: %s", lwtype_name(lwgeom->type));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deep-clone an #LWGEOM object. #POINTARRAY <em>are</em> copied.
|
|
|
|
*/
|
|
|
|
LWGEOM *
|
|
|
|
lwgeom_clone_deep(const LWGEOM *lwgeom)
|
|
|
|
{
|
|
|
|
LWDEBUGF(2, "lwgeom_clone called with %p, %s",
|
|
|
|
lwgeom, lwtype_name(lwgeom->type));
|
|
|
|
|
|
|
|
switch (lwgeom->type)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
case LINETYPE:
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
return (LWGEOM *)lwline_clone_deep((LWLINE *)lwgeom);
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return (LWGEOM *)lwpoly_clone_deep((LWPOLY *)lwgeom);
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case POLYHEDRALSURFACETYPE:
|
|
|
|
case TINTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return (LWGEOM *)lwcollection_clone_deep((LWCOLLECTION *)lwgeom);
|
|
|
|
default:
|
|
|
|
lwerror("lwgeom_clone_deep: Unknown geometry type: %s", lwtype_name(lwgeom->type));
|
2009-06-11 16:44:03 +00:00
|
|
|
return NULL;
|
2004-10-01 14:49:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-13 10:50:56 +00:00
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/**
|
2004-10-07 10:03:23 +00:00
|
|
|
* Return an alloced string
|
|
|
|
*/
|
2010-03-16 03:13:33 +00:00
|
|
|
char*
|
2011-08-10 22:28:05 +00:00
|
|
|
lwgeom_to_ewkt(const LWGEOM *lwgeom)
|
2004-10-07 10:03:23 +00:00
|
|
|
{
|
2011-08-10 22:28:05 +00:00
|
|
|
char* wkt = NULL;
|
|
|
|
size_t wkt_size = 0;
|
|
|
|
|
|
|
|
wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, 12, &wkt_size);
|
2008-12-24 17:09:18 +00:00
|
|
|
|
2011-08-10 22:28:05 +00:00
|
|
|
if ( ! wkt )
|
2010-12-07 21:08:05 +00:00
|
|
|
{
|
2011-08-10 22:28:05 +00:00
|
|
|
lwerror("Error writing geom %p to WKT", lwgeom);
|
2010-12-07 21:08:05 +00:00
|
|
|
}
|
2008-12-24 17:09:18 +00:00
|
|
|
|
2011-08-10 22:28:05 +00:00
|
|
|
return wkt;
|
2008-07-13 10:50:56 +00:00
|
|
|
}
|
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/**
|
|
|
|
* @brief geom1 same as geom2
|
|
|
|
* iff
|
|
|
|
* + have same type
|
|
|
|
* + have same # objects
|
|
|
|
* + have same bvol
|
|
|
|
* + each object in geom1 has a corresponding object in geom2 (see above)
|
|
|
|
* @param lwgeom1
|
|
|
|
* @param lwgeom2
|
2005-12-30 17:40:37 +00:00
|
|
|
*/
|
2004-10-08 13:20:55 +00:00
|
|
|
char
|
2004-10-11 07:15:20 +00:00
|
|
|
lwgeom_same(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
|
2004-10-08 13:20:55 +00:00
|
|
|
{
|
2008-05-31 09:56:44 +00:00
|
|
|
LWDEBUGF(2, "lwgeom_same(%s, %s) called",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(lwgeom1->type),
|
|
|
|
lwtype_name(lwgeom2->type));
|
2006-01-29 13:54:38 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( lwgeom1->type != lwgeom2->type )
|
2006-01-29 13:54:38 +00:00
|
|
|
{
|
2008-05-31 09:56:44 +00:00
|
|
|
LWDEBUG(3, " type differ");
|
|
|
|
|
2009-11-11 19:57:24 +00:00
|
|
|
return LW_FALSE;
|
2006-01-29 13:54:38 +00:00
|
|
|
}
|
2004-10-08 13:20:55 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( FLAGS_GET_ZM(lwgeom1->flags) != FLAGS_GET_ZM(lwgeom2->flags) )
|
2006-01-29 13:54:38 +00:00
|
|
|
{
|
2008-05-31 09:56:44 +00:00
|
|
|
LWDEBUG(3, " ZM flags differ");
|
|
|
|
|
2009-11-11 19:57:24 +00:00
|
|
|
return LW_FALSE;
|
2006-01-29 13:54:38 +00:00
|
|
|
}
|
2004-10-08 13:20:55 +00:00
|
|
|
|
2005-12-30 17:40:37 +00:00
|
|
|
/* Check boxes if both already computed */
|
2004-10-08 13:20:55 +00:00
|
|
|
if ( lwgeom1->bbox && lwgeom2->bbox )
|
|
|
|
{
|
2005-12-30 17:40:37 +00:00
|
|
|
/*lwnotice("bbox1:%p, bbox2:%p", lwgeom1->bbox, lwgeom2->bbox);*/
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( ! gbox_same(lwgeom1->bbox, lwgeom2->bbox) )
|
2006-01-29 13:54:38 +00:00
|
|
|
{
|
2008-05-31 09:56:44 +00:00
|
|
|
LWDEBUG(3, " bounding boxes differ");
|
|
|
|
|
2009-11-11 19:57:24 +00:00
|
|
|
return LW_FALSE;
|
2006-01-29 13:54:38 +00:00
|
|
|
}
|
2004-10-08 13:20:55 +00:00
|
|
|
}
|
|
|
|
|
2005-12-30 17:40:37 +00:00
|
|
|
/* geoms have same type, invoke type-specific function */
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom1->type)
|
2004-10-11 07:15:20 +00:00
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
case POINTTYPE:
|
|
|
|
return lwpoint_same((LWPOINT *)lwgeom1,
|
|
|
|
(LWPOINT *)lwgeom2);
|
|
|
|
case LINETYPE:
|
|
|
|
return lwline_same((LWLINE *)lwgeom1,
|
|
|
|
(LWLINE *)lwgeom2);
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return lwpoly_same((LWPOLY *)lwgeom1,
|
|
|
|
(LWPOLY *)lwgeom2);
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
return lwtriangle_same((LWTRIANGLE *)lwgeom1,
|
|
|
|
(LWTRIANGLE *)lwgeom2);
|
2012-01-16 10:11:44 +00:00
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
return lwcircstring_same((LWCIRCSTRING *)lwgeom1,
|
|
|
|
(LWCIRCSTRING *)lwgeom2);
|
2009-06-11 16:44:03 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
2012-01-16 10:18:07 +00:00
|
|
|
case COMPOUNDTYPE:
|
2012-01-16 10:21:09 +00:00
|
|
|
case CURVEPOLYTYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return lwcollection_same((LWCOLLECTION *)lwgeom1,
|
|
|
|
(LWCOLLECTION *)lwgeom2);
|
|
|
|
default:
|
|
|
|
lwerror("lwgeom_same: unsupported geometry type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(lwgeom1->type));
|
2009-11-11 19:57:24 +00:00
|
|
|
return LW_FALSE;
|
2004-10-11 07:15:20 +00:00
|
|
|
}
|
|
|
|
|
2004-10-08 13:20:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-03-09 14:36:15 +00:00
|
|
|
lwgeom_drop_bbox(LWGEOM *lwgeom)
|
2004-10-08 13:20:55 +00:00
|
|
|
{
|
2005-11-14 09:01:15 +00:00
|
|
|
if ( lwgeom->bbox ) lwfree(lwgeom->bbox);
|
2004-10-08 13:20:55 +00:00
|
|
|
lwgeom->bbox = NULL;
|
2010-11-21 19:02:23 +00:00
|
|
|
FLAGS_SET_BBOX(lwgeom->flags, 0);
|
2004-10-08 13:20:55 +00:00
|
|
|
}
|
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/**
|
2004-10-11 09:32:44 +00:00
|
|
|
* Ensure there's a box in the LWGEOM.
|
|
|
|
* If the box is already there just return,
|
|
|
|
* else compute it.
|
|
|
|
*/
|
|
|
|
void
|
2009-03-09 14:36:15 +00:00
|
|
|
lwgeom_add_bbox(LWGEOM *lwgeom)
|
2004-10-11 09:32:44 +00:00
|
|
|
{
|
2011-12-09 14:37:11 +00:00
|
|
|
/* an empty LWGEOM has no bbox */
|
|
|
|
if( lwgeom_is_empty(lwgeom) ) return;
|
|
|
|
|
2004-10-11 09:32:44 +00:00
|
|
|
if ( lwgeom->bbox ) return;
|
2010-11-21 19:02:23 +00:00
|
|
|
FLAGS_SET_BBOX(lwgeom->flags, 1);
|
2010-12-20 19:16:33 +00:00
|
|
|
lwgeom->bbox = gbox_new(lwgeom->flags);
|
|
|
|
lwgeom_calculate_gbox(lwgeom, lwgeom->bbox);
|
2004-10-11 09:32:44 +00:00
|
|
|
}
|
|
|
|
|
2011-12-09 14:37:16 +00:00
|
|
|
const GBOX *
|
|
|
|
lwgeom_get_bbox(const LWGEOM *lwg)
|
|
|
|
{
|
|
|
|
/* add it if not already there */
|
|
|
|
lwgeom_add_bbox((LWGEOM *)lwg);
|
|
|
|
return lwg->bbox;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-17 20:10:36 +00:00
|
|
|
/**
|
|
|
|
* Calculate the gbox for this goemetry, a cartesian box or
|
|
|
|
* geodetic box, depending on how it is flagged.
|
|
|
|
*/
|
|
|
|
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
|
|
|
|
{
|
|
|
|
gbox->flags = lwgeom->flags;
|
|
|
|
if( FLAGS_GET_GEODETIC(lwgeom->flags) )
|
|
|
|
return lwgeom_calculate_gbox_geodetic(lwgeom, gbox);
|
|
|
|
else
|
|
|
|
return lwgeom_calculate_gbox_cartesian(lwgeom, gbox);
|
|
|
|
}
|
|
|
|
|
2004-10-08 13:20:55 +00:00
|
|
|
void
|
2010-11-02 05:52:32 +00:00
|
|
|
lwgeom_drop_srid(LWGEOM *lwgeom)
|
2004-10-08 13:20:55 +00:00
|
|
|
{
|
2010-12-13 19:25:15 +00:00
|
|
|
lwgeom->srid = SRID_UNKNOWN; /* TODO: To be changed to SRID_UNKNOWN */
|
2004-10-08 13:20:55 +00:00
|
|
|
}
|
2004-10-10 20:31:23 +00:00
|
|
|
|
|
|
|
LWGEOM *
|
|
|
|
lwgeom_segmentize2d(LWGEOM *lwgeom, double dist)
|
|
|
|
{
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom->type)
|
2004-10-10 20:31:23 +00:00
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
case LINETYPE:
|
|
|
|
return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
|
|
|
|
dist);
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
|
|
|
|
dist);
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return (LWGEOM *)lwcollection_segmentize2d(
|
|
|
|
(LWCOLLECTION *)lwgeom, dist);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return lwgeom_clone(lwgeom);
|
2004-10-10 20:31:23 +00:00
|
|
|
}
|
|
|
|
}
|
2005-10-25 11:38:28 +00:00
|
|
|
|
2010-11-18 05:28:19 +00:00
|
|
|
LWGEOM*
|
|
|
|
lwgeom_force_2d(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
return lwgeom_force_dims(geom, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
LWGEOM*
|
|
|
|
lwgeom_force_3dz(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
return lwgeom_force_dims(geom, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
LWGEOM*
|
|
|
|
lwgeom_force_3dm(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
return lwgeom_force_dims(geom, 0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
LWGEOM*
|
|
|
|
lwgeom_force_4d(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
return lwgeom_force_dims(geom, 1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
LWGEOM*
|
|
|
|
lwgeom_force_dims(const LWGEOM *geom, int hasz, int hasm)
|
|
|
|
{
|
2010-11-21 19:02:23 +00:00
|
|
|
switch(geom->type)
|
2010-11-18 05:28:19 +00:00
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
return lwpoint_as_lwgeom(lwpoint_force_dims((LWPOINT*)geom, hasz, hasm));
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case LINETYPE:
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
return lwline_as_lwgeom(lwline_force_dims((LWLINE*)geom, hasz, hasm));
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return lwpoly_as_lwgeom(lwpoly_force_dims((LWPOLY*)geom, hasz, hasm));
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case POLYHEDRALSURFACETYPE:
|
|
|
|
case TINTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return lwcollection_as_lwgeom(lwcollection_force_dims((LWCOLLECTION*)geom, hasz, hasm));
|
|
|
|
default:
|
2010-11-21 19:02:23 +00:00
|
|
|
lwerror("lwgeom_force_2d: unsupported geom type: %s", lwtype_name(geom->type));
|
2010-11-18 05:28:19 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-06 21:39:50 +00:00
|
|
|
int32_t
|
|
|
|
lwgeom_get_srid(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
if ( ! geom ) return SRID_UNKNOWN;
|
|
|
|
return geom->srid;
|
|
|
|
}
|
|
|
|
|
2011-06-26 17:31:30 +00:00
|
|
|
int
|
|
|
|
lwgeom_has_z(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
if ( ! geom ) return LW_FALSE;
|
|
|
|
return FLAGS_GET_Z(geom->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
lwgeom_has_m(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
if ( ! geom ) return LW_FALSE;
|
|
|
|
return FLAGS_GET_M(geom->flags);
|
|
|
|
}
|
|
|
|
|
2011-10-29 20:35:41 +00:00
|
|
|
int
|
|
|
|
lwgeom_ndims(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
if ( ! geom ) return 0;
|
|
|
|
return FLAGS_NDIMS(geom->flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-17 20:10:36 +00:00
|
|
|
void
|
|
|
|
lwgeom_set_geodetic(LWGEOM *geom, int value)
|
|
|
|
{
|
|
|
|
LWPOINT *pt;
|
|
|
|
LWLINE *ln;
|
|
|
|
LWPOLY *ply;
|
|
|
|
LWCOLLECTION *col;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
FLAGS_SET_GEODETIC(geom->flags, value);
|
2010-12-20 19:16:33 +00:00
|
|
|
if ( geom->bbox )
|
|
|
|
FLAGS_SET_GEODETIC(geom->bbox->flags, value);
|
|
|
|
|
2010-12-17 20:10:36 +00:00
|
|
|
switch(geom->type)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
pt = (LWPOINT*)geom;
|
|
|
|
if ( pt->point )
|
|
|
|
FLAGS_SET_GEODETIC(pt->point->flags, value);
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
ln = (LWLINE*)geom;
|
|
|
|
if ( ln->points )
|
|
|
|
FLAGS_SET_GEODETIC(ln->points->flags, value);
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
ply = (LWPOLY*)geom;
|
|
|
|
for ( i = 0; i < ply->nrings; i++ )
|
|
|
|
FLAGS_SET_GEODETIC(ply->rings[i]->flags, value);
|
|
|
|
break;
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
col = (LWCOLLECTION*)geom;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
lwgeom_set_geodetic(col->geoms[i], value);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
lwerror("lwgeom_set_geodetic: unsupported geom type: %s", lwtype_name(geom->type));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-25 11:38:28 +00:00
|
|
|
void
|
|
|
|
lwgeom_longitude_shift(LWGEOM *lwgeom)
|
|
|
|
{
|
|
|
|
int i;
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom->type)
|
2005-10-25 11:38:28 +00:00
|
|
|
{
|
|
|
|
LWPOINT *point;
|
|
|
|
LWLINE *line;
|
|
|
|
LWPOLY *poly;
|
2010-08-13 17:29:29 +00:00
|
|
|
LWTRIANGLE *triangle;
|
2005-10-25 11:38:28 +00:00
|
|
|
LWCOLLECTION *coll;
|
|
|
|
|
2009-06-11 16:44:03 +00:00
|
|
|
case POINTTYPE:
|
|
|
|
point = (LWPOINT *)lwgeom;
|
|
|
|
ptarray_longitude_shift(point->point);
|
|
|
|
return;
|
|
|
|
case LINETYPE:
|
|
|
|
line = (LWLINE *)lwgeom;
|
|
|
|
ptarray_longitude_shift(line->points);
|
|
|
|
return;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
poly = (LWPOLY *)lwgeom;
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
ptarray_longitude_shift(poly->rings[i]);
|
|
|
|
return;
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
triangle = (LWTRIANGLE *)lwgeom;
|
|
|
|
ptarray_longitude_shift(triangle->points);
|
|
|
|
return;
|
2009-06-11 16:44:03 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
coll = (LWCOLLECTION *)lwgeom;
|
|
|
|
for (i=0; i<coll->ngeoms; i++)
|
|
|
|
lwgeom_longitude_shift(coll->geoms[i]);
|
|
|
|
return;
|
|
|
|
default:
|
2010-02-26 00:16:25 +00:00
|
|
|
lwerror("lwgeom_longitude_shift: unsupported geom type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(lwgeom->type));
|
2005-10-25 11:38:28 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-24 11:01:39 +00:00
|
|
|
|
2010-12-02 19:09:57 +00:00
|
|
|
int
|
|
|
|
lwgeom_is_closed(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
|
2010-12-30 16:54:32 +00:00
|
|
|
if( lwgeom_is_empty(geom) )
|
|
|
|
return LW_FALSE;
|
|
|
|
|
2010-12-02 19:09:57 +00:00
|
|
|
/* Test linear types for closure */
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case LINETYPE:
|
|
|
|
return lwline_is_closed((LWLINE*)geom);
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
return lwcircstring_is_closed((LWCIRCSTRING*)geom);
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
return lwcompound_is_closed((LWCOMPOUND*)geom);
|
|
|
|
case TINTYPE:
|
|
|
|
return lwtin_is_closed((LWTIN*)geom);
|
|
|
|
case POLYHEDRALSURFACETYPE:
|
|
|
|
return lwpsurface_is_closed((LWPSURFACE*)geom);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Recurse into collections and see if anything is not closed */
|
|
|
|
if ( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
|
|
|
|
int i;
|
|
|
|
int closed;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
{
|
|
|
|
closed = lwgeom_is_closed(col->geoms[i]);
|
|
|
|
if ( ! closed )
|
|
|
|
return LW_FALSE;
|
|
|
|
}
|
|
|
|
return LW_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* All non-linear non-collection types we will call closed */
|
|
|
|
return LW_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-11-02 05:52:32 +00:00
|
|
|
int
|
|
|
|
lwgeom_is_collection(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
if( ! geom ) return LW_FALSE;
|
2010-11-21 19:02:23 +00:00
|
|
|
return lwtype_is_collection(geom->type);
|
2010-11-02 05:52:32 +00:00
|
|
|
}
|
|
|
|
|
2009-05-03 03:58:20 +00:00
|
|
|
/** Return TRUE if the geometry may contain sub-geometries, i.e. it is a MULTI* or COMPOUNDCURVE */
|
2008-11-24 11:01:39 +00:00
|
|
|
int
|
2011-10-28 17:01:02 +00:00
|
|
|
lwtype_is_collection(uint8_t type)
|
2008-11-24 11:01:39 +00:00
|
|
|
{
|
2009-05-03 03:58:20 +00:00
|
|
|
|
2009-06-11 16:44:03 +00:00
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
2012-01-16 09:11:45 +00:00
|
|
|
case CURVEPOLYTYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2010-03-16 03:13:33 +00:00
|
|
|
return LW_TRUE;
|
2009-06-11 16:44:03 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2010-03-16 03:13:33 +00:00
|
|
|
return LW_FALSE;
|
2008-11-24 11:01:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-18 05:28:19 +00:00
|
|
|
/**
|
|
|
|
* Given an lwtype number, what homogeneous collection can hold it?
|
|
|
|
*/
|
|
|
|
int
|
2011-10-28 17:01:02 +00:00
|
|
|
lwtype_get_collectiontype(uint8_t type)
|
2010-11-18 05:28:19 +00:00
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
return MULTIPOINTTYPE;
|
|
|
|
case LINETYPE:
|
|
|
|
return MULTILINETYPE;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return MULTIPOLYGONTYPE;
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
return MULTICURVETYPE;
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
return MULTICURVETYPE;
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
return MULTISURFACETYPE;
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
return TINTYPE;
|
|
|
|
default:
|
|
|
|
return COLLECTIONTYPE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-11 16:44:03 +00:00
|
|
|
void lwgeom_free(LWGEOM *lwgeom)
|
|
|
|
{
|
2008-12-24 17:37:53 +00:00
|
|
|
|
2010-12-07 21:08:05 +00:00
|
|
|
/* There's nothing here to free... */
|
|
|
|
if( ! lwgeom ) return;
|
2011-07-04 22:51:37 +00:00
|
|
|
|
|
|
|
LWDEBUGF(5,"freeing a %s",lwtype_name(lwgeom->type));
|
2010-12-07 21:08:05 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (lwgeom->type)
|
2008-12-24 17:37:53 +00:00
|
|
|
{
|
2009-06-11 16:44:03 +00:00
|
|
|
case POINTTYPE:
|
|
|
|
lwpoint_free((LWPOINT *)lwgeom);
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
lwline_free((LWLINE *)lwgeom);
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
lwpoly_free((LWPOLY *)lwgeom);
|
|
|
|
break;
|
2010-12-11 00:28:57 +00:00
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
lwcircstring_free((LWCIRCSTRING *)lwgeom);
|
|
|
|
break;
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
lwtriangle_free((LWTRIANGLE *)lwgeom);
|
|
|
|
break;
|
2009-06-11 16:44:03 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
lwmpoint_free((LWMPOINT *)lwgeom);
|
|
|
|
break;
|
|
|
|
case MULTILINETYPE:
|
|
|
|
lwmline_free((LWMLINE *)lwgeom);
|
|
|
|
break;
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
lwmpoly_free((LWMPOLY *)lwgeom);
|
|
|
|
break;
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
|
|
|
lwpsurface_free((LWPSURFACE *)lwgeom);
|
|
|
|
break;
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
|
|
|
lwtin_free((LWTIN *)lwgeom);
|
|
|
|
break;
|
2010-12-11 00:28:57 +00:00
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
2009-06-11 16:44:03 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
lwcollection_free((LWCOLLECTION *)lwgeom);
|
|
|
|
break;
|
2010-12-11 00:28:57 +00:00
|
|
|
default:
|
|
|
|
lwerror("lwgeom_free called with unknown type (%d) %s", lwgeom->type, lwtype_name(lwgeom->type));
|
2009-05-03 03:58:20 +00:00
|
|
|
}
|
2008-12-24 17:37:53 +00:00
|
|
|
return;
|
2009-12-20 17:42:44 +00:00
|
|
|
}
|
2009-09-14 20:30:35 +00:00
|
|
|
|
2009-11-21 06:08:40 +00:00
|
|
|
int lwgeom_needs_bbox(const LWGEOM *geom)
|
2009-09-14 20:30:35 +00:00
|
|
|
{
|
|
|
|
assert(geom);
|
2010-11-21 19:02:23 +00:00
|
|
|
if ( geom->type == POINTTYPE )
|
2009-09-14 20:30:35 +00:00
|
|
|
{
|
|
|
|
return LW_FALSE;
|
|
|
|
}
|
|
|
|
return LW_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-11-18 05:28:19 +00:00
|
|
|
/**
|
|
|
|
* Count points in an #LWGEOM.
|
2009-09-14 20:30:35 +00:00
|
|
|
*/
|
2010-03-16 03:13:33 +00:00
|
|
|
int lwgeom_count_vertices(const LWGEOM *geom)
|
2009-09-14 20:30:35 +00:00
|
|
|
{
|
|
|
|
int result = 0;
|
2010-11-18 05:28:19 +00:00
|
|
|
|
|
|
|
/* Null? Zero. */
|
|
|
|
if( ! geom ) return 0;
|
|
|
|
|
2010-02-25 17:54:08 +00:00
|
|
|
LWDEBUGF(4, "lwgeom_count_vertices got type %s",
|
2010-12-02 16:13:39 +00:00
|
|
|
lwtype_name(geom->type));
|
2010-02-25 17:54:08 +00:00
|
|
|
|
2010-11-18 05:28:19 +00:00
|
|
|
/* Empty? Zero. */
|
|
|
|
if( lwgeom_is_empty(geom) ) return 0;
|
|
|
|
|
2010-12-02 16:13:39 +00:00
|
|
|
switch (geom->type)
|
2009-09-14 20:30:35 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
case POINTTYPE:
|
2010-11-18 05:28:19 +00:00
|
|
|
result = 1;
|
2010-02-01 17:35:55 +00:00
|
|
|
break;
|
2010-11-18 05:28:19 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
case CIRCSTRINGTYPE:
|
2010-02-01 17:35:55 +00:00
|
|
|
case LINETYPE:
|
|
|
|
result = lwline_count_vertices((LWLINE *)geom);
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
2010-11-18 05:28:19 +00:00
|
|
|
result = lwpoly_count_vertices((LWPOLY *)geom);
|
2010-08-13 17:29:29 +00:00
|
|
|
break;
|
2010-11-18 05:28:19 +00:00
|
|
|
case COMPOUNDTYPE:
|
2010-11-18 18:13:25 +00:00
|
|
|
case CURVEPOLYTYPE:
|
2010-11-18 05:28:19 +00:00
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
2010-02-01 17:35:55 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2010-02-01 17:35:55 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
result = lwcollection_count_vertices((LWCOLLECTION *)geom);
|
|
|
|
break;
|
|
|
|
default:
|
2010-02-25 17:54:08 +00:00
|
|
|
lwerror("lwgeom_count_vertices: unsupported input geometry type: %s",
|
2010-12-02 16:13:39 +00:00
|
|
|
lwtype_name(geom->type));
|
2010-02-01 17:35:55 +00:00
|
|
|
break;
|
2009-09-14 20:30:35 +00:00
|
|
|
}
|
|
|
|
LWDEBUGF(3, "counted %d vertices", result);
|
|
|
|
return result;
|
|
|
|
}
|
2009-09-17 02:33:49 +00:00
|
|
|
|
2010-12-02 17:38:18 +00:00
|
|
|
/**
|
|
|
|
* For an #LWGEOM, returns 0 for points, 1 for lines,
|
|
|
|
* 2 for polygons, 3 for volume, and the max dimension
|
|
|
|
* of a collection.
|
|
|
|
*/
|
|
|
|
int lwgeom_dimension(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Null? Zero. */
|
|
|
|
if( ! geom ) return -1;
|
|
|
|
|
|
|
|
LWDEBUGF(4, "lwgeom_dimension got type %s",
|
|
|
|
lwtype_name(geom->type));
|
|
|
|
|
|
|
|
/* Empty? Zero. */
|
2012-01-10 14:58:16 +00:00
|
|
|
/* if( lwgeom_is_empty(geom) ) return 0; */
|
2010-12-02 17:38:18 +00:00
|
|
|
|
|
|
|
switch (geom->type)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
return 0;
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case LINETYPE:
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
return 1;
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
case POLYGONTYPE:
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case TINTYPE:
|
|
|
|
return 2;
|
|
|
|
case POLYHEDRALSURFACETYPE:
|
|
|
|
{
|
|
|
|
/* A closed polyhedral surface contains a volume. */
|
|
|
|
int closed = lwpsurface_is_closed((LWPSURFACE*)geom);
|
|
|
|
return ( closed ? 3 : 2 );
|
|
|
|
}
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
{
|
|
|
|
int maxdim = 0, i;
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
for( i = 0; i < col->ngeoms; i++ )
|
|
|
|
{
|
|
|
|
int dim = lwgeom_dimension(col->geoms[i]);
|
|
|
|
maxdim = ( dim > maxdim ? dim : maxdim );
|
|
|
|
}
|
|
|
|
return maxdim;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
lwerror("lwgeom_dimension: unsupported input geometry type: %s",
|
|
|
|
lwtype_name(geom->type));
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-11-18 18:37:27 +00:00
|
|
|
/**
|
|
|
|
* Count rings in an #LWGEOM.
|
|
|
|
*/
|
|
|
|
int lwgeom_count_rings(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
/* Null? Empty? Zero. */
|
|
|
|
if( ! geom || lwgeom_is_empty(geom) )
|
|
|
|
return 0;
|
|
|
|
|
2010-12-02 16:13:39 +00:00
|
|
|
switch (geom->type)
|
2010-11-18 18:37:27 +00:00
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case LINETYPE:
|
|
|
|
result = 0;
|
|
|
|
break;
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
result = 1;
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
result = ((LWPOLY *)geom)->nrings;
|
|
|
|
break;
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
result = ((LWCURVEPOLY *)geom)->nrings;
|
|
|
|
break;
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case POLYHEDRALSURFACETYPE:
|
|
|
|
case TINTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
{
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
int i = 0;
|
|
|
|
for( i = 0; i < col->ngeoms; i++ )
|
|
|
|
result += lwgeom_count_rings(col->geoms[i]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
2010-12-02 16:13:39 +00:00
|
|
|
lwerror("lwgeom_count_rings: unsupported input geometry type: %s", lwtype_name(geom->type));
|
2010-11-18 18:37:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
LWDEBUGF(3, "counted %d rings", result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2009-11-21 06:08:40 +00:00
|
|
|
int lwgeom_is_empty(const LWGEOM *geom)
|
2009-09-17 02:33:49 +00:00
|
|
|
{
|
|
|
|
int result = LW_FALSE;
|
2010-02-25 17:54:08 +00:00
|
|
|
LWDEBUGF(4, "lwgeom_is_empty: got type %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(geom->type));
|
2010-02-25 17:54:08 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (geom->type)
|
2009-09-17 02:33:49 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
case POINTTYPE:
|
|
|
|
return lwpoint_is_empty((LWPOINT*)geom);
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
return lwline_is_empty((LWLINE*)geom);
|
|
|
|
break;
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
return lwcircstring_is_empty((LWCIRCSTRING*)geom);
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return lwpoly_is_empty((LWPOLY*)geom);
|
|
|
|
break;
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
return lwtriangle_is_empty((LWTRIANGLE*)geom);
|
|
|
|
break;
|
2010-02-01 17:35:55 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COMPOUNDTYPE:
|
2010-11-18 05:28:19 +00:00
|
|
|
case CURVEPOLYTYPE:
|
2010-02-01 17:35:55 +00:00
|
|
|
case MULTICURVETYPE:
|
|
|
|
case MULTISURFACETYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2010-02-01 17:35:55 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return lwcollection_is_empty((LWCOLLECTION *)geom);
|
|
|
|
break;
|
|
|
|
default:
|
2010-02-25 17:54:08 +00:00
|
|
|
lwerror("lwgeom_is_empty: unsupported input geometry type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(geom->type));
|
2010-02-01 17:35:55 +00:00
|
|
|
break;
|
2009-09-17 02:33:49 +00:00
|
|
|
}
|
|
|
|
return result;
|
2009-09-30 23:59:01 +00:00
|
|
|
}
|
|
|
|
|
2010-02-24 13:50:22 +00:00
|
|
|
int lwgeom_has_srid(const LWGEOM *geom)
|
|
|
|
{
|
2011-09-28 23:38:56 +00:00
|
|
|
if ( geom->srid != SRID_UNKNOWN )
|
2010-02-24 13:50:22 +00:00
|
|
|
return LW_TRUE;
|
2010-08-15 08:30:08 +00:00
|
|
|
|
2010-02-24 13:50:22 +00:00
|
|
|
return LW_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-30 23:59:01 +00:00
|
|
|
static int lwcollection_dimensionality(LWCOLLECTION *col)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int dimensionality = 0;
|
2010-02-01 17:35:55 +00:00
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
2009-09-30 23:59:01 +00:00
|
|
|
{
|
|
|
|
int d = lwgeom_dimensionality(col->geoms[i]);
|
2010-02-01 17:35:55 +00:00
|
|
|
if ( d > dimensionality )
|
2009-09-30 23:59:01 +00:00
|
|
|
dimensionality = d;
|
|
|
|
}
|
|
|
|
return dimensionality;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int lwgeom_dimensionality(LWGEOM *geom)
|
|
|
|
{
|
2010-09-05 15:25:50 +00:00
|
|
|
int dim;
|
|
|
|
|
2010-02-25 17:54:08 +00:00
|
|
|
LWDEBUGF(3, "lwgeom_dimensionality got type %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(geom->type));
|
2010-02-25 17:54:08 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (geom->type)
|
2009-09-30 23:59:01 +00:00
|
|
|
{
|
2010-02-01 17:35:55 +00:00
|
|
|
case POINTTYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case POLYGONTYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
2010-02-01 17:35:55 +00:00
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
return 2;
|
|
|
|
break;
|
2010-09-05 15:25:50 +00:00
|
|
|
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2010-09-05 15:25:50 +00:00
|
|
|
dim = lwgeom_is_solid(geom)?3:2;
|
|
|
|
return dim;
|
2010-07-25 21:20:09 +00:00
|
|
|
break;
|
2010-09-05 15:25:50 +00:00
|
|
|
|
2010-02-01 17:35:55 +00:00
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return lwcollection_dimensionality((LWCOLLECTION *)geom);
|
|
|
|
break;
|
|
|
|
default:
|
2010-02-25 17:54:08 +00:00
|
|
|
lwerror("lwgeom_dimensionality: unsupported input geometry type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(geom->type));
|
2010-02-01 17:35:55 +00:00
|
|
|
break;
|
2009-09-30 23:59:01 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-02-21 12:22:08 +00:00
|
|
|
|
|
|
|
extern LWGEOM* lwgeom_remove_repeated_points(LWGEOM *in)
|
|
|
|
{
|
2010-02-25 17:54:08 +00:00
|
|
|
LWDEBUGF(4, "lwgeom_remove_repeated_points got type %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(in->type));
|
2010-02-25 17:54:08 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (in->type)
|
2010-02-21 12:22:08 +00:00
|
|
|
{
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
return lwmpoint_remove_repeated_points((LWMPOINT*)in);
|
|
|
|
break;
|
|
|
|
case LINETYPE:
|
|
|
|
return lwline_remove_repeated_points((LWLINE*)in);
|
|
|
|
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-02-21 12:22:08 +00:00
|
|
|
return lwcollection_remove_repeated_points((LWCOLLECTION *)in);
|
|
|
|
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return lwpoly_remove_repeated_points((LWPOLY *)in);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POINTTYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
case TINTYPE:
|
|
|
|
/* No point is repeated for a single point, or for Triangle or TIN */
|
2010-02-21 12:22:08 +00:00
|
|
|
return in;
|
|
|
|
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTICURVETYPE:
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
/* Dunno how to handle these, will return untouched */
|
|
|
|
return in;
|
|
|
|
|
|
|
|
default:
|
2010-02-26 00:16:25 +00:00
|
|
|
lwnotice("lwgeom_remove_repeated_points: unsupported geometry type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(in->type));
|
2010-02-21 12:22:08 +00:00
|
|
|
return in;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-02-25 13:38:57 +00:00
|
|
|
|
2010-11-18 05:28:19 +00:00
|
|
|
LWGEOM* lwgeom_flip_coordinates(LWGEOM *in)
|
2010-02-25 13:38:57 +00:00
|
|
|
{
|
|
|
|
LWCOLLECTION *col;
|
|
|
|
LWPOLY *poly;
|
|
|
|
int i;
|
|
|
|
|
2010-07-25 21:20:09 +00:00
|
|
|
LWDEBUGF(4, "lwgeom_flip_coordinates, got type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(in->type));
|
2010-02-25 13:38:57 +00:00
|
|
|
|
2010-11-21 19:02:23 +00:00
|
|
|
switch (in->type)
|
2010-02-25 13:38:57 +00:00
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
ptarray_flip_coordinates(lwgeom_as_lwpoint(in)->point);
|
|
|
|
return in;
|
|
|
|
|
|
|
|
case LINETYPE:
|
|
|
|
ptarray_flip_coordinates(lwgeom_as_lwline(in)->points);
|
|
|
|
return in;
|
|
|
|
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
ptarray_flip_coordinates(lwgeom_as_lwcircstring(in)->points);
|
|
|
|
return in;
|
|
|
|
|
|
|
|
case POLYGONTYPE:
|
|
|
|
poly = (LWPOLY *) in;
|
|
|
|
for (i=0; i<poly->nrings; i++)
|
|
|
|
ptarray_flip_coordinates(poly->rings[i]);
|
|
|
|
return in;
|
|
|
|
|
2010-08-13 17:29:29 +00:00
|
|
|
case TRIANGLETYPE:
|
|
|
|
ptarray_flip_coordinates(lwgeom_as_lwtriangle(in)->points);
|
|
|
|
return in;
|
|
|
|
|
2010-02-25 13:38:57 +00:00
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
case MULTISURFACETYPE:
|
|
|
|
case MULTICURVETYPE:
|
2010-07-25 21:20:09 +00:00
|
|
|
case POLYHEDRALSURFACETYPE:
|
2010-08-13 17:29:29 +00:00
|
|
|
case TINTYPE:
|
2010-02-25 13:38:57 +00:00
|
|
|
col = (LWCOLLECTION *) in;
|
|
|
|
for (i=0; i<col->ngeoms; i++)
|
|
|
|
lwgeom_flip_coordinates(col->geoms[i]);
|
2010-02-25 17:54:08 +00:00
|
|
|
return in;
|
2010-02-25 13:38:57 +00:00
|
|
|
|
|
|
|
default:
|
2010-02-25 17:54:08 +00:00
|
|
|
lwerror("lwgeom_flip_coordinates: unsupported geometry type: %s",
|
2010-11-21 19:02:23 +00:00
|
|
|
lwtype_name(in->type));
|
2010-02-25 13:38:57 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-10-20 22:51:30 +00:00
|
|
|
|
2011-08-19 09:34:58 +00:00
|
|
|
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
|
2010-10-20 22:51:30 +00:00
|
|
|
{
|
|
|
|
int i;
|
2010-10-25 04:57:14 +00:00
|
|
|
|
2010-12-21 18:01:27 +00:00
|
|
|
LWDEBUGF(4,"entered with srid=%d",srid);
|
|
|
|
|
2010-12-22 21:16:06 +00:00
|
|
|
geom->srid = srid;
|
2010-10-25 04:57:14 +00:00
|
|
|
|
2010-11-02 06:20:22 +00:00
|
|
|
if ( lwgeom_is_collection(geom) )
|
2010-10-20 22:51:30 +00:00
|
|
|
{
|
2010-12-21 21:39:28 +00:00
|
|
|
/* All the children are set to the unknown SRID value
|
|
|
|
TODO: change this so the children have a known SRID? */
|
2010-10-20 22:51:30 +00:00
|
|
|
LWCOLLECTION *col = lwgeom_as_lwcollection(geom);
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
{
|
|
|
|
lwgeom_set_srid(col->geoms[i], SRID_UNKNOWN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-18 05:28:19 +00:00
|
|
|
LWGEOM* lwgeom_simplify(const LWGEOM *igeom, double dist)
|
|
|
|
{
|
2010-12-02 16:13:39 +00:00
|
|
|
switch (igeom->type)
|
2010-11-18 05:28:19 +00:00
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
return lwgeom_clone(igeom);
|
|
|
|
case LINETYPE:
|
|
|
|
return (LWGEOM*)lwline_simplify((LWLINE*)igeom, dist);
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return (LWGEOM*)lwpoly_simplify((LWPOLY*)igeom, dist);
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return (LWGEOM*)lwcollection_simplify((LWCOLLECTION *)igeom, dist);
|
|
|
|
default:
|
2010-12-02 16:13:39 +00:00
|
|
|
lwerror("lwgeom_simplify: unsupported geometry type: %s",lwtype_name(igeom->type));
|
2010-11-18 05:28:19 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-11-30 21:54:55 +00:00
|
|
|
|
|
|
|
double lwgeom_area(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
return lwpoly_area((LWPOLY*)geom);
|
|
|
|
else if ( type == CURVEPOLYTYPE )
|
|
|
|
return lwcurvepoly_area((LWCURVEPOLY*)geom);
|
|
|
|
else if (type == TRIANGLETYPE )
|
|
|
|
return lwtriangle_area((LWTRIANGLE*)geom);
|
|
|
|
else if ( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
double area = 0.0;
|
|
|
|
int i;
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
area += lwgeom_area(col->geoms[i]);
|
|
|
|
return area;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
2010-11-30 22:55:54 +00:00
|
|
|
|
2010-12-01 20:28:29 +00:00
|
|
|
double lwgeom_perimeter(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
return lwpoly_perimeter((LWPOLY*)geom);
|
|
|
|
else if ( type == CURVEPOLYTYPE )
|
|
|
|
return lwcurvepoly_perimeter((LWCURVEPOLY*)geom);
|
|
|
|
else if ( type == TRIANGLETYPE )
|
|
|
|
return lwtriangle_perimeter((LWTRIANGLE*)geom);
|
|
|
|
else if ( type == POLYHEDRALSURFACETYPE || type == TINTYPE )
|
|
|
|
{
|
|
|
|
return tgeom_perimeter(tgeom_from_lwgeom(geom));
|
|
|
|
}
|
|
|
|
else if ( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
double perimeter = 0.0;
|
|
|
|
int i;
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
perimeter += lwgeom_perimeter(col->geoms[i]);
|
|
|
|
return perimeter;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double lwgeom_perimeter_2d(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
if ( type == POLYGONTYPE )
|
|
|
|
return lwpoly_perimeter_2d((LWPOLY*)geom);
|
|
|
|
else if ( type == CURVEPOLYTYPE )
|
|
|
|
return lwcurvepoly_perimeter_2d((LWCURVEPOLY*)geom);
|
|
|
|
else if ( type == TRIANGLETYPE )
|
|
|
|
return lwtriangle_perimeter_2d((LWTRIANGLE*)geom);
|
|
|
|
else if ( type == POLYHEDRALSURFACETYPE || type == TINTYPE )
|
|
|
|
{
|
|
|
|
return tgeom_perimeter(tgeom_from_lwgeom(geom));
|
|
|
|
}
|
|
|
|
else if ( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
double perimeter = 0.0;
|
|
|
|
int i;
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
perimeter += lwgeom_perimeter_2d(col->geoms[i]);
|
|
|
|
return perimeter;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
2010-11-30 22:55:54 +00:00
|
|
|
double lwgeom_length(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
if ( type == LINETYPE )
|
|
|
|
return lwline_length((LWLINE*)geom);
|
|
|
|
else if ( type == CIRCSTRINGTYPE )
|
|
|
|
return lwcircstring_length((LWCIRCSTRING*)geom);
|
|
|
|
else if ( type == COMPOUNDTYPE )
|
|
|
|
return lwcompound_length((LWCOMPOUND*)geom);
|
|
|
|
else if ( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
double length = 0.0;
|
|
|
|
int i;
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
length += lwgeom_length(col->geoms[i]);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
double lwgeom_length_2d(const LWGEOM *geom)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
if ( type == LINETYPE )
|
|
|
|
return lwline_length_2d((LWLINE*)geom);
|
|
|
|
else if ( type == CIRCSTRINGTYPE )
|
|
|
|
return lwcircstring_length_2d((LWCIRCSTRING*)geom);
|
|
|
|
else if ( type == COMPOUNDTYPE )
|
|
|
|
return lwcompound_length_2d((LWCOMPOUND*)geom);
|
|
|
|
else if ( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
double length = 0.0;
|
|
|
|
int i;
|
|
|
|
LWCOLLECTION *col = (LWCOLLECTION*)geom;
|
|
|
|
for ( i = 0; i < col->ngeoms; i++ )
|
|
|
|
length += lwgeom_length_2d(col->geoms[i]);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
2010-12-01 00:53:03 +00:00
|
|
|
void
|
|
|
|
lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
|
|
|
|
{
|
|
|
|
int type = geom->type;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
/* Take advantage of fact tht pt/ln/circ/tri have same memory structure */
|
|
|
|
case POINTTYPE:
|
|
|
|
case LINETYPE:
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
{
|
|
|
|
LWLINE *l = (LWLINE*)geom;
|
|
|
|
ptarray_affine(l->points, affine);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case POLYGONTYPE:
|
|
|
|
{
|
|
|
|
LWPOLY *p = (LWPOLY*)geom;
|
|
|
|
for( i = 0; i < p->nrings; i++ )
|
|
|
|
ptarray_affine(p->rings[i], affine);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
{
|
|
|
|
LWCURVEPOLY *c = (LWCURVEPOLY*)geom;
|
|
|
|
for( i = 0; i < c->nrings; i++ )
|
|
|
|
lwgeom_affine(c->rings[i], affine);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
if( lwgeom_is_collection(geom) )
|
|
|
|
{
|
|
|
|
LWCOLLECTION *c = (LWCOLLECTION*)geom;
|
|
|
|
for( i = 0; i < c->ngeoms; i++ )
|
|
|
|
{
|
|
|
|
lwgeom_affine(c->geoms[i], affine);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lwerror("lwgeom_affine: unable to handle type '%s'", lwtype_name(type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-01-09 17:01:48 +00:00
|
|
|
LWGEOM *
|
|
|
|
lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
|
|
|
|
{
|
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case POINTTYPE:
|
|
|
|
return lwpoint_as_lwgeom(lwpoint_construct_empty(srid, hasz, hasm));
|
|
|
|
case LINETYPE:
|
|
|
|
return lwline_as_lwgeom(lwline_construct_empty(srid, hasz, hasm));
|
|
|
|
case POLYGONTYPE:
|
|
|
|
return lwpoly_as_lwgeom(lwpoly_construct_empty(srid, hasz, hasm));
|
|
|
|
case CURVEPOLYTYPE:
|
|
|
|
return lwcurvepoly_as_lwgeom(lwcurvepoly_construct_empty(srid, hasz, hasm));
|
|
|
|
case CIRCSTRINGTYPE:
|
|
|
|
return lwcircstring_as_lwgeom(lwcircstring_construct_empty(srid, hasz, hasm));
|
|
|
|
case TRIANGLETYPE:
|
|
|
|
return lwtriangle_as_lwgeom(lwtriangle_construct_empty(srid, hasz, hasm));
|
|
|
|
case COMPOUNDTYPE:
|
|
|
|
case MULTIPOINTTYPE:
|
|
|
|
case MULTILINETYPE:
|
|
|
|
case MULTIPOLYGONTYPE:
|
|
|
|
case COLLECTIONTYPE:
|
|
|
|
return lwcollection_as_lwgeom(lwcollection_construct_empty(type, srid, hasz, hasm));
|
|
|
|
default:
|
|
|
|
lwerror("lwgeom_construct_empty: unsupported geometry type: %s",
|
|
|
|
lwtype_name(type));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-01 00:53:03 +00:00
|
|
|
|