Skip to content

Commit

Permalink
Adding EWKB and EWKT adapters
Browse files Browse the repository at this point in the history
  • Loading branch information
phayes committed Apr 5, 2012
1 parent d6727f1 commit 342b9d9
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 12 deletions.
18 changes: 14 additions & 4 deletions geoPHP.inc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
include_once("lib/adapters/GeoAdapter.class.php"); // Abtract class
include_once("lib/adapters/GeoJSON.class.php");
include_once("lib/adapters/WKT.class.php");
include_once("lib/adapters/EWKT.class.php");
include_once("lib/adapters/WKB.class.php");
include_once("lib/adapters/EWKB.class.php");
include_once("lib/adapters/KML.class.php");
include_once("lib/adapters/GPX.class.php");
include_once("lib/adapters/GeoRSS.class.php");
Expand Down Expand Up @@ -46,6 +48,12 @@ class geoPHP
$type_map = geoPHP::getAdapterMap();

$processor_type = $type_map[$type];

if (!$processor_type) {
throw new exception('geoPHP could not find an adapter of type '.htmlentities($type));
exit;
}

$processor = new $processor_type();

// Data is not an array, just pass it normally
Expand All @@ -66,11 +74,13 @@ class geoPHP

static function getAdapterMap() {
return array (
'wkt' => 'WKT',
'wkb' => 'WKB',
'wkt' => 'WKT',
'ewkt' => 'EWKT',
'wkb' => 'WKB',
'ewkb' => 'EWKB',
'json' => 'GeoJSON',
'kml' => 'KML',
'gpx' => 'GPX',
'kml' => 'KML',
'gpx' => 'GPX',
'georss' => 'GeoRSS',
'google_geocode' => 'GoogleGeocode',
);
Expand Down
93 changes: 93 additions & 0 deletions lib/adapters/EWKB.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* EWKB (Extended Well Known Binary) Adapter
*/
class EWKB extends WKB
{

/**
* Read WKB binary string into geometry objects
*
* @param string $wkb An Extended-WKB binary string
*
* @return Geometry
*/
public function read($wkb, $is_hex_string = FALSE) {
if ($is_hex_string) {
$wkb = pack('H*',$wkb);
}

// Open the wkb up in memory so we can examine the SRID
$mem = fopen('php://memory', 'r+');
fwrite($mem, $wkb);
fseek($mem, 0);
$base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
if ($base_info['s']) {
$srid = unpack("Lsrid", fread($mem, 4));
}
fclose($mem);

// Run the wkb through the normal WKB reader to get the geometry
$wkb_reader = new WKB();
$geom = $wkb_reader->read($wkb);

// If there is an SRID, add it to the geometry
if ($srid) {
$geom->setSRID($srid);
}

return $geom;
}

/**
* Serialize geometries into an EWKB binary string.
*
* @param Geometry $geometry
*
* @return string The Extended-WKB binary string representation of the input geometries
*/
public function write(Geometry $geometry) {
// We always write into NDR (little endian)
$wkb = pack('c',1);

switch ($geometry->getGeomType()) {
case 'Point';
$wkb .= pack('L',1);
$wkb .= $this->writePoint($geometry);
break;
case 'LineString';
$wkb .= pack('L',2);
$wkb .= $this->writeLineString($geometry);
break;
case 'Polygon';
$wkb .= pack('L',3);
$wkb .= $this->writePolygon($geometry);
break;
case 'MultiPoint';
$wkb .= pack('L',4);
$wkb .= $this->writeMulti($geometry);
break;
case 'MultiLineString';
$wkb .= pack('L',5);
$wkb .= $this->writeMulti($geometry);
break;
case 'MultiPolygon';
$wkb .= pack('L',6);
$wkb .= $this->writeMulti($geometry);
break;
case 'GeometryCollection';
$wkb .= pack('L',7);
$wkb .= $this->writeMulti($geometry);
break;
}

if ($write_as_hex) {
$unpacked = unpack('H*',$wkb);
return $unpacked[1];
}
else {
return $wkb;
}
}

}
27 changes: 27 additions & 0 deletions lib/adapters/EWKT.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
/**
* EWKT (Extended Well Known Text) Adapter
*/
class EWKT extends WKT
{

/**
* Serialize geometries into an EWKT string.
*
* @param Geometry $geometry
*
* @return string The Extended-WKT string representation of the input geometries
*/
public function write(Geometry $geometry) {
$srid = $geometry->SRID();
$wkt = '';
if ($srid) {
$wkt = 'SRID=' . $srid . ';';
$wkt .= $geometry->out('wkt');
return $wkt;
}
else {
return $geometry->out('wkt');
}
}
}
19 changes: 14 additions & 5 deletions lib/adapters/WKB.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ class WKB extends GeoAdapter
/**
* Read WKB into geometry objects
*
* @param string $wkb Well-known-binary string
* @param bool $is_hex_string If this is a hexedecimal string that is in need of packing
* @return Geometry|GeometryCollection
* @param string $wkb
* Well-known-binary string
* @param bool $is_hex_string
* If this is a hexedecimal string that is in need of packing
*
* @return Geometry
*/
public function read($wkb, $is_hex_string = FALSE) {
if ($is_hex_string) {
Expand All @@ -36,10 +39,16 @@ public function read($wkb, $is_hex_string = FALSE) {
}

function getGeometry(&$mem) {
$base_info = unpack("corder/Ltype", fread($mem, 5));
$base_info = unpack("corder/ctype/cz/cm/cs", fread($mem, 5));
if ($base_info['order'] !== 1) {
throw new Exception('Only NDR (little endian) SKB format is supported at the moment');
}

// If there is SRID information, ignore it - use EWKB Adapter to get SRID support
if ($base_info['s']) {
fread($mem, 4);
}

switch ($base_info['type']) {
case 1:
return $this->getPoint($mem);
Expand Down Expand Up @@ -69,7 +78,7 @@ function getLinstring(&$mem) {

// Read the nubmer of points x2 (each point is two coords) into decimal-floats
$line_coords = unpack('d'.$line_length[1]*2, fread($mem,$line_length[1]*16));

// We have our coords, build up the linestring
$components = array();
$i = 1;
Expand Down
31 changes: 29 additions & 2 deletions lib/adapters/WKT.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,28 @@ class WKT extends GeoAdapter
public function read($wkt) {
$wkt = trim($wkt);

// If it contains a ';', then it contains additional SRID data
if (strpos($wkt,';')) {
$parts = explode(';', $wkt);
$wkt = $parts[1];
$eparts = explode('=',$parts[0]);
$srid = $eparts[1];
}
else {
$srid = NULL;
}

// If geos is installed, then we take a shortcut and let it parse the WKT
if (geoPHP::geosInstalled()) {
$reader = new GEOSWKTReader();
return geoPHP::geosToGeometry($reader->read($wkt));
if ($srid) {
$geom = geoPHP::geosToGeometry($reader->read($wkt));
$geom->setSRID($srid);
return $geom;
}
else {
return geoPHP::geosToGeometry($reader->read($wkt));
}
}
$wkt = str_replace(', ', ',', $wkt);

Expand All @@ -29,7 +47,16 @@ public function read($wkt) {
if (strtoupper(substr($wkt, 0, strlen($wkt_geom))) == $wkt_geom) {
$data_string = $this->getDataString($wkt, $wkt_geom);
$method = 'parse'.$geom_type;
return $this->$method($data_string);

if ($srid) {
$geom = $this->$method($data_string);
$geom->setSRID($srid);
return $geom;
}
else {
return $this->$method($data_string);
}

}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/geometry/Geometry.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
abstract class Geometry
{
private $geos = NULL;
protected $srid = NULL;
protected $geom_type;
protected $srid;

// Abtract: Standard
// -----------------
Expand Down
82 changes: 82 additions & 0 deletions tests/postgis.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?
// Uncomment to test
# run_test();

function run_test() {

header("Content-type: text");

include_once('../geoPHP.inc');

// Your database test table should contain 3 columns: name (text), type (text), geom (geometry)
$host = 'localhost';
$database = 'phayes';
$table = 'test';
$column = 'geom';
$user = 'phayes';
$pass = 'supersecret';

$connection = pg_connect("host=$host dbname=$database user=$user password=$pass");

// Truncate
pg_query($connection, "DELETE FROM $table");

// Working with PostGIS and EWKB
// ----------------------------

foreach (scandir('./input') as $file) {
$parts = explode('.',$file);
if ($parts[0]) {
$name = $parts[0];
$format = $parts[1];
$value = file_get_contents('./input/'.$file);
print '---- Testing '.$file."\n";
flush();
$geometry = geoPHP::load($value, $format);
test_postgis($name, $format, $geometry, $connection, 'wkb');
$geometry->setSRID(4326);
test_postgis($name, $format, $geometry, $connection, 'ewkb');
}
}
print "Testing Done!";
}

function test_postgis($name, $type, $geom, $connection, $format) {
global $table;

// Let's insert into the database using GeomFromWKB
$insert_string = pg_escape_bytea($geom->out($format));
pg_query($connection, "INSERT INTO $table (name, type, geom) values ('$name', '$type', GeomFromWKB('$insert_string'))");

// SELECT using asBinary PostGIS
$result = pg_fetch_all(pg_query($connection, "SELECT asBinary(geom) as geom FROM $table WHERE name='$name'"));
foreach ($result as $item) {
$wkb = pg_unescape_bytea($item['geom']); // Make sure to unescape the hex blob
$geom = geoPHP::load($wkb, $format); // We now a full geoPHP Geometry object
}

// SELECT and INSERT directly, with no wrapping functions
$result = pg_fetch_all(pg_query($connection, "SELECT geom as geom FROM $table WHERE name='$name'"));
foreach ($result as $item) {
$wkb = pack('H*',$item['geom']); // Unpacking the hex blob
$geom = geoPHP::load($wkb, $format); // We now have a geoPHP Geometry

// Let's re-insert directly into postGIS
// We need to unpack the WKB
$unpacked = unpack('H*', $geom->out($format));
$insert_string = $unpacked[1];
pg_query($connection, "INSERT INTO $table (name, type, geom) values ('$name', '$type', '$insert_string')");
}

// SELECT and INSERT using as EWKT (ST_GeomFromEWKT and ST_AsEWKT)
$result = pg_fetch_all(pg_query($connection, "SELECT ST_AsEWKT(geom) as geom FROM $table WHERE name='$name'"));
foreach ($result as $item) {
$wkt = $item['geom']; // Make sure to unescape the hex blob
$geom = geoPHP::load($wkt, 'ewkt'); // We now a full geoPHP Geometry object

// Let's re-insert directly into postGIS
$insert_string = $geom->out('ewkt');
pg_query($connection, "INSERT INTO $table (name, type, geom) values ('$name', '$type', ST_GeomFromEWKT('$insert_string'))");
}
}

0 comments on commit 342b9d9

Please sign in to comment.