add relation_type
parent
b4cf7b91f3
commit
7157b5252a
|
@ -20,14 +20,15 @@ type Field struct {
|
|||
}
|
||||
|
||||
type Table struct {
|
||||
Name string
|
||||
Type TableType `yaml:"type"`
|
||||
Mapping KeyValues `yaml:"mapping"`
|
||||
Mappings map[string]SubMapping `yaml:"mappings"`
|
||||
TypeMappings TypeMappings `yaml:"type_mappings"`
|
||||
Fields []*Field `yaml:"columns"` // TODO rename Fields internaly to Columns
|
||||
OldFields []*Field `yaml:"fields"`
|
||||
Filters *Filters `yaml:"filters"`
|
||||
Name string
|
||||
Type TableType `yaml:"type"`
|
||||
Mapping KeyValues `yaml:"mapping"`
|
||||
Mappings map[string]SubMapping `yaml:"mappings"`
|
||||
TypeMappings TypeMappings `yaml:"type_mappings"`
|
||||
Fields []*Field `yaml:"columns"` // TODO rename Fields internaly to Columns
|
||||
OldFields []*Field `yaml:"fields"`
|
||||
Filters *Filters `yaml:"filters"`
|
||||
RelationTypes []string `yaml:"relation_types"`
|
||||
}
|
||||
|
||||
type GeneralizedTable struct {
|
||||
|
@ -179,19 +180,6 @@ func NewMapping(filename string) (*Mapping, error) {
|
|||
return &mapping, nil
|
||||
}
|
||||
|
||||
func (t *Table) ExtraTags() map[Key]bool {
|
||||
tags := make(map[Key]bool)
|
||||
for _, field := range t.Fields {
|
||||
if field.Key != "" {
|
||||
tags[field.Key] = true
|
||||
}
|
||||
for _, k := range field.Keys {
|
||||
tags[k] = true
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func (m *Mapping) prepare() error {
|
||||
for name, t := range m.Tables {
|
||||
t.Name = name
|
||||
|
@ -247,7 +235,7 @@ func (m *Mapping) mappings(tableType TableType, mappings TagTables) {
|
|||
func (m *Mapping) tables(tableType TableType) map[string]*TableFields {
|
||||
result := make(map[string]*TableFields)
|
||||
for name, t := range m.Tables {
|
||||
if t.Type == tableType || t.Type == "geometry" {
|
||||
if t.Type == tableType || t.Type == GeometryTable {
|
||||
result[name] = t.TableFields()
|
||||
}
|
||||
}
|
||||
|
@ -256,17 +244,30 @@ func (m *Mapping) tables(tableType TableType) map[string]*TableFields {
|
|||
|
||||
func (m *Mapping) extraTags(tableType TableType, tags map[Key]bool) {
|
||||
for _, t := range m.Tables {
|
||||
if t.Type != tableType && t.Type != "geometry" {
|
||||
if t.Type != tableType && t.Type != GeometryTable {
|
||||
continue
|
||||
}
|
||||
for key, _ := range t.ExtraTags() {
|
||||
tags[key] = true
|
||||
|
||||
for _, field := range t.Fields {
|
||||
if field.Key != "" {
|
||||
tags[field.Key] = true
|
||||
}
|
||||
for _, k := range field.Keys {
|
||||
tags[k] = true
|
||||
}
|
||||
}
|
||||
|
||||
if t.Filters != nil && t.Filters.ExcludeTags != nil {
|
||||
for _, keyVal := range *t.Filters.ExcludeTags {
|
||||
tags[Key(keyVal[0])] = true
|
||||
}
|
||||
}
|
||||
|
||||
if tableType == PolygonTable || tableType == RelationTable || tableType == RelationMemberTable {
|
||||
if t.RelationTypes != nil {
|
||||
tags["type"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, k := range m.Tags.Include {
|
||||
tags[k] = true
|
||||
|
@ -331,6 +332,37 @@ func (m *Mapping) addTypedFilters(tableType TableType, filters tableFilters) {
|
|||
}
|
||||
}
|
||||
|
||||
func (m *Mapping) addRelationFilters(tableType TableType, filters tableFilters) {
|
||||
for name, t := range m.Tables {
|
||||
if t.RelationTypes != nil {
|
||||
f := func(tags element.Tags, key Key, closed bool) bool {
|
||||
if v, ok := tags["type"]; ok {
|
||||
for _, rtype := range t.RelationTypes {
|
||||
if v == rtype {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
filters[name] = append(filters[name], f)
|
||||
} else {
|
||||
if t.Type == PolygonTable {
|
||||
// standard mulipolygon handling (boundary and land_area are for backwards compatibility)
|
||||
f := func(tags element.Tags, key Key, closed bool) bool {
|
||||
if v, ok := tags["type"]; ok {
|
||||
if v == "multipolygon" || v == "boundary" || v == "land_area" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
filters[name] = append(filters[name], f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mapping) addFilters(filters tableFilters) {
|
||||
for name, t := range m.Tables {
|
||||
if t.Filters == nil {
|
||||
|
|
|
@ -12,9 +12,10 @@ func (m *Mapping) NodeTagFilter() TagFilterer {
|
|||
return newExcludeFilter(m.Tags.Exclude)
|
||||
}
|
||||
mappings := make(map[Key]map[Value][]OrderedDestTable)
|
||||
m.mappings("point", mappings)
|
||||
m.mappings(PointTable, mappings)
|
||||
tags := make(map[Key]bool)
|
||||
m.extraTags("point", tags)
|
||||
m.extraTags(PointTable, tags)
|
||||
m.extraTags(RelationMemberTable, tags)
|
||||
return &TagFilter{mappings, tags}
|
||||
}
|
||||
|
||||
|
@ -23,11 +24,12 @@ func (m *Mapping) WayTagFilter() TagFilterer {
|
|||
return newExcludeFilter(m.Tags.Exclude)
|
||||
}
|
||||
mappings := make(map[Key]map[Value][]OrderedDestTable)
|
||||
m.mappings("linestring", mappings)
|
||||
m.mappings("polygon", mappings)
|
||||
m.mappings(LineStringTable, mappings)
|
||||
m.mappings(PolygonTable, mappings)
|
||||
tags := make(map[Key]bool)
|
||||
m.extraTags("linestring", tags)
|
||||
m.extraTags("polygon", tags)
|
||||
m.extraTags(LineStringTable, tags)
|
||||
m.extraTags(PolygonTable, tags)
|
||||
m.extraTags(RelationMemberTable, tags)
|
||||
return &TagFilter{mappings, tags}
|
||||
}
|
||||
|
||||
|
@ -42,11 +44,15 @@ func (m *Mapping) RelationTagFilter() TagFilterer {
|
|||
"boundary": []OrderedDestTable{},
|
||||
"land_area": []OrderedDestTable{},
|
||||
}
|
||||
m.mappings("linestring", mappings)
|
||||
m.mappings("polygon", mappings)
|
||||
m.mappings(LineStringTable, mappings)
|
||||
m.mappings(PolygonTable, mappings)
|
||||
m.mappings(RelationTable, mappings)
|
||||
m.mappings(RelationMemberTable, mappings)
|
||||
tags := make(map[Key]bool)
|
||||
m.extraTags("linestring", tags)
|
||||
m.extraTags("polygon", tags)
|
||||
m.extraTags(LineStringTable, tags)
|
||||
m.extraTags(PolygonTable, tags)
|
||||
m.extraTags(RelationTable, tags)
|
||||
m.extraTags(RelationMemberTable, tags)
|
||||
return &TagFilter{mappings, tags}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,22 +17,6 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func stringMapEquals(t *testing.T, expected, actual map[string]string) {
|
||||
if len(expected) != len(actual) {
|
||||
t.Errorf("different length in %v and %v\n", expected, actual)
|
||||
}
|
||||
|
||||
for k, v := range expected {
|
||||
if actualV, ok := actual[k]; ok {
|
||||
if actualV != v {
|
||||
t.Errorf("%s != %s in %v and %v\n", v, actualV, expected, actual)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("%s not in %v\n", k, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stringMapEqual(expected, actual map[string]string) bool {
|
||||
if len(expected) != len(actual) {
|
||||
return false
|
||||
|
@ -50,12 +34,12 @@ func stringMapEqual(expected, actual map[string]string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func matchesEqual(t *testing.T, expected []Match, actual []Match) {
|
||||
func matchesEqual(expected []Match, actual []Match) bool {
|
||||
expectedMatches := make(map[DestTable]Match)
|
||||
actualMatches := make(map[DestTable]Match)
|
||||
|
||||
if len(expected) != len(actual) {
|
||||
t.Fatalf("different length in %v and %v\n", expected, actual)
|
||||
return false
|
||||
}
|
||||
|
||||
for _, match := range expected {
|
||||
|
@ -70,12 +54,13 @@ func matchesEqual(t *testing.T, expected []Match, actual []Match) {
|
|||
if expectedMatch.Table != actualMatch.Table ||
|
||||
expectedMatch.Key != actualMatch.Key ||
|
||||
expectedMatch.Value != actualMatch.Value {
|
||||
t.Fatalf("match differ %v != %v", expectedMatch, actualMatch)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
t.Fatalf("%s not in %v", name, actualMatches)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestTagFilterNodes(t *testing.T) {
|
||||
|
@ -154,151 +139,209 @@ func TestTagFilterRelations(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPointMatcher(t *testing.T) {
|
||||
elem := element.Node{}
|
||||
points := mapping.PointMatcher()
|
||||
|
||||
elem.Tags = element.Tags{"unknown": "baz"}
|
||||
matchesEqual(t, []Match{}, points.MatchNode(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"place": "unknown"}
|
||||
matchesEqual(t, []Match{}, points.MatchNode(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"place": "city"}
|
||||
matchesEqual(t, []Match{{"place", "city", DestTable{Name: "places"}, nil}}, points.MatchNode(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"place": "city", "highway": "unknown"}
|
||||
matchesEqual(t, []Match{{"place", "city", DestTable{Name: "places"}, nil}}, points.MatchNode(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"place": "city", "highway": "bus_stop"}
|
||||
matchesEqual(t,
|
||||
[]Match{
|
||||
tests := []struct {
|
||||
tags element.Tags
|
||||
matches []Match
|
||||
}{
|
||||
{element.Tags{"unknown": "baz"}, []Match{}},
|
||||
{element.Tags{"place": "unknown"}, []Match{}},
|
||||
{element.Tags{"place": "city"}, []Match{{"place", "city", DestTable{Name: "places"}, nil}}},
|
||||
{element.Tags{"place": "city", "highway": "unknown"}, []Match{{"place", "city", DestTable{Name: "places"}, nil}}},
|
||||
{element.Tags{"place": "city", "highway": "bus_stop"}, []Match{
|
||||
{"place", "city", DestTable{Name: "places"}, nil},
|
||||
{"highway", "bus_stop", DestTable{Name: "transport_points"}, nil}},
|
||||
points.MatchNode(&elem))
|
||||
},
|
||||
}
|
||||
|
||||
elem := element.Node{}
|
||||
m := mapping.PointMatcher()
|
||||
for i, test := range tests {
|
||||
elem.Tags = test.tags
|
||||
actual := m.MatchNode(&elem)
|
||||
if !matchesEqual(actual, test.matches) {
|
||||
t.Errorf("unexpected result for case %d: %v != %v", i+1, actual, test.matches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLineStringMatcher(t *testing.T) {
|
||||
tests := []struct {
|
||||
tags element.Tags
|
||||
matches []Match
|
||||
}{
|
||||
{element.Tags{"unknown": "baz"}, []Match{}},
|
||||
{element.Tags{"highway": "unknown"}, []Match{}},
|
||||
{element.Tags{"highway": "pedestrian"},
|
||||
[]Match{{"highway", "pedestrian", DestTable{Name: "roads", SubMapping: "roads"}, nil}}},
|
||||
|
||||
// exclude_tags area=yes
|
||||
{element.Tags{"highway": "pedestrian", "area": "yes"}, []Match{}},
|
||||
|
||||
{element.Tags{"barrier": "hedge"},
|
||||
[]Match{{"barrier", "hedge", DestTable{Name: "barrierways"}, nil}}},
|
||||
{element.Tags{"barrier": "hedge", "area": "yes"}, []Match{}},
|
||||
|
||||
{element.Tags{"aeroway": "runway"}, []Match{}},
|
||||
{element.Tags{"aeroway": "runway", "area": "no"},
|
||||
[]Match{{"aeroway", "runway", DestTable{Name: "aeroways"}, nil}}},
|
||||
|
||||
{element.Tags{"highway": "secondary", "railway": "tram"},
|
||||
[]Match{
|
||||
{"highway", "secondary", DestTable{Name: "roads", SubMapping: "roads"}, nil},
|
||||
{"railway", "tram", DestTable{Name: "roads", SubMapping: "railway"}, nil}},
|
||||
},
|
||||
{element.Tags{"highway": "footway", "landuse": "park", "barrier": "hedge"},
|
||||
// landusages not a linestring table
|
||||
[]Match{
|
||||
{"highway", "footway", DestTable{Name: "roads", SubMapping: "roads"}, nil},
|
||||
{"barrier", "hedge", DestTable{Name: "barrierways"}, nil}},
|
||||
},
|
||||
}
|
||||
|
||||
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"}
|
||||
matchesEqual(t, []Match{}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"highway": "unknown"}
|
||||
matchesEqual(t, []Match{}, ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"highway": "pedestrian"}
|
||||
matchesEqual(t, []Match{{"highway", "pedestrian", DestTable{Name: "roads", SubMapping: "roads"}, nil}}, ls.MatchWay(&elem))
|
||||
|
||||
// exclude_tags area=yes
|
||||
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{
|
||||
{"highway", "secondary", DestTable{Name: "roads", SubMapping: "roads"}, nil},
|
||||
{"railway", "tram", DestTable{Name: "roads", SubMapping: "railway"}, nil}},
|
||||
ls.MatchWay(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"highway": "footway", "landuse": "park"}
|
||||
// landusages not a linestring table
|
||||
matchesEqual(t, []Match{{"highway", "footway", DestTable{Name: "roads", SubMapping: "roads"}, nil}}, ls.MatchWay(&elem))
|
||||
m := mapping.LineStringMatcher()
|
||||
for i, test := range tests {
|
||||
elem.Tags = test.tags
|
||||
actual := m.MatchWay(&elem)
|
||||
if !matchesEqual(actual, test.matches) {
|
||||
t.Errorf("unexpected result for case %d: %v != %v", i+1, actual, test.matches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPolygonMatcher(t *testing.T) {
|
||||
elem := element.Relation{}
|
||||
polys := mapping.PolygonMatcher()
|
||||
func TestPolygonMatcher_MatchWay(t *testing.T) {
|
||||
tests := []struct {
|
||||
tags element.Tags
|
||||
matches []Match
|
||||
}{
|
||||
{element.Tags{}, []Match{}},
|
||||
{element.Tags{"unknown": "baz"}, []Match{}},
|
||||
{element.Tags{"landuse": "unknown"}, []Match{}},
|
||||
{element.Tags{"landuse": "unknown", "type": "multipolygon"}, []Match{}},
|
||||
{element.Tags{"building": "yes"}, []Match{{"building", "yes", DestTable{Name: "buildings"}, nil}}},
|
||||
{element.Tags{"building": "residential"}, []Match{{"building", "residential", DestTable{Name: "buildings"}, nil}}},
|
||||
// line type requires area=yes
|
||||
{element.Tags{"barrier": "hedge"}, []Match{}},
|
||||
{element.Tags{"barrier": "hedge", "area": "yes"}, []Match{{"barrier", "hedge", DestTable{Name: "landusages"}, nil}}},
|
||||
|
||||
elem.Tags = element.Tags{"unknown": "baz"}
|
||||
matchesEqual(t, []Match{}, polys.MatchRelation(&elem))
|
||||
{element.Tags{"building": "shop"}, []Match{
|
||||
{"building", "shop", DestTable{Name: "buildings"}, nil},
|
||||
{"building", "shop", DestTable{Name: "amenity_areas"}, nil},
|
||||
}},
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "unknowns"}
|
||||
matchesEqual(t, []Match{}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"building": "yes"}
|
||||
matchesEqual(t, []Match{{"building", "yes", DestTable{Name: "buildings"}, nil}}, polys.MatchRelation(&elem))
|
||||
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},
|
||||
{"building", "shop", DestTable{Name: "amenity_areas"}, nil}},
|
||||
polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "farm"}
|
||||
matchesEqual(t, []Match{{"landuse", "farm", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "farm", "highway": "secondary"}
|
||||
matchesEqual(t, []Match{{"landuse", "farm", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "farm", "aeroway": "apron"}
|
||||
matchesEqual(t,
|
||||
[]Match{
|
||||
{element.Tags{"aeroway": "apron", "landuse": "farm"}, []Match{
|
||||
{"aeroway", "apron", DestTable{Name: "transport_areas"}, nil},
|
||||
{"landuse", "farm", DestTable{Name: "landusages"}, nil}},
|
||||
polys.MatchRelation(&elem))
|
||||
{"landuse", "farm", DestTable{Name: "landusages"}, nil},
|
||||
}},
|
||||
|
||||
elem.Tags = element.Tags{"highway": "footway"} // linear by default
|
||||
matchesEqual(t, []Match{}, polys.MatchRelation(&elem))
|
||||
{element.Tags{"landuse": "farm", "highway": "secondary"}, []Match{
|
||||
{"landuse", "farm", DestTable{Name: "landusages"}, nil},
|
||||
}},
|
||||
|
||||
elem.Tags = element.Tags{"highway": "footway", "area": "yes"}
|
||||
matchesEqual(t, []Match{{"highway", "footway", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
{element.Tags{"highway": "footway"}, []Match{}},
|
||||
{element.Tags{"highway": "footway", "area": "yes"}, []Match{
|
||||
{"highway", "footway", DestTable{Name: "landusages"}, nil},
|
||||
}},
|
||||
|
||||
elem.Tags = element.Tags{"boundary": "administrative", "admin_level": "8"}
|
||||
matchesEqual(t, []Match{{"boundary", "administrative", DestTable{Name: "admin"}, nil}}, polys.MatchRelation(&elem))
|
||||
{element.Tags{"boundary": "administrative", "admin_level": "8"}, []Match{{"boundary", "administrative", DestTable{Name: "admin"}, nil}}},
|
||||
|
||||
/*
|
||||
landusages mapping has the following order,
|
||||
check that XxxMatcher always uses the first
|
||||
|
||||
amenity:
|
||||
- university
|
||||
landuse:
|
||||
- forest
|
||||
leisure:
|
||||
- park
|
||||
landuse:
|
||||
- park
|
||||
*/
|
||||
|
||||
{element.Tags{"landuse": "forest", "leisure": "park"}, []Match{{"landuse", "forest", DestTable{Name: "landusages"}, nil}}},
|
||||
{element.Tags{"landuse": "park", "leisure": "park"}, []Match{{"leisure", "park", DestTable{Name: "landusages"}, nil}}},
|
||||
{element.Tags{"landuse": "park", "leisure": "park", "amenity": "university"}, []Match{{"amenity", "university", DestTable{Name: "landusages"}, nil}}},
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
m := mapping.PolygonMatcher()
|
||||
for i, test := range tests {
|
||||
elem.Tags = test.tags
|
||||
actual := m.MatchWay(&elem)
|
||||
if !matchesEqual(actual, test.matches) {
|
||||
t.Errorf("unexpected result for case %d: %v != %v", i+1, actual, test.matches)
|
||||
}
|
||||
}
|
||||
|
||||
elem.Refs = nil
|
||||
elem.Tags = element.Tags{"building": "yes"}
|
||||
actual := m.MatchWay(&elem)
|
||||
if !matchesEqual([]Match{}, actual) {
|
||||
t.Error("open way matched as polygon")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatcherMappingOrder(t *testing.T) {
|
||||
func TestPolygonMatcher_MatchRelation(t *testing.T) {
|
||||
// check that only relations with type=multipolygon/boundary are matched as polygon
|
||||
|
||||
tests := []struct {
|
||||
tags element.Tags
|
||||
matches []Match
|
||||
}{
|
||||
{element.Tags{}, []Match{}},
|
||||
{element.Tags{"unknown": "baz"}, []Match{}},
|
||||
{element.Tags{"landuse": "unknown"}, []Match{}},
|
||||
{element.Tags{"landuse": "unknown", "type": "multipolygon"}, []Match{}},
|
||||
{element.Tags{"building": "yes"}, []Match{}},
|
||||
{element.Tags{"building": "yes", "type": "multipolygon"}, []Match{{"building", "yes", DestTable{Name: "buildings"}, nil}}},
|
||||
{element.Tags{"building": "residential", "type": "multipolygon"}, []Match{{"building", "residential", DestTable{Name: "buildings"}, nil}}},
|
||||
// line type requires area=yes
|
||||
{element.Tags{"barrier": "hedge", "type": "multipolygon"}, []Match{}},
|
||||
{element.Tags{"barrier": "hedge", "area": "yes", "type": "multipolygon"}, []Match{{"barrier", "hedge", DestTable{Name: "landusages"}, nil}}},
|
||||
|
||||
{element.Tags{"building": "shop", "type": "multipolygon"}, []Match{
|
||||
{"building", "shop", DestTable{Name: "buildings"}, nil},
|
||||
{"building", "shop", DestTable{Name: "amenity_areas"}, nil},
|
||||
}},
|
||||
|
||||
{element.Tags{"aeroway": "apron", "landuse": "farm", "type": "multipolygon"}, []Match{
|
||||
{"aeroway", "apron", DestTable{Name: "transport_areas"}, nil},
|
||||
{"landuse", "farm", DestTable{Name: "landusages"}, nil},
|
||||
}},
|
||||
|
||||
{element.Tags{"landuse": "farm", "highway": "secondary", "type": "multipolygon"}, []Match{
|
||||
{"landuse", "farm", DestTable{Name: "landusages"}, nil},
|
||||
}},
|
||||
|
||||
{element.Tags{"highway": "footway", "type": "multipolygon"}, []Match{}},
|
||||
{element.Tags{"highway": "footway", "area": "yes", "type": "multipolygon"}, []Match{
|
||||
{"highway", "footway", DestTable{Name: "landusages"}, nil},
|
||||
}},
|
||||
|
||||
{element.Tags{"boundary": "administrative", "admin_level": "8"}, []Match{}},
|
||||
{element.Tags{"boundary": "administrative", "admin_level": "8", "type": "boundary"}, []Match{{"boundary", "administrative", DestTable{Name: "admin"}, nil}}},
|
||||
}
|
||||
|
||||
elem := element.Relation{}
|
||||
polys := mapping.PolygonMatcher()
|
||||
|
||||
/*
|
||||
landusages mapping has the following order,
|
||||
check that XxxMatcher always uses the first
|
||||
|
||||
amenity:
|
||||
- university
|
||||
landuse:
|
||||
- forest
|
||||
leisure:
|
||||
- park
|
||||
landuse:
|
||||
- park
|
||||
*/
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "forest", "leisure": "park"}
|
||||
matchesEqual(t, []Match{{"landuse", "forest", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "park", "leisure": "park"}
|
||||
matchesEqual(t, []Match{{"leisure", "park", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
|
||||
elem.Tags = element.Tags{"landuse": "park", "leisure": "park", "amenity": "university"}
|
||||
matchesEqual(t, []Match{{"amenity", "university", DestTable{Name: "landusages"}, nil}}, polys.MatchRelation(&elem))
|
||||
m := mapping.PolygonMatcher()
|
||||
for i, test := range tests {
|
||||
elem.Tags = test.tags
|
||||
actual := m.MatchRelation(&elem)
|
||||
if !matchesEqual(actual, test.matches) {
|
||||
t.Errorf("unexpected result for case %d: %v != %v", i+1, actual, test.matches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExcludeFilter(t *testing.T) {
|
||||
|
|
|
@ -39,10 +39,13 @@ func (m *Mapping) PolygonMatcher() RelWayMatcher {
|
|||
filters := make(tableFilters)
|
||||
m.addFilters(filters)
|
||||
m.addTypedFilters(PolygonTable, filters)
|
||||
relFilters := make(tableFilters)
|
||||
m.addRelationFilters(PolygonTable, relFilters)
|
||||
return &tagMatcher{
|
||||
mappings: mappings,
|
||||
tables: m.tables(PolygonTable),
|
||||
filters: filters,
|
||||
relFilters: relFilters,
|
||||
matchAreas: true,
|
||||
}
|
||||
}
|
||||
|
@ -54,10 +57,13 @@ func (m *Mapping) RelationMatcher() RelationMatcher {
|
|||
m.addFilters(filters)
|
||||
m.addTypedFilters(PolygonTable, filters)
|
||||
m.addTypedFilters(RelationTable, filters)
|
||||
relFilters := make(tableFilters)
|
||||
m.addRelationFilters(RelationTable, relFilters)
|
||||
return &tagMatcher{
|
||||
mappings: mappings,
|
||||
tables: m.tables(RelationTable),
|
||||
filters: filters,
|
||||
relFilters: relFilters,
|
||||
matchAreas: true,
|
||||
}
|
||||
}
|
||||
|
@ -68,10 +74,13 @@ func (m *Mapping) RelationMemberMatcher() RelationMatcher {
|
|||
filters := make(tableFilters)
|
||||
m.addFilters(filters)
|
||||
m.addTypedFilters(RelationMemberTable, filters)
|
||||
relFilters := make(tableFilters)
|
||||
m.addRelationFilters(RelationMemberTable, relFilters)
|
||||
return &tagMatcher{
|
||||
mappings: mappings,
|
||||
tables: m.tables(RelationMemberTable),
|
||||
filters: filters,
|
||||
relFilters: relFilters,
|
||||
matchAreas: true,
|
||||
}
|
||||
}
|
||||
|
@ -104,6 +113,7 @@ type tagMatcher struct {
|
|||
mappings TagTables
|
||||
tables map[string]*TableFields
|
||||
filters map[string][]ElementFilter
|
||||
relFilters map[string][]ElementFilter
|
||||
matchAreas bool
|
||||
}
|
||||
|
||||
|
@ -116,7 +126,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, false)
|
||||
return tm.match(node.Tags, false, false)
|
||||
}
|
||||
|
||||
func (tm *tagMatcher) MatchWay(way *element.Way) []Match {
|
||||
|
@ -125,22 +135,22 @@ func (tm *tagMatcher) MatchWay(way *element.Way) []Match {
|
|||
if way.Tags["area"] == "no" {
|
||||
return nil
|
||||
}
|
||||
return tm.match(way.Tags, true)
|
||||
return tm.match(way.Tags, true, false)
|
||||
}
|
||||
} 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, true, false)
|
||||
}
|
||||
return tm.match(way.Tags, false)
|
||||
return tm.match(way.Tags, false, false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tm *tagMatcher) MatchRelation(rel *element.Relation) []Match {
|
||||
return tm.match(rel.Tags, true)
|
||||
return tm.match(rel.Tags, true, true)
|
||||
}
|
||||
|
||||
type orderedMatch struct {
|
||||
|
@ -148,7 +158,7 @@ type orderedMatch struct {
|
|||
order int
|
||||
}
|
||||
|
||||
func (tm *tagMatcher) match(tags element.Tags, closed bool) []Match {
|
||||
func (tm *tagMatcher) match(tags element.Tags, closed bool, relation bool) []Match {
|
||||
tables := make(map[DestTable]orderedMatch)
|
||||
|
||||
addTables := func(k, v string, tbls []OrderedDestTable) {
|
||||
|
@ -198,6 +208,18 @@ func (tm *tagMatcher) match(tags element.Tags, closed bool) []Match {
|
|||
}
|
||||
}
|
||||
}
|
||||
if relation && !filteredOut {
|
||||
filters, ok := tm.relFilters[t.Name]
|
||||
if ok {
|
||||
for _, filter := range filters {
|
||||
if !filter(tags, Key(match.Key), closed) {
|
||||
filteredOut = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !filteredOut {
|
||||
matches = append(matches, match.Match)
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestSelectRelationPolygonsSimple(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
r := element.Relation{}
|
||||
r.Tags = element.Tags{"landuse": "park"}
|
||||
r.Tags = element.Tags{"landuse": "park", "type": "multipolygon"}
|
||||
r.Members = []element.Member{
|
||||
makeMember(0, element.Tags{"landuse": "forest"}),
|
||||
makeMember(1, element.Tags{"landuse": "park"}),
|
||||
|
@ -68,7 +68,7 @@ func TestSelectRelationPolygonsUnrelatedTags(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
r := element.Relation{}
|
||||
r.Tags = element.Tags{"landuse": "park"}
|
||||
r.Tags = element.Tags{"landuse": "park", "type": "multipolygon"}
|
||||
r.Members = []element.Member{
|
||||
makeMember(0, element.Tags{"landuse": "park", "layer": "2", "name": "foo"}),
|
||||
makeMember(1, element.Tags{"landuse": "forest"}),
|
||||
|
@ -91,7 +91,7 @@ func TestSelectRelationPolygonsMultiple(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
r := element.Relation{}
|
||||
r.Tags = element.Tags{"landuse": "park"}
|
||||
r.Tags = element.Tags{"landuse": "park", "type": "multipolygon"}
|
||||
r.Members = []element.Member{
|
||||
makeMember(0, element.Tags{"landuse": "park"}),
|
||||
makeMember(1, element.Tags{"natural": "forest"}),
|
||||
|
@ -117,7 +117,7 @@ func TestSelectRelationPolygonsMultipleTags(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
r := element.Relation{}
|
||||
r.Tags = element.Tags{"landuse": "forest", "natural": "scrub"}
|
||||
r.Tags = element.Tags{"landuse": "forest", "natural": "scrub", "type": "multipolygon"}
|
||||
r.Members = []element.Member{
|
||||
makeMember(0, element.Tags{"natural": "scrub"}),
|
||||
makeMember(1, element.Tags{"landuse": "forest"}),
|
||||
|
@ -139,7 +139,7 @@ func TestSelectRelationPolygonsMultipleTagsOnWay(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
r := element.Relation{}
|
||||
r.Tags = element.Tags{"waterway": "riverbank"}
|
||||
r.Tags = element.Tags{"waterway": "riverbank", "type": "multipolygon"}
|
||||
r.Members = []element.Member{
|
||||
makeMemberRole(0, element.Tags{"waterway": "riverbank", "natural": "water"}, "outer"),
|
||||
makeMemberRole(1, element.Tags{"natural": "water"}, "inner"),
|
||||
|
|
|
@ -94,6 +94,7 @@
|
|||
<nd ref="1005"/>
|
||||
<nd ref="1001"/>
|
||||
<tag k="name" v="way 1001"/>
|
||||
<tag k="landuse" v="wood"/>
|
||||
</way>
|
||||
<way id="1002" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<nd ref="1006"/>
|
||||
|
@ -269,6 +270,16 @@
|
|||
<tag k="landuse" v="wood"/>
|
||||
<tag k="type" v="multipolygon"/>
|
||||
</relation>
|
||||
<relation id="1011" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<member type="way" ref="1001" role="outer"/>
|
||||
<member type="way" ref="1002" role="inner"/>
|
||||
<tag k="type" v="multipolygon"/>
|
||||
</relation>
|
||||
<relation id="1021" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<member type="way" ref="1001" role="outer"/>
|
||||
<member type="way" ref="1002" role="inner"/>
|
||||
<tag k="landuse" v="wood"/>
|
||||
</relation>
|
||||
<relation id="2001" version="1" timestamp="2011-11-11T00:11:11Z">
|
||||
<member type="way" ref="2001" role="outer"/>
|
||||
<member type="way" ref="2002" role="inner"/>
|
||||
|
|
|
@ -61,6 +61,14 @@ func TestComplete_Deploy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestComplete_OnlyNewStyleMultipolgon(t *testing.T) {
|
||||
assertRecords(t, []checkElem{
|
||||
{"osm_landusages", -1001, "wood", nil},
|
||||
{"osm_landusages", -1011, Missing, nil},
|
||||
{"osm_landusages", -1021, Missing, nil},
|
||||
})
|
||||
}
|
||||
|
||||
func TestComplete_LandusageToWaterarea1(t *testing.T) {
|
||||
// Parks inserted into landusages
|
||||
cache := ts.cache(t)
|
||||
|
|
|
@ -153,5 +153,15 @@
|
|||
<tag k="type" v="route"/>
|
||||
</relation>
|
||||
|
||||
<!-- non-route type is not imported -->
|
||||
<node id="130101" version="1" timestamp="2015-12-31T23:59:99Z" lat="53.0" lon="8.200">
|
||||
<tag k="name" v="Stop"/>
|
||||
</node>
|
||||
|
||||
<relation id="130901" version="23" timestamp="2015-06-02T04:13:19Z">
|
||||
<member type="node" ref="130101" role="stop"/>
|
||||
<tag k="route" v="bus"/>
|
||||
<tag k="type" v="bus_route"/> <!-- invalid type -->
|
||||
</relation>
|
||||
|
||||
</osm>
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
tags:
|
||||
load_all: true
|
||||
exclude:
|
||||
- created_by
|
||||
- source
|
||||
|
||||
tables:
|
||||
master_routes:
|
||||
type: relation_member
|
||||
|
@ -27,6 +21,7 @@ tables:
|
|||
- key: name
|
||||
name: name
|
||||
type: string
|
||||
relation_types: [route_master]
|
||||
mapping:
|
||||
route_master: [bus]
|
||||
route_members:
|
||||
|
@ -54,6 +49,7 @@ tables:
|
|||
key: name
|
||||
type: string
|
||||
from_member: true
|
||||
relation_types: [route]
|
||||
mapping:
|
||||
route: [bus, tram, rail]
|
||||
routes:
|
||||
|
@ -66,5 +62,7 @@ tables:
|
|||
type: string
|
||||
- name: tags
|
||||
type: hstore_tags
|
||||
relation_types: [route, route_master]
|
||||
mapping:
|
||||
route_master: [bus, tram, rail]
|
||||
route: [bus, tram, rail]
|
||||
|
|
|
@ -58,6 +58,23 @@ func TestRouteRelation_RelationData(t *testing.T) {
|
|||
if r.tags["name"] != "Bus 301: A => B" {
|
||||
t.Error(r)
|
||||
}
|
||||
|
||||
// check tags of master relation
|
||||
r = ts.queryTags(t, "osm_routes", -100911)
|
||||
if r.tags["name"] != "Bus 301" {
|
||||
t.Error(r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouteRelation_MemberUpdatedByNode1(t *testing.T) {
|
||||
// check that member is updated after node was modified
|
||||
rows := ts.queryDynamic(t, "osm_route_members", "osm_id = -110901 AND member = 110101")
|
||||
if len(rows) != 1 {
|
||||
t.Fatal(rows)
|
||||
}
|
||||
if rows[0]["name"] != "Stop" {
|
||||
t.Error(rows[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouteRelation_MemberGeomUpdated1(t *testing.T) {
|
||||
|
@ -131,7 +148,7 @@ func TestRouteRelation_MemberGeomUpdated2(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestRouteRelation_MemberUpdatedByNode(t *testing.T) {
|
||||
func TestRouteRelation_MemberUpdatedByNode2(t *testing.T) {
|
||||
// check that member is updated after node was modified
|
||||
rows := ts.queryDynamic(t, "osm_route_members", "osm_id = -110901 AND member = 110101")
|
||||
if len(rows) != 1 {
|
||||
|
|
Loading…
Reference in New Issue