Skip to content

Commit

Permalink
Merge branch 'master' into multiple_geos_versions_in_ci
Browse files Browse the repository at this point in the history
  • Loading branch information
peterstace committed May 22, 2023
2 parents 6d7a785 + fdf65a0 commit 3bde799
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
36 changes: 36 additions & 0 deletions geos/entrypoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ package geos
GEOSGeometry *GEOSMakeValid_r(GEOSContextHandle_t handle, const GEOSGeometry* g) { return NULL; }
#endif
#define COVERAGE_UNION_MIN_VERSION "3.8.0"
#define COVERAGE_UNION_MISSING ( \
GEOS_VERSION_MAJOR < 3 || \
(GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 8) \
)
#if COVERAGE_UNION_MISSING
// This stub implementation always fails:
GEOSGeometry *GEOSCoverageUnion_r(GEOSContextHandle_t handle, const GEOSGeometry* g) { return NULL; }
#endif
*/
import "C"

Expand Down Expand Up @@ -337,3 +347,29 @@ func MakeValid(g geom.Geometry, opts ...geom.ConstructorOption) (geom.Geometry,
})
return result, wrap(err, "executing GEOSMakeValid_r")
}

// The CoverageUnion function is used to union polygonal inputs that form a
// coverage, which are typically provided as a GeometryCollection. This method
// is much faster than other unioning methods, but there are some constraints
// that must be met by the inputs to form a valid polygonal coverage. These
// constraints are:
//
// 1. all input geometries must be polygonal,
// 2. the interiors of the inputs must not intersect, and
// 3. the common boundaries of adjacent polygons have the same set of vertices in both polygons.
//
// It should be noted that while CoverageUnion may detect constraint violations
// and return an error, but this is not guaranteed, and an invalid result may
// be returned without an error. It is the responsibility of the caller to
// ensure that the constraints are met before using this function.
func CoverageUnion(g geom.Geometry, opts ...geom.ConstructorOption) (geom.Geometry, error) {
if C.COVERAGE_UNION_MISSING != 0 {
return geom.Geometry{}, unsupportedGEOSVersionError{
C.COVERAGE_UNION_MIN_VERSION, "CoverageUnion",
}
}
result, err := unaryOpG(g, opts, func(ctx C.GEOSContextHandle_t, g *C.GEOSGeometry) *C.GEOSGeometry {
return C.GEOSCoverageUnion_r(ctx, g)
})
return result, wrap(err, "executing GEOSCoverageUnion_r")
}
77 changes: 77 additions & 0 deletions geos/entrypoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -829,3 +829,80 @@ func TestMakeValid(t *testing.T) {
})
}
}

func TestCoverageUnion(t *testing.T) {
for i, tc := range []struct {
input string
output string
wantErr bool
}{
{
// Noded correctly (shared edge).
input: `GEOMETRYCOLLECTION(
POLYGON((0 0,0 1,1 0,0 0)),
POLYGON((1 1,0 1,1 0,1 1))
)`,
output: `POLYGON((0 0,0 1,1 1,1 0,0 0))`,
},
{
// Noded correctly (shared vertex but no shared edge).
input: `GEOMETRYCOLLECTION(
POLYGON((0 0,0 1,1 1,1 0,0 0)),
POLYGON((1 1,1 2,2 2,2 1,1 1))
)`,
output: `MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)),((1 1,1 2,2 2,2 1,1 1)))`,
},
{
// Noded correctly (completely disjoint).
input: `GEOMETRYCOLLECTION(
POLYGON((0 0,0 1,1 1,1 0,0 0)),
POLYGON((2 2,2 3,3 3,3 2,2 2))
)`,
output: `MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)),((2 2,2 3,3 3,3 2,2 2)))`,
},
{
// Input constraint violated: inputs overlap.
input: `GEOMETRYCOLLECTION(
POLYGON((0 0,0 1,1 0,0 0)),
POLYGON((0 0,0 1,1 1,1 0,0 0))
)`,
wantErr: true,
},
{
// Input constraint violated: inputs overlap and not noded correctly.
input: `GEOMETRYCOLLECTION(
POLYGON((0 0,0 1,1 0,0 0)),
POLYGON((0 0,0 1,1 1,0 0))
)`,
wantErr: true,
},
{
// Input constraint violated: not noded correctly.
input: `GEOMETRYCOLLECTION(
POLYGON((0 0,0 1,1 1,1 0,0 0)),
POLYGON((0 1,2 1,2 2,0 2,0 1))
)`,
wantErr: true,
},
{
// Input constraint violation: not everything is a polygon.
input: `GEOMETRYCOLLECTION(POINT(1 2),POLYGON((0 0,0 1,1 0,0 0)))`,
wantErr: true,
},
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
in := geomFromWKT(t, tc.input)
gotGeom, err := CoverageUnion(in)
if _, ok := err.(unsupportedGEOSVersionError); ok {
t.Skip(err)
}
if tc.wantErr {
expectErr(t, err)
} else {
expectNoErr(t, err)
wantGeom := geomFromWKT(t, tc.output)
expectGeomEq(t, gotGeom, wantGeom, geom.IgnoreOrder)
}
})
}
}

0 comments on commit 3bde799

Please sign in to comment.