Skip to content

Commit

Permalink
Merge remote-tracking branch 'refs/remotes/origin/dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
DaanDeSmedt committed Jul 19, 2019
2 parents 7e21aa8 + c90b9bc commit 4876d11
Show file tree
Hide file tree
Showing 8 changed files with 1,204 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Daan De Smedt

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
94 changes: 94 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
PHPWKTParser
===============

Well-known text (WKT) is a text markup language for representing vector geometry objects on a map, spatial reference systems of spatial objects and transformations between spatial reference systems.


EWKT (Extended Well-Known Text), a PostGIS-specific format that includes the spatial reference system identifier (SRID) and up to 4 ordinate values (XYZM), is also supported (ex: `SRID=31370;POINT(44 60)`).


`PHPWKTParser` provides a simple usage helper class to read WKT and EWKT and parse this text representation to a workable PHP array holding the parsed WKT/EWKT definition. Read and parse 2D, 3D and 4D WKT (Well Known Text) / EWKT (Extended Well-Known Text) object strings into geometry objects with this simple WKT PHP adapter library.



## Installation

Install the package through [composer](http://getcomposer.org):

```
composer require daandesmedt/phpwktadapter
```

Make sure, that you include the composer [autoloader](https://getcomposer.org/doc/01-basic-usage.md#autoloading) somewhere in your codebase.


## Supported geometry

| Geometry Type | Example |
| --- | --- |
| POINT | POINT(30 10) |
| LNESTRING | LINESTRING(30 10, 10 30, 40 40) |
| POLYGON | POLYGON((0 0,10 0,10 10,0 10,0 0)) |
| MULTIPOINT | MULTIPOINTZM(0 0 10 10,10 0 0 0,10 10 0 0,20 20 0 10) |
| MULTILINESTRING | MULTILINESTRING((0 0,10 0,10 10,0 10)) |
| MULTIPOLYGON | MULTIPOLYGON(((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20))) |
| GEOMETRYCOLLECTION | GEOMETRYCOLLECTION(POINT(10 20),LINESTRING(0 0,10 0)) |


## PHPWKTParser parsed and returned geometry array response

The `read($wkt)` function of the `PHPWKTParser` adapter will return a associative array as representation of the parsed WKT/EWKT (in case of valid).


```
array(
// the geometry object type
"type" => string,
// integer or float values for POINT - nested array (integer or float) for other geometry types
"value" => array,
// integer representing the EWKT SRID, null when not present
"srid" => integer | null,
// string (Z, M or ZM) representing the dimension, null when not present
"dimension" => string | null
)
```

## Working examples

Working examples can be found in the `examples` folder.


## Sample usage

```php
<?php

require __DIR__ . '/../vendor/autoload.php';

use daandesmedt\PHPWKTAdapter\WKTAdapter;

$adapter = new WKTAdapter();
$res = $adapter->read('SRID=31370;POINT(30 10)');
var_dump($res);
```

## Handling exceptions

Invalid format in the specified WKT / EWKT will result in a `UnexpectedValueException` thrown by the `WKTAdapter` .


```php
<?php

require __DIR__ . '/../vendor/autoload.php';

use daandesmedt\PHPWKTAdapter\WKTAdapter;

$adapter = new WKTAdapter();

try {
$res = $adapter->read('SRID=31370;POINT(bad format)');
} catch (UnexpectedValueException $e) {
var_dump($e->getMessage());
}
```
31 changes: 31 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "daandesmedt/phpwktadapter",
"description": "Read and parse 2D, 3D and 4D WKT (Well Known Text) / EWKT (Extended Well-Known Text) object strings into geometry objects with this simple WKT PHP adapter library.",
"keywords": ["php", "string", "text", "geometry", "geography", "spatial", "wkt", "ewkt"],
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Daan De Smedt",
"email": "[email protected]"
}
],
"autoload": {
"psr-4": {
"daandesmedt\\PHPWKTAdapter\\": "src/PHPWKTAdapter"
}
},
"autoload-dev": {
"psr-4": {
"daandesmedt\\Tests\\PHPWKTAdapter\\": "tests/PHPWKTAdapter"
}
},
"minimum-stability": "stable",
"require": {
"php": ">=7.0",
"doctrine/lexer": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^8.2"
}
}
81 changes: 81 additions & 0 deletions examples/WKTAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

require __DIR__ . '/../vendor/autoload.php';

use daandesmedt\PHPWKTAdapter\WKTAdapter;


$adapter = new WKTAdapter();


// HANDLE EXCEPTION
// #########################################################
try {
$res = $adapter->read('SRID=31370;POINT(bad format)');
} catch (UnexpectedValueException $e) {
var_dump($e->getMessage());
}


// POINT
// #########################################################
$res = $adapter->read('SRID=31370;POINT(30 10)');
$res = $adapter->read('SRID=31370;POINTZM(30 10 5 60)');
$res = $adapter->read('SRID=31370;POINT ZM (30 10 5 60)');
$res = $adapter->read('SRID=31370;POINTM(30 10 80)');
$res = $adapter->read('SRID=31370;POINT M (30 10 80)');
$res = $adapter->read('SRID=31370;POINT Z (30 10 80)');


// POLYGON
// #########################################################
$res = $adapter->read('SRID=31370;POLYGON((0 0,10 0,10 10,0 10,0 0))');
var_dump($res);
exit;

$res = $adapter->read('SRID=31370;POLYGON((0 0,10 0,10 10,0 10,0 0))');
$res = $adapter->read('SRID=31370;POLYGONZM((0 0 0 1,10 0 0 1,10 10 0 1,0 10 0 1,0 0 0 1))');
$res = $adapter->read('SRID=31370;POLYGONM((0 0 1,10 0 1,10 0 1,0 0 1,0 0 1))');


// LINESTRING
// #########################################################
$res = $adapter->read('SRID=31370;LINESTRING(30 10, 10 30, 40 40)');
$res = $adapter->read('SRID=31370;LINESTRINGZM(15 15 0 0, 20 20 0 0)');
$res = $adapter->read('SRID=31370;LINESTRINGM(15 15 0, 20 20 0)');


// MULTIPOINT
// #########################################################
$res = $adapter->read('SRID=31370;MULTIPOINT(0 10,10 10,10 20,10 30)');
$res = $adapter->read('SRID=31370;MULTIPOINTZM(0 0 10 10,10 0 0 0,10 10 0 0,20 20 0 10)');
$res = $adapter->read('SRID=31370;MULTIPOINTM(0 10 10,10 10 10,0 0 0,20 10 30)');


// MULTILINESTRING
// #########################################################
$res = $adapter->read('SRID=31370;MULTILINESTRING((0 0,10 0,10 10,0 10))');
$res = $adapter->read('SRID=31370;MULTILINESTRING((0 0,10 0,10 10,0 10),(5 5,7 5,7 7,5 7))');
$res = $adapter->read('SRID=31370;MULTILINESTRINGZM((0 0 10 10,10 0 0 0,10 10 0 0,20 20 0 10),(60 40 10 10,70 10 20 40))');
$res = $adapter->read('SRID=31370;MULTILINESTRINGM((0 10 10,10 10 10,0 0 0,20 10 30))');


// MULTIPOLYGON
// #########################################################
$res = $adapter->read('SRID=31370;MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))');
$res = $adapter->read('SRID=31370;MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)), ((20 35, 10 30, 10 10, 30 5, 45 20, 20 35), (30 20, 20 15, 20 25, 30 20)))');
$res = $adapter->read('SRID=31370;MULTIPOLYGONZM(((40 40 10 10, 20 45 10 10, 45 30 10 10, 40 40 10 10)), ((20 35 10 10, 10 30 10 10, 10 10 10 10, 30 5 10 10, 45 20 10 10, 20 35 10 10)))');
$res = $adapter->read('SRID=31370;MULTIPOLYGONM(((40 40 10, 20 45 10, 45 30 10, 40 40 10)), ((20 35 10, 10 30 10, 10 10 10, 30 5 10, 45 20 10, 20 35 10)))');


// GEOMETRYCOLLECTION
// #########################################################
$res = $adapter->read('SRID=31370;GEOMETRYCOLLECTION(POINT(10 20),LINESTRING(0 0,10 0))');
$res = $adapter->read('GEOMETRYCOLLECTION(POINT(10 20),POINT(0 10))');
$res = $adapter->read('GEOMETRYCOLLECTIONM(POINT(10 20 0),POINT(10 0 10))');
$res = $adapter->read('GEOMETRYCOLLECTIONZM(POINT(10 20 0 0),POINT(10 0 0 10))');


// DUMP
// #########################################################
var_dump($res);
18 changes: 18 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="true"
>

<testsuites>
<testsuite name="WKTAdapterTest">
<directory>tests/PHPWKTAdapter</directory>
</testsuite>
</testsuites>

</phpunit>
129 changes: 129 additions & 0 deletions src/PHPWKTAdapter/Lexer/WKTLexer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php

namespace daandesmedt\PHPWKTAdapter\Lexer;

use Doctrine\Common\Lexer\AbstractLexer;


class WKTLexer extends AbstractLexer
{
// character types
const T_NONE = 1;
const T_INTEGER = 2;
const T_STRING = 3;
const T_FLOAT = 5;
const T_CLOSE_PARENTHESIS = 6;
const T_OPEN_PARENTHESIS = 7;
const T_COMMA = 8;
const T_DOT = 10;
const T_EQUALS = 11;
const T_SEMICOLON = 50;

// SRID
const T_SRID = 500;
const T_Z = 501;
const T_M = 502;
const T_ZM = 501;

// Geometry types
const T_TYPE = 600;
const T_POINT = 601;
const T_LINESTRING = 602;
const T_POLYGON = 603;
const T_MULTIPOINT = 604;
const T_MULTILINESTRING = 605;
const T_MULTIPOLYGON = 606;
const T_GEOMETRYCOLLECTION = 607;

/**
* getCatchablePatterns
*
* @return array
*/
protected function getCatchablePatterns()
{
return array(
'',
'zm|[a-z]+[a-ln-y]',
'[+-]?[0-9]+(?:[\.][0-9]+)?(?:e[+-]?[0-9]+)?'
);
}


/**
* getNonCatchablePatterns
*
* @return array
*/
protected function getNonCatchablePatterns()
{
return array('\s+');
}


/**
* getType
*
* @param string $value
* @return int
*/
protected function getType(&$value) : int
{
// check numeric
if (is_numeric($value)) {
$value += 0;
if (is_int($value)) {
return self::T_INTEGER;
}
return self::T_FLOAT;
}

// check geom / srid type
if (ctype_alpha($value)) {
$name = __class__ . '::T_' . strtoupper($value);
if (defined($name)) {
return constant($name);
}
return self::T_STRING;
}

// check characteral type
switch ($value) {
case '.':
return self::T_DOT;
case ',':
return self::T_COMMA;
case '(':
return self::T_OPEN_PARENTHESIS;
case ')':
return self::T_CLOSE_PARENTHESIS;
case '=':
return self::T_EQUALS;
case ';':
return self::T_SEMICOLON;
default:
return self::T_NONE;
}
}

/**
* getValue
*
* @return string
*/
public function getValue() : string
{
return $this->token['value'];
}

/**
* getLookaheadType
*
* @return int
*/
public function getLookaheadType() : int
{
return (int)$this->lookahead['type'];
}

}
Loading

0 comments on commit 4876d11

Please sign in to comment.