[postgis-users] LWGEOM -- initial lwgeom.h file

Ralph Mason ralph.mason at telogis.com
Mon Mar 1 18:03:30 PST 2004


Hi David,

I think it would be good not to have to do any allocations to used these 
things. Make everything a LW_GEOM then there is no need to allocate, 
copy and reformat.

Lets take the LW_LINE for example, I suggest there is no LW_LINE type

some macros

LW_SRID(lw_geom) //returns the SRID if one exists or -1 if none
LW_TYPE(lw_geom) //returns the type
LW_LINEPOINTS(lw_geom) //gets point data

debug version can do checking on the types etc.

so then we can do

switch(LW_TYPE(lw_geom) ){
    case LW_LINE:
          if ( LW_3D(lw_geom) ){
                POINT3D * points = LW_LINEPOINTS(lw_geom);
                //use points
        }
          else{
                POINT2D * points = LW_LINEPOINTS(lw_geom);
                //use points
            }

       default:
          //AN ERROR - We only work with lines
}

No data is copied.  There functions to create a LW_LINE would return a 
LW_GEOM.

Another macro could be something to verify the type of a geometry and 
return an error if it's the wrong type

eg

LW_VERIFY_TYPE(a_geom,LW_LINE);

construction

extern LWGEOM lwline_construct(char is3d, int SRID, int npoints, POINT3D *points);


With a single type, there becomes only one bounding box function. I also 
suggest you pass the bounding box to the creation function, then the box 
can sit on the heap if required, or go directly into the right structure.

extern void findbbox(LW_GEOM *a_geom,/* out */BOX3D* ret_box);

I am not sure I understand why bounding box can not be calculated and 
stored when a geometry goes over a given size? Then the above function 
can copy when one exists and calculate if not.

This also leads to only a single serialize function etc.

While we are talking about this, I suggest a standard flex bison/parser 
for WKT, the parser can pretty easily output a LW_GEOM with a bounding 
box when it exceeds a given threashold.  I would be happy to put this 
together.

Regards
Ralph





David Blasby wrote:

> I quickly put together a lwgeom.h file so you could see what the 
> lwgeom type will look like and the basic API for it.
>
> If folks could take a look and give me some feedback, I'll incorporate 
> your suggestions.
>
> As I note in the header, the "get" functions for the LWGEOM might be 
> slow, so we might want to make an "analysed lwgeom" that pre-computes 
> the position of the actual sub-geometries.
>
> typedef struct
> {
>     char    *serialized_form;
>     char    **subgeometries;
>     int     numSubGeometries;
> } LWGEOM_analysed;
>
> and :
>
> lwgeom_getsubgeometry(serialized_form, n) == 
> <LWGEOM_analysed>.subgeometries[n]
>
> dave
> ps. C really sucks compared to C++ and Java!
>
>------------------------------------------------------------------------
>
>//lwgeom.h
>
>// basic API for handling the LWGEOM, BOX2DFLOAT4, LWPOINT, LWLINE, and LWPOLY.
>
>
>typedef struct
>{
>	float xmin,
>	float ymin,
>	float xmax,
>	float ymax
>} BOX2DFLOAT4;
>
>
>/*
>
> LWGEOM types are an 8-bit char in this format:
>
>xxSDtttt
>
>WHERE
>    x = unused
>    S = 4 byte SRID attached (0= not attached (-1), 1= attached)
>    D = dimentionality (0=2d, 1=3d)
>    tttt = actual type (as per the WKB type):
>
>    enum wkbGeometryType {
>        wkbPoint = 1,
>        wkbLineString = 2,
>        wkbPolygon = 3,
>        wkbMultiPoint = 4,
>        wkbMultiLineString = 5,
>        wkbMultiPolygon = 6,
>        wkbGeometryCollection = 7
>    };
>
>*/
>
>
>/* already defined in postgis.h
>
> #define	POINTTYPE	1
> #define	LINETYPE	2
> #define	POLYGONTYPE	3
> #define	MULTIPOINTTYPE	4
> #define	MULTILINETYPE	5
> #define	MULTIPOLYGONTYPE	6
> #define	COLLECTIONTYPE	7
>
>*/
>
>
>extern boolean lwgeom_hasSRID(char type); // true iff S bit is set
>extern boolean lwgeom_is3d(char type);    // true iff D bit is set
>extern int     lwgeom_getType(char type); // returns the tttt value
>
>// POINT3D already defined in postgis.h
>// ALL LWGEOM structures will use POINT3D as an abstract point.
>// This means a 2d geometry will be stored as (x,y) in its serialized
>// form, but all functions will work on (x,y,0).  This keeps all the
>// analysis functions simple.
>// NOTE: for GEOS integration, we'll probably set z=NaN
>//        so look out - z might be NaN for 2d geometries!
>// typedef struct {	double	x,y,z;  } POINT3D;
>
>
>// all the base types (point/line/polygon) will have a
>// basic constructor, basic de-serializer, basic serializer, and
>// bounding box finder.
>
>
>
>//--------------------------------------------------------
>
>typedef struct
>{
>	char     is3d;   // true means points represent 3d points
>	int      SRID;   // spatial ref sys -1=none
>	int      npoint; // number of points in the points array
>	POINT3D *points; // array of POINT3D
>} LWLINE; //"light-weight line"
>
>// construct a new LWLINE.  points will be copied
>// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
>extern LWLINE lwline_construct(char is3d, int SRID, int npoints, POINT3D *points);
>
>// given the LWGEOM serialized form (or a pointer into a muli* one)
>// construct a proper LWLINE.
>// serialized_from should point to the 8bit type format (with type = 2)
>// See serialized form doc
>extern LWLINE lwline_deserialize(char *serialized_from);
>
>// convert this line into its serialize form
>// result's first char will be the 8bit type.  See serialized form doc
>extern char  *lwline_serialize(LWLINE *line);
>
>// find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
>extern BOX3D *lwline_findbbox(LWLINE *line);
>
>
>//--------------------------------------------------------
>
>typedef struct
>{
>   	char     is3d;   // true means points represent 3d points
>   	int      SRID;   // spatial ref sys
>   	POINT3D  point;  // NOTE: not a pointer!
>}  LWPOINT; // "light-weight point"
>
>// construct a new point.  point will be copied
>// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
>extern LWPOINT  lwpoint_construct(char is3d, int SRID, POINT3D *point);
>
>// given the LWPOINT serialized form (or a pointer into a muli* one)
>// construct a proper LWPOINT.
>// serialized_from should point to the 8bit type format (with type = 1)
>// See serialized form doc
>extern LWLINE lwpoint_deserialize(char *serialized_from);
>
>// convert this line into its serialize form
>// result's first char will be the 8bit type.  See serialized form doc
>extern char  *lwpoint_serialize(LWLINE *line);
>
>// find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
>extern BOX3D *lwpoint_findbbox(LWLINE *line);
>
>
>
>//--------------------------------------------------------
>
>
>typedef struct
>{
>	char is3d;
>	int  SRID;
>	int  nrings;
>	int  *npointsPerRing; // list of int (one per ring)
>	POINT3D **rings; // list of rings (list of points)
>} LWPOLY; // "light-weight polygon"
>
>// construct a new LWLINE.  arrays (points/points per ring) will be copied
>// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
>extern LWLINE lwpoly_construct(char is3d, int SRID, int nrings,int  *npointsPerRing, POINT3D **points);
>
>// construct a new LWLINE.  points will be copied
>// use SRID=-1 for unknown SRID (will have 8bit type's S = 0)
>// NOTE: this version takes a single list of points.  this will automatically
>//       create the **point struct.
>extern LWLINE lwpoly_construct2(char is3d, int SRID, int nrings,int  *npointsPerRing, POINT3D *points);
>
>// given the LWPOLY serialized form (or a pointer into a muli* one)
>// construct a proper LWPOLY.
>// serialized_from should point to the 8bit type format (with type = 3)
>// See serialized form doc
>extern LWPOLY lwpoly_deserialize(char *serialized_from);
>
>// find bounding box (standard one)  zmin=zmax=0 if 2d (might change to NaN)
>extern BOX3D *lwpoly_findbbox(LWPOLY *line);
>
>
>
>//------------------------------------------------------
>// Multi-geometries
>
>// These are all handled equivelently so its easy to write iterator code.
>//  NOTE NOTE: you can hand in a non-multigeometry to most of these functions
>//             and get usual behavior (ie. get geometry 0 on a POINT will return the
>//             point).  This makes coding even easier since you dont have to necessarily
>//             differenciate between the multi* and non-multi geometries.
>//
>// NOTE: these usually work directly off the serialized form, so they're a little more
>//        difficult to handle (and slower)
>// NOTE NOTE: the get functions maybe slow, so we may want to have an "analysed"
>//            lwgeom that would just have pointer to the start of each sub-geometry.
>
>
>
>// 1st geometry has geom_number = 0
>// if the actual sub-geometry isnt a POINT, null is returned (see _gettype()).
>// if there arent enough geometries, return null.
>// this is fine to call on a point (with geom_num=0), multipoint or geometrycollection
>extern LWPOINT lwgeom_getpoint(char *serialized_form, int geom_number);
>
>// 1st geometry has geom_number = 0
>// if the actual geometry isnt a LINE, null is returned (see _gettype()).
>// if there arent enough geometries, return null.
>// this is fine to call on a line, multiline or geometrycollection
>extern LWLINE lwgeom_getline(char *serialized_form, int geom_number);
>
>
>// 1st geometry has geom_number = 0
>// if the actual geometry isnt a POLYGON, null is returned (see _gettype()).
>// if there arent enough geometries, return null.
>// this is fine to call on a polygon, multipolygon or geometrycollection
>extern LWPOLY lwgeom_getpoly(char *serialized_form, int geom_number);
>
>// this gets the serialized form of a sub-geometry
>// 1st geometry has geom_number = 0
>// if this isnt a multi* geometry, and geom_number ==0 then it returns
>// itself
>// returns null on problems.
>// in the future this is how you would access a muli* portion of a
>// geometry collection.
>//    GEOMETRYCOLLECTION(MULTIPOINT(0 0, 1 1), LINESTRING(0 0, 1 1))
>//   ie. lwgeom_getpoint( lwgeom_getsubgeometry( serialized, 0), 1)
>//           --> POINT(1 1)
>extern char *lwgeom_getsubgeometry(char *serialized_form, int geom_number);
>
>// 1st geometry has geom_number = 0
>//  use geom_number = -1 to find the actual type of the serialized form.
>//    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)
>//                 --> multipoint
>//   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
>//                 --> point
>// gets the 8bit type of the geometry at location geom_number
>extern char lwgeom_gettype(char *serialized_form, int geom_number);
>
>// how many sub-geometries are there?
>//  for point,line,polygon will return 1.
>extern int lwgeom_getnumgeometries(char *serialized_from);
>
>// set finalType to 0 and this will choose an appropriate type
>//  if you specify a wrong type, the best type will be chosen
>//   (ie. give it 2 points and ask it to be a multilinestring)
>//  use SRID=-1 for unknown SRID  (will have 8bit type's S = 0)
>// all subgeometries must have the same SRID
>extern char *lwgeom_construct(int SRID,int finalType, int nsubgeometries, char **serialized_subs);
>
>
>// construct the empty geometry (GEOMETRYCOLLECTION(EMPTY))
>extern char *lwgeom_constructempty();
>
>// helper function (not for general use)
>// find the size a geometry (or a sub-geometry)
>// 1st geometry has geom_number = 0
>//  use geom_number = -1 to find the actual type of the serialized form.
>//    ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, -1)
>//                 --> size of the multipoint
>//   ie lwgeom_gettype( <'MULTIPOINT(0 0, 1 1)'>, 0)
>//                 --> size of the point
>extern int lwgeom_seralizedformlength(char *serialized_form, int geom_number);
>
>//------------------------------------------------------
>// other stuff
>
>// handle the double-to-float conversion.  The results of this
>// will usually be a slightly bigger box because of the difference
>// between float8 and float4 representations.
>
>extern BOX2DFLOAT4 box3d_to_box2df(BOX3D *box);
>extern BOX2DFLOAT4 box_to_box2df(BOX *box);  // postgresql standard type
>
>extern BOX3D box2df_to_box3d(BOX2DFLOAT4 *box);
>extern BOX   box2df_to_box(BOX *box);  // postgresql standard type
>
>
>
>
>
>//------------------------------------------------------------
>//------------------------------------------------------------
>// On serialized form  (see top for the 8bit type implementation)
>
>// NOTE: contrary to the original proposal, bounding boxes are *never*
>//       included in the geometry.  You must either refer to the index
>//       or compute it on demand.
>
>
>// The serialized form is always a stream of bytes.  The first four are always
>// the memory size of the LWGEOM (including the 4 byte memory size).
>
>// The easiest way to describe the serialed form is with examples:
>
>//3D point w/o bounding box::
>//<int32> size = 29 bytes
>//<char> type:  S=0,D=1, tttt= 1
>//<double> X
>//<double> Y
>//<double> Z
>
>//2D line String
>//<int32> size = ...
>//<char> type:  S=0,D=0, tttt= 2
>//<uint32> npoints
>//<double> X0
>//<double> Y0
>//<double> X1
>//<double> Y1
>//<double> X2
>//<double> Y2
>//...
>
>//3D polygon w/o bounding box
>//<int32> size = ...
>//<char> type:  S=0,D=0, tttt= 3
>//<uint32> nrings
>//<uint32> npoints in ring0
>//<double> X0
>//<double> Y0
>//<double> X1
>//<double> Y1
>//<double> X2
>//<double> Y2
>//...
>//<uint32> npoints in ring1
>//<double> X0
>//<double> Y0
>//<double> X1
>//<double> Y1
>//<double> X2
>//<double> Y2
>//...
>//...
>
>
>// the multi* representations are very simple
>
>//<int32> size = ...
>//<char> type:  ... with  tttt= <multi* or geometrycollection>
>//<int32> ngeometries
>// <geometry zero, serialized form>
>// <geometry one, serialized form>
>// <geometry two, serialzied form>
>// ...
>
>
>
>// see implementation for more exact details.
>
>
>//----------------------------------------------------------------
>// example function (computes total length of the lines in a LWGEOM).
>//   This works for a LINESTRING, MULTILINESTRING, OR GEOMETRYCOLLECTION
>
>
>
>// 	  char *serialized_form = (char *)  [[get from database]]
>//
>//    double total_length_so_far = 0;
>//    for (int t=0;t< lwgeom_getnumgeometries(serialized_form) ; t++)
>//    {
>//         LWLINE *line = lwgeom_getline(serialized_form, t);
>//         if (line != NULL)
>//		   {
>//		        double length = findlength( line->npoints, line->points);
>//         	    total_length_so_far + = length;
>//         }
>//    }
>//    return total_length_so_far;
>
>------------------------------------------------------------------------
>
>_______________________________________________
>postgis-users mailing list
>postgis-users at postgis.refractions.net
>http://postgis.refractions.net/mailman/listinfo/postgis-users
>  
>



More information about the postgis-users mailing list