postgis/liblwgeom/libgeom.h
Paul Ramsey 2f24c23327 Add gbox string constructor for testing purposes
git-svn-id: http://svn.osgeo.org/postgis/trunk@4504 b70326c6-7e19-0410-871a-916f4a2858ee
2009-09-16 21:09:24 +00:00

469 lines
14 KiB
C

/**********************************************************************
* $Id$
*
* PostGIS - Spatial Types for PostgreSQL
* http://postgis.refractions.net
* Copyright 2001-2006 Refractions Research Inc.
* Copyright 2007-2008 Mark Cave-Ayland
* Copyright 2008 Paul Ramsey <pramsey@cleverelephant.ca>
*
* This is free software; you can redistribute and/or modify it under
* the terms of the GNU General Public Licence. See the COPYING file.
*
**********************************************************************/
#include "liblwgeom.h"
#include <string.h>
#include <assert.h>
#include <regex.h>
/**
* PI
*/
#define PI 3.1415926535897932384626433832795
/**
* Return types for functions with status returns.
*/
#define G_FAILURE 0
#define G_SUCCESS 1
#define LW_TRUE 1
#define LW_FALSE 0
/**
* Maximum allowed SRID value.
* Currently we are using 20 bits (1048575) of storage for SRID.
*/
#define SRID_MAXIMUM 999999
/**
* Macros for manipulating the 'flags' byte. A uchar used as follows:
* ---RGBMZ
* Three unused bits, followed by ReadOnly, Geodetic, HasBBox, HasM and HasZ flags.
*/
#define FLAGS_GET_Z(flags) ((flags) & 0x01)
#define FLAGS_GET_M(flags) (((flags) & 0x02)>>1)
#define FLAGS_GET_BBOX(flags) (((flags) & 0x4)>>2)
#define FLAGS_GET_GEODETIC(flags) (((flags) & 0x08)>>3)
#define FLAGS_GET_READONLY(flags) (((flags) & 0x10)>>4)
#define FLAGS_SET_Z(flags, value) ((value) ? ((flags) | 0x01) : ((flags) & 0xFE))
#define FLAGS_SET_M(flags, value) ((value) ? ((flags) | 0x02) : ((flags) & 0xFD))
#define FLAGS_SET_BBOX(flags, value) ((value) ? ((flags) | 0x04) : ((flags) & 0xFB))
#define FLAGS_SET_GEODETIC(flags, value) ((value) ? ((flags) | 0x08) : ((flags) & 0xF7))
#define FLAGS_SET_READONLY(flags, value) ((value) ? ((flags) | 0x10) : ((flags) & 0xEF))
#define FLAGS_NDIMS(flags) (2 + FLAGS_GET_Z(flags) + FLAGS_GET_M(flags))
/**
* Macro for reading the size from the GSERIALIZED size attribute.
* Cribbed from PgSQL, top 30 bits are size. Use VARSIZE() when working
* internally with PgSQL.
*/
#define SIZE_GET(varsize) (((varsize) >> 2) & 0x3FFFFFFF)
#define SIZE_SET(varsize, size) (((varsize) & 0x00000003)|(((size) & 0x3FFFFFFF) << 2 ))
/**
* Macros for manipulating the 'typemod' int. An int32 used as follows:
* Plus/minus = Top bit.
* Spare bits = Next 3 bits.
* SRID = Next 20 bits.
* TYPE = Next 6 bits.
* ZM Flags = Bottom 2 bits.
*/
#define TYPMOD_GET_SRID(typmod) ((typmod & 0x0FFFFF00)>>8)
#define TYPMOD_SET_SRID(typmod, srid) ((typmod & 0x000000FF) | ((srid & 0x000FFFFF)<<8))
#define TYPMOD_GET_TYPE(typmod) ((typmod & 0x000000FC)>>2)
#define TYPMOD_SET_TYPE(typmod, type) ((typmod & 0xFFFFFF03) | ((type & 0x0000003F)<<2))
#define TYPMOD_GET_Z(typmod) ((typmod & 0x00000002)>>1)
#define TYPMOD_SET_Z(typmod) (typmod | 0x00000002)
#define TYPMOD_GET_M(typmod) (typmod & 0x00000001)
#define TYPMOD_SET_M(typmod) (typmod | 0x00000001)
#define TYPMOD_GET_NDIMS(typmod) (2+TYPMOD_GET_Z(typmod)+TYPMOD_GET_M(typmod))
/**
* GBOX structure.
* Include the flags, so we don't have to constantly pass them
* into the functions.
*/
typedef struct
{
uchar flags;
double xmin;
double xmax;
double ymin;
double ymax;
double zmin;
double zmax;
double mmin;
double mmax;
} GBOX;
/**
* Coordinate structure. This will be created on demand from GPTARRAY when
* needed by algorithms and whatnot.
*/
typedef struct
{
uchar flags;
double *ordinates;
} GCOORDINATE;
/* Start with space for 16 points */
#define G_PT_ARRAY_DEFAULT_POINTS 16
/**
* GPTARRAY structure. Holder of our ordinates. Dynamically sized
* container for coordinate arrays.
*/
typedef struct
{
uchar flags;
size_t capacity;
uint32 npoints;
double *ordinates;
} GPTARRAY;
/**
* GSERIALIZED
*/
typedef struct
{
uint32 size; /* For PgSQL use only, use VAR* macros to manipulate. */
uchar srid[3]; /* 24 bits of SRID */
uchar flags; /* HasZ, HasM, HasBBox, IsGeodetic, IsReadOnly */
uchar data[1]; /* See gserialized.txt */
} GSERIALIZED;
/**
* G_GEOMETRY
*
* flags = bit flags, see FLAGS_HAS_* defines
* type = enumerated OGC geometry type number
*/
typedef struct
{
uchar flags;
uint32 type;
GBOX *bbox; /* NULL == unneeded */
uint32 srid; /* 0 == unknown */
void *data;
} G_GEOMETRY;
/* POINTTYPE */
typedef struct
{
uchar flags;
uint32 type;
GBOX *bbox; /* NULL == unneeded */
uint32 srid; /* 0 == unknown */
GPTARRAY *point;
} G_POINT;
/* LINETYPE */
/* CIRCSTRINGTYPE */
typedef struct
{
uchar flags;
uint32 type;
GBOX *bbox; /* NULL == unneeded */
uint32 srid; /* 0 == unknown */
GPTARRAY *points;
} G_LINESTRING;
typedef G_LINESTRING G_CIRCULARSTRING;
/* POLYGONTYPE */
typedef struct
{
uchar flags;
uint32 type;
GBOX *bbox; /* NULL == unneeded */
uint32 srid; /* 0 == unknown */
size_t capacity; /* How much space is allocated for *rings? */
uint32 nrings;
GPTARRAY **rings; /* rings[0] is the exterior ring */
} G_POLYGON;
/* MULTIPOINTTYPE */
/* MULTILINETYPE */
/* MULTIPOINTTYPE */
/* COMPOUNDTYPE */
/* CURVEPOLYTYPE */
/* MULTICURVETYPE */
/* MULTISURFACETYPE */
/* COLLECTIONTYPE */
typedef struct
{
uchar flags;
uint32 type;
GBOX *bbox; /* NULL == unneeded */
uint32 srid; /* 0 == unknown */
size_t capacity; /* How much space is allocated for *geoms? */
uint32 ngeoms;
G_GEOMETRY **geoms;
} G_COLLECTION;
/*
** All the collection types share the same physical structure as the
** generic geometry collection. We add type aliases so we can be more
** explicit in our functions later.
*/
typedef G_COLLECTION G_MPOINT;
typedef G_COLLECTION G_MLINESTRING;
typedef G_COLLECTION G_MPOLYGON;
typedef G_COLLECTION G_MSURFACE;
typedef G_COLLECTION G_MCURVE;
typedef G_COLLECTION G_COMPOUNDCURVE;
typedef G_COLLECTION G_CURVEPOLYGON;
/*
* Utility casts from GEOMETRY to concrete type.
* Return NULL if cast is illegal.
extern G_POINT* g_geometry_as_point(G_GEOMETRY *g);
extern G_LINESTRING* g_geometry_as_linestring(G_GEOMETRY *g);
extern G_POLYGON* g_geometry_as_polygon(G_GEOMETRY *g);
extern G_MPOINT* g_geometry_as_mpoint(G_GEOMETRY *g);
extern G_MLINESTRING* g_geometry_as_mlinestring(G_GEOMETRY *g);
extern G_MPOLYGON* g_geometry_as_mpolygon(G_GEOMETRY *g);
*/
/*
* Utility casts from concrete type to GEOMETRY.
* Return NULL if cast is illegal.
extern G_GEOMETRY* g_point_as_geometry(G_POINT *g);
extern G_GEOMETRY* g_linestring_as_geometry(G_LINESTRING *g);
extern G_GEOMETRY* g_polygon_as_geometry(G_POLYGON *g);
extern G_GEOMETRY* g_mpoint_as_geometry(G_MPOINT *g);
extern G_GEOMETRY* g_mlinestring_as_geometry(G_MLINESTRING *g);
extern G_GEOMETRY* g_mpolygon_as_geometry(G_POLYGON *g);
extern G_GEOMETRY* g_collection_as_geometry(G_COLLECTION *g);
*/
/***********************************************************************
* Coordinate creator, set, get and destroy.
*/
extern GCOORDINATE* gcoord_new(int ndims);
extern GCOORDINATE* gcoord_new_with_flags(uchar flags);
extern GCOORDINATE* gcoord_new_with_flags_and_ordinates(uchar flags, double *ordinates);
extern GCOORDINATE* gcoord_copy(GCOORDINATE *coord);
extern void gcoord_free(GCOORDINATE *coord);
extern void gcoord_set_x(GCOORDINATE *coord, double x);
extern void gcoord_set_y(GCOORDINATE *coord, double y);
extern void gcoord_set_z(GCOORDINATE *coord, double z);
extern void gcoord_set_m(GCOORDINATE *coord, double m);
extern void gcoord_set_ordinates(GCOORDINATE *coord, double *ordinates);
extern void gcoord_set_ordinate(GCOORDINATE *coord, double ordinate, int index);
extern double gcoord_get_x(GCOORDINATE *coord);
extern double gcoord_get_y(GCOORDINATE *coord);
extern double gcoord_get_z(GCOORDINATE *coord);
extern double gcoord_get_m(GCOORDINATE *coord);
/***********************************************************************
* Point arrays, set, get and destroy.
*/
extern GPTARRAY* gptarray_new(uchar flags);
extern GPTARRAY* gptarray_new_with_size(uchar flags, int npoints);
extern GPTARRAY* gptarray_new_with_ordinates(uchar flags, int npoints, double *ordinates);
extern GPTARRAY* gptarray_copy(GPTARRAY *ptarray);
extern void gptarray_free(GPTARRAY *ptarray);
extern void gptarray_add_coord(GPTARRAY *ptarray, GCOORDINATE *coord);
extern GCOORDINATE* gptarray_get_coord_ro(GPTARRAY *ptarray, int i);
extern GCOORDINATE* gptarray_get_coord_new(GPTARRAY *ptarray, int i);
extern void gptarray_set_coord(GPTARRAY *ptarray, int i, GCOORDINATE *coord);
extern void gptarray_set_x(GPTARRAY *ptarray, int i, double x);
extern void gptarray_set_y(GPTARRAY *ptarray, int i, double y);
extern void gptarray_set_z(GPTARRAY *ptarray, int i, double z);
extern void gptarray_set_m(GPTARRAY *ptarray, int i, double m);
extern double gptarray_get_x(GPTARRAY *ptarray, int i);
extern double gptarray_get_y(GPTARRAY *ptarray, int i);
extern double gptarray_get_z(GPTARRAY *ptarray, int i);
extern double gptarray_get_m(GPTARRAY *ptarray, int i);
/***********************************************************************
** Linestrings
*/
extern G_LINESTRING* glinestring_new_from_gptarray(GPTARRAY *ptarray);
extern G_LINESTRING* glinestring_new(uchar flags);
/***********************************************************************
** Utility functions for flag byte and srid_flag integer.
*/
/**
* Construct a new flags char.
*/
extern uchar gflags(int hasz, int hasm, int geodetic);
/**
* Extract the geometry type from the serialized form (it hides in
* the anonymous data area, so this is a handy function).
*/
extern uint32 gserialized_get_type(GSERIALIZED *g);
/**
* Extract the SRID from the serialized form (it is packed into
* three bytes so this is a handy function).
*/
extern uint32 gserialized_get_srid(GSERIALIZED *g);
/**
* Write the SRID into the serialized form (it is packed into
* three bytes so this is a handy function).
*/
extern void gserialized_set_srid(GSERIALIZED *g, uint32 srid);
/***********************************************************************
** Functions for managing serialized forms and bounding boxes.
*/
/**
* Calculate the geocentric bounding box directly from the serialized
* form of the geodetic coordinates. Only accepts serialized geographies
* flagged as geodetic. Caller is responsible for disposing of the GBOX.
*/
extern GBOX* gserialized_calculate_gbox_geocentric(GSERIALIZED *g);
/**
* Calculate the geocentric bounding box directly from the serialized
* form of the geodetic coordinates. Only accepts serialized geographies
* flagged as geodetic.
*/
int gserialized_calculate_gbox_geocentric_p(GSERIALIZED *g, GBOX *g_box);
/**
* Return a WKT representation of the gserialized geometry.
* Caller is responsible for disposing of the char*.
*/
extern char* gserialized_to_string(GSERIALIZED *g);
/**
* Return a copy of the input serialized geometry.
*/
extern GSERIALIZED* gserialized_copy(GSERIALIZED *g);
/**
* Check that coordinates of LWGEOM are all within the geodetic range.
*/
extern int lwgeom_check_geodetic(const LWGEOM *geom);
/**
* Calculate the geodetic bounding box for an LWGEOM. Z/M coordinates are
* ignored for this calculation. Pass in non-null, geodetic bounding box for function
* to fill out. LWGEOM must have been built from a GSERIALIZED to provide
* double aligned point arrays.
*/
extern int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox);
/**
* Calculate the 2-4D bounding box of a geometry. Z/M coordinates are honored
* for this calculation, though for curves they are not included in calculations
* of curvature.
*/
extern int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox);
/**
* New function to read doubles directly from the double* coordinate array
* of an aligned lwgeom #POINTARRAY (built by de-serializing a #GSERIALIZED).
*/
extern int getPoint2d_p_ro(const POINTARRAY *pa, int n, POINT2D **point);
/**
* Calculate box and add values to gbox. Return #G_SUCCESS on success.
*/
extern int ptarray_calculate_gbox_geodetic(POINTARRAY *pa, GBOX *gbox);
/**
* Create a new gbox with the dimensionality indicated by the flags. Caller
* is responsible for freeing.
*/
extern GBOX* gbox_new(uchar flags);
/**
* Update the merged #GBOX to be large enough to include itself and the new box.
*/
extern int gbox_merge(GBOX new_box, GBOX *merged_box);
/**
* Update the #GBOX to be large enough to include itself and the new point.
*/
extern int gbox_merge_point3d(POINT3D p, GBOX *gbox);
/**
* Allocate a string representation of the #GBOX, based on dimensionality of flags.
*/
extern char* gbox_to_string(GBOX *gbox);
/**
* Return a copy of the #GBOX, based on dimensionality of flags.
*/
extern GBOX* gbox_copy(GBOX *gbox);
/**
* Warning, do not use this function, it is very particular about inputs.
*/
extern GBOX* gbox_from_string(char *str);
/**
* Return #LW_TRUE if the #GBOX overlaps, #LW_FALSE otherwise.
*/
extern int gbox_overlaps(GBOX *g1, GBOX *g2);
/**
* Copy the values of original #GBOX into duplicate.
*/
extern void gbox_duplicate(GBOX original, GBOX *duplicate);
/**
* Return the number of bytes necessary to hold a #GBOX of this dimension in
* serialized form.
*/
extern size_t gbox_serialized_size(uchar flags);
/**
* Utility function to get type number from string. For example, a string 'POINTZ'
* would return type of 1 and z of 1 and m of 0. Valid
*/
extern int geometry_type_from_string(char *str, int *type, int *z, int *m);
/**
* Calculate required memory segment to contain a serialized form of the LWGEOM.
* Primarily used internally by the serialization code. Exposed to allow the cunit
* tests to exercise it.
*/
extern size_t gserialized_from_lwgeom_size(LWGEOM *geom, GBOX *gbox);
/**
* Allocate a new #GSERIALIZED from an #LWGEOM. For all non-point types, a bounding
* box will be calculated and embedded in the serialization. The geodetic flag is used
* to control the box calculation (cartesian or geocentric). If set, the size pointer
* will contain the size of the final output, which is useful for setting the PgSQL
* VARSIZE information.
*/
extern GSERIALIZED* gserialized_from_lwgeom(LWGEOM *geom, int is_geodetic, size_t *size);
/**
* Allocate a new #LWGEOM from a #GSERIALIZED. The resulting #LWGEOM will have coordinates
* that are double aligned and suitable for direct reading using getPoint2d_p_ro
*/
extern LWGEOM* lwgeom_from_gserialized(GSERIALIZED *g);
/**
* Serialize/deserialize from/to #G_GEOMETRY into #GSERIALIZED
extern size_t gserialized_from_ggeometry_size(G_GEOMETRY *geom);
extern GSERIALIZED* gserialized_from_ggeometry(G_GEOMETRY *geom);
extern G_GEOMETRY* ggeometry_from_gserialized(GSERIALIZED *g);
*/