瀏覽代碼

search: Find OSM ways in a second pass

search::par_search_blocking: Remember node ids for matching ways and
return the positions of these nodes in a second pass over the file.
Johannes Hofmann 7 年之前
父節點
當前提交
e2f7171031
共有 1 個文件被更改,包括 53 次插入5 次删除
  1. 53
    5
      src/search.rs

+ 53
- 5
src/search.rs 查看文件

@@ -2,6 +2,7 @@ use coord::LatLon;
2 2
 use osmpbf::{Blob, BlobDecode, BlobReader, PrimitiveBlock};
3 3
 use regex::Regex;
4 4
 use scoped_threadpool::Pool;
5
+use std::collections::hash_set::HashSet;
5 6
 use std::path::{Path, PathBuf};
6 7
 use std::sync::mpsc::sync_channel;
7 8
 use std::thread;
@@ -60,8 +61,9 @@ where P: AsRef<Path>,
60 61
         .map_err(|e| format!("{}", e))?;
61 62
     let re = &re;
62 63
 
63
-    let search = move |block: &PrimitiveBlock, _: &()| {
64
+    let first_pass = move |block: &PrimitiveBlock, _: &()| {
64 65
         let mut matches = vec![];
66
+        let mut way_node_ids = vec![];
65 67
 
66 68
         for node in block.groups().flat_map(|g| g.nodes()) {
67 69
             for (_key, val) in node.tags() {
@@ -83,13 +85,59 @@ where P: AsRef<Path>,
83 85
             }
84 86
         }
85 87
 
88
+        for way in block.groups().flat_map(|g| g.ways()) {
89
+            for (_key, val) in way.tags() {
90
+                if re.is_match(val) && !way.refs_slice().is_empty() {
91
+                    //TODO take middle node, not first one
92
+                    way_node_ids.push(way.refs_slice()[0]);
93
+                    break;
94
+                }
95
+            }
96
+        }
97
+
98
+        (matches, way_node_ids)
99
+    };
100
+
101
+    let mut way_node_ids: HashSet<i64> = HashSet::new();
102
+
103
+    par_iter_blobs(
104
+        &pbf_path,
105
+        || {},
106
+        first_pass,
107
+        |(matches, node_ids)| {
108
+            way_node_ids.extend(&node_ids);
109
+            found_func(matches)
110
+        },
111
+    )?;
112
+
113
+    let way_node_ids = &way_node_ids;
114
+
115
+    let second_pass = move |block: &PrimitiveBlock, _: &()| {
116
+        let mut matches = vec![];
117
+
118
+        for node in block.groups().flat_map(|g| g.nodes()) {
119
+            if way_node_ids.contains(&node.id()) {
120
+                let pos = LatLon::new(node.lat(), node.lon());
121
+                matches.push(pos);
122
+                break;
123
+            }
124
+        }
125
+
126
+        for node in block.groups().flat_map(|g| g.dense_nodes()) {
127
+            if way_node_ids.contains(&node.id) {
128
+                let pos = LatLon::new(node.lat(), node.lon());
129
+                matches.push(pos);
130
+                break;
131
+            }
132
+        }
133
+
86 134
         matches
87 135
     };
88 136
 
89 137
     par_iter_blobs(
90
-        pbf_path,
138
+        &pbf_path,
91 139
         || {},
92
-        search,
140
+        second_pass,
93 141
         found_func,
94 142
     )
95 143
 }
@@ -98,12 +146,12 @@ fn par_iter_blobs<P, D, R, IF, CF, RF>(
98 146
     pbf_path: P,
99 147
     init_func: IF,
100 148
     compute_func: CF,
101
-    result_func: RF,
149
+    mut result_func: RF,
102 150
 ) -> Result<(), String>
103 151
 where P: AsRef<Path>,
104 152
       IF: Fn() -> D,
105 153
       CF: Fn(&PrimitiveBlock, &D) -> R + Send + Sync,
106
-      RF: Fn(R) -> ControlFlow + Send + 'static,
154
+      RF: FnMut(R) -> ControlFlow,
107 155
       R: Send,
108 156
       D: Send,
109 157
 {