improve area=yes/no handling
parent
81e363ef1a
commit
b6b3d262d4
|
@ -316,3 +316,27 @@ To load all tags except ``created_by``, ``source``, and ``tiger:county``, ``tige
|
|||
load_all: true,
|
||||
exclude: [created_by, source, "tiger:*"]
|
||||
|
||||
|
||||
|
||||
.. _Areas:
|
||||
|
||||
Areas
|
||||
-----
|
||||
|
||||
A closed way is way where the first and last nodes are identical. These closed ways are used to represent elements like building, forest or park polygons, but they can also represent linear (non-polygon) features, like a roundabout or a race track.
|
||||
|
||||
OpenStreetMap uses the `area <http://wiki.openstreetmap.org/wiki/Key:area>`_ tag to specify if a closed way is an area (polygon) or a linear feature (linestring). For example ``highway=pedestrian, area=yes`` is a polygon feature.
|
||||
|
||||
By default, Imposm inserts all closed ways into polygon tables as long as ``area`` is not ``no`` and linestring tables will contain all closed ways as long as the ``area`` is not ``yes``.
|
||||
However, the ``area`` tag is missing from most OSM elements, as buildings, landuse, etc. should be interpreted as ``area=yes`` by default and highways for example are ``area=no`` by default.
|
||||
|
||||
You can configure these default interpretations with the ``areas`` option.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
areas:
|
||||
area_tags: [buildings, landuse, leisure, natural, aeroway]
|
||||
linear_tags: [highway, barrier]
|
||||
|
||||
|
||||
With this ``areas`` configuration, ``highway`` elements are only inserted into polygon tables if there is an ``area=yes`` tag. ``aeroway`` elements are only inserted into linestring tables if there is an ``area=no`` tag.
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
areas:
|
||||
area_tags: [buildings, landuse, leisure, natural, aeroway]
|
||||
linear_tags: [highway, barrier]
|
||||
generalized_tables:
|
||||
landusages_gen0:
|
||||
source: landusages_gen1
|
||||
|
|
|
@ -49,11 +49,17 @@ type Mapping struct {
|
|||
Tables Tables `yaml:"tables"`
|
||||
GeneralizedTables GeneralizedTables `yaml:"generalized_tables"`
|
||||
Tags Tags `yaml:"tags"`
|
||||
Areas Areas `yaml:"areas"`
|
||||
// SingleIdSpace mangles the overlapping node/way/relation IDs
|
||||
// to be unique (nodes positive, ways negative, relations negative -1e17)
|
||||
SingleIdSpace bool `yaml:"use_single_id_space"`
|
||||
}
|
||||
|
||||
type Areas struct {
|
||||
AreaTags []Key `yaml:"area_tags"`
|
||||
LinearTags []Key `yaml:"linear_tags"`
|
||||
}
|
||||
|
||||
type Tags struct {
|
||||
LoadAll bool `yaml:"load_all"`
|
||||
Exclude []Key `yaml:"exclude"`
|
||||
|
@ -106,7 +112,7 @@ type TypeMappings struct {
|
|||
Polygons KeyValues `yaml:"polygons"`
|
||||
}
|
||||
|
||||
type ElementFilter func(tags *element.Tags) bool
|
||||
type ElementFilter func(tags element.Tags, key Key, closed bool) bool
|
||||
|
||||
type TagTables map[Key]map[Value][]OrderedDestTable
|
||||
|
||||
|
@ -261,18 +267,67 @@ func (m *Mapping) extraTags(tableType TableType, tags map[Key]bool) {
|
|||
}
|
||||
}
|
||||
}
|
||||
// always include area tag for closed-way handling
|
||||
tags["area"] = true
|
||||
}
|
||||
|
||||
func (m *Mapping) ElementFilters() map[string][]ElementFilter {
|
||||
result := make(map[string][]ElementFilter)
|
||||
|
||||
var areaTags map[Key]struct{}
|
||||
var linearTags map[Key]struct{}
|
||||
if m.Areas.AreaTags != nil {
|
||||
areaTags = make(map[Key]struct{})
|
||||
for _, tag := range m.Areas.AreaTags {
|
||||
areaTags[tag] = struct{}{}
|
||||
}
|
||||
}
|
||||
if m.Areas.LinearTags != nil {
|
||||
linearTags = make(map[Key]struct{})
|
||||
for _, tag := range m.Areas.LinearTags {
|
||||
linearTags[tag] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for name, t := range m.Tables {
|
||||
if t.Type == LineStringTable && areaTags != nil {
|
||||
f := func(tags element.Tags, key Key, closed bool) bool {
|
||||
if closed {
|
||||
if tags["area"] == "yes" {
|
||||
return false
|
||||
}
|
||||
if tags["area"] != "no" {
|
||||
if _, ok := areaTags[key]; ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
result[name] = append(result[name], f)
|
||||
}
|
||||
if t.Type == PolygonTable && linearTags != nil {
|
||||
f := func(tags element.Tags, key Key, closed bool) bool {
|
||||
if closed && tags["area"] == "no" {
|
||||
return false
|
||||
}
|
||||
if tags["area"] != "yes" {
|
||||
if _, ok := linearTags[key]; ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
result[name] = append(result[name], f)
|
||||
}
|
||||
|
||||
if t.Filters == nil {
|
||||
continue
|
||||
}
|
||||
if t.Filters.ExcludeTags != nil {
|
||||
for _, filterKeyVal := range *t.Filters.ExcludeTags {
|
||||
f := func(tags *element.Tags) bool {
|
||||
if v, ok := (*tags)[filterKeyVal[0]]; ok {
|
||||
f := func(tags element.Tags, key Key, closed bool) bool {
|
||||
if v, ok := tags[filterKeyVal[0]]; ok {
|
||||
if filterKeyVal[1] == "__any__" || v == filterKeyVal[1] {
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -278,6 +278,11 @@ func TestPointMatcher(t *testing.T) {
|
|||
|
||||
func TestLineStringMatcher(t *testing.T) {
|
||||
elem := element.Way{}
|
||||
// fake closed way for area matching
|
||||
elem.Refs = []int64{1, 2, 3, 4, 1}
|
||||
if !elem.IsClosed() {
|
||||
t.Fatal("way not closed")
|
||||
}
|
||||
ls := mapping.LineStringMatcher()
|
||||
|
||||
elem.Tags = element.Tags{"unknown": "baz"}
|
||||
|
@ -293,6 +298,18 @@ func TestLineStringMatcher(t *testing.T) {
|
|||
elem.Tags = element.Tags{"highway": "pedestrian", "area": "yes"}
|
||||
matchesEqual(t, []Match{}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"barrier": "hedge"}
|
||||
matchesEqual(t, []Match{{"barrier", "hedge", DestTable{Name: "barrierways"}, nil}}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"barrier": "hedge", "area": "yes"}
|
||||
matchesEqual(t, []Match{}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"aeroway": "runway", "area": "no"}
|
||||
matchesEqual(t, []Match{{"aeroway", "runway", DestTable{Name: "aeroways"}, nil}}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"aeroway": "runway"}
|
||||
matchesEqual(t, []Match{}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"highway": "secondary", "railway": "tram"}
|
||||
matchesEqual(t,
|
||||
[]Match{
|
||||
|
@ -320,6 +337,12 @@ func TestPolygonMatcher(t *testing.T) {
|
|||
elem.Tags = element.Tags{"building": "residential"}
|
||||
matchesEqual(t, []Match{{"building", "residential", DestTable{Name: "buildings"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"barrier": "hedge"}
|
||||
matchesEqual(t, []Match{}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"barrier": "hedge", "area": "yes"}
|
||||
matchesEqual(t, []Match{{"barrier", "hedge", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"building": "shop"}
|
||||
matchesEqual(t, []Match{
|
||||
{"building", "shop", DestTable{Name: "buildings"}, nil},
|
||||
|
@ -339,7 +362,10 @@ func TestPolygonMatcher(t *testing.T) {
|
|||
{"landuse", "farm", DestTable{Name: "landusages"}, nil}},
|
||||
polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"highway": "footway"}
|
||||
elem.Tags = element.Tags{"highway": "footway"} // linear by default
|
||||
matchesEqual(t, []Match{}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"highway": "footway", "area": "yes"}
|
||||
matchesEqual(t, []Match{{"highway", "footway", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"boundary": "administrative", "admin_level": "8"}
|
||||
|
|
|
@ -105,7 +105,7 @@ func (m *Match) MemberRow(rel *element.Relation, member *element.Member, geom *g
|
|||
}
|
||||
|
||||
func (tm *tagMatcher) MatchNode(node *element.Node) []Match {
|
||||
return tm.match(&node.Tags)
|
||||
return tm.match(node.Tags, false)
|
||||
}
|
||||
|
||||
func (tm *tagMatcher) MatchWay(way *element.Way) []Match {
|
||||
|
@ -114,21 +114,22 @@ func (tm *tagMatcher) MatchWay(way *element.Way) []Match {
|
|||
if way.Tags["area"] == "no" {
|
||||
return nil
|
||||
}
|
||||
return tm.match(&way.Tags)
|
||||
return tm.match(way.Tags, true)
|
||||
}
|
||||
} else { // match way as linestring
|
||||
if way.IsClosed() {
|
||||
if way.Tags["area"] == "yes" {
|
||||
return nil
|
||||
}
|
||||
return tm.match(way.Tags, true)
|
||||
}
|
||||
return tm.match(&way.Tags)
|
||||
return tm.match(way.Tags, false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tm *tagMatcher) MatchRelation(rel *element.Relation) []Match {
|
||||
return tm.match(&rel.Tags)
|
||||
return tm.match(rel.Tags, true)
|
||||
}
|
||||
|
||||
type orderedMatch struct {
|
||||
|
@ -136,13 +137,18 @@ type orderedMatch struct {
|
|||
order int
|
||||
}
|
||||
|
||||
func (tm *tagMatcher) match(tags *element.Tags) []Match {
|
||||
func (tm *tagMatcher) match(tags element.Tags, closed bool) []Match {
|
||||
tables := make(map[DestTable]orderedMatch)
|
||||
|
||||
addTables := func(k, v string, tbls []OrderedDestTable) {
|
||||
for _, t := range tbls {
|
||||
this := orderedMatch{
|
||||
Match: Match{k, v, t.DestTable, tm.tables[t.Name]},
|
||||
Match: Match{
|
||||
Key: k,
|
||||
Value: v,
|
||||
Table: t.DestTable,
|
||||
tableFields: tm.tables[t.Name],
|
||||
},
|
||||
order: t.order,
|
||||
}
|
||||
if other, ok := tables[t.DestTable]; ok {
|
||||
|
@ -158,7 +164,7 @@ func (tm *tagMatcher) match(tags *element.Tags) []Match {
|
|||
addTables("__any__", "__any__", values["__any__"])
|
||||
}
|
||||
|
||||
for k, v := range *tags {
|
||||
for k, v := range tags {
|
||||
values, ok := tm.mappings[Key(k)]
|
||||
if ok {
|
||||
if tbls, ok := values["__any__"]; ok {
|
||||
|
@ -175,7 +181,7 @@ func (tm *tagMatcher) match(tags *element.Tags) []Match {
|
|||
filteredOut := false
|
||||
if ok {
|
||||
for _, filter := range filters {
|
||||
if !filter(tags) {
|
||||
if !filter(tags, Key(match.Key), closed) {
|
||||
filteredOut = true
|
||||
break
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
areas:
|
||||
area_tags: [buildings, landuse, leisure, natural, aeroway]
|
||||
linear_tags: [highway, barrier]
|
||||
generalized_tables:
|
||||
landusages_gen0:
|
||||
source: landusages_gen1
|
||||
|
|
|
@ -1155,4 +1155,49 @@
|
|||
<tag k="landuse" v="park"/>
|
||||
</way>
|
||||
|
||||
|
||||
|
||||
<!-- test area mapping -->
|
||||
<node id="301101" version="1" timestamp="2011-11-11T00:11:11Z" lat="-32" lon="10"/>
|
||||
<node id="301102" version="1" timestamp="2011-11-11T00:11:11Z" lat="-32" lon="11"/>
|
||||
<node id="301103" version="1" timestamp="2011-11-11T00:11:11Z" lat="-34" lon="11"/>
|
||||
<node id="301104" version="1" timestamp="2011-11-11T00:11:11Z" lat="-34" lon="10"/>
|
||||
<way id="301151" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<nd ref="301101"/>
|
||||
<nd ref="301102"/>
|
||||
<nd ref="301103"/>
|
||||
<nd ref="301104"/>
|
||||
<nd ref="301101"/>
|
||||
<tag k="highway" v="pedestrian"/>
|
||||
<tag k="name" v="name"/>
|
||||
</way>
|
||||
<way id="301152" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<nd ref="301101"/>
|
||||
<nd ref="301102"/>
|
||||
<nd ref="301103"/>
|
||||
<nd ref="301104"/>
|
||||
<nd ref="301101"/>
|
||||
<tag k="highway" v="pedestrian"/>
|
||||
<tag k="name" v="name"/>
|
||||
<tag k="area" v="yes"/>
|
||||
</way>
|
||||
|
||||
<way id="301153" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<nd ref="301101"/>
|
||||
<nd ref="301102"/>
|
||||
<nd ref="301103"/>
|
||||
<nd ref="301104"/>
|
||||
<nd ref="301101"/>
|
||||
<tag k="leisure" v="track"/>
|
||||
</way>
|
||||
<way id="301154" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<nd ref="301101"/>
|
||||
<nd ref="301102"/>
|
||||
<nd ref="301103"/>
|
||||
<nd ref="301104"/>
|
||||
<nd ref="301101"/>
|
||||
<tag k="leisure" v="track"/>
|
||||
<tag k="area" v="no"/>
|
||||
</way>
|
||||
|
||||
</osm>
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
{
|
||||
"areas": {
|
||||
"area_tags": ["leisure"],
|
||||
"linear_tags": ["highway"],
|
||||
},
|
||||
"generalized_tables": {
|
||||
"waterareas_gen1": {
|
||||
"source": "waterareas",
|
||||
|
@ -125,7 +129,8 @@
|
|||
"pitch",
|
||||
"stadium",
|
||||
"common",
|
||||
"nature_reserve"
|
||||
"nature_reserve",
|
||||
"track"
|
||||
],
|
||||
"tourism": [
|
||||
"zoo"
|
||||
|
@ -202,6 +207,7 @@
|
|||
}
|
||||
],
|
||||
"type": "polygon",
|
||||
"filters": {"areas": {}},
|
||||
"mapping": {
|
||||
"building": [
|
||||
"__any__"
|
||||
|
@ -711,9 +717,7 @@
|
|||
],
|
||||
"type": "linestring",
|
||||
"filters": {
|
||||
"exclude_tags": [
|
||||
["area", "yes"]
|
||||
]
|
||||
"areas": {},
|
||||
},
|
||||
"mappings": {
|
||||
"railway": {
|
||||
|
@ -733,10 +737,6 @@
|
|||
},
|
||||
"roads": {
|
||||
"mapping": {
|
||||
"man_made": [
|
||||
"pier",
|
||||
"groyne"
|
||||
],
|
||||
"highway": [
|
||||
"motorway",
|
||||
"motorway_link",
|
||||
|
@ -761,6 +761,13 @@
|
|||
"unclassified",
|
||||
"residential",
|
||||
"raceway"
|
||||
],
|
||||
"man_made": [
|
||||
"pier",
|
||||
"groyne"
|
||||
],
|
||||
"leisure": [
|
||||
"track"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -364,6 +364,28 @@ func TestComplete_EnumerateKey(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestComplete_AreaMapping(t *testing.T) {
|
||||
// Mapping type dependent area-defaults.
|
||||
|
||||
assertRecords(t, []checkElem{
|
||||
// highway=pedestrian
|
||||
{"osm_roads", 301151, "pedestrian", nil},
|
||||
{"osm_landusages", 301151, Missing, nil},
|
||||
|
||||
// // highway=pedestrian, area=yes
|
||||
{"osm_roads", 301152, Missing, nil},
|
||||
{"osm_landusages", 301152, "pedestrian", nil},
|
||||
|
||||
// // leisure=track
|
||||
{"osm_roads", 301153, Missing, nil},
|
||||
{"osm_landusages", 301153, "track", nil},
|
||||
|
||||
// // leisure=track, area=no
|
||||
{"osm_roads", 301154, "track", nil},
|
||||
{"osm_landusages", 301154, Missing, nil},
|
||||
})
|
||||
}
|
||||
|
||||
func TestComplete_Update(t *testing.T) {
|
||||
ts.updateOsm(t, "./build/complete_db.osc.gz")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue