Skip to content

Commit

Permalink
Merge pull request #95 from paulmach/wkt
Browse files Browse the repository at this point in the history
encoding/wkt: various code improvements
  • Loading branch information
paulmach authored Apr 6, 2022
2 parents a67580d + 916420e commit 215f32c
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 207 deletions.
17 changes: 9 additions & 8 deletions encoding/wkt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ This package provides encoding and decoding of [WKT](https://en.wikipedia.org/wi
data. The interface is defined as:

```go
func MarshalString(g orb.Geometry) string
func MarshalString(orb.Geometry) string

func UnmarshalCollection(s string) (p orb.Collection, err error)
func UnmarshalLineString(s string) (p orb.LineString, err error)
func UnmarshalMultiLineString(s string) (p orb.MultiLineString, err error)
func UnmarshalMultiPoint(s string) (p orb.MultiPoint, err error)
func UnmarshalMultiPolygon(s string) (p orb.MultiPolygon, err error)
func UnmarshalPoint(s string) (p orb.Point, err error)
func UnmarshalPolygon(s string) (p orb.Polygon, err error)
func Unmarshal(string) (orb.Geometry, error)
func UnmarshalPoint(string) (orb.Point, err error)
func UnmarshalMultiPoint(string) (orb.MultiPoint, err error)
func UnmarshalLineString(string) (orb.LineString, err error)
func UnmarshalMultiLineString(string) (orb.MultiLineString, err error)
func UnmarshalPolygon(string) (orb.Polygon, err error)
func UnmarshalMultiPolygon(string) (orb.MultiPolygon, err error)
func UnmarshalCollection(string) (orb.Collection, err error)
```
177 changes: 70 additions & 107 deletions encoding/wkt/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,127 +9,112 @@ import (
)

var (
errEmptyGeometry = errors.New("empty geometry")
errUnMarshalPoint = errors.New("unmarshal point error")
errUnMarshalMultiPoint = errors.New("unmarshal multipoint error")
errUnMarshaLineString = errors.New("unmarshal linestring error")
errUnMarshaMultiLineString = errors.New("unmarshal multilinestring error")
errUnMarshaPolygon = errors.New("unmarshal polygon error")
errUnMarshaMultiPolygon = errors.New("unmarshal multipolygon error")
errUnMarshaGeometryCollection = errors.New("unmarshal collection error")
// ErrNotWKT is returned when unmarshalling WKT and the data is not valid.
ErrNotWKT = errors.New("wkt: invalid data")

errConvertToPoint = errors.New("convert to point error")
errConvertToMultiPoint = errors.New("convert to multi point error")
errConvertToLineString = errors.New("convert to line string error")
errConvertToMultiLineString = errors.New("convert to multi line string error")
errConvertToPolygon = errors.New("convert to polygon error")
errConvertToMultiPolygon = errors.New("convert to multi polygon error")
errConvertToGeometryCollection = errors.New("convert to geometry collection error")
)

// errWrap errWarp
func errWrap(err error, es ...error) error {
s := make([]string, 0)
if err != nil {
s = append(s, err.Error())
}

for _, e := range es {
if e != nil {
s = append(s, e.Error())
}
}
// ErrIncorrectGeometry is returned when unmarshalling WKT data into the wrong type.
// For example, unmarshaling linestring data into a point.
ErrIncorrectGeometry = errors.New("wkt: incorrect geometry")

return errors.New(strings.Join(s, "\n"))
}
// ErrUnsupportedGeometry is returned when geometry type is not supported by this lib.
ErrUnsupportedGeometry = errors.New("wkt: unsupported geometry")
)

// UnmarshalPoint return point by parse wkt point string
// UnmarshalPoint returns the point represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a point.
func UnmarshalPoint(s string) (p orb.Point, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.Point{}, errWrap(err, errEmptyGeometry)
return orb.Point{}, err
}
g, ok := geom.(orb.Point)
if !ok {
return orb.Point{}, errWrap(err, errConvertToPoint)
return orb.Point{}, ErrIncorrectGeometry
}
return g, nil
}

// UnmarshalMultiPoint return multipoint by parse wkt multipoint string
// UnmarshalMultiPoint returns the multi-point represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a multi-point.
func UnmarshalMultiPoint(s string) (p orb.MultiPoint, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.MultiPoint{}, errWrap(err, errEmptyGeometry)
return nil, err
}

g, ok := geom.(orb.MultiPoint)
if !ok {
return orb.MultiPoint{}, errWrap(err, errConvertToMultiPoint)
return nil, ErrIncorrectGeometry
}
return g, nil
}

// UnmarshalLineString return linestring by parse wkt linestring string
// UnmarshalLineString returns the linestring represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a linestring.
func UnmarshalLineString(s string) (p orb.LineString, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.LineString{}, errWrap(err, errEmptyGeometry)
return nil, err
}
g, ok := geom.(orb.LineString)
if !ok {
return orb.LineString{}, errWrap(err, errConvertToLineString)
return nil, ErrIncorrectGeometry
}
return g, nil
}

// UnmarshalMultiLineString return linestring by parse wkt multilinestring string
// UnmarshalMultiLineString returns the multi-linestring represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a multi-linestring.
func UnmarshalMultiLineString(s string) (p orb.MultiLineString, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.MultiLineString{}, errWrap(err, errEmptyGeometry)
return nil, err
}
g, ok := geom.(orb.MultiLineString)
if !ok {
return orb.MultiLineString{}, errWrap(err, errConvertToMultiLineString)
return nil, ErrIncorrectGeometry
}
return g, nil
}

// UnmarshalPolygon return linestring by parse wkt polygon string
// UnmarshalPolygon returns the polygon represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a polygon.
func UnmarshalPolygon(s string) (p orb.Polygon, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.Polygon{}, errWrap(err, errEmptyGeometry)
return nil, err
}
g, ok := geom.(orb.Polygon)
if !ok {
return orb.Polygon{}, errWrap(err, errConvertToPolygon)
return nil, ErrIncorrectGeometry
}
return g, nil
}

// UnmarshalMultiPolygon return linestring by parse wkt multipolygon string
// UnmarshalMultiPolygon returns the multi-polygon represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a multi-polygon.
func UnmarshalMultiPolygon(s string) (p orb.MultiPolygon, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.MultiPolygon{}, errWrap(err, errEmptyGeometry)
return nil, err
}
g, ok := geom.(orb.MultiPolygon)
if !ok {
return orb.MultiPolygon{}, errWrap(err, errConvertToMultiPolygon)
return nil, ErrIncorrectGeometry
}
return g, nil
}

// UnmarshalCollection return linestring by parse wkt collection string
// UnmarshalCollection returns the geometry collection represented by the wkt string.
// Will return ErrIncorrectGeometry if the wkt is not a geometry collection.
func UnmarshalCollection(s string) (p orb.Collection, err error) {
geom, err := unmarshal(s)
geom, err := Unmarshal(s)
if err != nil {
return orb.Collection{}, errWrap(err, errEmptyGeometry)
return orb.Collection{}, err
}
g, ok := geom.(orb.Collection)
if !ok {
return orb.Collection{}, errWrap(err, errConvertToGeometryCollection)
return nil, ErrIncorrectGeometry
}
return g, nil
}
Expand All @@ -143,26 +128,28 @@ func trimSpaceBrackets(s string) string {
if s[len(s)-1] == ')' {
s = s[:len(s)-1]
}
s = strings.Trim(s, " ")
return s

return strings.Trim(s, " ")
}

// parsePoint pase point by (x y)
func parsePoint(s string) (p orb.Point, err error) {
ps := strings.Split(s, " ")
if len(ps) != 2 {
return orb.Point{}, errors.New("can't get x,y")
return orb.Point{}, ErrNotWKT
}

x, err := strconv.ParseFloat(ps[0], 64)
if err != nil {
return orb.Point{}, err
}

y, err := strconv.ParseFloat(ps[1], 64)
if err != nil {
return orb.Point{}, err
}
p = orb.Point{x, y}
return p, nil

return orb.Point{x, y}, nil
}

// splitGeometryCollection split GEOMETRYCOLLECTION to more geometry
Expand Down Expand Up @@ -191,37 +178,27 @@ func splitGeometryCollection(s string) (r []string) {
return
}

/*
unmarshal return a geometry by parse wkt string
order:
GEOMETRYCOLLECTION
MULTIPOINT
POINT
MULTILINESTRING
LINESTRING
MULTIPOLYGON
POLYGON
*/
func unmarshal(s string) (geom orb.Geometry, err error) {
// Unmarshal return a geometry by parsing the WKT string.
func Unmarshal(s string) (geom orb.Geometry, err error) {
s = strings.ToUpper(strings.Trim(s, " "))
switch {
case strings.Contains(s, "GEOMETRYCOLLECTION"):
if s == "GEOMETRYCOLLECTION " {
if s == "GEOMETRYCOLLECTION EMPTY" {
return orb.Collection{}, nil
}
s = strings.Replace(s, "GEOMETRYCOLLECTION", "", -1)
c := orb.Collection{}
ms := splitGeometryCollection(s)
if len(ms) == 0 {
return nil, errUnMarshaGeometryCollection
return nil, err
}
for _, v := range ms {
if len(v) == 0 {
continue
}
g, err := unmarshal(v)
g, err := Unmarshal(v)
if err != nil {
return nil, errWrap(errUnMarshaGeometryCollection, err)
return nil, err
}
c = append(c, g)
}
Expand All @@ -238,7 +215,7 @@ func unmarshal(s string) (geom orb.Geometry, err error) {
for _, p := range ps {
tp, err := parsePoint(trimSpaceBrackets(p))
if err != nil {
return nil, errWrap(errUnMarshalPoint, err)
return nil, err
}
mp = append(mp, tp)
}
Expand All @@ -248,7 +225,7 @@ func unmarshal(s string) (geom orb.Geometry, err error) {
s = strings.Replace(s, "POINT", "", -1)
tp, err := parsePoint(trimSpaceBrackets(s))
if err != nil {
return nil, errWrap(errUnMarshalPoint, err)
return nil, err
}
geom = tp

Expand All @@ -263,7 +240,7 @@ func unmarshal(s string) (geom orb.Geometry, err error) {
for _, p := range strings.Split(trimSpaceBrackets(l), ",") {
tp, err := parsePoint(trimSpaceBrackets(p))
if err != nil {
return nil, errWrap(errUnMarshaMultiLineString, err)
return nil, err
}
tl = append(tl, tp)
}
Expand All @@ -282,7 +259,7 @@ func unmarshal(s string) (geom orb.Geometry, err error) {
for _, p := range ps {
tp, err := parsePoint(trimSpaceBrackets(p))
if err != nil {
return nil, errWrap(errUnMarshaLineString, err)
return nil, err
}
ls = append(ls, tp)
}
Expand All @@ -301,7 +278,7 @@ func unmarshal(s string) (geom orb.Geometry, err error) {
for _, p := range strings.Split(ls, ",") {
tp, err := parsePoint(trimSpaceBrackets(p))
if err != nil {
return nil, errWrap(errUnMarshaMultiPolygon, err)
return nil, err
}
ring = append(ring, tp)
}
Expand All @@ -317,38 +294,24 @@ func unmarshal(s string) (geom orb.Geometry, err error) {
}
s = strings.Replace(s, "POLYGON", "", -1)
s = trimSpaceBrackets(s)

rs := strings.Split(s, "),(")
if len(rs) == 1 {
// ring
ps := strings.Split(trimSpaceBrackets(s), ",")
pol := make(orb.Polygon, 0, len(rs))
for _, r := range rs {
ps := strings.Split(trimSpaceBrackets(r), ",")
ring := orb.Ring{}
for _, p := range ps {
tp, err := parsePoint(trimSpaceBrackets(p))
if err != nil {
return nil, errWrap(errUnMarshaLineString, err)
return nil, err
}
ring = append(ring, tp)
}
geom = orb.Polygon{ring}
} else {
// more ring
pol := orb.Polygon{}
for _, r := range rs {
ps := strings.Split(trimSpaceBrackets(r), ",")
ring := orb.Ring{}
for _, p := range ps {
tp, err := parsePoint(trimSpaceBrackets(p))
if err != nil {
return nil, errWrap(errUnMarshaLineString, err)
}
ring = append(ring, tp)
}
pol = append(pol, ring)
}
geom = pol
pol = append(pol, ring)
}
geom = pol
default:
return nil, errors.New("wkt: unsupported geometry")
return nil, ErrUnsupportedGeometry
}

return
Expand Down
Loading

0 comments on commit 215f32c

Please sign in to comment.