1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
extern crate osmpbfreader;
use geo_types::Point;
use std::collections::BTreeMap;

pub fn named_node(lon: f64, lat: f64, name: &'static str) -> (Point<f64>, Option<String>) {
    (Point::new(lon, lat), Some(name.into()))
}

pub struct Relation<'a> {
    builder: &'a mut OsmBuilder,
    pub relation_id: osmpbfreader::RelationId,
}

impl<'a> Relation<'a> {
    pub fn outer(&mut self, coords: Vec<(Point<f64>, Option<String>)>) -> &'a mut Relation {
        let id = self.builder.way(coords);
        if let osmpbfreader::OsmObj::Relation(ref mut rel) = self
            .builder
            .objects
            .get_mut(&self.relation_id.into())
            .unwrap()
        {
            rel.refs.push(osmpbfreader::Ref {
                role: "outer".into(),
                member: id.into(),
            });
        }
        self
    }
}

impl<'a> Relation<'a> {
    pub fn inner(&mut self, coords: Vec<(Point<f64>, Option<String>)>) -> &'a mut Relation {
        let id = self.builder.way(coords);
        if let osmpbfreader::OsmObj::Relation(ref mut rel) = self
            .builder
            .objects
            .get_mut(&self.relation_id.into())
            .unwrap()
        {
            rel.refs.push(osmpbfreader::Ref {
                role: "inner".into(),
                member: id.into(),
            });
        }
        self
    }
}

#[derive(Default)]
pub struct OsmBuilder {
    node_id: i64,
    way_id: i64,
    relation_id: i64,
    pub objects: BTreeMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>,
    named_nodes: BTreeMap<String, osmpbfreader::NodeId>,
}

impl OsmBuilder {
    pub fn new() -> OsmBuilder {
        Self::default()
    }

    pub fn relation(&mut self) -> Relation {
        let id = osmpbfreader::RelationId(self.relation_id);
        let r = osmpbfreader::Relation {
            id,
            refs: vec![],
            tags: osmpbfreader::Tags::new(),
        };
        self.relation_id += 1;
        self.objects.insert(id.into(), r.into());
        Relation {
            builder: self,
            relation_id: id,
        }
    }

    pub fn way(&mut self, coords: Vec<(Point<f64>, Option<String>)>) -> osmpbfreader::WayId {
        let nodes = coords
            .into_iter()
            .map(|pair| self.node(pair.0, pair.1))
            .collect::<Vec<_>>();
        let id = osmpbfreader::WayId(self.way_id);
        let w = osmpbfreader::Way {
            id,
            nodes,
            tags: osmpbfreader::Tags::new(),
        };
        self.way_id += 1;
        self.objects.insert(id.into(), w.into());
        id
    }

    pub fn node(&mut self, coord: Point<f64>, name: Option<String>) -> osmpbfreader::NodeId {
        if let Some(value) = name.as_ref().and_then(|n| self.named_nodes.get(n)) {
            return *value;
        }
        let id = osmpbfreader::NodeId(self.node_id);
        let n = osmpbfreader::Node {
            id,
            decimicro_lat: (coord.y() * 1e7) as i32,
            decimicro_lon: (coord.x() * 1e7) as i32,
            tags: osmpbfreader::Tags::new(),
        };
        self.node_id += 1;
        self.objects.insert(id.into(), n.into());
        if let Some(ref n) = name {
            self.named_nodes.insert(n.clone(), id);
        }
        id
    }
}