diff --git a/element/element.go b/element/element.go
index fcc6ce2..f3efa81 100644
--- a/element/element.go
+++ b/element/element.go
@@ -2,6 +2,7 @@ package element
import (
"fmt"
+ "math"
"sort"
"github.com/omniscale/imposm3/geom/geos"
@@ -40,6 +41,26 @@ func (w *Way) IsClosed() bool {
return len(w.Refs) >= 4 && w.Refs[0] == w.Refs[len(w.Refs)-1]
}
+func (w *Way) TryClose(maxGap float64) bool {
+ return TryCloseWay(w.Refs, w.Nodes, maxGap)
+}
+
+// TryCloseWay closes the way if both end nodes are nearly identical.
+// Returns true if it succeeds.
+func TryCloseWay(refs []int64, nodes []Node, maxGap float64) bool {
+ if len(refs) < 4 {
+ return false
+ }
+ start, end := nodes[0], nodes[len(nodes)-1]
+ dist := math.Hypot(start.Lat-end.Lat, start.Long-end.Long)
+ if dist < maxGap {
+ refs[len(refs)-1] = refs[0]
+ nodes[len(nodes)-1] = nodes[0]
+ return true
+ }
+ return false
+}
+
type MemberType int
const (
diff --git a/geom/ring.go b/geom/ring.go
index 0889aa6..2de5048 100644
--- a/geom/ring.go
+++ b/geom/ring.go
@@ -1,8 +1,6 @@
package geom
import (
- "math"
-
"github.com/omniscale/imposm3/element"
"github.com/omniscale/imposm3/geom/geos"
)
@@ -22,20 +20,8 @@ func (r *Ring) IsClosed() bool {
return len(r.refs) >= 4 && r.refs[0] == r.refs[len(r.refs)-1]
}
-// TryClose closes the ring if both end nodes are nearly identical.
-// Returns true if it succeeds.
func (r *Ring) TryClose(maxRingGap float64) bool {
- if len(r.refs) < 4 {
- return false
- }
- start, end := r.nodes[0], r.nodes[len(r.nodes)-1]
- dist := math.Hypot(start.Lat-end.Lat, start.Long-end.Long)
- if dist < maxRingGap {
- r.refs[len(r.refs)-1] = r.refs[0]
- r.nodes[len(r.nodes)-1] = r.nodes[0]
- return true
- }
- return false
+ return element.TryCloseWay(r.refs, r.nodes, maxRingGap)
}
func (r *Ring) MarkInserted(tags element.Tags) {
diff --git a/test/complete_db.osm b/test/complete_db.osm
index b6cd142..4ebfd11 100644
--- a/test/complete_db.osm
+++ b/test/complete_db.osm
@@ -353,7 +353,7 @@
-
+
@@ -377,6 +377,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/test/complete_db_test.py b/test/complete_db_test.py
index 9db33c0..be60f9e 100644
--- a/test/complete_db_test.py
+++ b/test/complete_db_test.py
@@ -254,11 +254,14 @@ def test_generalized_linestring_is_valid():
assert road['geometry'].is_valid, road['geometry'].wkt
assert road['geometry'].length > 1000000
-def test_relation_with_gap():
- """Multipolygon with gap (overlapping but different endpoints) gets closed"""
+def test_ring_with_gap():
+ """Multipolygon and way with gap (overlapping but different endpoints) gets closed"""
park = t.query_row(t.db_conf, 'osm_landusages', -7301)
assert park['geometry'].is_valid, park
+ park = t.query_row(t.db_conf, 'osm_landusages', 7311)
+ assert park['geometry'].is_valid, park
+
def test_updated_nodes1():
"""Zig-Zag line is inserted."""
road = t.query_row(t.db_conf, 'osm_roads', 60000)
diff --git a/writer/relations.go b/writer/relations.go
index 9262b18..1c5b5fb 100644
--- a/writer/relations.go
+++ b/writer/relations.go
@@ -19,7 +19,7 @@ type RelationWriter struct {
singleIdSpace bool
rel chan *element.Relation
polygonMatcher mapping.RelWayMatcher
- maxRingGap float64
+ maxGap float64
}
func NewRelationWriter(
@@ -32,9 +32,9 @@ func NewRelationWriter(
matcher mapping.RelWayMatcher,
srid int,
) *OsmElemWriter {
- maxRingGap := 1e-1 // 0.1m
+ maxGap := 1e-1 // 0.1m
if srid == 4326 {
- maxRingGap = 1e-6 // ~0.1m
+ maxGap = 1e-6 // ~0.1m
}
rw := RelationWriter{
OsmElemWriter: OsmElemWriter{
@@ -48,7 +48,7 @@ func NewRelationWriter(
singleIdSpace: singleIdSpace,
polygonMatcher: matcher,
rel: rel,
- maxRingGap: maxRingGap,
+ maxGap: maxGap,
}
rw.OsmElemWriter.writer = &rw
return &rw.OsmElemWriter
@@ -96,7 +96,7 @@ NextRel:
// prepare relation first (build rings and compute actual
// relation tags)
- prepedRel, err := geom.PrepareRelation(r, rw.srid, rw.maxRingGap)
+ prepedRel, err := geom.PrepareRelation(r, rw.srid, rw.maxGap)
if err != nil {
if errl, ok := err.(ErrorLevel); !ok || errl.Level() > 0 {
log.Warn(err)
diff --git a/writer/ways.go b/writer/ways.go
index 099c577..5644d68 100644
--- a/writer/ways.go
+++ b/writer/ways.go
@@ -19,6 +19,7 @@ type WayWriter struct {
ways chan *element.Way
lineMatcher mapping.WayMatcher
polygonMatcher mapping.WayMatcher
+ maxGap float64
}
func NewWayWriter(
@@ -32,6 +33,10 @@ func NewWayWriter(
lineMatcher mapping.WayMatcher,
srid int,
) *OsmElemWriter {
+ maxGap := 1e-1 // 0.1m
+ if srid == 4326 {
+ maxGap = 1e-6 // ~0.1m
+ }
ww := WayWriter{
OsmElemWriter: OsmElemWriter{
osmCache: osmCache,
@@ -45,6 +50,7 @@ func NewWayWriter(
lineMatcher: lineMatcher,
polygonMatcher: polygonMatcher,
ways: ways,
+ maxGap: maxGap,
}
ww.OsmElemWriter.writer = &ww
return &ww.OsmElemWriter
@@ -91,7 +97,7 @@ func (ww *WayWriter) loop() {
}
inserted = true
}
- if w.IsClosed() && !insertedAsRelation {
+ if !insertedAsRelation && (w.IsClosed() || w.TryClose(ww.maxGap)) {
// only add polygons that were not inserted as a MultiPolygon relation
if matches := ww.polygonMatcher.MatchWay(w); len(matches) > 0 {
err := ww.buildAndInsert(geos, w, matches, true)