Next Previous Contents

4. GIS Objects

PostGIS implements all the Simple Feature types specified by OGIS. The PostGIS objects are all 3-dimensional, so the representations are slightly different than those given in the OGIS standard. The PostGIS object types are as follows:

In addition, a " Box3d" type is included for indexing, querying and retrieval purposes.

4.1 External Representation

The external representation for all PostGIS objects is the OGIS " Well Known Text" (WKT) representation. SQL selects return the GIS objects in WKT format, and SQL inserts must represent GIS objects in WKT. Examples of the WKT representations are as follows:

2-D versus 3-D

The internal objects representation stores all objects with three coordinates, but the external interface allows users to insert and retrieve 2-D objects without supplying a third coordinate. For example, a 2-D object can be inserted into the database:

template=# INSERT INTO GEOMETRIES (GEOM) VALUES ('POINT(2 3)');
INSERT 2415151 1

The same feature will be retrieved as a 2-D feature when selected out of the database:

template=# SELECT * FROM GEOMETRIES;
geom
--------
POINT(2 3)
(1 row)

4.2 Internal Representation

The internal representation information is useful to people who intend to write C functions to directly manipulate the backend objects at the server. Reading postgis.h will give the exact type definitions used, and reading postgis.c will give some examples of how to manipulate the objects.

Basics

In the most basic sense, a GEOMETRY type is a list of sub-objects and a bounding volume. In an ideal world, the type should be defined as:


typedef struct
{
int32 size; // postgres variable-length type requirement
int32 type; // this type of geometry
bool is3d; // true if the points are 3d (only for output)
BOX3D bvol; // bounding volume of all the geo objects
int32 nobjs; // how many sub-objects in this object
int32 objType[1]; // type of object
int32 objOffset[1]; // offset (in bytes) into this structure where the object is located
char objData[1]; // store for actual objects
} GEOMETRY;

However, because of the way PostgreSQL handles memory allocation for objects, the type is actually organized as:


typedef struct
{
int32 size; // postgres variable-length type requirement
int32 type; // this type of geometry
bool is3d; // true if the points are 3d (only for output)
BOX3D bvol; // bounding volume of all the geo objects
int32 nobjs; // how many sub-objects in this object
char data[?]; //info about the sub-objects
} GEOMETRY;

This is because a Postgres type is a just a chuck of memory - it cannot contain any pointers. In a normal program objType and objData would be pointers to separate chunks of memory for these two lists (in fact, objData would likely be a list of pointers to other memory locations). That would look something like:

Since we cannot have pointers, the geometry structure actually has pseudo-pointers to its data portion, and looks like:

There are several important observations:

Usage

Normally, one will want to find the location of objOffset[0] so its accessible;


Int32 *offsets;
offsets = (int32 *) ( ((char *) &(geom1->objType[0] ))+ sizeof(int32) * geom1->nobjs ) ;

Next, one might want to get object i;


Char *obji;
oi = (char *) geom1 +offsets[i] ;
typei= geom1->objType[i];

Then one can re-cast the object;


POLYGON3D *poly;
LINE3D *line;
POINT3D *point;
if (typei == POINTTYPE) //point
{
point = (LINE3D *) oi;
...
}
if (type1 == LINETYPE) //line
{
line = (LINE3D *) oi;
...
}
if (type1 == POLYGONTYPE) //POLYGON
{
poly = (POLYGON3D *) oi;
...
}

What does everything mean?

Input/Output

The geometry type tries really hard to consistently reproduce objects. For example, if you insert a MULTIPOINT(), you?ll get a MULTIPOINT() when you select.

This is more difficult than you might expect because, internally, these objects are stored the same:

MULTIPOINT( 1 1, 2 2, 3 3)

GEOMETRYCOLLECTION(POINT(1 1), POINT(2 2), POINT(3 3) )

GEOMETRYCOLLECTION(MULTIPOINT( 1 1, 2 2, 3 3))

GEOMETRYCOLLECTION(MULTIPOINT( 1 1, 2 2), POINT( 3 3) )

Every GEOMETRY is a set (GEOMETRYCOLLECTION) of sub-objects (point, line, polygon). So, truthfully, the 2nd example is the best OGC WKT of the internal structure.

Therefore, if you start with a MULTI-geometry (MULTIPOINT, MULTILINE, MULTIPOLYGON), the type member will record that fact. On output, it does a simple conversion:

Single point, line, or polygon objects are returned as single point, line or polygon objects.

Unfortunately, GEOMETRYCOLLECTIONS() are not always returned the same as they are entered. They are always returned as a set of base types.

For example:

4.3 Sub-Geometry Types

POINT3D

This is the base geometry used by all the other sub-points. Its simply the X,Y,Z location represented as a double-precision floating point number. 2D locations are represented with the Z location set to 0.0. See above for a discussion on how to tell the difference between a 2D point, and 3D points with Z=0.0.


typedef struct
{
double x,y,z;
} POINT3D;

LINE3D

A lines is a set of connected points. The line moves from points[0]->points[1]->points[2]


typedef struct
{
int32 npoints; // how many points in the line
int32 junk; // double-word alignment
POINT3D points[1]; // array of actual points
} LINE3D;

POLYGON3D

A polygon is a set of rings. Each ring is a closed line.

For example:


POINT3D *pts;
pts = (POINT3D *) ( (char *)&(poly->npoints[poly->nrings] ) );
if ((int32) pts1 != (((int32)pts1>>3)<<3) )
pts1 = (POINT3D *) ((char *) pts1 + 4);

Therefore,


typedef struct
{
int32 nrings; // how many rings in this polygon
int32 npoints[1]; //how many points in each ring
/* could be 4 byes of filler here to make sure points[] is
double-word aligned*/
POINT3D points[1]; // array of actual points
} POLYGON3D;

BOX3D

Representation of a long diagonal of a cube, from the lower-left bottom (LLB) to the upper-right top (URT).


Minimum X is box3d->LLB.x 
Minimum Y is box3d->LLB.y 
Minimum Z is box3d->LLB.z 
Maximum X is box3d->URT.x
Maximum y is box3d->URT.y 
Maximum Z is box3d->URT.z
typedef struct
{
POINT3D LLB,URT; /* corner POINT3Ds on long diagonal */
} BOX3D;


Next Previous Contents