Binary Schema Well-Known Binary (WBK)

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:

  • Big Endian: 00
  • Little Endian: 01.

The next two bytes indecate the geometry type as short:

  • POINTTYPE 1
  • LINETYPE 2
  • POLYGONTYPE 3
  • MULTIPOINTTYPE 4
  • MULTILINETYPE 5
  • MULTIPOLYGONTYPE 6
  • COLLECTIONTYPE 7
  • CIRCSTRINGTYPE 8
  • COMPOUNDTYPE 9
  • CURVEPOLYTYPE 10
  • MULTICURVETYPE 11
  • MULTISURFACETYPE 12
  • POLYHEDRALSURFACETYPE 13
  • TRIANGLETYPE 14
  • TINTYPE 15
  • NUMTYPES 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.

Binary Schema Extended Well-Known Binary (EWBK)

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.

LineString PHP Class

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);

Twitter