Skip to content

Commit

Permalink
WIP handle overlapping inner rings
Browse files Browse the repository at this point in the history
PDOK-16135
  • Loading branch information
roelarents committed Feb 14, 2024
1 parent 440cd14 commit 5c54f85
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 7 deletions.
21 changes: 15 additions & 6 deletions snap/snap.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func tileMatrixIDsByLevels(tms tms20.TileMatrixSet, tmIDs []tms20.TMID) map[Leve
func addPointsAndSnap(ix *PointIndex, polygon geom.Polygon, levels []Level) map[Level][]geom.Polygon {
levelMap := asKeys(levels)
newPolygons := make(map[Level][][][][2]float64, len(levels))
newInners := make(map[Level][][][2]float64, len(levels))
newPointsAndLines := make(map[Level][][][2]float64, len(levels))

// Could use polygon.AsSegments(), but it skips rings with <3 segments and starts with the last segment.
Expand Down Expand Up @@ -129,17 +130,23 @@ func addPointsAndSnap(ix *PointIndex, polygon geom.Polygon, levels []Level) map[
delete(levelMap, level) // outer ring has become too small
continue
}
for _, outerRing := range outerRings { // (there are only outer rings if isOuter)
for _, outerRing := range outerRings {
newPolygons[level] = append(newPolygons[level], [][][2]float64{outerRing})
}
if len(innerRings) > 0 {
newPolygons[level] = matchInnersToPolygon(newPolygons[level], innerRings, len(polygon) > 1)
}
newInners[level] = append(newInners[level], innerRings...)
if keepPointsAndLines {
newPointsAndLines[level] = append(newPointsAndLines[level], pointsAndLines...)
}
}
}

for l := range levelMap {
newPolygonsForLevel := matchInnersToPolygons(newPolygons[l], newInners[l], len(polygon) > 1)
if len(newPolygonsForLevel) > 1 {
newPolygons[l] = newPolygonsForLevel
}
}

// points and lines at the end, as outer rings
for level, pointsAndLines := range newPointsAndLines {
for _, pointOrLine := range pointsAndLines {
Expand All @@ -149,11 +156,13 @@ func addPointsAndSnap(ix *PointIndex, polygon geom.Polygon, levels []Level) map[
return floatPolygonsToGeomPolygonsForAllLevels(newPolygons)
}

func matchInnersToPolygon(polygons [][][][2]float64, innerRings [][][2]float64, hasInners bool) [][][][2]float64 {
func matchInnersToPolygons(polygons [][][][2]float64, innerRings [][][2]float64, hasInners bool) [][][][2]float64 {
lenPolygons := len(polygons)
if len(innerRings) == 0 {
return polygons
}
_, polygons = dedupePolygonsByOuters(polygons)

var polyISortedByOuterAreaDesc []int
var innersTurnedOuters [][][2]float64
matchInners:
Expand Down Expand Up @@ -211,7 +220,7 @@ func sortPolyIdxsByOuterAreaDesc(polygons [][][][2]float64) []int {
return areas.Keys()
}

// helper for matchInnersToPolygon to delete duplicate polygons
// helper for matchInnersToPolygons to delete duplicate polygons
// comparing them only by their outers and asserting that a deleted polygon didn't have inner rings appended yet
// yes it's implemented as ~O(n^2),
// but it's expected that the (outer) rings are usually different even from the first point,
Expand Down
8 changes: 7 additions & 1 deletion snap/snap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,10 +613,11 @@ func TestSnap_snapPolygon(t *testing.T) {
tmIDs: []tms20.TMID{
1, // 32 * 8.0
},
polygon: geom.Polygon{ // TODO think of something with duplicate outer rings
polygon: geom.Polygon{
{{4.0, 124.0}, {4.0, 4.0}, {60.0, 4.0}, {60.0, 124.0}}, // big outer
{{12.0, 52.0}, {12.0, 12.0}, {52.0, 12.0}, {52.0, 52.0}, {30.0, 52.0}, {30.0, 44.0}, {44.0, 44.0}, {44.0, 20.0}, {20.0, 20.0}, {20.0, 44.0}, {27.0, 44.0}, {27.0, 52.0}}, // big letter C that turns into nested rings when snapped
{{12.0, 116.0}, {52.0, 116.0}, {52.0, 76.0}, {30.0, 76.0}, {30.0, 84.0}, {44.0, 84.0}, {44.0, 108.0}, {20.0, 108.0}, {20.0, 84.0}, {27.0, 84.0}, {27.0, 76.0}, {12.0, 76.0}}, // above mirrored vertically
{{30.0, 53.0}, {30.0, 54.0}, {54.0, 54.0}, {54.0, 10.0}, {10.0, 10.0}, {10.0, 54.0}, {27.0, 54.0}, {27.0, 53.0}, {11.0, 53.0}, {11.0, 11.0}, {53.0, 11.0}, {53.0, 53.0}}, // another C around the original C which snaps to a duplicate outer
{{28.0, 28.0}, {36.0, 28.0}, {36.0, 36.0}, {29.0, 36.0}, {29.0, 92.0}, {36.0, 92.0}, {36.0, 100.0}, {28.0, 100.0}}, // dumbbell inside the two C's that also turns into a nested ring when snapped (and some lines)
},
want: map[tms20.TMID][]geom.Polygon{
Expand All @@ -626,6 +627,11 @@ func TestSnap_snapPolygon(t *testing.T) {
{{4.0, 124.0}, {4.0, 4.0}, {60.0, 4.0}, {60.0, 124.0}}, // ccw
{{28.0, 52.0}, {52.0, 52.0}, {52.0, 12.0}, {12.0, 12.0}, {12.0, 52.0}}, // cw
{{12.0, 116.0}, {52.0, 116.0}, {52.0, 76.0}, {28.0, 76.0}, {12.0, 76.0}}, // cw
}, {
{{28.0, 52.0}, {12.0, 52.0}, {12.0, 12.0}, {52.0, 12.0}, {52.0, 52.0}, {28.0, 52.0}}, // ccw
{{28.0, 52.0}, {52.0, 52.0}, {52.0, 12.0}, {12.0, 12.0}, {12.0, 52.0}, {28.0, 52.0}}, // cw
// TODO order of separate outer rings OK. does this overlap the deepest nested square?
// TODO deduplicate this, remove totally?
}, {
{{28.0, 44.0}, {20.0, 44.0}, {20.0, 20.0}, {44.0, 20.0}, {44.0, 44.0}}, // ccw
{{28.0, 36.0}, {36.0, 36.0}, {36.0, 28.0}, {28.0, 28.0}}, // cw
Expand Down

0 comments on commit 5c54f85

Please sign in to comment.