Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methods to check geometry type and convert simultaneously #423

Merged
merged 3 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## Unreleased

- **Breaking change**: Renames the `AsFoo` methods of the Geometry type to
`MustAsFoo` (where `Foo` is a concrete geometry type such as `Point`). This
follows the go convention that methods and functions prefixed with Must may
panic if preconditions are not met. Note that there's no change in behaviour
here, it's simply a rename (these methods previously panicked). Users may
resolve this breaking change by just updating the names of any `AsFoo`
methods they are calling to `MustAsFoo`.

- **Breaking change**: Adds new methods named `AsFoo` to the Geometry type.
These methods have the signature `AsFoo() (Foo, bool)`. The boolean return
value indicates if the conversion was successful or not. These methods are
useful because they allow concrete geometries to be extracted from a Geometry
value, with the concrete type for the `Is` and `As` call only specified once.
Users now just have to call `AsFoo`, and can then check the flag. This helps
to eliminate the class of bugs there the type specified with `IsFoo`
erroneously differs from the type specified by `AsFoo`.

## v0.33.1

__Special thanks to Albert Teoh for contributing to this release.__
Expand Down
22 changes: 11 additions & 11 deletions geom/accessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import (
)

func TestPointAccessorNonEmpty(t *testing.T) {
xy, ok := geomFromWKT(t, "POINT(1 2)").AsPoint().XY()
xy, ok := geomFromWKT(t, "POINT(1 2)").MustAsPoint().XY()
expectBoolEq(t, ok, true)
expectXYEq(t, xy, XY{1, 2})
}

func TestPointAccessorEmpty(t *testing.T) {
_, ok := geomFromWKT(t, "POINT EMPTY").AsPoint().XY()
_, ok := geomFromWKT(t, "POINT EMPTY").MustAsPoint().XY()
expectBoolEq(t, ok, false)
}

func TestLineStringAccessor(t *testing.T) {
ls := geomFromWKT(t, "LINESTRING(1 2,3 4,5 6)").AsLineString()
ls := geomFromWKT(t, "LINESTRING(1 2,3 4,5 6)").MustAsLineString()
seq := ls.Coordinates()
pt12 := xyCoords(1, 2)
pt34 := xyCoords(3, 4)
Expand Down Expand Up @@ -47,7 +47,7 @@ func TestLineStringAccessor(t *testing.T) {
}

func TestLineStringEmptyAccessor(t *testing.T) {
ls := geomFromWKT(t, "LINESTRING EMPTY").AsLineString()
ls := geomFromWKT(t, "LINESTRING EMPTY").MustAsLineString()
seq := ls.Coordinates()
emptyPoint := geomFromWKT(t, "POINT EMPTY")

Expand All @@ -68,7 +68,7 @@ func TestLineStringEmptyAccessor(t *testing.T) {
}

func TestLineStringAccessorWithDuplicates(t *testing.T) {
ls := geomFromWKT(t, "LINESTRING(1 2,3 4,3 4,5 6)").AsLineString()
ls := geomFromWKT(t, "LINESTRING(1 2,3 4,3 4,5 6)").MustAsLineString()
seq := ls.Coordinates()
pt12 := xyCoords(1, 2)
pt34 := xyCoords(3, 4)
Expand All @@ -88,7 +88,7 @@ func TestLineStringAccessorWithDuplicates(t *testing.T) {
}

func TestLineStringAccessorWithMoreDuplicates(t *testing.T) {
ls := geomFromWKT(t, "LINESTRING(1 2,1 2,3 4,3 4,3 4,5 6,5 6)").AsLineString()
ls := geomFromWKT(t, "LINESTRING(1 2,1 2,3 4,3 4,3 4,5 6,5 6)").MustAsLineString()
seq := ls.Coordinates()
pt12 := xyCoords(1, 2)
pt34 := xyCoords(3, 4)
Expand All @@ -111,7 +111,7 @@ func TestLineStringAccessorWithMoreDuplicates(t *testing.T) {
}

func TestPolygonAccessor(t *testing.T) {
poly := geomFromWKT(t, "POLYGON((0 0,5 0,5 3,0 3,0 0),(1 1,2 1,2 2,1 2,1 1),(3 1,4 1,4 2,3 2,3 1))").AsPolygon()
poly := geomFromWKT(t, "POLYGON((0 0,5 0,5 3,0 3,0 0),(1 1,2 1,2 2,1 2,1 1),(3 1,4 1,4 2,3 2,3 1))").MustAsPolygon()
outer := geomFromWKT(t, "LINESTRING(0 0,5 0,5 3,0 3,0 0)")
inner0 := geomFromWKT(t, "LINESTRING(1 1,2 1,2 2,1 2,1 1)")
inner1 := geomFromWKT(t, "LINESTRING(3 1,4 1,4 2,3 2,3 1)")
Expand All @@ -125,7 +125,7 @@ func TestPolygonAccessor(t *testing.T) {
}

func TestMultiPointAccessor(t *testing.T) {
mp := geomFromWKT(t, "MULTIPOINT((4 5),(2 3),(8 7))").AsMultiPoint()
mp := geomFromWKT(t, "MULTIPOINT((4 5),(2 3),(8 7))").MustAsMultiPoint()
pt0 := geomFromWKT(t, "POINT(4 5)")
pt1 := geomFromWKT(t, "POINT(2 3)")
pt2 := geomFromWKT(t, "POINT(8 7)")
Expand All @@ -139,7 +139,7 @@ func TestMultiPointAccessor(t *testing.T) {
}

func TestMultiLineStringAccessors(t *testing.T) {
mls := geomFromWKT(t, "MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10,11 12))").AsMultiLineString()
mls := geomFromWKT(t, "MULTILINESTRING((1 2,3 4,5 6),(7 8,9 10,11 12))").MustAsMultiLineString()
ls0 := geomFromWKT(t, "LINESTRING(1 2,3 4,5 6)")
ls1 := geomFromWKT(t, "LINESTRING(7 8,9 10,11 12)")

Expand All @@ -151,7 +151,7 @@ func TestMultiLineStringAccessors(t *testing.T) {
}

func TestMultiPolygonAccessors(t *testing.T) {
polys := geomFromWKT(t, "MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((2 0,2 1,3 0,2 0)))").AsMultiPolygon()
polys := geomFromWKT(t, "MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((2 0,2 1,3 0,2 0)))").MustAsMultiPolygon()
poly0 := geomFromWKT(t, "POLYGON((0 0,0 1,1 0,0 0))")
poly1 := geomFromWKT(t, "POLYGON((2 0,2 1,3 0,2 0))")

Expand All @@ -163,7 +163,7 @@ func TestMultiPolygonAccessors(t *testing.T) {
}

func TestGeometryCollectionAccessors(t *testing.T) {
geoms := geomFromWKT(t, "GEOMETRYCOLLECTION(POLYGON((0 0,0 1,1 0,0 0)),POLYGON((2 0,2 1,3 0,2 0)))").AsGeometryCollection()
geoms := geomFromWKT(t, "GEOMETRYCOLLECTION(POLYGON((0 0,0 1,1 0,0 0)),POLYGON((2 0,2 1,3 0,2 0)))").MustAsGeometryCollection()
geom0 := geomFromWKT(t, "POLYGON((0 0,0 1,1 0,0 0))")
geom1 := geomFromWKT(t, "POLYGON((2 0,2 1,3 0,2 0))")

Expand Down
14 changes: 7 additions & 7 deletions geom/alg_convex_hull.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func convexHullPointSet(g Geometry) []XY {
switch {
case g.IsGeometryCollection():
var points []XY
c := g.AsGeometryCollection()
c := g.MustAsGeometryCollection()
n := c.NumGeometries()
for i := 0; i < n; i++ {
points = append(
Expand All @@ -90,24 +90,24 @@ func convexHullPointSet(g Geometry) []XY {
}
return points
case g.IsPoint():
xy, ok := g.AsPoint().XY()
xy, ok := g.MustAsPoint().XY()
if !ok {
return nil
}
return []XY{xy}
case g.IsLineString():
cs := g.AsLineString().Coordinates()
cs := g.MustAsLineString().Coordinates()
n := cs.Length()
points := make([]XY, n)
for i := 0; i < n; i++ {
points[i] = cs.GetXY(i)
}
return points
case g.IsPolygon():
p := g.AsPolygon()
p := g.MustAsPolygon()
return convexHullPointSet(p.ExteriorRing().AsGeometry())
case g.IsMultiPoint():
m := g.AsMultiPoint()
m := g.MustAsMultiPoint()
n := m.NumPoints()
points := make([]XY, 0, n)
for i := 0; i < n; i++ {
Expand All @@ -118,7 +118,7 @@ func convexHullPointSet(g Geometry) []XY {
}
return points
case g.IsMultiLineString():
m := g.AsMultiLineString()
m := g.MustAsMultiLineString()
var points []XY
n := m.NumLineStrings()
for i := 0; i < n; i++ {
Expand All @@ -130,7 +130,7 @@ func convexHullPointSet(g Geometry) []XY {
}
return points
case g.IsMultiPolygon():
m := g.AsMultiPolygon()
m := g.MustAsMultiPolygon()
var points []XY
numPolys := m.NumPolygons()
for i := 0; i < numPolys; i++ {
Expand Down
14 changes: 7 additions & 7 deletions geom/alg_distance.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,21 @@ func Distance(g1, g2 Geometry) (float64, bool) {
func extractXYsAndLines(g Geometry) ([]XY, []line) {
switch g.Type() {
case TypePoint:
return g.AsPoint().asXYs(), nil
return g.MustAsPoint().asXYs(), nil
case TypeLineString:
return nil, g.AsLineString().asLines()
return nil, g.MustAsLineString().asLines()
case TypePolygon:
return nil, g.AsPolygon().Boundary().asLines()
return nil, g.MustAsPolygon().Boundary().asLines()
case TypeMultiPoint:
return g.AsMultiPoint().asXYs(), nil
return g.MustAsMultiPoint().asXYs(), nil
case TypeMultiLineString:
return nil, g.AsMultiLineString().asLines()
return nil, g.MustAsMultiLineString().asLines()
case TypeMultiPolygon:
return nil, g.AsMultiPolygon().Boundary().asLines()
return nil, g.MustAsMultiPolygon().Boundary().asLines()
case TypeGeometryCollection:
var allXYs []XY
var allLines []line
g.AsGeometryCollection().walk(func(child Geometry) {
g.MustAsGeometryCollection().walk(func(child Geometry) {
xys, lns := extractXYsAndLines(child)
allXYs = append(allXYs, xys...)
allLines = append(allLines, lns...)
Expand Down
8 changes: 4 additions & 4 deletions geom/alg_dump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestDumpMultiPoint(t *testing.T) {
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
want := geomsFromWKTs(t, tc.wantOutputWKT)
got := upcastPoints(geomFromWKT(t, tc.inputWKT).AsMultiPoint().Dump())
got := upcastPoints(geomFromWKT(t, tc.inputWKT).MustAsMultiPoint().Dump())
expectGeomsEq(t, got, want)
})
}
Expand Down Expand Up @@ -153,7 +153,7 @@ func TestDumpMultiLineString(t *testing.T) {
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
want := geomsFromWKTs(t, tc.wantOutputWKT)
got := upcastLineStrings(geomFromWKT(t, tc.inputWKT).AsMultiLineString().Dump())
got := upcastLineStrings(geomFromWKT(t, tc.inputWKT).MustAsMultiLineString().Dump())
expectGeomsEq(t, got, want)
})
}
Expand All @@ -179,7 +179,7 @@ func TestDumpMultiPolygon(t *testing.T) {
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
want := geomsFromWKTs(t, tc.wantOutputWKT)
got := upcastPolygons(geomFromWKT(t, tc.inputWKT).AsMultiPolygon().Dump())
got := upcastPolygons(geomFromWKT(t, tc.inputWKT).MustAsMultiPolygon().Dump())
expectGeomsEq(t, got, want)
})
}
Expand Down Expand Up @@ -213,7 +213,7 @@ func TestDumpGeometryCollection(t *testing.T) {
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
want := geomsFromWKTs(t, tc.wantOutputWKT)
got := geomFromWKT(t, tc.inputWKT).AsGeometryCollection().Dump()
got := geomFromWKT(t, tc.inputWKT).MustAsGeometryCollection().Dump()
expectGeomsEq(t, got, want)
})
}
Expand Down
14 changes: 7 additions & 7 deletions geom/alg_exact_equals.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,19 @@ func (c exactEqualsComparator) geometriesEq(g1, g2 Geometry) bool {
}
switch typ := g1.Type(); typ {
case TypePoint:
return c.pointsEq(g1.AsPoint(), g2.AsPoint())
return c.pointsEq(g1.MustAsPoint(), g2.MustAsPoint())
case TypeMultiPoint:
return c.multiPointsEq(g1.AsMultiPoint(), g2.AsMultiPoint())
return c.multiPointsEq(g1.MustAsMultiPoint(), g2.MustAsMultiPoint())
case TypeLineString:
return c.lineStringsEq(g1.AsLineString(), g2.AsLineString())
return c.lineStringsEq(g1.MustAsLineString(), g2.MustAsLineString())
case TypeMultiLineString:
return c.multiLineStringsEq(g1.AsMultiLineString(), g2.AsMultiLineString())
return c.multiLineStringsEq(g1.MustAsMultiLineString(), g2.MustAsMultiLineString())
case TypePolygon:
return c.polygonsEq(g1.AsPolygon(), g2.AsPolygon())
return c.polygonsEq(g1.MustAsPolygon(), g2.MustAsPolygon())
case TypeMultiPolygon:
return c.multiPolygonsEq(g1.AsMultiPolygon(), g2.AsMultiPolygon())
return c.multiPolygonsEq(g1.MustAsMultiPolygon(), g2.MustAsMultiPolygon())
case TypeGeometryCollection:
return c.geometryCollectionsEq(g1.AsGeometryCollection(), g2.AsGeometryCollection())
return c.geometryCollectionsEq(g1.MustAsGeometryCollection(), g2.MustAsGeometryCollection())
default:
panic("unknown geometry type: " + typ.String())
}
Expand Down
Loading