diff --git a/geom/geom.go b/geom/geom.go index 13b4b05..9e9cb29 100644 --- a/geom/geom.go +++ b/geom/geom.go @@ -4,6 +4,7 @@ import ( "errors" "imposm3/element" "imposm3/geom/geos" + "math" ) type GeomError struct { @@ -37,7 +38,43 @@ func Point(g *geos.Geos, node element.Node) (*geos.Geom, error) { return geom, nil } +func nodesEqual(a, b element.Node) bool { + if d := a.Long - b.Long; math.Abs(d) < 1e-9 { + if d := a.Lat - b.Lat; math.Abs(d) < 1e-9 { + return true + } + } + return false +} + +func unduplicateNodes(nodes []element.Node) []element.Node { + if len(nodes) < 2 { + return nodes + } + foundDup := false + for i := 1; i < len(nodes); i++ { + if nodesEqual(nodes[i-1], nodes[i]) { + foundDup = true + break + } + } + if !foundDup { + return nodes + } + + result := make([]element.Node, 0, len(nodes)) + result = append(result, nodes[0]) + for i := 1; i < len(nodes); i++ { + if nodesEqual(nodes[i-1], nodes[i]) { + continue + } + result = append(result, nodes[i]) + } + return result +} + func LineString(g *geos.Geos, nodes []element.Node) (*geos.Geom, error) { + nodes = unduplicateNodes(nodes) if len(nodes) < 2 { return nil, ErrorOneNodeWay } @@ -60,6 +97,11 @@ func LineString(g *geos.Geos, nodes []element.Node) (*geos.Geom, error) { } func Polygon(g *geos.Geos, nodes []element.Node) (*geos.Geom, error) { + nodes = unduplicateNodes(nodes) + if len(nodes) < 4 { + return nil, ErrorNoRing + } + coordSeq, err := g.CreateCoordSeq(uint32(len(nodes)), 2) if err != nil { return nil, err diff --git a/geom/geom_test.go b/geom/geom_test.go index fc8b1a1..55e0b04 100644 --- a/geom/geom_test.go +++ b/geom/geom_test.go @@ -90,3 +90,57 @@ func BenchmarkLineString(b *testing.B) { LineString(g, nodes) } } + +func TestUnduplicateNodes(t *testing.T) { + var nodes []element.Node + + nodes = []element.Node{ + element.Node{Lat: 0, Long: 0}, + } + if res := unduplicateNodes(nodes); len(res) != 1 { + t.Fatal(res) + } + nodes = []element.Node{ + element.Node{Lat: 47.0, Long: 80.0}, + element.Node{Lat: 47.0, Long: 80.0}, + } + if res := unduplicateNodes(nodes); len(res) != 1 { + t.Fatal(res) + } + + nodes = []element.Node{ + element.Node{Lat: 0, Long: -10}, + element.Node{Lat: 0, Long: -10}, + element.Node{Lat: 0, Long: -10}, + element.Node{Lat: 10, Long: 10}, + element.Node{Lat: 10, Long: 10}, + element.Node{Lat: 10, Long: 10}, + } + if res := unduplicateNodes(nodes); len(res) != 2 { + t.Fatal(res) + } + + nodes = []element.Node{ + element.Node{Lat: 10, Long: 10}, + element.Node{Lat: 0, Long: 10}, + element.Node{Lat: 10, Long: 10}, + element.Node{Lat: 10, Long: 10}, + element.Node{Lat: 0, Long: 10}, + element.Node{Lat: 0, Long: 10}, + } + if res := unduplicateNodes(nodes); len(res) != 4 { + t.Fatal(res) + } + + nodes = []element.Node{ + element.Node{Lat: 0, Long: 0}, + element.Node{Lat: 0, Long: -10}, + element.Node{Lat: 10, Long: -10}, + element.Node{Lat: 10, Long: 0}, + element.Node{Lat: 0, Long: 0}, + } + if res := unduplicateNodes(nodes); len(res) != 5 { + t.Fatal(res) + } + +} diff --git a/test/imposm_system_test.py b/test/imposm_system_test.py index 6cece26..b9f0bb9 100644 --- a/test/imposm_system_test.py +++ b/test/imposm_system_test.py @@ -230,6 +230,23 @@ def test_relation_way_inserted(): assert park['name'] == 'rel 8001' assert query_row(db_conf, 'osm_roads', 8009)["type"] == 'residential' +def test_single_node_ways_not_inserted(): + """Ways with single/duplicate nodes are not inserted.""" + assert not query_row(db_conf, 'osm_roads', 30001) + assert not query_row(db_conf, 'osm_roads', 30002) + assert not query_row(db_conf, 'osm_roads', 30003) + +def test_polygon_with_duplicate_nodes_is_valid(): + """Polygon with duplicate nodes is valid.""" + geom = query_row(db_conf, 'osm_landusages', 30005)['geometry'] + assert geom.is_valid + assert len(geom.exterior.coords) == 4 + +def test_incomplete_polygons(): + """Non-closed/incomplete polygons are not inserted.""" + assert not query_row(db_conf, 'osm_landusages', 30004) + assert not query_row(db_conf, 'osm_landusages', 30006) + ####################################################################### def test_update(): diff --git a/test/test.osm b/test/test.osm index 82440a7..3854106 100644 --- a/test/test.osm +++ b/test/test.osm @@ -302,6 +302,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +