2013-05-14 12:04:11 +04:00
|
|
|
package mapping
|
2013-05-13 15:58:44 +04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"flag"
|
2013-05-14 18:15:35 +04:00
|
|
|
"goposm/element"
|
2013-05-13 15:58:44 +04:00
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Field struct {
|
|
|
|
Key string `json:"key"`
|
|
|
|
Type string `json:"type"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Table struct {
|
2013-05-14 18:15:35 +04:00
|
|
|
Name string
|
2013-05-13 15:58:44 +04:00
|
|
|
Type string `json:"type"`
|
|
|
|
Mapping map[string][]string `json:"mapping"`
|
|
|
|
Fields map[string]*Field `json:"fields"`
|
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
type Tables map[string]*Table
|
2013-05-13 15:58:44 +04:00
|
|
|
|
|
|
|
type Mapping struct {
|
|
|
|
Tables Tables `json:"tables"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) FillFieldKeys() {
|
|
|
|
for key, field := range t.Fields {
|
|
|
|
if field.Key == "" {
|
|
|
|
field.Key = key
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) Mappings() map[string][]string {
|
|
|
|
return t.Mapping
|
|
|
|
}
|
|
|
|
|
|
|
|
func (t *Table) ExtraTags() map[string]bool {
|
|
|
|
tags := make(map[string]bool)
|
|
|
|
for _, field := range t.Fields {
|
|
|
|
tags[field.Key] = true
|
|
|
|
}
|
|
|
|
return tags
|
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
func (m *Mapping) prepare() {
|
|
|
|
for name, t := range m.Tables {
|
2013-05-13 15:58:44 +04:00
|
|
|
t.FillFieldKeys()
|
2013-05-14 18:15:35 +04:00
|
|
|
t.Name = name
|
2013-05-13 15:58:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mapping) mappings(tableType string, mappings map[string]map[string][]string) {
|
|
|
|
for name, t := range m.Tables {
|
|
|
|
if t.Type != tableType {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for key, vals := range t.Mappings() {
|
|
|
|
for _, v := range vals {
|
|
|
|
vals, ok := mappings[key]
|
|
|
|
if ok {
|
|
|
|
vals[v] = append(vals[v], name)
|
|
|
|
} else {
|
|
|
|
mappings[key] = make(map[string][]string)
|
|
|
|
mappings[key][v] = append(mappings[key][v], name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
func (m *Mapping) tables(tableType string) map[string]*TableFields {
|
|
|
|
result := make(map[string]*TableFields)
|
|
|
|
for name, t := range m.Tables {
|
|
|
|
if t.Type == tableType {
|
|
|
|
result[name] = t.TableFields()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2013-05-13 15:58:44 +04:00
|
|
|
func (m *Mapping) extraTags(tableType string, tags map[string]bool) {
|
|
|
|
for _, t := range m.Tables {
|
|
|
|
if t.Type != tableType {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for key, _ := range t.ExtraTags() {
|
|
|
|
tags[key] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mapping) NodeTagFilter() *TagFilter {
|
|
|
|
mappings := make(map[string]map[string][]string)
|
|
|
|
m.mappings("point", mappings)
|
|
|
|
tags := make(map[string]bool)
|
|
|
|
m.extraTags("point", tags)
|
|
|
|
return &TagFilter{mappings, tags}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mapping) WayTagFilter() *TagFilter {
|
|
|
|
mappings := make(map[string]map[string][]string)
|
|
|
|
m.mappings("linestring", mappings)
|
|
|
|
m.mappings("polygon", mappings)
|
|
|
|
tags := make(map[string]bool)
|
|
|
|
m.extraTags("linestring", tags)
|
|
|
|
m.extraTags("polygon", tags)
|
|
|
|
return &TagFilter{mappings, tags}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Mapping) RelationTagFilter() *TagFilter {
|
|
|
|
mappings := make(map[string]map[string][]string)
|
|
|
|
m.mappings("linestring", mappings)
|
|
|
|
m.mappings("polygon", mappings)
|
|
|
|
tags := make(map[string]bool)
|
|
|
|
m.extraTags("linestring", tags)
|
|
|
|
m.extraTags("polygon", tags)
|
|
|
|
return &TagFilter{mappings, tags}
|
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
func (m *Mapping) PointMatcher() *TagMatcher {
|
2013-05-13 17:19:39 +04:00
|
|
|
mappings := make(map[string]map[string][]string)
|
|
|
|
m.mappings("point", mappings)
|
2013-05-14 18:15:35 +04:00
|
|
|
return &TagMatcher{mappings, m.tables("point")}
|
2013-05-13 17:19:39 +04:00
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
func (m *Mapping) LineStringMatcher() *TagMatcher {
|
2013-05-13 17:19:39 +04:00
|
|
|
mappings := make(map[string]map[string][]string)
|
|
|
|
m.mappings("linestring", mappings)
|
2013-05-14 18:15:35 +04:00
|
|
|
return &TagMatcher{mappings, m.tables("linestring")}
|
2013-05-13 17:19:39 +04:00
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
func (m *Mapping) PolygonMatcher() *TagMatcher {
|
2013-05-13 17:19:39 +04:00
|
|
|
mappings := make(map[string]map[string][]string)
|
|
|
|
m.mappings("polygon", mappings)
|
2013-05-14 18:15:35 +04:00
|
|
|
return &TagMatcher{mappings, m.tables("polygon")}
|
2013-05-13 17:19:39 +04:00
|
|
|
}
|
|
|
|
|
2013-05-13 15:58:44 +04:00
|
|
|
type TagFilter struct {
|
|
|
|
mappings map[string]map[string][]string
|
|
|
|
extraTags map[string]bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type RelationTagFilter struct {
|
|
|
|
TagFilter
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *TagFilter) Filter(tags map[string]string) bool {
|
|
|
|
foundMapping := false
|
|
|
|
for k, v := range tags {
|
|
|
|
values, ok := f.mappings[k]
|
|
|
|
if ok {
|
|
|
|
if _, ok := values["__any__"]; ok {
|
|
|
|
foundMapping = true
|
|
|
|
continue
|
|
|
|
} else if _, ok := values[v]; ok {
|
|
|
|
foundMapping = true
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
delete(tags, k)
|
|
|
|
}
|
|
|
|
} else if _, ok := f.extraTags[k]; !ok {
|
|
|
|
delete(tags, k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if foundMapping {
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *RelationTagFilter) Filter(tags map[string]string) bool {
|
|
|
|
if t, ok := tags["type"]; ok {
|
|
|
|
if t != "multipolygon" || t != "boundary" || t != "land_area" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return f.TagFilter.Filter(tags)
|
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
type TagMatcher struct {
|
|
|
|
mappings map[string]map[string][]string
|
|
|
|
tables map[string]*TableFields
|
|
|
|
}
|
2013-05-13 15:58:44 +04:00
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
type Match struct {
|
|
|
|
Key string
|
|
|
|
Value string
|
|
|
|
Table string
|
|
|
|
tableFields *TableFields
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *Match) Row(elem *element.OSMElem) []interface{} {
|
|
|
|
return m.tableFields.MakeRow(elem, *m)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tagMatcher *TagMatcher) Match(elem element.OSMElem) []Match {
|
|
|
|
tables := make(map[string]Match)
|
|
|
|
|
|
|
|
for k, v := range elem.Tags {
|
|
|
|
values, ok := tagMatcher.mappings[k]
|
2013-05-13 15:58:44 +04:00
|
|
|
if ok {
|
|
|
|
if tbls, ok := values["__any__"]; ok {
|
|
|
|
for _, t := range tbls {
|
2013-05-14 18:15:35 +04:00
|
|
|
tables[t] = Match{k, v, t, tagMatcher.tables[t]}
|
2013-05-13 15:58:44 +04:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
} else if tbls, ok := values[v]; ok {
|
|
|
|
for _, t := range tbls {
|
2013-05-14 18:15:35 +04:00
|
|
|
tables[t] = Match{k, v, t, tagMatcher.tables[t]}
|
2013-05-13 15:58:44 +04:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
var matches []Match
|
|
|
|
for _, match := range tables {
|
|
|
|
matches = append(matches, match)
|
2013-05-13 15:58:44 +04:00
|
|
|
}
|
2013-05-14 18:15:35 +04:00
|
|
|
return matches
|
2013-05-13 15:58:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewMapping(filename string) (*Mapping, error) {
|
|
|
|
f, err := os.Open(filename)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
decoder := json.NewDecoder(f)
|
|
|
|
|
|
|
|
mapping := Mapping{}
|
|
|
|
err = decoder.Decode(&mapping)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2013-05-14 18:15:35 +04:00
|
|
|
mapping.prepare()
|
2013-05-13 15:58:44 +04:00
|
|
|
return &mapping, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// data := `
|
|
|
|
// {
|
|
|
|
// "tables": {
|
|
|
|
// "roads": {
|
|
|
|
// "mapping": {
|
|
|
|
// "highway": [
|
|
|
|
// "motorway",
|
|
|
|
// "motorway_link",
|
|
|
|
// "trunk",
|
|
|
|
// "trunk_link"
|
|
|
|
// ]
|
|
|
|
// },
|
|
|
|
// "fields": {
|
|
|
|
// "tunnel": {"type": "bool", "key": "tunnel"},
|
|
|
|
// "bridge": {"type": "bool"},
|
|
|
|
// "oneway": {"type": "direction"},
|
|
|
|
// "ref": {"type": "string"},
|
|
|
|
// "z_order": {"type": "wayzorder", "key": "NONE"}
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// `
|
|
|
|
|
|
|
|
// t := Table{map[string][]string{"highway": {"motorway", "trunk"}}}
|
|
|
|
// b, err := json.Marshal(t)
|
|
|
|
// if err != nil {
|
|
|
|
// log.Fatal(err)
|
|
|
|
// }
|
|
|
|
// log.Println(string(b))
|
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
mapping, err := NewMapping(flag.Arg(0))
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
// log.Println(mapping.Mappings("point"))
|
|
|
|
// log.Println(mapping.ExtraTags("point"))
|
|
|
|
log.Println(mapping.NodeTagFilter())
|
|
|
|
log.Println(mapping.WayTagFilter())
|
|
|
|
log.Println(mapping.RelationTagFilter())
|
|
|
|
|
|
|
|
// log.Println(mapping)
|
|
|
|
|
|
|
|
// b, err := json.MarshalIndent(mapping, "", " ")
|
|
|
|
// if err != nil {
|
|
|
|
// log.Fatal(err)
|
|
|
|
// }
|
|
|
|
// log.Println(string(b))
|
|
|
|
}
|