Skip to content

Commit

Permalink
geo/wkt: add support for parsing polygons with Z and M dimensions
Browse files Browse the repository at this point in the history
This patch extends the capabilities of the WKT parser to include
parsing of polygons with Z and M dimensions.

Release note: None
  • Loading branch information
Andy Yang committed Feb 5, 2021
1 parent a2b8a80 commit 85b81e1
Show file tree
Hide file tree
Showing 4 changed files with 565 additions and 124 deletions.
8 changes: 8 additions & 0 deletions pkg/geo/wkt/lex.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ func getKeywordToken(tokStr string) int {
return LINESTRINGZ
case "LINESTRINGZM":
return LINESTRINGZM
case "POLYGON":
return POLYGON
case "POLYGONM":
return POLYGONM
case "POLYGONZ":
return POLYGONZ
case "POLYGONZM":
return POLYGONZM
default:
return eof
}
Expand Down
179 changes: 164 additions & 15 deletions pkg/geo/wkt/wkt.y
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,57 @@ package wkt

import "github.com/twpayne/go-geom"

func isValidLinestring(wktlex wktLexer, flatCoords []float64, stride int) bool {
if len(flatCoords) < 2 * stride {
wktlex.(*wktLex).Error("syntax error: non-empty linestring with only one point")
return false
}
return true
}

func isValidPolygonRing(wktlex wktLexer, flatCoords []float64, stride int) bool {
if len(flatCoords) < 4 * stride {
wktlex.(*wktLex).Error("syntax error: polygon ring doesn't have enough points")
return false
}
for i := 0; i < stride; i++ {
if flatCoords[i] != flatCoords[len(flatCoords)-stride+i] {
wktlex.(*wktLex).Error("syntax error: polygon ring not closed")
return false
}
}
return true
}

type geomPair struct {
flatCoords []float64
ends []int
}

%}

%union {
str string
geom geom.T
coord float64
coordList []float64
pair geomPair
}

%token <str> POINT POINTM POINTZ POINTZM
%token <str> LINESTRING LINESTRINGM LINESTRINGZ LINESTRINGZM
%token <str> POLYGON POLYGONM POLYGONZ POLYGONZM
%token <str> EMPTY
//%token <str> POLYGON MULTIPOINT MULTILINESTRING MULTIPOLYGON GEOMETRYCOLLECTION
//%token <str> MULTIPOINT MULTILINESTRING MULTIPOLYGON GEOMETRYCOLLECTION
%token <coord> NUM

%type <geom> geometry
%type <geom> point linestring
%type <geom> point linestring polygon
%type <coordList> two_coords three_coords four_coords
%type <coordList> two_coords_list three_coords_list four_coords_list
%type <coordList> two_coords_line three_coords_line four_coords_line
%type <pair> two_coords_ring three_coords_ring four_coords_ring
%type <pair> two_coords_ring_list three_coords_ring_list four_coords_ring_list

%%

Expand All @@ -44,8 +76,8 @@ start:

geometry:
point
// TODO(ayang) have parser check that linestrings are either empty or have 2+ points
| linestring
| polygon

point:
POINT '(' two_coords ')'
Expand Down Expand Up @@ -90,29 +122,29 @@ point:
}

linestring:
LINESTRING '(' two_coords_list ')'
LINESTRING two_coords_line
{
$$ = geom.NewLineStringFlat(geom.XY, $3)
$$ = geom.NewLineStringFlat(geom.XY, $2)
}
| LINESTRING '(' three_coords_list ')'
| LINESTRING three_coords_line
{
$$ = geom.NewLineStringFlat(geom.XYZ, $3)
$$ = geom.NewLineStringFlat(geom.XYZ, $2)
}
| LINESTRING '(' four_coords_list ')'
| LINESTRING four_coords_line
{
$$ = geom.NewLineStringFlat(geom.XYZM, $3)
$$ = geom.NewLineStringFlat(geom.XYZM, $2)
}
| LINESTRINGM '(' three_coords_list ')'
| LINESTRINGM three_coords_line
{
$$ = geom.NewLineStringFlat(geom.XYM, $3)
$$ = geom.NewLineStringFlat(geom.XYM, $2)
}
| LINESTRINGZ '(' three_coords_list ')'
| LINESTRINGZ three_coords_line
{
$$ = geom.NewLineStringFlat(geom.XYZ, $3)
$$ = geom.NewLineStringFlat(geom.XYZ, $2)
}
| LINESTRINGZM '(' four_coords_list ')'
| LINESTRINGZM four_coords_line
{
$$ = geom.NewLineStringFlat(geom.XYZM, $3)
$$ = geom.NewLineStringFlat(geom.XYZM, $2)
}
| LINESTRING EMPTY
{
Expand All @@ -131,6 +163,123 @@ linestring:
$$ = geom.NewLineString(geom.XYZM)
}

polygon:
POLYGON '(' two_coords_ring_list ')'
{
$$ = geom.NewPolygonFlat(geom.XY, $3.flatCoords, $3.ends)
}
| POLYGON '(' three_coords_ring_list ')'
{
$$ = geom.NewPolygonFlat(geom.XYZ, $3.flatCoords, $3.ends)
}
| POLYGON '(' four_coords_ring_list ')'
{
$$ = geom.NewPolygonFlat(geom.XYZM, $3.flatCoords, $3.ends)
}
| POLYGONM '(' three_coords_ring_list ')'
{
$$ = geom.NewPolygonFlat(geom.XYM, $3.flatCoords, $3.ends)
}
| POLYGONZ '(' three_coords_ring_list ')'
{
$$ = geom.NewPolygonFlat(geom.XYZ, $3.flatCoords, $3.ends)
}
| POLYGONZM '(' four_coords_ring_list ')'
{
$$ = geom.NewPolygonFlat(geom.XYZM, $3.flatCoords, $3.ends)
}
| POLYGON EMPTY
{
$$ = geom.NewPolygon(geom.XY)
}
| POLYGONM EMPTY
{
$$ = geom.NewPolygon(geom.XYM)
}
| POLYGONZ EMPTY
{
$$ = geom.NewPolygon(geom.XYZ)
}
| POLYGONZM EMPTY
{
$$ = geom.NewPolygon(geom.XYZM)
}

two_coords_ring_list:
two_coords_ring_list ',' two_coords_ring
{
$$ = geomPair{append($1.flatCoords, $3.flatCoords...), append($1.ends, $1.ends[len($1.ends)-1] + $3.ends[0])}
}
| two_coords_ring

three_coords_ring_list:
three_coords_ring_list ',' three_coords_ring
{
$$ = geomPair{append($1.flatCoords, $3.flatCoords...), append($1.ends, $1.ends[len($1.ends)-1] + $3.ends[0])}
}
| three_coords_ring

four_coords_ring_list:
four_coords_ring_list ',' four_coords_ring
{
$$ = geomPair{append($1.flatCoords, $3.flatCoords...), append($1.ends, $1.ends[len($1.ends)-1] + $3.ends[0])}
}
| four_coords_ring

two_coords_ring:
two_coords_line
{
if !isValidPolygonRing(wktlex, $1, 2) {
return 1
}
$$ = geomPair{$1, []int{len($1)}}
}

three_coords_ring:
three_coords_line
{
if !isValidPolygonRing(wktlex, $1, 3) {
return 1
}
$$ = geomPair{$1, []int{len($1)}}
}

four_coords_ring:
four_coords_line
{
if !isValidPolygonRing(wktlex, $1, 4) {
return 1
}
$$ = geomPair{$1, []int{len($1)}}
}

two_coords_line:
'(' two_coords_list ')'
{
if !isValidLinestring(wktlex, $2, 2) {
return 1
}
$$ = $2
}

three_coords_line:
'(' three_coords_list ')'
{
if !isValidLinestring(wktlex, $2, 3) {
return 1
}
$$ = $2
}

four_coords_line:
'(' four_coords_list ')'
{
if !isValidLinestring(wktlex, $2, 4) {
return 1
}
$$ = $2
}

two_coords_list:
two_coords ',' two_coords_list
{
Expand Down
Loading

0 comments on commit 85b81e1

Please sign in to comment.