2013-05-17 17:44:50 +04:00
|
|
|
package mapping
|
|
|
|
|
2015-04-30 10:42:49 +03:00
|
|
|
import (
|
|
|
|
"github.com/omniscale/imposm3/element"
|
|
|
|
"github.com/omniscale/imposm3/geom"
|
|
|
|
)
|
2013-05-17 17:44:50 +04:00
|
|
|
|
2014-06-19 13:51:15 +04:00
|
|
|
func (m *Mapping) PointMatcher() NodeMatcher {
|
2013-05-17 17:44:50 +04:00
|
|
|
mappings := make(TagTables)
|
2016-01-04 13:19:28 +03:00
|
|
|
m.mappings(PointTable, mappings)
|
2013-05-17 17:44:50 +04:00
|
|
|
filters := m.ElementFilters()
|
2016-11-07 13:29:17 +03:00
|
|
|
return &tagMatcher{
|
|
|
|
mappings: mappings,
|
|
|
|
tables: m.tables(PointTable),
|
|
|
|
filters: filters,
|
|
|
|
matchAreas: false,
|
|
|
|
}
|
2013-05-17 17:44:50 +04:00
|
|
|
}
|
|
|
|
|
2014-06-19 13:51:15 +04:00
|
|
|
func (m *Mapping) LineStringMatcher() WayMatcher {
|
2013-05-17 17:44:50 +04:00
|
|
|
mappings := make(TagTables)
|
2016-01-04 13:19:28 +03:00
|
|
|
m.mappings(LineStringTable, mappings)
|
2013-05-17 17:44:50 +04:00
|
|
|
filters := m.ElementFilters()
|
2016-11-07 13:29:17 +03:00
|
|
|
return &tagMatcher{
|
|
|
|
mappings: mappings,
|
|
|
|
tables: m.tables(LineStringTable),
|
|
|
|
filters: filters,
|
|
|
|
matchAreas: false,
|
|
|
|
}
|
2013-05-17 17:44:50 +04:00
|
|
|
}
|
|
|
|
|
2014-06-19 13:51:15 +04:00
|
|
|
func (m *Mapping) PolygonMatcher() RelWayMatcher {
|
2013-05-17 17:44:50 +04:00
|
|
|
mappings := make(TagTables)
|
2016-01-04 13:19:28 +03:00
|
|
|
m.mappings(PolygonTable, mappings)
|
|
|
|
filters := m.ElementFilters()
|
2016-11-07 13:29:17 +03:00
|
|
|
return &tagMatcher{
|
|
|
|
mappings: mappings,
|
|
|
|
tables: m.tables(PolygonTable),
|
|
|
|
filters: filters,
|
|
|
|
matchAreas: true,
|
|
|
|
}
|
2016-01-04 13:19:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mapping) RelationMatcher() RelationMatcher {
|
|
|
|
mappings := make(TagTables)
|
|
|
|
m.mappings(RelationTable, mappings)
|
2013-05-17 17:44:50 +04:00
|
|
|
filters := m.ElementFilters()
|
2016-11-07 13:29:17 +03:00
|
|
|
return &tagMatcher{
|
|
|
|
mappings: mappings,
|
|
|
|
tables: m.tables(RelationTable),
|
|
|
|
filters: filters,
|
|
|
|
matchAreas: true,
|
|
|
|
}
|
2016-01-04 13:19:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mapping) RelationMemberMatcher() RelationMatcher {
|
|
|
|
mappings := make(TagTables)
|
|
|
|
m.mappings(RelationMemberTable, mappings)
|
|
|
|
filters := m.ElementFilters()
|
2016-11-07 13:29:17 +03:00
|
|
|
return &tagMatcher{
|
|
|
|
mappings: mappings,
|
|
|
|
tables: m.tables(RelationMemberTable),
|
|
|
|
filters: filters,
|
|
|
|
matchAreas: true,
|
|
|
|
}
|
2013-05-17 17:44:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
type Match struct {
|
|
|
|
Key string
|
|
|
|
Value string
|
2013-05-27 13:24:22 +04:00
|
|
|
Table DestTable
|
2013-05-17 17:44:50 +04:00
|
|
|
tableFields *TableFields
|
|
|
|
}
|
2015-09-25 14:36:23 +03:00
|
|
|
|
2014-06-19 13:51:15 +04:00
|
|
|
type NodeMatcher interface {
|
|
|
|
MatchNode(node *element.Node) []Match
|
|
|
|
}
|
|
|
|
|
|
|
|
type WayMatcher interface {
|
|
|
|
MatchWay(way *element.Way) []Match
|
|
|
|
}
|
|
|
|
|
|
|
|
type RelationMatcher interface {
|
|
|
|
MatchRelation(rel *element.Relation) []Match
|
|
|
|
}
|
|
|
|
|
|
|
|
type RelWayMatcher interface {
|
|
|
|
WayMatcher
|
|
|
|
RelationMatcher
|
|
|
|
}
|
|
|
|
|
|
|
|
type tagMatcher struct {
|
|
|
|
mappings TagTables
|
|
|
|
tables map[string]*TableFields
|
|
|
|
filters map[string][]ElementFilter
|
|
|
|
matchAreas bool
|
|
|
|
}
|
2013-05-17 17:44:50 +04:00
|
|
|
|
2015-04-30 10:42:49 +03:00
|
|
|
func (m *Match) Row(elem *element.OSMElem, geom *geom.Geometry) []interface{} {
|
|
|
|
return m.tableFields.MakeRow(elem, geom, *m)
|
2013-05-17 17:44:50 +04:00
|
|
|
}
|
|
|
|
|
2016-01-04 13:19:28 +03:00
|
|
|
func (m *Match) MemberRow(rel *element.Relation, member *element.Member, geom *geom.Geometry) []interface{} {
|
|
|
|
return m.tableFields.MakeMemberRow(rel, member, geom, *m)
|
|
|
|
}
|
|
|
|
|
2014-06-19 13:51:15 +04:00
|
|
|
func (tm *tagMatcher) MatchNode(node *element.Node) []Match {
|
2016-11-10 13:00:34 +03:00
|
|
|
return tm.match(node.Tags, false)
|
2014-06-19 13:51:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (tm *tagMatcher) MatchWay(way *element.Way) []Match {
|
|
|
|
if tm.matchAreas { // match way as polygon
|
|
|
|
if way.IsClosed() {
|
|
|
|
if way.Tags["area"] == "no" {
|
|
|
|
return nil
|
|
|
|
}
|
2016-11-10 13:00:34 +03:00
|
|
|
return tm.match(way.Tags, true)
|
2014-06-19 13:51:15 +04:00
|
|
|
}
|
|
|
|
} else { // match way as linestring
|
|
|
|
if way.IsClosed() {
|
|
|
|
if way.Tags["area"] == "yes" {
|
|
|
|
return nil
|
|
|
|
}
|
2016-11-10 13:00:34 +03:00
|
|
|
return tm.match(way.Tags, true)
|
2014-06-19 13:51:15 +04:00
|
|
|
}
|
2016-11-10 13:00:34 +03:00
|
|
|
return tm.match(way.Tags, false)
|
2014-06-19 13:51:15 +04:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tm *tagMatcher) MatchRelation(rel *element.Relation) []Match {
|
2016-11-10 13:00:34 +03:00
|
|
|
return tm.match(rel.Tags, true)
|
2014-06-19 13:51:15 +04:00
|
|
|
}
|
|
|
|
|
2015-09-25 14:36:23 +03:00
|
|
|
type orderedMatch struct {
|
|
|
|
Match
|
|
|
|
order int
|
|
|
|
}
|
|
|
|
|
2016-11-10 13:00:34 +03:00
|
|
|
func (tm *tagMatcher) match(tags element.Tags, closed bool) []Match {
|
2015-09-25 14:36:23 +03:00
|
|
|
tables := make(map[DestTable]orderedMatch)
|
|
|
|
|
|
|
|
addTables := func(k, v string, tbls []OrderedDestTable) {
|
|
|
|
for _, t := range tbls {
|
|
|
|
this := orderedMatch{
|
2016-11-10 13:00:34 +03:00
|
|
|
Match: Match{
|
|
|
|
Key: k,
|
|
|
|
Value: v,
|
|
|
|
Table: t.DestTable,
|
|
|
|
tableFields: tm.tables[t.Name],
|
|
|
|
},
|
2015-09-25 14:36:23 +03:00
|
|
|
order: t.order,
|
|
|
|
}
|
|
|
|
if other, ok := tables[t.DestTable]; ok {
|
|
|
|
if other.order < this.order {
|
|
|
|
this = other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tables[t.DestTable] = this
|
|
|
|
}
|
2016-06-15 14:37:20 +03:00
|
|
|
}
|
2015-09-25 14:36:23 +03:00
|
|
|
|
2016-06-15 14:37:20 +03:00
|
|
|
if values, ok := tm.mappings[Key("__any__")]; ok {
|
|
|
|
addTables("__any__", "__any__", values["__any__"])
|
2015-09-25 14:36:23 +03:00
|
|
|
}
|
2013-05-17 17:44:50 +04:00
|
|
|
|
2016-11-10 13:00:34 +03:00
|
|
|
for k, v := range tags {
|
2014-06-19 13:51:15 +04:00
|
|
|
values, ok := tm.mappings[Key(k)]
|
2013-05-17 17:44:50 +04:00
|
|
|
if ok {
|
|
|
|
if tbls, ok := values["__any__"]; ok {
|
2015-09-25 14:36:23 +03:00
|
|
|
addTables(k, v, tbls)
|
2014-01-22 14:35:53 +04:00
|
|
|
}
|
2014-04-30 18:33:07 +04:00
|
|
|
if tbls, ok := values[Value(v)]; ok {
|
2015-09-25 14:36:23 +03:00
|
|
|
addTables(k, v, tbls)
|
2013-05-17 17:44:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var matches []Match
|
|
|
|
for t, match := range tables {
|
2014-06-19 13:51:15 +04:00
|
|
|
filters, ok := tm.filters[t.Name]
|
2013-05-17 17:44:50 +04:00
|
|
|
filteredOut := false
|
|
|
|
if ok {
|
|
|
|
for _, filter := range filters {
|
2016-11-10 13:00:34 +03:00
|
|
|
if !filter(tags, Key(match.Key), closed) {
|
2013-05-17 17:44:50 +04:00
|
|
|
filteredOut = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !filteredOut {
|
2015-09-25 14:36:23 +03:00
|
|
|
matches = append(matches, match.Match)
|
2013-05-17 17:44:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return matches
|
|
|
|
}
|
2014-05-05 12:21:46 +04:00
|
|
|
|
|
|
|
// SelectRelationPolygons returns a slice of all members that are already
|
2015-01-05 17:49:11 +03:00
|
|
|
// imported as part of the relation.
|
|
|
|
// Outer members are "imported" if they share the same destination table. Inner members
|
|
|
|
// are "imported" when they also share the same key/value.
|
2014-06-19 13:51:15 +04:00
|
|
|
func SelectRelationPolygons(polygonTagMatcher RelWayMatcher, rel *element.Relation) []element.Member {
|
|
|
|
relMatches := polygonTagMatcher.MatchRelation(rel)
|
2014-05-05 12:21:46 +04:00
|
|
|
result := []element.Member{}
|
2014-06-19 13:51:15 +04:00
|
|
|
for _, m := range rel.Members {
|
2014-05-05 12:21:46 +04:00
|
|
|
if m.Type != element.WAY {
|
|
|
|
continue
|
|
|
|
}
|
2014-06-19 13:51:15 +04:00
|
|
|
memberMatches := polygonTagMatcher.MatchWay(m.Way)
|
2015-01-05 17:49:11 +03:00
|
|
|
if m.Role == "outer" && dstEquals(relMatches, memberMatches) {
|
|
|
|
result = append(result, m)
|
|
|
|
} else if matchEquals(relMatches, memberMatches) {
|
2014-05-05 12:21:46 +04:00
|
|
|
result = append(result, m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2015-01-05 17:49:11 +03:00
|
|
|
// matchEquals returns true if both matches share key/value and table
|
2014-05-05 12:21:46 +04:00
|
|
|
func matchEquals(matchesA, matchesB []Match) bool {
|
|
|
|
for _, matchA := range matchesA {
|
|
|
|
for _, matchB := range matchesB {
|
|
|
|
if matchA.Key == matchB.Key &&
|
|
|
|
matchA.Value == matchB.Value &&
|
|
|
|
matchA.Table == matchB.Table {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2015-01-05 17:49:11 +03:00
|
|
|
|
|
|
|
// dstEquals returns true if both matches share a single destination table
|
|
|
|
func dstEquals(matchesA, matchesB []Match) bool {
|
|
|
|
for _, matchA := range matchesA {
|
|
|
|
for _, matchB := range matchesB {
|
|
|
|
if matchA.Table == matchB.Table {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|