Skip to content

Commit

Permalink
Merge pull request #623 from peterstace/coverage_simplify
Browse files Browse the repository at this point in the history
Add GEOS wrapper for `GEOSCoverageSimplifyVW_r`
  • Loading branch information
peterstace authored Jun 13, 2024
2 parents 5de4f13 + 3990227 commit f5eca62
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 6 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
- Adds a wrapper to the `geos` package for the `GEOSTopologyPreserveSimplify_r`
function (exposed as `TopologyPreserveSimplify`).

- Adds a wrapper to the `geos` package for the `GEOSCoverageSimplifyVW_r`
function (exposed as `CoverageSimplifyVW`).

## v0.50.0

2024-05-07
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: all
all: unit lint pgscan cmppg cmpgeos
all: unit lint geos pgscan cmppg cmpgeos

DC_RUN = \
docker compose \
Expand Down
17 changes: 17 additions & 0 deletions geos/entrypoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,23 @@ func CoverageUnion(g geom.Geometry) (geom.Geometry, error) {
return rawgeos.CoverageUnion(g)
}

// CoverageSimplifyVW simplifies inputs that form a polygon coverage, provided
// as a GeometryCollection of Polygons and/or MultiPolygons. It uses the
// Visvalingam–Whyatt algorithm and relies on the fact that the input is a
// valid polygon coverage, i.e.:
//
// 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 may not check that these constraints are met, so it's possible that an
// incorrect result is returned without an error if they are not.
//
// The validity of the result is not checked.
func CoverageSimplifyVW(g geom.Geometry, tolerance float64, preserveBoundary bool) (geom.Geometry, error) {
return rawgeos.CoverageSimplifyVW(g, tolerance, preserveBoundary)
}

// UnaryUnion is a single argument version of Union. It is most useful when
// supplied with a GeometryCollection, resulting in the union of the
// GeometryCollection's child geometries.
Expand Down
24 changes: 24 additions & 0 deletions geos/entrypoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package geos_test

import (
"math"
"os"
"strconv"
"strings"
"testing"
Expand All @@ -19,6 +20,13 @@ func geomFromWKT(t *testing.T, wkt string, nv ...geom.NoValidate) geom.Geometry
return geom
}

func geomFromWKTFile(t *testing.T, path string, nv ...geom.NoValidate) geom.Geometry {
t.Helper()
wkt, err := os.ReadFile(path)
expectNoErr(t, err)
return geomFromWKT(t, string(wkt), nv...)
}

func expectNoErr(t *testing.T, err error) {
t.Helper()
if err != nil {
Expand Down Expand Up @@ -927,3 +935,19 @@ func TestCoverageUnion(t *testing.T) {
})
}
}

func TestCoverageSimplifyVW(t *testing.T) {
input := geom.NewGeometryCollection(
[]geom.Geometry{
geomFromWKTFile(t, "testdata/coverage_simplify_input_birchgrove.wkt"),
geomFromWKTFile(t, "testdata/coverage_simplify_input_balmain.wkt"),
},
)
got, err := geos.CoverageSimplifyVW(input.AsGeometry(), 0.001, false)
if err != nil && strings.Contains(err.Error(), "unsupported") {
t.Skip(err)
}
expectNoErr(t, err)
want := geomFromWKTFile(t, "testdata/coverage_simplify_output.wkt")
expectGeomEq(t, got, want)
}
1 change: 1 addition & 0 deletions geos/testdata/coverage_simplify_input_balmain.wkt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MULTIPOLYGON(((151.17562157 -33.852492,151.17610434 -33.85293458,151.17653708 -33.85258046,151.17664705 -33.85268229,151.17635201 -33.85292177,151.17703513 -33.85355284,151.17752868 -33.85329725,151.17760962 -33.85341627,151.17789714 -33.8532749,151.17813638 -33.85355944,151.17787658 -33.85368893,151.17794364 -33.85375775,151.17817861 -33.85364202,151.17829404 -33.85380574,151.17851529 -33.85368774,151.17863944 -33.85383985,151.17825035 -33.85406584,151.17831976 -33.8541354,151.17861349 -33.85396523,151.17888675 -33.85429772,151.17869385 -33.85451408,151.17897699 -33.85466425,151.17923305 -33.85451707,151.1793722 -33.85468909,151.17923626 -33.85476768,151.17934972 -33.8548113,151.17960694 -33.85466363,151.17975564 -33.85485334,151.1799324 -33.85475283,151.18008374 -33.85494999,151.17992892 -33.85504022,151.18004059 -33.85508669,151.18024687 -33.85496532,151.18047698 -33.85510386,151.18057018 -33.85504907,151.18072799 -33.85523191,151.1806061 -33.85530431,151.18095598 -33.85553991,151.18179702 -33.85509033,151.18163194 -33.85484523,151.18182783 -33.85507189,151.18236497 -33.85468442,151.18247432 -33.85482159,151.18263573 -33.85473058,151.18273565 -33.85485813,151.18288381 -33.8547757,151.18279125 -33.85465935,151.18425398 -33.85393118,151.18481299 -33.85462981,151.18515941 -33.85464942,151.1856686 -33.85498144,151.18602454 -33.85477304,151.18634885 -33.85493575,151.18689314 -33.85505367,151.18766825 -33.85565725,151.18764139 -33.85580755,151.18785861 -33.85617518,151.18813822 -33.85627391,151.18848034 -33.85655411,151.18845636 -33.85666427,151.18874913 -33.85675219,151.18871911 -33.8570698,151.18844014 -33.8571684,151.18834672 -33.85775106,151.18859877 -33.85773378,151.18858846 -33.85782662,151.18848071 -33.85783249,151.18845465 -33.85805513,151.18893474 -33.85808091,151.18894716 -33.85815697,151.18941834 -33.85808216,151.18979997 -33.85845525,151.19060903 -33.85829987,151.19074384 -33.85824933,151.19073681 -33.85811149,151.19088604 -33.858132,151.19089161 -33.85819461,151.19188407 -33.85815769,151.1920783 -33.85885077,151.19226281 -33.85882375,151.19243245 -33.85945026,151.19266264 -33.85940856,151.19272075 -33.8596754,151.19201066 -33.8596363,151.19164724 -33.85925607,151.19161325 -33.85908805,151.19077421 -33.85873108,151.19022884 -33.85924577,151.19019373 -33.85961462,151.19030245 -33.86020011,151.19137082 -33.86018757,151.19237275 -33.8605375,151.19234778 -33.86060066,151.19171625 -33.86047889,151.19116962 -33.86102952,151.19122106 -33.86121966,151.18680314 -33.86136574,151.18164151 -33.8638001,151.18089125 -33.86334185,151.18071207 -33.86348688,151.18073576 -33.86360511,151.18042706 -33.86368329,151.18029913 -33.86347669,151.17989585 -33.86364402,151.17990122 -33.86404778,151.1795342 -33.86417184,151.17952829 -33.86369808,151.17911921 -33.86308979,151.17913111 -33.8622604,151.17892008 -33.86204881,151.17835989 -33.86232404,151.17851032 -33.86279427,151.17808042 -33.86288972,151.17778637 -33.86247385,151.17650112 -33.86281741,151.17630906 -33.86245507,151.17599931 -33.86250726,151.17597124 -33.86224142,151.17528962 -33.86234787,151.17444549 -33.86208818,151.17449779 -33.86198789,151.17436897 -33.86194273,151.17445034 -33.86179621,151.17419163 -33.8617317,151.17424196 -33.86162827,151.17411313 -33.86154668,151.17416669 -33.86144509,151.17395707 -33.86139227,151.17403184 -33.86124238,151.17393452 -33.8612261,151.17399894 -33.86107266,151.17295536 -33.86093852,151.17296923 -33.86085877,151.17267324 -33.86082292,151.17265752 -33.86034748,151.17229531 -33.86032,151.17244093 -33.85897694,151.172487 -33.85879708,151.17261284 -33.85880772,151.17264664 -33.85867398,151.17253642 -33.85866344,151.17259684 -33.85841767,151.17200881 -33.85819881,151.17101707 -33.85819379,151.17104768 -33.85760108,151.16988059 -33.85726533,151.1698966 -33.85744043,151.16935085 -33.85729849,151.16935826 -33.85716401,151.16947786 -33.85716685,151.16935023 -33.85706307,151.16925185 -33.85652192,151.16913408 -33.85654678,151.16873529 -33.85591302,151.16866673 -33.85511082,151.16872679 -33.85496086,151.16951413 -33.8546535,151.17077305 -33.85497744,151.17109831 -33.85485889,151.17138435 -33.85442554,151.17138822 -33.85373359,151.17133183 -33.85370213,151.17139593 -33.85335123,151.1712631 -33.85286008,151.17138825 -33.85272859,151.17178041 -33.85280195,151.17251637 -33.85339421,151.17272474 -33.85348034,151.17269209 -33.85336499,151.17349568 -33.85316641,151.17363463 -33.85357628,151.17448299 -33.85313989,151.17477125 -33.85303491,151.17484645 -33.85314004,151.17511686 -33.85300693,151.17504206 -33.85292464,151.17562157 -33.852492)))
1 change: 1 addition & 0 deletions geos/testdata/coverage_simplify_input_birchgrove.wkt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MULTIPOLYGON(((151.18548351 -33.84598785,151.18584268 -33.84624592,151.1857423 -33.84631734,151.18594953 -33.84636702,151.18615016 -33.84649602,151.18633781 -33.84649924,151.18690883 -33.84682487,151.18688258 -33.8469871,151.18656403 -33.84709663,151.18576996 -33.84716717,151.1857308 -33.84709965,151.1852197 -33.84735202,151.18479416 -33.84777024,151.18453976 -33.84791395,151.18359937 -33.84799928,151.18357148 -33.84792909,151.18338813 -33.84800376,151.18341095 -33.84806503,151.18322751 -33.84811131,151.18319511 -33.84803093,151.18307436 -33.84805145,151.18311025 -33.84813895,151.18243728 -33.8483085,151.1822388 -33.84843244,151.1822325 -33.84883917,151.1824452 -33.84926884,151.18284292 -33.84966277,151.18300231 -33.84957748,151.183634 -33.84954128,151.18429403 -33.8498145,151.18421932 -33.84987575,151.18432162 -33.84980016,151.1849602 -33.85027605,151.18547786 -33.85074492,151.18543893 -33.85079035,151.18597511 -33.85080932,151.1865003 -33.85116371,151.18700228 -33.8512558,151.18723252 -33.85138504,151.18717657 -33.85144488,151.18730358 -33.85156741,151.18736608 -33.85148978,151.18800725 -33.85179123,151.18801734 -33.85186512,151.18856615 -33.85184505,151.1890631 -33.85168387,151.19056762 -33.85180017,151.19044047 -33.85225499,151.18961572 -33.85284594,151.18831799 -33.85326861,151.18681272 -33.85311358,151.18671228 -33.85348185,151.18659345 -33.85351808,151.18551016 -33.85286741,151.18474128 -33.85326036,151.18496648 -33.85338689,151.18491944 -33.85352382,151.18482791 -33.85353087,151.18468821 -33.85338413,151.18458915 -33.85350098,151.18482395 -33.85374968,151.18596723 -33.85457753,151.18594271 -33.854742,151.1860377 -33.85476487,151.18569014 -33.85498534,151.18515941 -33.85464942,151.18481299 -33.85462981,151.18433623 -33.85397179,151.18418711 -33.85394107,151.18279125 -33.85465935,151.18288381 -33.8547757,151.18273565 -33.85485813,151.18263573 -33.85473058,151.18247432 -33.85482159,151.18236497 -33.85468442,151.18182783 -33.85507189,151.18163194 -33.85484523,151.18179702 -33.85509033,151.18095598 -33.85553991,151.1806061 -33.85530431,151.18072799 -33.85523191,151.18057018 -33.85504907,151.18047698 -33.85510386,151.18024687 -33.85496532,151.18004059 -33.85508669,151.17992892 -33.85504022,151.18008374 -33.85494999,151.1799324 -33.85475283,151.17975564 -33.85485334,151.17960694 -33.85466363,151.17934972 -33.8548113,151.17923626 -33.85476768,151.1793722 -33.85468909,151.17923305 -33.85451707,151.17897699 -33.85466425,151.17869385 -33.85451408,151.17888675 -33.85429772,151.17861349 -33.85396523,151.17831976 -33.8541354,151.17825035 -33.85406584,151.17863944 -33.85383985,151.17851529 -33.85368774,151.17829404 -33.85380574,151.17817861 -33.85364202,151.17794364 -33.85375775,151.17787658 -33.85368893,151.17813638 -33.85355944,151.17789714 -33.8532749,151.17760962 -33.85341627,151.17752868 -33.85329725,151.17703513 -33.85355284,151.17635201 -33.85292177,151.17664705 -33.85268229,151.17653708 -33.85258046,151.17610434 -33.85293458,151.17561437 -33.85248505,151.17755075 -33.85175451,151.17786913 -33.8515087,151.17790808 -33.85130797,151.17886167 -33.8498608,151.17898189 -33.84984837,151.17943716 -33.84935868,151.17939403 -33.84932594,151.17949738 -33.84929365,151.1796185 -33.84913311,151.17957397 -33.84910821,151.18030812 -33.84831506,151.18037655 -33.8483303,151.18078044 -33.8477586,151.18125515 -33.8477006,151.18131013 -33.8478212,151.18143686 -33.84770508,151.18164166 -33.84772524,151.18167182 -33.84784314,151.1826884 -33.8476568,151.18364305 -33.84723942,151.1837356 -33.84729306,151.18391502 -33.8471234,151.18402239 -33.84715291,151.18432684 -33.84703225,151.18424258 -33.8469065,151.18454738 -33.84665859,151.18467392 -33.84671318,151.1849512 -33.84646297,151.18489575 -33.84632727,151.18504819 -33.84615146,151.18513899 -33.84618889,151.18510369 -33.84612146,151.18548351 -33.84598785)))
1 change: 1 addition & 0 deletions geos/testdata/coverage_simplify_output.wkt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GEOMETRYCOLLECTION(MULTIPOLYGON(((151.18515941 -33.85464942,151.18481299 -33.85462981,151.18279125 -33.85465935,151.18095598 -33.85553991,151.17789714 -33.8532749,151.17610434 -33.85293458,151.18078044 -33.8477586,151.1826884 -33.8476568,151.18548351 -33.84598785,151.18690883 -33.84682487,151.18243728 -33.8483085,151.18800725 -33.85179123,151.19056762 -33.85180017,151.18831799 -33.85326861,151.18551016 -33.85286741,151.18458915 -33.85350098,151.1860377 -33.85476487,151.18569014 -33.85498534,151.18515941 -33.85464942))),MULTIPOLYGON(((151.17610434 -33.85293458,151.17789714 -33.8532749,151.18095598 -33.85553991,151.18279125 -33.85465935,151.18425398 -33.85393118,151.18481299 -33.85462981,151.18515941 -33.85464942,151.18689314 -33.85505367,151.18874913 -33.85675219,151.18845465 -33.85805513,151.19188407 -33.85815769,151.19272075 -33.8596754,151.19077421 -33.85873108,151.19122106 -33.86121966,151.18680314 -33.86136574,151.18164151 -33.8638001,151.17952829 -33.86369808,151.17913111 -33.8622604,151.17650112 -33.86281741,151.17444549 -33.86208818,151.17229531 -33.86032,151.17259684 -33.85841767,151.16935085 -33.85729849,151.16872679 -33.85496086,151.17077305 -33.85497744,151.1712631 -33.85286008,151.17363463 -33.85357628,151.17610434 -33.85293458))))
28 changes: 23 additions & 5 deletions internal/rawgeos/entrypoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ GEOSGeometry *GEOSMakeValid_r(GEOSContextHandle_t handle, const GEOSGeometry* g)
GEOSGeometry *GEOSCoverageUnion_r(GEOSContextHandle_t handle, const GEOSGeometry* g) { return NULL; }
#endif
#define COVERAGE_SIMPLIFY_VW_MIN_VERSION "3.12.0"
#define COVERAGE_SIMPLIFY_VW_MISSING ( \
GEOS_VERSION_MAJOR < 3 || \
(GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 12) \
)
#if COVERAGE_SIMPLIFY_VW_MISSING
// This stub implementation always fails:
GEOSGeometry *GEOSCoverageSimplifyVW_r(GEOSContextHandle_t handle, const GEOSGeometry* g, double tolerance, int preserveTopology) { return NULL; }
#endif
#define CONCAVE_HULL_MIN_VERSION "3.11.0"
#define CONCAVE_HULL_MISSING ( \
GEOS_VERSION_MAJOR < 3 || \
Expand Down Expand Up @@ -267,6 +277,18 @@ func CoverageUnion(g geom.Geometry) (geom.Geometry, error) {
return result, wrap(err, "executing GEOSCoverageUnion_r")
}

func CoverageSimplifyVW(g geom.Geometry, tolerance float64, preserveBoundary bool) (geom.Geometry, error) {
if C.COVERAGE_SIMPLIFY_VW_MISSING != 0 {
return geom.Geometry{}, unsupportedGEOSVersionError{
C.COVERAGE_SIMPLIFY_VW_MIN_VERSION, "CoverageSimplifyVW",
}
}
result, err := unaryOpG(g, func(ctx C.GEOSContextHandle_t, g *C.GEOSGeometry) *C.GEOSGeometry {
return C.GEOSCoverageSimplifyVW_r(ctx, g, C.double(tolerance), goBoolToCInt(preserveBoundary))
})
return result, wrap(err, "executing GEOSCoverageSimplifyVW_r")
}

func UnaryUnion(g geom.Geometry) (geom.Geometry, error) {
result, err := unaryOpG(g, func(ctx C.GEOSContextHandle_t, g *C.GEOSGeometry) *C.GEOSGeometry {
return C.GEOSUnaryUnion_r(ctx, g)
Expand Down Expand Up @@ -378,11 +400,7 @@ func ConcaveHull(g geom.Geometry, ratio float64, allowHoles bool) (geom.Geometry
}
}
result, err := unaryOpG(g, func(ctx C.GEOSContextHandle_t, g *C.GEOSGeometry) *C.GEOSGeometry {
ah := C.uint(0)
if allowHoles {
ah = 1
}
return C.GEOSConcaveHull_r(ctx, g, C.double(ratio), ah)
return C.GEOSConcaveHull_r(ctx, g, C.double(ratio), goBoolToCUint(allowHoles))
})
return result, wrap(err, "executing GEOSConcaveHull_r")
}
Expand Down
14 changes: 14 additions & 0 deletions internal/rawgeos/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,17 @@ func (h *handle) decode(gh *C.GEOSGeometry) (geom.Geometry, error) {
g, err := geom.UnmarshalWKB(wkb, geom.NoValidate{})
return g, wrap(err, "failed to unmarshal GEOS WKB result")
}

func goBoolToCInt(b bool) C.int {
if b {
return 1
}
return 0
}

func goBoolToCUint(b bool) C.uint {
if b {
return 1
}
return 0
}

0 comments on commit f5eca62

Please sign in to comment.