===PostGIS Serialized Geometry Format===


==Introduction==


This document describe the serialied form of
Geometries as implemented starting from version 1.x.

Prior versions used a different format.

The new format is aimed at reducing geometries size, for
this reason we refer to the old format as HWGEOM (High Weight GEOMetry)
and to the new one as LWGEOM (Light Weight GEOMetry).


==Serialized Form and PostgreSQL varlena objects==


PostGIS serialized form is a recursive structure, where
elements in a collection (multi* or geometrycollections)
are complete serialized forms themself.

PostgreSQL requires to add an header to variable-lenght
user defined types, for this reason, the type actually
stored on disk is a SERIALIZED geometry wrapped in this
required header. We call the complete PostgreSQL type
``PG_LWGEOM''.


==Geometry Type byte==


All serialiezd geometries start with a single byte
encoding geometry type (lower nibble) and flags
(higher nibble). 

Geometry Type Byte:

     [BSZM] [TTTT]

Flags values:

      B = 16 byte BOX2DFLOAT4 follows (probably not aligned) [before SRID]
      S = 4 byte SRID attached (0= not attached (-1), 1= attached)
      ZM = dimensionality (hasZ, hasM)

Type values:

      wkbPoint = 1
      wkbLineString = 2
      wkbPolygon = 3
      wkbMultiPoint = 4
      wkbMultiLineString = 5
      wkbMultiPolygon = 6
      wkbGeometryCollection = 7


==Bounding box and SRID==


Following the Geometry type byte we find optional bounding box
and/or SRID values. Presence of them is encoded in the type byte.

If both objects are present the bounding box come first.

Bounding box is composed by 4 16-bit float:

	[FLOAT16] [FLOAT16] [FLOAT16] [FLOAT16]
	   xmin      ymin      xmax      ymax

SRID is composed by a 32-bit integer:

	[INT32]
	 SRID


==Ordinate Arrays==


When it comes to ordinate values all geometries use arrays of 32-bit
floats. Number and semantic of values depend on the dimension flags
on the geometry type byte:

	 2D (ZM=0x00)
		[FLOAT32] [FLOAT32]
		    x         y

	3DM (ZM=0x01)
		[FLOAT32] [FLOAT32] [FLOAT32]
		    x         y         m

	3DZ (ZM=0x10)
		[FLOAT32] [FLOAT32] [FLOAT32]
		    x         y         z

	 4D (ZM=0x11)
		[FLOAT32] [FLOAT32] [FLOAT32] [FLOAT32]
		    x         y         z         m


==Geometry types==

What you find after the type byte and optional bbox and SRID
(COMMON_HEADER from now on) depends on actual geometry type.

=Point=

A Point geometry is as follows:

	<COMMON_HEADER>
	<ORDINATE_ARRAY> -- single element

=LineString=

A LineString geometry is as follows:

	<COMMON_HEADER>
	<UINT32> -- number of elements in following ORDINATE_ARRAY
	<ORDINATE_ARRAY>

=Polygon=

A Polygon geometry is as follows:

	<COMMON_HEADER>

	<UINT32> -- number of ORDINATE_ARRAYs (at least 1, the shell)

	One or more arrays (rings) as specified by previous uint32:

		<UINT32> -- number of elements in following ORDINATE_ARRAY
		<ORDINATE_ARRAY> -- single element

=Collections=

All collection types (MultiPoint, MultiLineString, MultiPolygon,
GeometryCollection) have the same structure. Real type is just
an hint on what one should expect from element geometries.
Note that the GeometryCollection type is also used for EMPTY
Geometries (number_of_geometries is set to 0 in this case).

A Collection geometry is as follows:

	<COMMON_HEADER>

	<UINT32> -- number of GEOMETRIES

	Zero (EMPTY) or more geometries as specified by previous uint32:

		<SERIALIZED_GEOMETRY> -- starting from type byte again


==Examples==


=3DZ point, no bounding box, no SRID=

	<char>   TYPE - flags:__Z_  type:1
	<double> X
	<double> Y
	<double> Z

=3DM point, bounding box, no SRID=

	<char>   TYPE - flags:B__M  type:1
	<float>  XMIN
	<float>  YMIN
	<float>  XMAX
	<float>  YMAX
	<double> X
	<double> Y
	<double> M

=2D LineString, no bounding box, SRID=

	<char>   TYPE - flags:_S__  type:2

	<uint32> NPOINTS - 3

	<uint32> SRID

	<double> X0
	<double> Y0

	<double> X1
	<double> Y1

	<double> X2
	<double> Y2

=2D polygon, no bounding box, no SRID=

	<char>   TYPE - flags:____  type:3

	<uint32> NRINGS - 2

	<uint32> NPOINTS - 4
	<double> X0
	<double> Y0
	<double> X1
	<double> Y1
	<double> X2
	<double> Y2
	<double> X3
	<double> Y3

	<uint32> NPOINTS - 6
	<double> X0
	<double> Y0
	<double> X1
	<double> Y1
	<double> X2
	<double> Y2
	<double> X3
	<double> Y3
	<double> X4
	<double> Y4
	<double> X5
	<double> Y5

=2D Collection of a point and a line, SRID and bbox present=

	<char>   TYPE - flags:BS__  type:7

	-- BBOX
	<float>  XMIN
	<float>  YMIN
	<float>  XMAX
	<float>  YMAX

	-- SRID
	<uint32> SRID

	<uint32> NGEOMS - 2

	<char>   TYPE - flags:____  type:1 ( the point )
	<double> X0
	<double> Y0

	<char>   TYPE - flags:____  type:2 ( the line )
	<uint32> NPOINTS - 3
	<double> X0
	<double> Y0
	<double> X1
	<double> Y1
	<double> X2
	<double> Y2

Note that in the inner geometries:

	- SRID value is inherited by parent geometry type.

	- BBOX value is not present (can be, however)

	- ZM flags must exactly match those in the outer geometry type byte

