For example, the geometry POINT(2.0 4.0)
is represented as:
00
00000001
4000000000000000
4010000000000000
The first byte indecates the byteorder that is used:
00
01
. The next two bytes indecate the geometry type as short:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(taken from PostGIS source code, Wikipedia has a slightly different list.)
The last two blocks of each 8 byte contain the x- and y-coordinate of the point as double.
In the case of a LINESTYPE the type declaration is followed by another short indecating the number of points within this line. The coordinates are just concatenated as pairs of doubles like in the point example.
If you want to store more information in a LINETYPE like the altitude of each point and the geo reference system that should be used the binary becomes a little bit more complex.
For example, the geography ST_SetSRID(ST_MakeLine(ST_MakePoint(1,1,1), ST_MakePoint(2,2,2)), 4326)
, where the SRID 4326 indicates the WGS84 ellypsoid, is represented as:
01
020000A0
E6100000
02000000
000000000000F03F
000000000000F03F
000000000000F03F
0000000000000040
0000000000000040
0000000000000040
This time we have the byteorder 01
followed by something that should be the type 2
(apparently there seem to be some additions) and the SRID in the third and the line length in the fourth place. So what has changed? We use the SRID whose existence is masked into the type as 0x20000000
. An other mask 0x40000000
is used to indecate the z-coordinate.
Assuming there is a class representing a Point
with three coordinates a LineString
might contain a getBin
method like this
class LineString implements \ArrayAccess, \Countable {
const BYTE_ORDER = 1; // 0 -> Big Endian, 1 -> Little Endian
const GEOMETRY_TYPE = 2;
const SRID = 4326; // Wgs84
const WKBZOFFSET = 0x80000000; // Mask for geometry type indecating z-offset
const WKBMOFFSET = 0x40000000; // Mask for geometry type indecating m-offset
const WKBSRIDFLAG = 0x20000000; // Mask for geometry type indecating srid
/**
* Ordered point stack
* @var [Point]
*/
private $points;
public function __construct(array $points = [])
{
$this->points = $points;
}
/* ...... */
/**
* Transforms the LineString to a EWKB string.
*
* @return string
*/
public function getBin() : string
{
$b = self::BYTE_ORDER ? 'V' : 'N';
$bin = pack("C{$b}{$b}{$b}",
self::BYTE_ORDER,
self::GEOMETRY_TYPE | self::WKBSRIDFLAG | self::WKBZOFFSET,
self::SRID,
$this->count()
);
foreach ($this->points as $point) {
$bin .= pack('ddd', $point->getLat(), $point->getLng(), $point->getAlt());
}
return $bin;
}
}
Unsing PosgreSQL and PDO you must indecate the binary character of the column using
$stmt->bindValue(':waypoints', $ls->getBin(), PDO::PARAM_LOB);