Patrick Brosi 4 lat temu
rodzic
commit
0a89a21ad1
46 zmienionych plików z 2928 dodań i 871 usunięć
  1. 4 1
      src/osmfixer/FixerMain.cpp
  2. 283 0
      src/osmfixer/index/SearchIdx.cpp
  3. 69 0
      src/osmfixer/index/SearchIdx.h
  4. 73 37
      src/osmfixer/index/StatIdx.cpp
  5. 9 0
      src/osmfixer/index/StatIdx.h
  6. 127 69
      src/osmfixer/server/StatServer.cpp
  7. 5 2
      src/osmfixer/server/StatServer.h
  8. 62 3
      src/util/Misc.h
  9. 85 19
      src/util/String.h
  10. 1 1
      src/util/geo/BezierCurve.tpp
  11. 41 0
      src/util/geo/CircularSegment.h
  12. 51 0
      src/util/geo/CircularSegment.tpp
  13. 283 6
      src/util/geo/Geo.h
  14. 3 3
      src/util/geo/Grid.h
  15. 2 1
      src/util/geo/Grid.tpp
  16. 2 3
      src/util/geo/PolyLine.h
  17. 11 4
      src/util/geo/PolyLine.tpp
  18. 89 0
      src/util/geo/QuadTree.h
  19. 107 0
      src/util/geo/QuadTree.tpp
  20. 10 0
      src/util/geo/output/GeoGraphJsonOutput.h
  21. 29 3
      src/util/geo/output/GeoGraphJsonOutput.tpp
  22. 10 2
      src/util/geo/output/GeoJsonOutput.h
  23. 16 0
      src/util/geo/output/GeoJsonOutput.tpp
  24. 15 2
      src/util/graph/Algorithm.h
  25. 10 2
      src/util/graph/Algorithm.tpp
  26. 7 0
      src/util/graph/BiDijkstra.cpp
  27. 129 0
      src/util/graph/BiDijkstra.h
  28. 283 0
      src/util/graph/BiDijkstra.tpp
  29. 1 0
      src/util/graph/Dijkstra.cpp
  30. 29 25
      src/util/graph/Dijkstra.h
  31. 41 26
      src/util/graph/Dijkstra.tpp
  32. 0 2
      src/util/graph/DirGraph.h
  33. 0 4
      src/util/graph/DirGraph.tpp
  34. 20 17
      src/util/graph/EDijkstra.h
  35. 44 28
      src/util/graph/EDijkstra.tpp
  36. 0 3
      src/util/graph/Edge.h
  37. 2 0
      src/util/graph/Graph.h
  38. 11 0
      src/util/graph/Graph.tpp
  39. 89 59
      src/util/graph/ShortestPath.h
  40. 7 1
      src/util/http/Server.cpp
  41. 7 2
      src/util/log/Log.h
  42. 38 0
      src/util/tests/QuadTreeTest.cpp
  43. 12 0
      src/util/tests/QuadTreeTest.h
  44. 603 525
      src/util/tests/TestMain.cpp
  45. 98 1
      web/index.html
  46. 110 20
      web/script.js

+ 4 - 1
src/osmfixer/FixerMain.cpp

@@ -69,8 +69,11 @@ int main(int argc, char** argv) {
69 69
         idx[i].first.suggIdStart + idx[i].second.maxSuggId() + 1;
70 70
   }
71 71
 
72
+  LOG(INFO) << "Building search index...";
73
+  osmfixer::SearchIdx searchIdx(idx.front().second);
74
+
72 75
   LOG(INFO) << "Starting server...";
73
-  StatServer serv(idx);
76
+  StatServer serv(idx, searchIdx);
74 77
 
75 78
   LOG(INFO) << "Listening on port " << port;
76 79
   util::http::HttpServer(port, &serv).run();

+ 283 - 0
src/osmfixer/index/SearchIdx.cpp

@@ -0,0 +1,283 @@
1
+// Copyright 2019, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>.
4
+
5
+#include <algorithm>
6
+#include <codecvt>
7
+#include <fstream>
8
+#include <locale>
9
+#include <queue>
10
+#include <string>
11
+#include <vector>
12
+#include "util/log/Log.h"
13
+
14
+#include "osmfixer/index/SearchIdx.h"
15
+
16
+using osmfixer::SearchIdx;
17
+using osmfixer::TupleList;
18
+using osmfixer::TripleList;
19
+
20
+// _____________________________________________________________________________
21
+void SearchIdx::build() {
22
+  _qGramIndex.clear();
23
+
24
+  size_t nameid = 0;
25
+
26
+  std::map<std::wstring, size_t> tokenIds;
27
+
28
+  for (size_t gid = 0; gid < _stats.getGroups().size(); gid++) {
29
+		auto group = _stats.getGroup(gid);
30
+
31
+		// dont index empty groups
32
+		if (group->stations.size() == 0) continue;
33
+		if (group->polyStations.size() == 0) continue;
34
+
35
+    for (const auto& name : _stats.getGroup(gid)->uniqueNames) {
36
+      // use wstring to get UTF-8 chars right
37
+      std::wstring wname =
38
+          std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(name);
39
+
40
+      _nameToGroup[nameid] = gid;
41
+			_names.push_back(name);
42
+
43
+      for (const auto& token : tokenize(wname)) {
44
+        if (tokenIds.count(token)) {
45
+          if (_inv[tokenIds.find(token)->second].size() == 0 ||
46
+              _inv[tokenIds.find(token)->second].back().first != nameid) {
47
+            // only use a token once per station
48
+            _inv[tokenIds.find(token)->second].push_back({nameid, 1});
49
+          }
50
+        } else {
51
+          tokenIds[token] = _tokens.size();
52
+          _tokens.push_back(token);
53
+          _inv.push_back(TupleList());
54
+          _inv.back().push_back({nameid, 1});
55
+        }
56
+
57
+        size_t tokenId = tokenIds.find(token)->second;
58
+        for (const auto& qGram : getQGrams(token)) {
59
+          if (_qGramIndex[qGram].size() &&
60
+              _qGramIndex[qGram].back().first == tokenId) {
61
+            _qGramIndex[qGram].back().second++;
62
+          } else {
63
+            _qGramIndex[qGram].push_back({tokenId, 1});
64
+          }
65
+        }
66
+      }
67
+      nameid++;
68
+    }
69
+  }
70
+
71
+  for (auto& idx : _qGramIndex) std::sort(idx.second.begin(), idx.second.end());
72
+
73
+  for (auto& idx : _qGramIndex) {
74
+    TupleList tl;
75
+    for (auto& cur : idx.second) {
76
+      if (tl.size() != 0 && tl.back().first == cur.first)
77
+        tl.back().second += cur.second;
78
+      else
79
+        tl.push_back(cur);
80
+    }
81
+    idx.second = tl;
82
+  }
83
+}
84
+
85
+// _____________________________________________________________________________
86
+std::vector<std::wstring> SearchIdx::getQGrams(const std::wstring& word) {
87
+  std::vector<std::wstring> ret;
88
+
89
+  std::wstring s;
90
+  for (size_t i = 0; i < 2; ++i) s += '$';
91
+
92
+  s += normalize(word);
93
+
94
+  for (size_t i = 0; i < s.size() - 2; ++i) ret.push_back(s.substr(i, 3));
95
+
96
+  return ret;
97
+}
98
+
99
+// _____________________________________________________________________________
100
+std::vector<std::wstring> SearchIdx::tokenize(const std::wstring& str) {
101
+  std::vector<std::wstring> ret;
102
+  std::wstring cur;
103
+
104
+  const wchar_t* seps = L"_-?'\"|!@#$%^&*()_+}|><.,\\";
105
+
106
+  for (size_t i = 0; i < str.size(); i++) {
107
+    if (std::iswspace(str[i]) || wcschr(seps, str[i])) {
108
+      if (cur.size()) {
109
+        ret.push_back(cur);
110
+        cur.clear();
111
+      }
112
+    } else {
113
+      cur += std::towlower(str[i]);
114
+    }
115
+  }
116
+
117
+  if (cur.size()) ret.push_back(cur);
118
+
119
+  return ret;
120
+}
121
+
122
+// _____________________________________________________________________________
123
+std::wstring SearchIdx::normalize(const std::wstring& str) {
124
+  std::wstring s;
125
+  const wchar_t* unallowed = L"_-?'\"|!@#$%^&*()_+}|><.,\\";
126
+  for (size_t i = 0; i < str.size(); ++i) {
127
+    if (std::iswspace(str[i]) || wcschr(unallowed, str[i])) {
128
+      continue;
129
+    }
130
+    s += std::towlower(str[i]);
131
+  }
132
+
133
+  return s;
134
+}
135
+
136
+// _____________________________________________________________________________
137
+TripleList SearchIdx::find(const std::string& qry) const {
138
+  TupleList ret;
139
+  std::wstring wqry =
140
+      std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(qry);
141
+
142
+  const auto& tokens = tokenize(wqry);
143
+
144
+  std::vector<TupleList> lists;
145
+
146
+  for (const auto& token : tokens) {
147
+    double delta = token.size() / 4.0;
148
+    auto res = tokenFind(token);
149
+
150
+    std::partial_sort(res.begin(), res.begin() + std::min<size_t>(100, res.size()), res.end(), resComp);
151
+
152
+    std::map<size_t, double> bests;
153
+    std::map<size_t, size_t> bestToken;
154
+
155
+		size_t TOPK = 100;
156
+
157
+		// res contains the 100 best token matches
158
+    for (size_t i = 0; i < res.size() && i < TOPK; i++) {
159
+      for (size_t j = 0; j < _inv[res[i].first].size(); j++) {
160
+
161
+				double score = _inv[res[i].first][j].second * (delta / (1.0 + res[i].second));
162
+
163
+				if (score > bests[_inv[res[i].first][j].first]) {
164
+						bests[_inv[res[i].first][j].first] = score;
165
+						bestToken[_inv[res[i].first][j].first] = res[i].first;
166
+				}
167
+      }
168
+    }
169
+
170
+    for (size_t i = 0; i < res.size() && i < TOPK; i++) {
171
+			// inv[res[i]] contains all the names the token res[i] occurs in
172
+
173
+      lists.push_back(_inv[res[i].first]);
174
+
175
+      // give them a score based on their PED
176
+			for (size_t j = 0; j < lists.back().size(); j++) {
177
+				double score = lists.back()[j].second *
178
+                                 (delta / (1.0 + res[i].second));
179
+				// best is the token for this name that matched best for the input token
180
+				size_t best = bestToken[lists.back()[j].first];
181
+
182
+				// if it is not this token, we dont count it
183
+				if (res[i].first != best) score = 0;
184
+        lists.back()[j].second = score;
185
+			}
186
+    }
187
+  }
188
+
189
+  std::vector<const TupleList*> mlists;
190
+  for (const auto& l : lists) mlists.push_back(&l);
191
+
192
+  ret = lmerge(mlists);
193
+
194
+  TripleList fr;
195
+
196
+  for (const auto& r : ret) {
197
+    fr.push_back({{_nameToGroup.find(r.first)->second, r.first}, r.second});
198
+  }
199
+
200
+  std::sort(fr.begin(), fr.end(), resGidCompInv);
201
+
202
+  TripleList fin;
203
+  for (const auto& r : fr) {
204
+    if (fin.size() == 0 || fin.back().first.first != r.first.first) fin.push_back(r);
205
+  }
206
+
207
+  std::partial_sort(fin.begin(), fin.begin() + std::min<size_t>(fin.size(), 10),
208
+                    fin.end(), resCompInv);
209
+
210
+  TripleList top10;
211
+  for (const auto& r : fin) {
212
+    top10.push_back(r);
213
+    if (top10.size() == 10) break;
214
+  }
215
+
216
+  return top10;
217
+}
218
+
219
+// _____________________________________________________________________________
220
+TupleList SearchIdx::tokenFind(const std::wstring& prefix) const {
221
+  TupleList result;
222
+
223
+  size_t delta = prefix.size() / 4;
224
+
225
+  std::vector<const TupleList*> lists;
226
+  for (const auto& qGram : getQGrams(prefix)) {
227
+    auto it = _qGramIndex.find(qGram);
228
+    if (it != _qGramIndex.end()) lists.push_back(&it->second);
229
+  }
230
+
231
+  size_t threshold = prefix.size() - 3 * delta;
232
+
233
+  for (const auto& tpl : lmerge(lists)) {
234
+    if (tpl.second >= threshold) {
235
+      size_t ped = util::prefixEditDist(prefix, _tokens[tpl.first], delta);
236
+      if (ped <= delta) result.push_back({tpl.first, ped});
237
+    }
238
+  }
239
+
240
+  return result;
241
+}
242
+
243
+// _____________________________________________________________________________
244
+TupleList SearchIdx::lmerge(const std::vector<const TupleList*>& lists) {
245
+  if (lists.size() == 0) return {};
246
+
247
+  TupleList a = *lists[0];
248
+
249
+  for (size_t k = 1; k < lists.size(); k++) {
250
+    const auto& b = lists[k];
251
+
252
+    TupleList ret;
253
+    size_t i = 0;
254
+    size_t j = 0;
255
+    while (i < a.size() && j < b->size()) {
256
+      if (a[i].first < (*b)[j].first) {
257
+        ret.push_back(a[i]);
258
+        i++;
259
+      } else if ((*b)[j].first < a[i].first) {
260
+        ret.push_back((*b)[j]);
261
+        j++;
262
+      } else {
263
+        ret.push_back({a[i].first, a[i].second + (*b)[j].second});
264
+        i++;
265
+        j++;
266
+      }
267
+    }
268
+
269
+    while (i < a.size()) {
270
+      ret.push_back(a[i]);
271
+      i++;
272
+    }
273
+
274
+    while (j < b->size()) {
275
+      ret.push_back((*b)[j]);
276
+      j++;
277
+    }
278
+
279
+    a = ret;
280
+  }
281
+
282
+  return a;
283
+}

+ 69 - 0
src/osmfixer/index/SearchIdx.h

@@ -0,0 +1,69 @@
1
+// Copyright 2019, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>.
4
+
5
+#ifndef OSMFIXER_INDEX_SEARCHIDX_H_
6
+#define OSMFIXER_INDEX_SEARCHIDX_H_
7
+
8
+#include <string>
9
+#include <unordered_map>
10
+#include <vector>
11
+#include "osmfixer/index/StatIdx.h"
12
+
13
+namespace osmfixer {
14
+
15
+
16
+typedef std::pair<size_t, double> Tuple;
17
+typedef std::vector<Tuple> TupleList;
18
+typedef std::pair<std::pair<size_t, size_t>, double> Triple;
19
+typedef std::vector<Triple> TripleList;
20
+typedef std::unordered_map<std::wstring, TupleList> Index;
21
+
22
+inline bool resComp(const Tuple& lh, const Tuple& rh) {
23
+  return lh.second < rh.second;
24
+}
25
+
26
+inline bool resCompInv(const Triple& lh, const Triple& rh) {
27
+  return lh.second > rh.second;
28
+}
29
+
30
+inline bool resGidCompInv(const Triple& lh, const Triple& rh) {
31
+  if (lh.first.first < rh.first.first) return true;
32
+  if (lh.first.first == rh.first.first) return lh.second > rh.second;
33
+  return false;
34
+}
35
+
36
+class SearchIdx {
37
+ public:
38
+  explicit SearchIdx(const StatIdx& sidx) : _stats(sidx) { build(); }
39
+
40
+  void build();
41
+
42
+  TripleList find(const std::string& qry) const;
43
+
44
+  static std::wstring normalize(const std::wstring& str);
45
+  static std::vector<std::wstring> tokenize(const std::wstring& str);
46
+
47
+  static std::vector<std::wstring> getQGrams(const std::wstring& word);
48
+
49
+  const Index& getIndex() const { return _qGramIndex; }
50
+
51
+  const std::string& getName(size_t nid) const { return _names[nid]; }
52
+
53
+ private:
54
+  TupleList tokenFind(const std::wstring& prefix) const;
55
+  static TupleList lmerge(const std::vector<const TupleList*>& lists);
56
+
57
+  const StatIdx& _stats;
58
+
59
+  Index _qGramIndex;
60
+
61
+  std::unordered_map<size_t, size_t> _nameToGroup;
62
+  std::vector<std::wstring> _tokens;
63
+  std::vector<std::string> _names;
64
+
65
+  std::vector<TupleList> _inv;
66
+};
67
+}  // namespace osmfixer
68
+
69
+#endif  // OSMFIXER_INDEX_SEARCHIDX_H_

+ 73 - 37
src/osmfixer/index/StatIdx.cpp

@@ -210,6 +210,7 @@ void StatIdx::addGroup(size_t osmid, const OsmAttrs& attrs) {
210 210
 // _____________________________________________________________________________
211 211
 void StatIdx::initGroups() {
212 212
   for (size_t i = 0; i < _stations.size(); i++) {
213
+
213 214
     // this should be ensured by the input file
214 215
     assert(_stations[i].origGroup < _groups.size());
215 216
     _groups[_stations[i].origGroup].polyStations.push_back(i);
@@ -228,6 +229,34 @@ void StatIdx::initGroups() {
228 229
     }
229 230
   }
230 231
 
232
+  // collect unique names
233
+  for (size_t gid = 0; gid < _groups.size(); gid++) {
234
+    std::set<std::string> usedGroupNames;
235
+
236
+    for (const auto& np : _groups[gid].attrs) {
237
+      for (const auto& name : np.second) {
238
+        if (usedGroupNames.count(name)) continue;
239
+        usedGroupNames.insert(name);
240
+
241
+        _groups[gid].uniqueNames.push_back(name);
242
+      }
243
+    }
244
+
245
+    for (size_t sid :_groups[gid].stations) {
246
+      for (const auto& np : _stations[sid].attrs) {
247
+        for (const auto& name : np.second) {
248
+          // use every name only once to keep the index small
249
+          if (usedGroupNames.count(name)) continue;
250
+          usedGroupNames.insert(name);
251
+
252
+          _groups[gid].uniqueNames.push_back(name);
253
+        }
254
+      }
255
+    }
256
+
257
+    // take the longest name as the identifier
258
+    std::sort(_groups[gid].uniqueNames.begin(), _groups[gid].uniqueNames.end(), byLen);
259
+  }
231 260
 
232 261
   // build hull polygon
233 262
   for (size_t i = 0; i < _groups.size(); i++) {
@@ -595,6 +624,46 @@ void StatIdx::initSuggestions() {
595 624
       stat.suggestions.push_back(_suggestions.size() - 1);
596 625
     }
597 626
 
627
+    Suggestion sug;
628
+    sug.station = i;
629
+
630
+    bool hasStationTrackHeur = false;
631
+
632
+    std::set<std::pair<std::string, uint16_t>> suggested;
633
+    for (auto attrErr : stat.attrErrs) {
634
+      if (attrErr.fromRel) continue;
635
+
636
+      const auto otherStat = getStation(attrErr.otherId);
637
+      if (stat.id == attrErr.otherId && attrErr.attr == attrErr.otherAttr) {
638
+        if (suggested.count({attrErr.attr, 8})) continue;
639
+        hasStationTrackHeur = true;
640
+        suggested.insert({attrErr.attr, 8});
641
+        // fix track number as name
642
+        sug.type = 8;
643
+        sug.orig_gid = 0;
644
+        sug.orig_osm_rel_id = 0;
645
+        sug.target_gid = 0;
646
+        sug.target_osm_rel_id = 0;
647
+        sug.attrErrName = attrErr.attr;
648
+
649
+        _suggestions.push_back(sug);
650
+        stat.suggestions.push_back(_suggestions.size() - 1);
651
+      } else if (otherStat->osmid == stat.osmid) {
652
+        if (suggested.count({attrErr.attr, 6})) continue;
653
+        suggested.insert({attrErr.attr, 6});
654
+        // fix attributes
655
+        sug.type = 6;
656
+        sug.orig_gid = 0;
657
+        sug.orig_osm_rel_id = 0;
658
+        sug.target_gid = 0;
659
+        sug.target_osm_rel_id = 0;
660
+        sug.attrErrName = attrErr.attr;
661
+
662
+        _suggestions.push_back(sug);
663
+        stat.suggestions.push_back(_suggestions.size() - 1);
664
+      }
665
+    }
666
+
598 667
     if (stat.group != stat.origGroup || getGroup(stat.group)->osmid == 1) {
599 668
       Suggestion sug;
600 669
       sug.station = i;
@@ -649,8 +718,11 @@ void StatIdx::initSuggestions() {
649 718
 
650 719
           _suggestions.push_back(sug);
651 720
           stat.suggestions.push_back(_suggestions.size() - 1);
652
-        } else {
721
+        } else if (!hasStationTrackHeur) {
653 722
           // move station out of relation
723
+          //
724
+          // don't show this suggestion if the station track heuristic was
725
+          // triggered
654 726
           sug.type = 5;
655 727
           sug.orig_gid = stat.origGroup;
656 728
           sug.target_gid = stat.group;
@@ -668,42 +740,6 @@ void StatIdx::initSuggestions() {
668 740
       }
669 741
     }
670 742
 
671
-    Suggestion sug;
672
-    sug.station = i;
673
-
674
-    std::set<std::pair<std::string, uint16_t>> suggested;
675
-    for (auto attrErr : stat.attrErrs) {
676
-      if (attrErr.fromRel) continue;
677
-
678
-      const auto otherStat = getStation(attrErr.otherId);
679
-      if (stat.id == attrErr.otherId && attrErr.attr == attrErr.otherAttr) {
680
-        if (suggested.count({attrErr.attr, 8})) continue;
681
-        suggested.insert({attrErr.attr, 8});
682
-        // fix track number as name
683
-        sug.type = 8;
684
-        sug.orig_gid = 0;
685
-        sug.orig_osm_rel_id = 0;
686
-        sug.target_gid = 0;
687
-        sug.target_osm_rel_id = 0;
688
-        sug.attrErrName = attrErr.attr;
689
-
690
-        _suggestions.push_back(sug);
691
-        stat.suggestions.push_back(_suggestions.size() - 1);
692
-      } else if (otherStat->osmid == stat.osmid) {
693
-        if (suggested.count({attrErr.attr, 6})) continue;
694
-        suggested.insert({attrErr.attr, 6});
695
-        // fix attributes
696
-        sug.type = 6;
697
-        sug.orig_gid = 0;
698
-        sug.orig_osm_rel_id = 0;
699
-        sug.target_gid = 0;
700
-        sug.target_osm_rel_id = 0;
701
-        sug.attrErrName = attrErr.attr;
702
-
703
-        _suggestions.push_back(sug);
704
-        stat.suggestions.push_back(_suggestions.size() - 1);
705
-      }
706
-    }
707 743
   }
708 744
 }
709 745
 

+ 9 - 0
src/osmfixer/index/StatIdx.h

@@ -15,6 +15,10 @@ namespace osmfixer {
15 15
 
16 16
 typedef std::map<std::string, std::vector<std::string>> OsmAttrs;
17 17
 
18
+inline bool byLen(const std::string& lh, const std::string& rh) {
19
+  return lh.size() > rh.size();
20
+}
21
+
18 22
 struct AttrErr {
19 23
   std::string attr;
20 24
   std::string otherAttr;
@@ -56,6 +60,7 @@ struct Group {
56 60
   std::vector<size_t> polyStations;
57 61
   std::vector<AttrErr> attrErrs;
58 62
   std::vector<size_t> suggestions;
63
+  std::vector<std::string> uniqueNames;
59 64
 };
60 65
 
61 66
 struct Cluster {
@@ -93,6 +98,10 @@ class StatIdx {
93 98
   std::vector<Cluster> getHeatGridErr(const util::geo::DBox bbox,
94 99
                                       size_t z) const;
95 100
 
101
+  const std::vector<Station>& getStations() const { return _stations; }
102
+  const std::vector<Group>& getGroups() const { return _groups; }
103
+
104
+
96 105
  private:
97 106
   void addStation(int64_t osmid, const util::geo::DLine& geom,
98 107
                   const util::geo::DLine& latLngs, size_t origGroup,

+ 127 - 69
src/osmfixer/server/StatServer.cpp

@@ -3,6 +3,8 @@
3 3
 // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4 4
 
5 5
 #include <vector>
6
+#include <codecvt>
7
+#include <locale>
6 8
 #include "osmfixer/build.h"
7 9
 #include "osmfixer/index.h"
8 10
 #include "osmfixer/server/StatServer.h"
@@ -42,6 +44,8 @@ util::http::Answer StatServer::handle(const util::http::Req& req,
42 44
       a = handleStatReq(params);
43 45
     } else if (cmd == "/group") {
44 46
       a = handleGroupReq(params);
47
+    } else if (cmd == "/search") {
48
+      a = handleSearch(params);
45 49
     } else {
46 50
       a = util::http::Answer("404 Not Found", "dunno");
47 51
     }
@@ -249,7 +253,8 @@ void StatServer::printStation(const Station* stat, size_t did, bool simple,
249 253
   std::string sep = "";
250 254
 
251 255
   if (simple) {
252
-      (*out) << sep << "[" << stat->centroid.getY() << "," << stat->centroid.getX() << "]";
256
+    (*out) << sep << "[" << stat->centroid.getY() << ","
257
+           << stat->centroid.getX() << "]";
253 258
   } else {
254 259
     for (const auto& ll : stat->latLng) {
255 260
       (*out) << sep << "[" << ll.getY() << "," << ll.getX() << "]";
@@ -259,11 +264,9 @@ void StatServer::printStation(const Station* stat, size_t did, bool simple,
259 264
 
260 265
   (*out) << "]";
261 266
 
262
-  if (stat->suggestions.size() > 0)
263
-    (*out) << ",\"s\":1";
267
+  if (stat->suggestions.size() > 0) (*out) << ",\"s\":1";
264 268
 
265
-  if (stat->attrErrs.size())
266
-    (*out) << ",\"e\":" << stat->attrErrs.size();
269
+  if (stat->attrErrs.size()) (*out) << ",\"e\":" << stat->attrErrs.size();
267 270
 
268 271
   (*out) << "}";
269 272
 }
@@ -279,7 +282,7 @@ void StatServer::printSugg(const Suggestion* sugg, size_t did,
279 282
     projArrow.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
280 283
   }
281 284
 
282
-  (*out) << "{\"i\":" << sugg->station + range.suggIdStart
285
+  (*out) << "{\"i\":" << sugg->station + range.sidStart
283 286
          << ",\"t\":" << sugg->type << ",\"a\":[";
284 287
   char sep = ' ';
285 288
   for (const auto& p : projArrow) {
@@ -298,7 +301,8 @@ void StatServer::printGroup(const Group* group, size_t did, bool simple,
298 301
   (*out) << "{\"i\":" << group->id + range.gidStart << ",\"g\":[";
299 302
   char sep = ' ';
300 303
   if (simple) {
301
-    (*out) << sep << "[" << group->centroid.getY() << "," << group->centroid.getX() << "]";
304
+    (*out) << sep << "[" << group->centroid.getY() << ","
305
+           << group->centroid.getX() << "]";
302 306
   } else {
303 307
     for (const auto& p : group->llPoly.getOuter()) {
304 308
       (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
@@ -308,11 +312,9 @@ void StatServer::printGroup(const Group* group, size_t did, bool simple,
308 312
   (*out) << "]";
309 313
   if (group->osmid == 1) (*out) << ",\"n\":1";
310 314
 
311
-  if (group->suggestions.size() > 0)
312
-    (*out) << ",\"s\":1";
315
+  if (group->suggestions.size() > 0) (*out) << ",\"s\":1";
313 316
 
314
-  if (group->attrErrs.size())
315
-    (*out) << ",\"e\":" << group->attrErrs.size();
317
+  if (group->attrErrs.size()) (*out) << ",\"e\":" << group->attrErrs.size();
316 318
   (*out) << "}";
317 319
 }
318 320
 
@@ -326,7 +328,7 @@ std::string StatServer::parseUrl(std::string u, std::string pl,
326 328
     for (const auto& kv : kvs) {
327 329
       auto kvp = util::split(kv, '=');
328 330
       if (kvp.size() == 1) kvp.push_back("");
329
-      (*params)[util::urlDecode(kvp[0])] = kvp[1];
331
+      (*params)[util::urlDecode(kvp[0])] = util::urlDecode(kvp[1]);
330 332
     }
331 333
   }
332 334
 
@@ -335,7 +337,7 @@ std::string StatServer::parseUrl(std::string u, std::string pl,
335 337
   for (const auto& kv : kvs) {
336 338
     auto kvp = util::split(kv, '=');
337 339
     if (kvp.size() == 1) kvp.push_back("");
338
-    (*params)[util::urlDecode(kvp[0])] = kvp[1];
340
+    (*params)[util::urlDecode(kvp[0])] = util::urlDecode(kvp[1]);
339 341
   }
340 342
 
341 343
   return util::urlDecode(parts.front());
@@ -372,6 +374,57 @@ size_t StatServer::getDidByGid(size_t gid) const {
372 374
 }
373 375
 
374 376
 // _____________________________________________________________________________
377
+util::http::Answer StatServer::handleSearch(const Params& pars) const {
378
+  if (pars.count("q") == 0)
379
+    throw std::invalid_argument("No query given.");
380
+  std::string cb;
381
+  if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
382
+
383
+  std::string query = pars.find("q")->second.c_str();
384
+
385
+  auto results = _searchIdx.find(query);
386
+
387
+  std::stringstream json;
388
+
389
+  json << std::setprecision(10);
390
+
391
+  if (cb.size()) json << cb << "(";
392
+  json << "[";
393
+
394
+  std::string sep = "";
395
+  for (const auto& res : results) {
396
+    size_t gid = res.first.first;
397
+    size_t did = getDidByGid(gid);
398
+
399
+    const auto& range = _idxs[did].first;
400
+    const auto& idx = _idxs[did].second;
401
+    size_t idxGid = gid - range.gidStart;
402
+    const auto group = idx.getGroup(idxGid);
403
+    json << sep << "{\"gid\":" << gid << ",\"score\":" << res.second << ", \"name\":";
404
+    std::string name = group->uniqueNames.front();
405
+    json << "\"" << util::jsonStringEscape(name) << "\"";
406
+    std::string via = _searchIdx.getName(res.first.second);
407
+    if (name != via) {
408
+      json << ",\"via\":" << "\"" << util::jsonStringEscape(via) << "\"";
409
+    }
410
+
411
+    json << ",\"latlng\":{\"lat\":" << group->centroid.getY() << ",\"lng\":" << group->centroid.getX() <<"}";
412
+
413
+    sep = ",";
414
+    json << "}";
415
+  }
416
+
417
+  json << "]";
418
+
419
+  if (cb.size()) json << ")";
420
+
421
+  auto answ = util::http::Answer("200 OK", json.str(), true);
422
+  answ.params["Content-Type"] = "application/javascript; charset=utf-8";
423
+
424
+  return answ;
425
+}
426
+
427
+// _____________________________________________________________________________
375 428
 util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
376 429
   if (pars.count("id") == 0 || pars.find("id")->second.empty())
377 430
     throw std::invalid_argument("No ID specified.");
@@ -420,13 +473,14 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
420 473
   sep = ' ';
421 474
   for (const auto& err : group->attrErrs) {
422 475
     // self errors denote names named as tracks
423
-    if (err.fromRel && err.otherId == group->id && err.attr == err.otherAttr) continue;
476
+    if (err.fromRel && err.otherId == group->id && err.attr == err.otherAttr)
477
+      continue;
424 478
 
425 479
     json << sep;
426 480
     sep = ',';
427 481
     json << "{";
428
-    json << "\"attr\":[\"" << err.attr << "\",\"" << group->attrs.at(err.attr)[0]
429
-         << "\"]";
482
+    json << "\"attr\":[\"" << err.attr << "\",\""
483
+         << group->attrs.at(err.attr)[0] << "\"]";
430 484
     json << ",\"conf\":" << err.conf;
431 485
 
432 486
     if (err.fromRel) {
@@ -476,11 +530,9 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
476 530
       json << "]";
477 531
     }
478 532
     json << "}";
479
-    if (stat->suggestions.size() > 0)
480
-      json << ",\"s\":1";
533
+    if (stat->suggestions.size() > 0) json << ",\"s\":1";
481 534
 
482
-    if (stat->attrErrs.size())
483
-      json << ",\"e\":" << stat->attrErrs.size();
535
+    if (stat->attrErrs.size()) json << ",\"e\":" << stat->attrErrs.size();
484 536
     json << "}";
485 537
   }
486 538
 
@@ -491,20 +543,20 @@ util::http::Answer StatServer::handleGroupReq(const Params& pars) const {
491 543
   std::string seper = "";
492 544
 
493 545
   for (size_t sid : group->suggestions) {
494
-      const auto* sugg = idx.getSuggestion(sid);
495
-      if (sugg->type == 6) {
496
-       json << seper << "{\"type\":6,\"attr\":\"" << sugg->attrErrName << "\""
497
-            << "}";
498
-      } else if (sugg->type == 7) {
499
-        json << seper << "{\"type\":7}";
500
-      } else if (sugg->type == 8) {
501
-       json << seper << "{\"type\":8,\"attr\":\"" << sugg->attrErrName << "\""
502
-            << "}";
503
-      } else {
504
-        json << seper << "{\"type\":" << sugg->type << "}";
505
-      }
506
-      seper = ',';
546
+    const auto* sugg = idx.getSuggestion(sid);
547
+    if (sugg->type == 6) {
548
+      json << seper << "{\"type\":6,\"attr\":\"" << sugg->attrErrName << "\""
549
+           << "}";
550
+    } else if (sugg->type == 7) {
551
+      json << seper << "{\"type\":7}";
552
+    } else if (sugg->type == 8) {
553
+      json << seper << "{\"type\":8,\"attr\":\"" << sugg->attrErrName << "\""
554
+           << "}";
555
+    } else {
556
+      json << seper << "{\"type\":" << sugg->type << "}";
507 557
     }
558
+    seper = ',';
559
+  }
508 560
 
509 561
   json << "]";
510 562
 
@@ -571,7 +623,8 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
571 623
   sep = ' ';
572 624
   for (const auto& err : stat->attrErrs) {
573 625
     // self errors denote names named as tracks
574
-    if (!err.fromRel && err.otherId == stat->id && err.attr == err.otherAttr) continue;
626
+    if (!err.fromRel && err.otherId == stat->id && err.attr == err.otherAttr)
627
+      continue;
575 628
     json << sep;
576 629
     sep = ',';
577 630
     json << "{";
@@ -603,42 +656,47 @@ util::http::Answer StatServer::handleStatReq(const Params& pars) const {
603 656
   std::string seper = "";
604 657
 
605 658
   for (size_t sid : stat->suggestions) {
606
-      const auto* sugg = idx.getSuggestion(sid);
607
-      if (sugg->type == 1) {
608
-        json << seper << "{\"type\":1, \"target_gid\":" << stat->group + range.gidStart
609
-             << "}";
610
-      } else if (sugg->type == 2) {
611
-        json << seper << "{\"type\":2, \"target_gid\":" << stat->group + range.gidStart
612
-             << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
613
-             << "}";
614
-      } else if (sugg->type == 3) {
615
-        json << seper << "{\"type\":3,\"orig_gid\":" << stat->origGroup + range.gidStart
616
-             << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
617
-             << ",\"target_gid\":" << stat->group + range.gidStart << "}";
618
-      } else if (sugg->type == 4) {
619
-        json << seper << "{\"type\":4,\"orig_gid\":" << stat->origGroup + range.gidStart
620
-             << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
621
-             << ",\"target_gid\":" << stat->group << ",\"target_osm_rel_id\":"
622
-             << idx.getGroup(stat->group)->osmid + range.gidStart << "}";
623
-      } else if (sugg->type == 5) {
624
-        json << seper << "{\"type\":5,\"orig_gid\":" << stat->origGroup + range.gidStart
625
-             << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
626
-             << ",\"target_gid\":" << stat->group + range.gidStart
627
-             << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
628
-             << "}";
629
-      } else if (sugg->type == 6) {
630
-       json << seper << "{\"type\":6,\"attr\":\"" << sugg->attrErrName << "\""
631
-            << "}";
632
-      } else if (sugg->type == 7) {
633
-        json << seper << "{\"type\":7}";
634
-      } else if (sugg->type == 8) {
635
-       json << seper << "{\"type\":8,\"attr\":\"" << sugg->attrErrName << "\""
636
-            << "}";
637
-      } else {
638
-        json << seper << "{\"type\":" << sugg->type << "}";
639
-      }
640
-      seper = ',';
659
+    const auto* sugg = idx.getSuggestion(sid);
660
+    if (sugg->type == 1) {
661
+      json << seper
662
+           << "{\"type\":1, \"target_gid\":" << stat->group + range.gidStart
663
+           << "}";
664
+    } else if (sugg->type == 2) {
665
+      json << seper
666
+           << "{\"type\":2, \"target_gid\":" << stat->group + range.gidStart
667
+           << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
668
+           << "}";
669
+    } else if (sugg->type == 3) {
670
+      json << seper
671
+           << "{\"type\":3,\"orig_gid\":" << stat->origGroup + range.gidStart
672
+           << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
673
+           << ",\"target_gid\":" << stat->group + range.gidStart << "}";
674
+    } else if (sugg->type == 4) {
675
+      json << seper
676
+           << "{\"type\":4,\"orig_gid\":" << stat->origGroup + range.gidStart
677
+           << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
678
+           << ",\"target_gid\":" << stat->group << ",\"target_osm_rel_id\":"
679
+           << idx.getGroup(stat->group)->osmid + range.gidStart << "}";
680
+    } else if (sugg->type == 5) {
681
+      json << seper
682
+           << "{\"type\":5,\"orig_gid\":" << stat->origGroup + range.gidStart
683
+           << ",\"orig_osm_rel_id\":" << idx.getGroup(stat->origGroup)->osmid
684
+           << ",\"target_gid\":" << stat->group + range.gidStart
685
+           << ",\"target_osm_rel_id\":" << idx.getGroup(stat->group)->osmid
686
+           << "}";
687
+    } else if (sugg->type == 6) {
688
+      json << seper << "{\"type\":6,\"attr\":\"" << sugg->attrErrName << "\""
689
+           << "}";
690
+    } else if (sugg->type == 7) {
691
+      json << seper << "{\"type\":7}";
692
+    } else if (sugg->type == 8) {
693
+      json << seper << "{\"type\":8,\"attr\":\"" << sugg->attrErrName << "\""
694
+           << "}";
695
+    } else {
696
+      json << seper << "{\"type\":" << sugg->type << "}";
641 697
     }
698
+    seper = ',';
699
+  }
642 700
 
643 701
   json << "]";
644 702
 

+ 5 - 2
src/osmfixer/server/StatServer.h

@@ -8,6 +8,7 @@
8 8
 #include <map>
9 9
 #include <string>
10 10
 #include "osmfixer/index/StatIdx.h"
11
+#include "osmfixer/index/SearchIdx.h"
11 12
 #include "util/http/Server.h"
12 13
 
13 14
 namespace osmfixer {
@@ -21,8 +22,8 @@ typedef std::map<std::string, std::string> Params;
21 22
 class StatServer : public util::http::Handler {
22 23
  public:
23 24
   explicit StatServer(
24
-      const std::vector<std::pair<IdRange, osmfixer::StatIdx>>& idxs)
25
-      : _idxs(idxs) {}
25
+      const std::vector<std::pair<IdRange, osmfixer::StatIdx>>& idxs, const SearchIdx& searchIdx)
26
+      : _idxs(idxs), _searchIdx(searchIdx) {}
26 27
 
27 28
   virtual util::http::Answer handle(const util::http::Req& request,
28 29
                                     int connection) const;
@@ -34,6 +35,7 @@ class StatServer : public util::http::Handler {
34 35
   util::http::Answer handleHeatMapReq(const Params& pars) const;
35 36
   util::http::Answer handleStatReq(const Params& pars) const;
36 37
   util::http::Answer handleGroupReq(const Params& pars) const;
38
+  util::http::Answer handleSearch(const Params& pars) const;
37 39
 
38 40
   void printStation(const Station* stat, size_t did, bool simple, std::ostream* out) const;
39 41
   void printGroup(const Group* stat, size_t did, bool simple, std::ostream* out) const;
@@ -44,6 +46,7 @@ class StatServer : public util::http::Handler {
44 46
   size_t getDidByGid(size_t gid) const;
45 47
 
46 48
   const std::vector<std::pair<IdRange, osmfixer::StatIdx>>& _idxs;
49
+  const SearchIdx& _searchIdx;
47 50
 };
48 51
 }  // namespace osmfixer
49 52
 

+ 62 - 3
src/util/Misc.h

@@ -9,15 +9,25 @@
9 9
 #include <cstring>
10 10
 #include <chrono>
11 11
 #include <sstream>
12
+#include <iostream>
12 13
 #include <unistd.h>
13 14
 #include <sys/types.h>
14 15
 #include <pwd.h>
15 16
 
16 17
 #define UNUSED(expr) do { (void)(expr); } while (0)
17 18
 #define TIME() std::chrono::high_resolution_clock::now()
18
-#define TOOK(t1, t2) (std::chrono::duration_cast<microseconds>(t2 - t1).count() / 1000.0)
19
+#define TOOK(t1, t2) (std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() / 1000.0)
19 20
 #define T_START(n)  auto _tstart_##n = std::chrono::high_resolution_clock::now()
20
-#define T_STOP(n) (std::chrono::duration_cast<microseconds>(std::chrono::high_resolution_clock::now() - _tstart_##n).count() / 1000.0)
21
+#define T_STOP(n) (std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - _tstart_##n).count() / 1000.0)
22
+
23
+#define _TEST3(s, o, e) if (!(s o e)) {  std::cerr << "\n" << __FILE__ << ":" << __LINE__ << ": Test failed!\n  Expected " << #s << " " << #o " " << (e) << ", got " << (s) << std::endl;  exit(1);}
24
+#define _TEST2(s, e) _TEST3(s, ==, o)
25
+#define _TEST1(s) _TEST3(static_cast<bool>(s), ==, true)
26
+
27
+#define _GET_TEST_MACRO(_1,_2,_3,NAME,...) NAME
28
+#define TEST(...) _GET_TEST_MACRO(__VA_ARGS__, _TEST3, _TEST2, _TEST1)(__VA_ARGS__)
29
+
30
+#define TODO(msg) std::cerr << "\n" __FILE__ << ":" << __LINE__ << ": TODO: " << #msg << std::endl;
21 31
 
22 32
 namespace util {
23 33
 
@@ -28,7 +38,7 @@ static int pow10[10] = {
28 38
 
29 39
 // _____________________________________________________________________________
30 40
 inline uint64_t factorial(uint64_t n) {
31
-  if (n == 1) return n;
41
+  if (n < 2) return 1;
32 42
   return n * factorial(n - 1);
33 43
 }
34 44
 
@@ -131,6 +141,55 @@ inline std::string getTmpDir() {
131 141
   return getHomeDir();
132 142
 }
133 143
 
144
+// _____________________________________________________________________________
145
+class approx {
146
+ public:
147
+  explicit approx(double magnitude)
148
+      : _epsilon{std::numeric_limits<float>::epsilon() * 100},
149
+        _magnitude{magnitude} {}
150
+
151
+  friend bool operator==(double lhs, approx const& rhs) {
152
+    return std::abs(lhs - rhs._magnitude) < rhs._epsilon;
153
+  }
154
+
155
+  friend bool operator==(approx const& lhs, double rhs) {
156
+    return operator==(rhs, lhs);
157
+  }
158
+
159
+  friend bool operator!=(double lhs, approx const& rhs) {
160
+    return !operator==(lhs, rhs);
161
+  }
162
+
163
+  friend bool operator!=(approx const& lhs, double rhs) {
164
+    return !operator==(rhs, lhs);
165
+  }
166
+
167
+  friend bool operator<=(double lhs, approx const& rhs) {
168
+    return lhs < rhs._magnitude || lhs == rhs;
169
+  }
170
+
171
+  friend bool operator<=(approx const& lhs, double rhs) {
172
+    return lhs._magnitude < rhs || lhs == rhs;
173
+  }
174
+
175
+  friend bool operator>=(double lhs, approx const& rhs) {
176
+    return lhs > rhs._magnitude || lhs == rhs;
177
+  }
178
+
179
+  friend bool operator>=(approx const& lhs, double rhs) {
180
+    return lhs._magnitude > rhs || lhs == rhs;
181
+  }
182
+
183
+  friend std::ostream& operator<< (std::ostream &out, const approx &a) {
184
+    out << "~" << a._magnitude;
185
+    return out;
186
+  }
187
+
188
+ private:
189
+  double _epsilon;
190
+  double _magnitude;
191
+};
192
+
134 193
 }  // namespace util
135 194
 
136 195
 #endif  // UTIL_MISC_H_

+ 85 - 19
src/util/String.h

@@ -6,7 +6,9 @@
6 6
 #define UTIL_STRING_H_
7 7
 
8 8
 #include <algorithm>
9
+#include <cassert>
9 10
 #include <cstring>
11
+#include <iomanip>
10 12
 #include <sstream>
11 13
 #include <string>
12 14
 #include <vector>
@@ -36,18 +38,43 @@ inline std::string urlDecode(const std::string& encoded) {
36 38
 }
37 39
 
38 40
 // _____________________________________________________________________________
39
-inline std::string jsonStringEscape(const std::string& unescaped) {
40
-  std::string escaped;
41
-  for (size_t i = 0; i < unescaped.size(); ++i) {
42
-    if (unescaped[i] == '"' || unescaped[i] == '\\') {
43
-      escaped += "\\";
41
+inline std::string jsonStringEscape(const std::string& unesc) {
42
+  // modified code from
43
+  // http://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c
44
+  std::ostringstream o;
45
+  for (auto c = unesc.cbegin(); c != unesc.cend(); c++) {
46
+    switch (*c) {
47
+      case '"':
48
+        o << "\\\"";
49
+        break;
50
+      case '\\':
51
+        o << "\\\\";
52
+        break;
53
+      case '\b':
54
+        o << "\\b";
55
+        break;
56
+      case '\f':
57
+        o << "\\f";
58
+        break;
59
+      case '\n':
60
+        o << "\\n";
61
+        break;
62
+      case '\r':
63
+        o << "\\r";
64
+        break;
65
+      case '\t':
66
+        o << "\\t";
67
+        break;
68
+      default:
69
+        if ('\x00' <= *c && *c <= '\x1f') {
70
+          o << "\\u" << std::hex << std::setw(4) << std::setfill('0')
71
+            << static_cast<int>(*c);
72
+        } else {
73
+          o << *c;
74
+        }
44 75
     }
45
-    if (iscntrl(unescaped[i])) {
46
-      escaped += " ";
47
-    }
48
-    escaped += unescaped[i];
49 76
   }
50
-  return escaped;
77
+  return o.str();
51 78
 }
52 79
 
53 80
 // _____________________________________________________________________________
@@ -143,7 +170,8 @@ inline size_t editDist(const std::string& s1, const std::string& s2) {
143 170
 }
144 171
 
145 172
 // _____________________________________________________________________________
146
-inline size_t prefixEditDist(const std::string& prefix, const std::string& s,
173
+template <class String>
174
+inline size_t prefixEditDist(const String& prefix, const String& s,
147 175
                              size_t deltaMax) {
148 176
   // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++
149 177
   size_t len1 = prefix.size();
@@ -152,38 +180,76 @@ inline size_t prefixEditDist(const std::string& prefix, const std::string& s,
152 180
 
153 181
   d[0] = 0;
154 182
   for (size_t i = 1; i <= len1; ++i) d[i * (len2 + 1)] = i;
155
-  for (size_t i = 1; i <= len2; ++i) d[ i] = i;
183
+  for (size_t i = 1; i <= len2; ++i) d[i] = i;
156 184
 
157 185
   for (size_t i = 1; i <= len1; i++) {
158 186
     for (size_t j = 1; j <= len2; j++) {
159
-      d[i * (len2 + 1) + j] = std::min(std::min(d[(i - 1) * (len2 + 1) + j] + 1, d[i * (len2 + 1) + j - 1] + 1),
160
-                         d[(i - 1) * (len2 + 1) + j - 1] + (prefix[i - 1] == s[j - 1] ? 0 : 1));
187
+      d[i * (len2 + 1) + j] = std::min(std::min(d[(i - 1) * (len2 + 1) + j] + 1,
188
+                                                d[i * (len2 + 1) + j - 1] + 1),
189
+                                       d[(i - 1) * (len2 + 1) + j - 1] +
190
+                                           (prefix[i - 1] == s[j - 1] ? 0 : 1));
161 191
     }
162 192
   }
163 193
 
164 194
   // take min of last row
165 195
   size_t deltaMin = std::max(std::max(deltaMax + 1, prefix.size()), s.size());
166 196
   for (size_t i = 0; i <= len2; i++) {
167
-    if (d[len1 * (len2 + 1) + i] < deltaMin) deltaMin = d[len1 * (len2 + 1) + i];
197
+    if (d[len1 * (len2 + 1) + i] < deltaMin)
198
+      deltaMin = d[len1 * (len2 + 1) + i];
168 199
   }
169 200
 
170 201
   return deltaMin;
171 202
 }
172 203
 
173 204
 // _____________________________________________________________________________
174
-inline size_t prefixEditDist(const std::string& prefix, const std::string& s) {
205
+template <class String>
206
+inline size_t prefixEditDist(const String& prefix, const String& s) {
175 207
   return prefixEditDist(prefix, s, s.size());
176 208
 }
177 209
 
178 210
 // _____________________________________________________________________________
211
+inline size_t prefixEditDist(const char* prefix, const char* s) {
212
+  return prefixEditDist<std::string>(std::string(prefix), std::string(s));
213
+}
214
+
215
+// _____________________________________________________________________________
216
+inline size_t prefixEditDist(const char* prefix, const char* s,
217
+                             size_t deltaMax) {
218
+  return prefixEditDist<std::string>(std::string(prefix), std::string(s),
219
+                                     deltaMax);
220
+}
221
+
222
+// _____________________________________________________________________________
223
+inline size_t prefixEditDist(const char* prefix, const std::string& s) {
224
+  return prefixEditDist<std::string>(std::string(prefix), s);
225
+}
226
+
227
+// _____________________________________________________________________________
228
+inline size_t prefixEditDist(const char* prefix, const std::string& s,
229
+                             size_t deltaMax) {
230
+  return prefixEditDist<std::string>(std::string(prefix), s, deltaMax);
231
+}
232
+
233
+// _____________________________________________________________________________
234
+inline size_t prefixEditDist(const std::string& prefix, const char* s) {
235
+  return prefixEditDist<std::string>(prefix, std::string(s));
236
+}
237
+
238
+// _____________________________________________________________________________
239
+inline size_t prefixEditDist(const std::string& prefix, const char* s,
240
+                             size_t deltaMax) {
241
+  return prefixEditDist<std::string>(prefix, std::string(s), deltaMax);
242
+}
243
+
244
+// _____________________________________________________________________________
179 245
 inline std::string toUpper(std::string str) {
180
-  std::transform(str.begin(), str.end(),str.begin(), toupper);
246
+  std::transform(str.begin(), str.end(), str.begin(), toupper);
181 247
   return str;
182 248
 }
183 249
 
184 250
 // _____________________________________________________________________________
185 251
 inline std::string toLower(std::string str) {
186
-  std::transform(str.begin(), str.end(),str.begin(), tolower);
252
+  std::transform(str.begin(), str.end(), str.begin(), tolower);
187 253
   return str;
188 254
 }
189 255
 
@@ -226,6 +292,6 @@ template <typename T>
226 292
 inline std::string implode(const std::vector<T>& vec, const char* del) {
227 293
   return implode(vec.begin(), vec.end(), del);
228 294
 }
229
-}
295
+}  // namespace util
230 296
 
231 297
 #endif  // UTIL_STRING_H_

+ 1 - 1
src/util/geo/BezierCurve.tpp

@@ -64,7 +64,7 @@ const PolyLine<T>& BezierCurve<T>::render(double d) {
64 64
 }
65 65
 
66 66
 // _____________________________________________________________________________
67
-double CubicPolynom::valueAt(double atx) const {
67
+inline double CubicPolynom::valueAt(double atx) const {
68 68
   double dx = atx - x;
69 69
   return a + b * dx + c * dx * dx + d * dx * dx * dx;
70 70
 }

+ 41 - 0
src/util/geo/CircularSegment.h

@@ -0,0 +1,41 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_CIRCULARSEGMENT_H_
6
+#define UTIL_GEO_CIRCULARSEGMENT_H_
7
+
8
+#include <vector>
9
+#include "util/geo/Geo.h"
10
+#include "util/geo/PolyLine.h"
11
+
12
+namespace util {
13
+namespace geo {
14
+
15
+/**
16
+ * Circular segment
17
+ */
18
+template <typename T>
19
+class CircularSegment {
20
+ public:
21
+  CircularSegment(const Point<T>& a, double ang, const Point<T>& c);
22
+
23
+  const PolyLine<T>& render(double d);
24
+
25
+ private:
26
+  // store the rendered polyline for quicker access
27
+  PolyLine<T> _rendered;
28
+
29
+  const Point<T>& _a, _c;
30
+  double _renderD;
31
+
32
+  double _ang, _rad, _s, _initAng;
33
+
34
+  Point<T> valueAt(double t) const;
35
+};
36
+
37
+#include "util/geo/CircularSegment.tpp"
38
+}
39
+}
40
+
41
+#endif  // UTIL_GEO_BEZIERCURVE_H_

+ 51 - 0
src/util/geo/CircularSegment.tpp

@@ -0,0 +1,51 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename T>
7
+CircularSegment<T>::CircularSegment(const Point<T>& a, double ang,
8
+                            const Point<T>& c) : _a(a), _c(c), _renderD(0), _ang(ang)
9
+     {
10
+
11
+  _rad = dist(a, c);
12
+  _s = fabs(_ang * _rad);
13
+  _initAng = angBetween(c, a);
14
+}
15
+
16
+// _____________________________________________________________________________
17
+template <typename T>
18
+Point<T> CircularSegment<T>::valueAt(double ang) const {
19
+  double xPos = _c.getX() + _rad * cos(ang);
20
+  double yPos = _c.getY() + _rad * sin(ang);
21
+  return Point<T>(xPos, yPos);
22
+}
23
+
24
+// _____________________________________________________________________________
25
+template <typename T>
26
+const PolyLine<T>& CircularSegment<T>::render(double d) {
27
+  assert(d > 0);
28
+  if (fabs(d - _renderD) < 0.001) return _rendered;
29
+  _renderD = d;
30
+
31
+  if (_s == 0) {
32
+    _rendered << _a << _a;
33
+    return _rendered;
34
+  }
35
+
36
+  _rendered.empty();
37
+  double n = _s / d, dt = 1 / n, t = 0;
38
+
39
+  bool cancel = false;
40
+  while (true) {
41
+    _rendered << valueAt(_initAng + t * _ang);
42
+    t += dt;
43
+    if (cancel) break;
44
+    if (t > 1) {
45
+      t = 1;
46
+      cancel = true;
47
+    }
48
+  }
49
+
50
+  return _rendered;
51
+}

+ 283 - 6
src/util/geo/Geo.h

@@ -51,6 +51,7 @@ typedef Polygon<int> IPolygon;
51 51
 
52 52
 const static double EPSILON = 0.00001;
53 53
 const static double RAD = 0.017453292519943295;  // PI/180
54
+const static double AVERAGING_STEP = 20;
54 55
 
55 56
 // _____________________________________________________________________________
56 57
 template <typename T>
@@ -204,6 +205,14 @@ inline Polygon<T> move(Polygon<T> geo, double x, double y) {
204 205
 }
205 206
 
206 207
 // _____________________________________________________________________________
208
+template <typename T>
209
+inline Box<T> move(Box<T> geo, double x, double y) {
210
+  geo.setLowerLeft(move(geo.getLowerLeft(), x, y));
211
+  geo.setUpperRight(move(geo.getUpperRight(), x, y));
212
+  return geo;
213
+}
214
+
215
+// _____________________________________________________________________________
207 216
 template <template <typename> class Geometry, typename T>
208 217
 inline std::vector<Geometry<T>> move(std::vector<Geometry<T>> multigeo,
209 218
                                      double x, double y) {
@@ -356,8 +365,9 @@ inline bool contains(const Polygon<T>& polyC, const Polygon<T>& poly) {
356 365
   }
357 366
 
358 367
   // also check the last hop
359
-  if (!contains(LineSegment<T>(polyC.getOuter().back(), polyC.getOuter().front()),
360
-                poly))
368
+  if (!contains(
369
+          LineSegment<T>(polyC.getOuter().back(), polyC.getOuter().front()),
370
+          poly))
361 371
     return false;
362 372
 
363 373
   return true;
@@ -628,6 +638,34 @@ inline bool intersects(const Box<T>& b, const Point<T>& p) {
628 638
 }
629 639
 
630 640
 // _____________________________________________________________________________
641
+template <template <typename> class GeometryA,
642
+          template <typename> class GeometryB, typename T>
643
+inline bool intersects(const std::vector<GeometryA<T>>& multigeom,
644
+                       const GeometryB<T>& b) {
645
+  for (const auto& geom : multigeom)
646
+    if (intersects(geom, b)) return true;
647
+  return false;
648
+}
649
+
650
+// _____________________________________________________________________________
651
+template <template <typename> class GeometryA,
652
+          template <typename> class GeometryB, typename T>
653
+inline bool intersects(const GeometryB<T>& b,
654
+                       const std::vector<GeometryA<T>>& multigeom) {
655
+  return intersects(multigeom, b);
656
+}
657
+
658
+// _____________________________________________________________________________
659
+template <template <typename> class GeometryA,
660
+          template <typename> class GeometryB, typename T>
661
+inline bool intersects(const std::vector<GeometryA<T>>& multigeomA,
662
+                       const std::vector<GeometryA<T>>& multigeomB) {
663
+  for (const auto& geom : multigeomA)
664
+    if (intersects(geom, multigeomB)) return true;
665
+  return false;
666
+}
667
+
668
+// _____________________________________________________________________________
631 669
 template <typename T>
632 670
 inline Point<T> intersection(T p1x, T p1y, T q1x, T q1y, T p2x, T p2y, T q2x,
633 671
                              T q2y) {
@@ -778,6 +816,36 @@ inline double dist(const Line<T>& la, const Line<T>& lb) {
778 816
 }
779 817
 
780 818
 // _____________________________________________________________________________
819
+template <template <typename> class GeometryA,
820
+          template <typename> class GeometryB, typename T>
821
+inline double dist(const std::vector<GeometryA<T>>& multigeom,
822
+                   const GeometryB<T>& b) {
823
+  double d = std::numeric_limits<double>::infinity();
824
+  for (const auto& geom : multigeom)
825
+    if (dist(geom, b) < d) d = dist(geom, b);
826
+  return d;
827
+}
828
+
829
+// _____________________________________________________________________________
830
+template <template <typename> class GeometryA,
831
+          template <typename> class GeometryB, typename T>
832
+inline double dist(const GeometryB<T>& b,
833
+                   const std::vector<GeometryA<T>>& multigeom) {
834
+  return dist(multigeom, b);
835
+}
836
+
837
+// _____________________________________________________________________________
838
+template <template <typename> class GeometryA,
839
+          template <typename> class GeometryB, typename T>
840
+inline double dist(const std::vector<GeometryA<T>>& multigeomA,
841
+                   const std::vector<GeometryB<T>>& multigeomB) {
842
+  double d = std::numeric_limits<double>::infinity();
843
+  for (const auto& geom : multigeomB)
844
+    if (dist(geom, multigeomA) < d) d = dist(geom, multigeomA);
845
+  return d;
846
+}
847
+
848
+// _____________________________________________________________________________
781 849
 inline double innerProd(double x1, double y1, double x2, double y2, double x3,
782 850
                         double y3) {
783 851
   double dx21 = x2 - x1;
@@ -1242,6 +1310,40 @@ inline Box<T> getBoundingBox(const std::vector<Geometry<T>>& multigeo) {
1242 1310
 
1243 1311
 // _____________________________________________________________________________
1244 1312
 template <typename T>
1313
+inline double getEnclosingRadius(const Point<T>& p, const Point<T>& pp) {
1314
+  return dist(p, pp);
1315
+}
1316
+
1317
+// _____________________________________________________________________________
1318
+template <typename T>
1319
+inline double getEnclosingRadius(const Point<T>& p, const Line<T>& l) {
1320
+  double ret = 0;
1321
+  for (const auto& pp : l)
1322
+    if (getEnclosingRadius(p, pp) > ret) ret = getEnclosingRadius(p, pp);
1323
+  return ret;
1324
+}
1325
+
1326
+// _____________________________________________________________________________
1327
+template <typename T>
1328
+inline double getEnclosingRadius(const Point<T>& p, const Polygon<T>& pg) {
1329
+  double ret = 0;
1330
+  for (const auto& pp : pg.getOuter())
1331
+    if (getEnclosingRadius(p, pp) > ret) ret = getEnclosingRadius(p, pp);
1332
+  return ret;
1333
+}
1334
+
1335
+// _____________________________________________________________________________
1336
+template <template <typename> class Geometry, typename T>
1337
+inline double getEnclosingRadius(const Point<T>& p,
1338
+                                 const std::vector<Geometry<T>>& multigeom) {
1339
+  double ret = 0;
1340
+  for (const auto& pp : multigeom)
1341
+    if (getEnclosingRadius(p, pp) > ret) ret = getEnclosingRadius(p, pp);
1342
+  return ret;
1343
+}
1344
+
1345
+// _____________________________________________________________________________
1346
+template <typename T>
1245 1347
 inline Polygon<T> convexHull(const Point<T>& p) {
1246 1348
   return Polygon<T>({p});
1247 1349
 }
@@ -1277,7 +1379,7 @@ inline size_t convexHullImpl(const MultiPoint<T>& a, size_t p1, size_t p2,
1277 1379
   for (const auto& p : a) {
1278 1380
     double tmpDist = distToSegment((*h)[p1], (*h)[p2], p);
1279 1381
     double cp = crossProd(p, LineSegment<T>((*h)[p1], (*h)[p2]));
1280
-    if ((cp > 0) && tmpDist > maxDist) {
1382
+    if ((cp > 0 + EPSILON) && tmpDist > maxDist) {
1281 1383
       pa = p;
1282 1384
       found = true;
1283 1385
       maxDist = tmpDist;
@@ -1308,7 +1410,7 @@ inline Polygon<T> convexHull(const MultiPoint<T>& l) {
1308 1410
   convexHullImpl(l, 0, 1, &hull);
1309 1411
   hull.push_back(hull.front());
1310 1412
   convexHullImpl(l, hull.size() - 2, hull.size() - 1, &hull);
1311
-	hull.pop_back();
1413
+  hull.pop_back();
1312 1414
 
1313 1415
   return Polygon<T>(hull);
1314 1416
 }
@@ -1357,6 +1459,181 @@ inline Box<T> extendBox(const std::vector<Geometry<T>>& multigeom, Box<T> b) {
1357 1459
 
1358 1460
 // _____________________________________________________________________________
1359 1461
 template <typename T>
1462
+Point<T> pointAt(const Line<T> l, double at) {
1463
+  return pointAtDist(l, at * len(l));
1464
+}
1465
+
1466
+// _____________________________________________________________________________
1467
+template <typename T>
1468
+Point<T> pointAt(const Line<T> l, double at, size_t* lastI, double* totPos) {
1469
+  return pointAtDist(l, at * len(l), lastI, totPos);
1470
+}
1471
+
1472
+// _____________________________________________________________________________
1473
+template <typename T>
1474
+Point<T> pointAtDist(const Line<T> l, double atDist) {
1475
+  return pointAtDist(l, atDist, 0, 0);
1476
+}
1477
+
1478
+// _____________________________________________________________________________
1479
+template <typename T>
1480
+Point<T> pointAtDist(const Line<T> l, double atDist, size_t* lastI,
1481
+                     double* totPos) {
1482
+  if (l.size() == 1) {
1483
+    if (lastI) *lastI = 0;
1484
+    if (totPos) *totPos = 0;
1485
+    return l[1];
1486
+  }
1487
+
1488
+  if (atDist > geo::len(l)) atDist = geo::len(l);
1489
+  if (atDist < 0) atDist = 0;
1490
+
1491
+  double dist = 0;
1492
+
1493
+  const Point<T>* last = &l[0];
1494
+
1495
+  for (size_t i = 1; i < l.size(); i++) {
1496
+    const Point<T>& cur = l[i];
1497
+    double d = geo::dist(*last, cur);
1498
+    dist += d;
1499
+
1500
+    if (dist > atDist) {
1501
+      double p = (d - (dist - atDist));
1502
+      if (lastI) *lastI = i - 1;
1503
+      if (totPos) *totPos = atDist / util::geo::len(l);
1504
+      return interpolate(*last, cur, p / dist);
1505
+    }
1506
+
1507
+    last = &l[i];
1508
+  }
1509
+
1510
+  if (lastI) *lastI = l.size() - 1;
1511
+  if (totPos) *totPos = 1;
1512
+  return l.back();
1513
+}
1514
+
1515
+// _____________________________________________________________________________
1516
+template <typename T>
1517
+Point<T> interpolate(const Point<T>& a, const Point<T>& b, double d) {
1518
+  double n1 = b.getX() - a.getX();
1519
+  double n2 = b.getY() - a.getY();
1520
+  return Point<T>(a.getX() + (n1 * d), a.getY() + (n2 * d));
1521
+}
1522
+
1523
+// _____________________________________________________________________________
1524
+template <typename T>
1525
+Line<T> orthoLineAtDist(const Line<T>& l, double d, double length) {
1526
+  Point<T> avgP = pointAtDist(l, d);
1527
+
1528
+  double angle = angBetween(pointAtDist(l, d - 5), pointAtDist(l, d + 5));
1529
+
1530
+  double angleX1 = avgP.getX() + cos(angle + M_PI / 2) * length / 2;
1531
+  double angleY1 = avgP.getY() + sin(angle + M_PI / 2) * length / 2;
1532
+
1533
+  double angleX2 = avgP.getX() + cos(angle + M_PI / 2) * -length / 2;
1534
+  double angleY2 = avgP.getY() + sin(angle + M_PI / 2) * -length / 2;
1535
+
1536
+  return Line<T>{Point<T>(angleX1, angleY1), Point<T>(angleX2, angleY2)};
1537
+}
1538
+
1539
+// _____________________________________________________________________________
1540
+template <typename T>
1541
+Line<T> segment(const Line<T>& line, double a, double b) {
1542
+  if (a > b) {
1543
+    double c = a;
1544
+    a = b;
1545
+    b = c;
1546
+  }
1547
+  size_t startI, endI;
1548
+  auto start = pointAt(line, a, &startI, 0);
1549
+  auto end = pointAt(line, b, &endI, 0);
1550
+
1551
+  return segment(line, start, startI, end, endI);
1552
+}
1553
+
1554
+// _____________________________________________________________________________
1555
+template <typename T>
1556
+Line<T> segment(const Line<T>& line, const Point<T>& start, size_t startI,
1557
+                const Point<T>& end, size_t endI) {
1558
+  Line<T> ret;
1559
+  ret.push_back(start);
1560
+
1561
+  if (startI + 1 <= endI) {
1562
+    ret.insert(ret.end(), line.begin() + startI + 1, line.begin() + endI + 1);
1563
+  }
1564
+  ret.push_back(end);
1565
+
1566
+  // find a more performant way to clear the result of above
1567
+  ret = util::geo::simplify(ret, 0);
1568
+
1569
+  assert(ret.size());
1570
+
1571
+  return ret;
1572
+}
1573
+
1574
+// _____________________________________________________________________________
1575
+template <typename T>
1576
+Line<T> average(const std::vector<const Line<T>*>& lines) {
1577
+  return average(lines, std::vector<double>());
1578
+}
1579
+
1580
+// _____________________________________________________________________________
1581
+template <typename T>
1582
+Line<T> average(const std::vector<const Line<T>*>& lines,
1583
+                const std::vector<double>& weights) {
1584
+  bool weighted = lines.size() == weights.size();
1585
+  double stepSize;
1586
+
1587
+  double longestLength =
1588
+      std::numeric_limits<double>::min();  // avoid recalc of length on each
1589
+                                           // comparision
1590
+  for (auto p : lines) {
1591
+    if (len(*p) > longestLength) {
1592
+      longestLength = len(*p);
1593
+    }
1594
+  }
1595
+
1596
+  Line<T> ret;
1597
+  double total = 0;
1598
+
1599
+  for (size_t i = 0; i < lines.size(); ++i) {
1600
+    if (weighted) {
1601
+      total += weights[i];
1602
+    } else {
1603
+      total += 1;
1604
+    }
1605
+  }
1606
+
1607
+  stepSize = AVERAGING_STEP / longestLength;
1608
+  bool end = false;
1609
+  for (double a = 0; !end; a += stepSize) {
1610
+    if (a > 1) {
1611
+      a = 1;
1612
+      end = true;
1613
+    }
1614
+    double x = 0, y = 0;
1615
+
1616
+    for (size_t i = 0; i < lines.size(); ++i) {
1617
+      auto pl = lines[i];
1618
+      Point<T> p = pointAt(*pl, a);
1619
+      if (weighted) {
1620
+        x += p.getX() * weights[i];
1621
+        y += p.getY() * weights[i];
1622
+      } else {
1623
+        x += p.getX();
1624
+        y += p.getY();
1625
+      }
1626
+    }
1627
+    ret.push_back(Point<T>(x / total, y / total));
1628
+  }
1629
+
1630
+  simplify(ret, 0);
1631
+
1632
+  return ret;
1633
+}
1634
+
1635
+// _____________________________________________________________________________
1636
+template <typename T>
1360 1637
 inline double area(const Point<T>& b) {
1361 1638
   UNUSED(b);
1362 1639
   return 0;
@@ -1624,7 +1901,7 @@ inline double webMercDistFactor(const G& a) {
1624 1901
   double lat = 2 * atan(exp(a.getY() / 6378137.0)) - 1.5707965;
1625 1902
   return cos(lat);
1626 1903
 }
1627
-}
1628
-}
1904
+}  // namespace geo
1905
+}  // namespace util
1629 1906
 
1630 1907
 #endif  // UTIL_GEO_GEO_H_

+ 3 - 3
src/util/geo/Grid.h

@@ -55,6 +55,9 @@ class Grid {
55 55
   size_t getXWidth() const;
56 56
   size_t getYHeight() const;
57 57
 
58
+  size_t getCellXFromX(double lon) const;
59
+  size_t getCellYFromY(double lat) const;
60
+
58 61
  private:
59 62
   double _width;
60 63
   double _height;
@@ -76,9 +79,6 @@ class Grid {
76 79
   std::set<V> _removed;
77 80
 
78 81
   Box<T> getBox(size_t x, size_t y) const;
79
-
80
-  size_t getCellXFromX(double lon) const;
81
-  size_t getCellYFromY(double lat) const;
82 82
 };
83 83
 
84 84
 #include "util/geo/Grid.tpp"

+ 2 - 1
src/util/geo/Grid.tpp

@@ -29,6 +29,7 @@ Grid<V, G, T>::Grid(double w, double h, const Box<T>& bbox, bool bValIdx)
29 29
       _cellHeight(fabs(h)),
30 30
       _bb(bbox),
31 31
       _hasValIdx(bValIdx) {
32
+
32 33
   _width =
33 34
       bbox.getUpperRight().getX() - bbox.getLowerLeft().getX();
34 35
   _height =
@@ -107,7 +108,7 @@ void Grid<V, G, T>::get(const G<T>& geom, double d, std::set<V>* s) const {
107 108
 // _____________________________________________________________________________
108 109
 template <typename V, template <typename> class G, typename T>
109 110
 void Grid<V, G, T>::get(size_t x, size_t y, std::set<V>* s) const {
110
-  if (_hasValIdx) {
111
+  if (_hasValIdx || _removed.size() == 0) {
111 112
     s->insert(_grid[x][y].begin(), _grid[x][y].end());
112 113
   } else {
113 114
     // if we dont have a value index, we have a set of deleted nodes.

+ 2 - 3
src/util/geo/PolyLine.h

@@ -17,7 +17,6 @@ namespace util {
17 17
 namespace geo {
18 18
 
19 19
 static const double MAX_EQ_DISTANCE = 15;
20
-static const double AVERAGING_STEP = 20;
21 20
 
22 21
 // legacy code, will be removed in the future
23 22
 
@@ -61,11 +60,11 @@ class PolyLine {
61 60
   PolyLine& operator>>(const Point<T>& p);
62 61
 
63 62
   void reverse();
64
-  PolyLine getReversed() const;
63
+  PolyLine reversed() const;
65 64
 
66 65
   void offsetPerp(double units);
67 66
 
68
-  PolyLine getPerpOffsetted(double units) const;
67
+  PolyLine offsetted(double units) const;
69 68
 
70 69
   const Line<T>& getLine() const;
71 70
 

+ 11 - 4
src/util/geo/PolyLine.tpp

@@ -38,7 +38,7 @@ void PolyLine<T>::reverse() {
38 38
 
39 39
 // _____________________________________________________________________________
40 40
 template <typename T>
41
-PolyLine<T> PolyLine<T>::getReversed() const {
41
+PolyLine<T> PolyLine<T>::reversed() const {
42 42
   PolyLine ret = *this;
43 43
   ret.reverse();
44 44
   return ret;
@@ -52,7 +52,7 @@ const Line<T>& PolyLine<T>::getLine() const {
52 52
 
53 53
 // _____________________________________________________________________________
54 54
 template <typename T>
55
-PolyLine<T> PolyLine<T>::getPerpOffsetted(double units) const {
55
+PolyLine<T> PolyLine<T>::offsetted(double units) const {
56 56
   PolyLine p = *this;
57 57
   p.offsetPerp(units);
58 58
   return p;
@@ -191,6 +191,8 @@ PolyLine<T> PolyLine<T>::getSegment(const LinePoint<T>& start,
191 191
   // find a more performant way to clear the result of above
192 192
   ret.simplify(0);
193 193
 
194
+  assert(ret.getLine().size());
195
+
194 196
   return ret;
195 197
 }
196 198
 
@@ -475,7 +477,7 @@ SharedSegments<T> PolyLine<T>::getSharedSegments(const PolyLine<T>& pl,
475 477
    */
476 478
   double STEP_SIZE = 2;
477 479
   double MAX_SKIPS = 4;
478
-  double MIN_SEG_LENGTH = 1;  // dmax / 2;  // make this configurable!
480
+  double MIN_SEG_LENGTH = 0.1;  // dmax / 2;  // make this configurable!
479 481
 
480 482
   SharedSegments<T> ret;
481 483
 
@@ -499,17 +501,22 @@ SharedSegments<T> PolyLine<T>::getSharedSegments(const PolyLine<T>& pl,
499 501
 
500 502
     double totalDist = dist(s, e);
501 503
     while (curSegDist <= totalDist) {
502
-      const Point<T>& curPointer = interpolate(s, e, curSegDist);
504
+      const auto& curPointer = interpolate(s, e, curSegDist);
503 505
 
504 506
       if (pl.distTo(curPointer) <= dmax) {
505 507
         LinePoint<T> curCmpPointer = pl.projectOn(curPointer);
506 508
         LinePoint<T> curBackProjectedPointer = projectOn(curCmpPointer.p);
509
+
507 510
         skips = 0;
508 511
 
509 512
         if (in) {
510 513
           curEndCand = curBackProjectedPointer;
511 514
           curEndCandCmp = curCmpPointer;
512 515
 
516
+          if (curEndCand.totalPos < curStartCand.totalPos) {
517
+            curEndCand = curStartCand;
518
+          }
519
+
513 520
           single = false;
514 521
 
515 522
           comp = fabs(curStartCand.totalPos * length -

+ 89 - 0
src/util/geo/QuadTree.h

@@ -0,0 +1,89 @@
1
+// Copyright 2020, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_QUADTREE_H_
6
+#define UTIL_GEO_QUADTREE_H_
7
+
8
+#include <map>
9
+#include <set>
10
+#include <vector>
11
+#include "util/geo/Geo.h"
12
+
13
+namespace util {
14
+namespace geo {
15
+
16
+template <typename V, typename T>
17
+struct QuadValue {
18
+  V val;           // the actual value of this entry
19
+  Point<T> point;  // the value's position
20
+
21
+  int64_t nextValue;  // index of the next quad value, -1 means no next value
22
+};
23
+
24
+template <typename T>
25
+struct QuadNode {
26
+  int64_t numEls;  // number of elements, -1 if this is not a leaf node
27
+  int64_t childs;  // for leafs, points to the first value contained. for
28
+                   // other nodes, points to the array block containing the
29
+                   // 4 childs
30
+  Box<T> bbox;
31
+};
32
+
33
+template <typename V, typename T>
34
+struct SplitFunc {
35
+  virtual ~SplitFunc() = default;
36
+  virtual bool operator()(const QuadNode<T>& nd,
37
+                       const QuadValue<V, T>& newVal) const = 0;
38
+};
39
+
40
+template <typename V, typename T>
41
+struct CapaSplitFunc : SplitFunc<V, T> {
42
+  CapaSplitFunc(size_t c) : _c(c) {}
43
+  virtual bool operator()(const QuadNode<T>& nd,
44
+                       const QuadValue<V, T>& newVal) const {
45
+    return static_cast<size_t>(nd.numEls) + 1 > _c;
46
+  }
47
+  size_t _c;
48
+};
49
+
50
+// QuadTree for point data (and only point data)
51
+template <typename V, typename T>
52
+class QuadTree {
53
+ public:
54
+  // initialization of a quad tree with maximum depth d and maximum node // capacity c
55
+  QuadTree(size_t d, size_t c, const Box<T>& bbox);
56
+
57
+  QuadTree(size_t d, const SplitFunc<V, T>& splitF, const Box<T>& bbox);
58
+
59
+  // insert into the tree
60
+  void insert(const V& val, const Point<T>& point);
61
+
62
+  // insert into a specific node
63
+  void insert(int64_t vid, int64_t nid, size_t d);
64
+
65
+  size_t size() const;
66
+
67
+  const std::vector<QuadNode<T>>& getNds() const;
68
+  const QuadNode<T>& getNd(size_t nid) const;
69
+
70
+ private:
71
+  size_t _maxDepth;
72
+  std::vector<QuadValue<V, T>> _vals;
73
+  std::vector<QuadNode<T>> _nds;
74
+
75
+  CapaSplitFunc<V, T> _capaFunc;
76
+
77
+  const SplitFunc<V, T>& _splFunc;
78
+
79
+
80
+  // split a node
81
+  void split(size_t nid, size_t d);
82
+};
83
+
84
+#include "util/geo/QuadTree.tpp"
85
+
86
+}  // namespace geo
87
+}  // namespace util
88
+
89
+#endif  // UTIL_GEO_QUADTREE_H_

+ 107 - 0
src/util/geo/QuadTree.tpp

@@ -0,0 +1,107 @@
1
+// _____________________________________________________________________________
2
+template <typename V, typename T>
3
+QuadTree<V, T>::QuadTree(size_t d, size_t c, const Box<T>& bbox)
4
+    : _maxDepth(d), _capaFunc(c), _splFunc(_capaFunc) {
5
+  _nds.push_back(QuadNode<T>{0, 0, bbox});
6
+}
7
+
8
+// _____________________________________________________________________________
9
+template <typename V, typename T>
10
+QuadTree<V, T>::QuadTree(size_t d, const SplitFunc<V, T>& splitF,
11
+                         const Box<T>& bbox)
12
+    : _maxDepth(d), _capaFunc(0), _splFunc(splitF) {
13
+  _nds.push_back(QuadNode<T>{0, 0, bbox});
14
+}
15
+
16
+// _____________________________________________________________________________
17
+template <typename V, typename T>
18
+void QuadTree<V, T>::insert(const V& val, const Point<T>& pos) {
19
+  if (!intersects(pos, _nds[0].bbox)) return;
20
+  int64_t valId = _vals.size();
21
+  _vals.push_back(QuadValue<V, T>{val, pos, -1});
22
+  _vals[valId].nextValue = -1;
23
+  insert(valId, 0, 0);
24
+}
25
+
26
+// _____________________________________________________________________________
27
+template <typename V, typename T>
28
+void QuadTree<V, T>::insert(int64_t vid, int64_t nid, size_t d) {
29
+  if (!intersects(_vals[vid].point, _nds[nid].bbox)) return;
30
+
31
+  if (d < _maxDepth && _nds[nid].numEls > -1 &&
32
+      _splFunc(_nds[nid], _vals[vid])) {
33
+    split(nid, d);
34
+  }
35
+
36
+  if (_nds[nid].numEls == -1) {
37
+    // insert into fitting subtree
38
+    for (size_t i = 0; i < 4; i++) insert(vid, _nds[nid].childs + i, d + 1);
39
+  } else {
40
+    if (_nds[nid].numEls == 0) {
41
+      _nds[nid].childs = vid;
42
+    } else {
43
+      _vals[vid].nextValue = _nds[nid].childs;
44
+      _nds[nid].childs = vid;
45
+    }
46
+    _nds[nid].numEls++;
47
+  }
48
+}
49
+
50
+// _____________________________________________________________________________
51
+template <typename V, typename T>
52
+void QuadTree<V, T>::split(size_t nid, size_t d) {
53
+  const auto& box = _nds[nid].bbox;
54
+  T w = (box.getUpperRight().getX() - box.getLowerLeft().getX()) / T(2);
55
+
56
+  int64_t curEl = _nds[nid].numEls > 0 ? _nds[nid].childs : -1;
57
+
58
+  _nds[nid].numEls = -1;           // the node is now a leaf node
59
+  _nds[nid].childs = _nds.size();  // the nodes quadrant block starts here
60
+
61
+  // box at 0, 0
62
+  _nds.push_back(QuadNode<T>{
63
+      0, 0,
64
+      Box<T>(box.getLowerLeft(), Point<T>(box.getLowerLeft().getX() + w,
65
+                                          box.getLowerLeft().getY() + w))});
66
+  // box at 0, 1
67
+  _nds.push_back(QuadNode<T>{
68
+      0, 0,
69
+      Box<T>(Point<T>(box.getLowerLeft().getX() + w, box.getLowerLeft().getY()),
70
+             Point<T>(box.getUpperRight().getX(),
71
+                      box.getLowerLeft().getY() + w))});
72
+  // box at 1,0
73
+  _nds.push_back(QuadNode<T>{
74
+      0, 0,
75
+      Box<T>(Point<T>(box.getLowerLeft().getX(), box.getLowerLeft().getY() + w),
76
+             Point<T>(box.getLowerLeft().getX() + w,
77
+                      box.getUpperRight().getY()))});
78
+  // box at 1,1
79
+  _nds.push_back(QuadNode<T>{0, 0,
80
+                             Box<T>(Point<T>(box.getLowerLeft().getX() + w,
81
+                                             box.getLowerLeft().getY() + w),
82
+                                    box.getUpperRight())});
83
+
84
+  while (curEl > -1) {
85
+    _vals[curEl].nextValue = -1;
86
+    insert(curEl, nid, d + 1);
87
+    curEl = _vals[curEl].nextValue;
88
+  }
89
+}
90
+
91
+// _____________________________________________________________________________
92
+template <typename V, typename T>
93
+size_t QuadTree<V, T>::size() const {
94
+  return _vals.size();
95
+}
96
+
97
+// _____________________________________________________________________________
98
+template <typename V, typename T>
99
+const QuadNode<T>& QuadTree<V, T>::getNd(size_t nid) const {
100
+  return _nds[nid];
101
+}
102
+
103
+// _____________________________________________________________________________
104
+template <typename V, typename T>
105
+const std::vector<QuadNode<T>>& QuadTree<V, T>::getNds() const {
106
+  return _nds;
107
+}

+ 10 - 0
src/util/geo/output/GeoGraphJsonOutput.h

@@ -18,13 +18,23 @@ namespace output {
18 18
 class GeoGraphJsonOutput {
19 19
  public:
20 20
   inline GeoGraphJsonOutput(){};
21
+
22
+  // print a graph to the provided path
21 23
   template <typename N, typename E>
22 24
   void print(const util::graph::Graph<N, E>& outG, std::ostream& str);
23 25
 
26
+  // print a graph to the provided path, but treat coordinates as Web Mercator coordinates and reproject to WGS84
27
+  template <typename N, typename E>
28
+  void printLatLng(const util::graph::Graph<N, E>& outG, std::ostream& str);
29
+
24 30
  private:
25 31
   template <typename T>
26 32
   Line<T> createLine(const util::geo::Point<T>& a,
27 33
                      const util::geo::Point<T>& b);
34
+
35
+  // print a graph to the provided path
36
+  template <typename N, typename E>
37
+  void printImpl(const util::graph::Graph<N, E>& outG, std::ostream& str, bool proj);
28 38
 };
29 39
 
30 40
 #include "util/geo/output/GeoGraphJsonOutput.tpp"

+ 29 - 3
src/util/geo/output/GeoGraphJsonOutput.tpp

@@ -16,6 +16,20 @@ Line<T> GeoGraphJsonOutput::createLine(const util::geo::Point<T>& a,
16 16
 template <typename N, typename E>
17 17
 void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
18 18
                                std::ostream& str) {
19
+  printImpl(outG, str, false);
20
+}
21
+
22
+// _____________________________________________________________________________
23
+template <typename N, typename E>
24
+void GeoGraphJsonOutput::printLatLng(const util::graph::Graph<N, E>& outG,
25
+                               std::ostream& str) {
26
+  printImpl(outG, str, true);
27
+}
28
+
29
+// _____________________________________________________________________________
30
+template <typename N, typename E>
31
+void GeoGraphJsonOutput::printImpl(const util::graph::Graph<N, E>& outG,
32
+                               std::ostream& str, bool proj) {
19 33
   GeoJsonOutput _out(str);
20 34
 
21 35
   // first pass, nodes
@@ -30,7 +44,11 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
30 44
     auto addProps = n->pl().getAttrs();
31 45
     props.insert(addProps.begin(), addProps.end());
32 46
 
33
-    _out.print(*n->pl().getGeom(), props);
47
+    if (proj) {
48
+      _out.printLatLng(*n->pl().getGeom(), props);
49
+    } else {
50
+      _out.print(*n->pl().getGeom(), props);
51
+    }
34 52
   }
35 53
 
36 54
   // second pass, edges
@@ -50,11 +68,19 @@ void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
50 68
           auto a = *e->getFrom()->pl().getGeom();
51 69
           if (e->getTo()->pl().getGeom()) {
52 70
             auto b = *e->getTo()->pl().getGeom();
53
-            _out.print(createLine(a, b), props);
71
+            if (proj) {
72
+              _out.printLatLng(createLine(a, b), props);
73
+            } else {
74
+              _out.print(createLine(a, b), props);
75
+            }
54 76
           }
55 77
         }
56 78
       } else {
57
-        _out.print(*e->pl().getGeom(), props);
79
+        if (proj) {
80
+          _out.printLatLng(*e->pl().getGeom(), props);
81
+        } else {
82
+          _out.print(*e->pl().getGeom(), props);
83
+        }
58 84
       }
59 85
     }
60 86
   }

+ 10 - 2
src/util/geo/output/GeoJsonOutput.h

@@ -5,9 +5,9 @@
5 5
 #ifndef UTIL_GEO_OUTPUT_GEOJSONOUTPUT_H_
6 6
 #define UTIL_GEO_OUTPUT_GEOJSONOUTPUT_H_
7 7
 
8
+#include <map>
8 9
 #include <ostream>
9 10
 #include <string>
10
-#include <map>
11 11
 #include "util/String.h"
12 12
 #include "util/geo/Geo.h"
13 13
 #include "util/json/Writer.h"
@@ -21,10 +21,19 @@ class GeoJsonOutput {
21 21
   GeoJsonOutput(std::ostream& str);
22 22
   GeoJsonOutput(std::ostream& str, json::Val attrs);
23 23
   ~GeoJsonOutput();
24
+
24 25
   template <typename T>
25 26
   void print(const Point<T>& p, json::Val attrs);
27
+
26 28
   template <typename T>
27 29
   void print(const Line<T>& l, json::Val attrs);
30
+
31
+  template <typename T>
32
+  void printLatLng(const Point<T>& p, json::Val attrs);
33
+
34
+  template <typename T>
35
+  void printLatLng(const Line<T>& l, json::Val attrs);
36
+
28 37
   void flush();
29 38
 
30 39
  private:
@@ -32,7 +41,6 @@ class GeoJsonOutput {
32 41
 };
33 42
 
34 43
 #include "util/geo/output/GeoJsonOutput.tpp"
35
-
36 44
 }
37 45
 }
38 46
 }

+ 16 - 0
src/util/geo/output/GeoJsonOutput.tpp

@@ -46,3 +46,19 @@ void GeoJsonOutput::print(const Line<T>& line, json::Val attrs) {
46 46
   _wr.val(attrs);
47 47
   _wr.close();
48 48
 }
49
+
50
+// _____________________________________________________________________________
51
+template <typename T>
52
+void GeoJsonOutput::printLatLng(const Point<T>& p, json::Val attrs) {
53
+  auto projP = util::geo::webMercToLatLng<double>(p.getX(), p.getY());
54
+  print(projP, attrs);
55
+}
56
+
57
+// _____________________________________________________________________________
58
+template <typename T>
59
+void GeoJsonOutput::printLatLng(const Line<T>& line, json::Val attrs) {
60
+  Line<T> projL;
61
+  for (auto p : line) projL.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
62
+
63
+  print(projL, attrs);
64
+}

+ 15 - 2
src/util/graph/Algorithm.h

@@ -7,8 +7,8 @@
7 7
 
8 8
 #include <stack>
9 9
 #include "util/graph/Edge.h"
10
-#include "util/graph/UndirGraph.h"
11 10
 #include "util/graph/Node.h"
11
+#include "util/graph/UndirGraph.h"
12 12
 
13 13
 namespace util {
14 14
 namespace graph {
@@ -21,12 +21,25 @@ using util::graph::Edge;
21 21
 class Algorithm {
22 22
  public:
23 23
   template <typename N, typename E>
24
+  struct EdgeCheckFunc {
25
+    virtual bool operator()(const Node<N, E>* frNd,
26
+                            const Edge<N, E>* edge) const {
27
+      UNUSED(frNd);
28
+      UNUSED(edge);
29
+      return true;
30
+    };
31
+  };
32
+
33
+  template <typename N, typename E>
24 34
   static std::vector<std::set<Node<N, E>*> > connectedComponents(
25 35
       const UndirGraph<N, E>& g);
36
+
37
+  template <typename N, typename E>
38
+  static std::vector<std::set<Node<N, E>*> > connectedComponents(
39
+      const UndirGraph<N, E>& g, const EdgeCheckFunc<N, E>& checkFunc);
26 40
 };
27 41
 
28 42
 #include "util/graph/Algorithm.tpp"
29
-
30 43
 }
31 44
 }
32 45
 

+ 10 - 2
src/util/graph/Algorithm.tpp

@@ -1,11 +1,18 @@
1 1
 // Copyright 2017, University of Freiburg,
2 2
 // Chair of Algorithms and Data Structures.
3 3
 // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
-
4
+//
5 5
 // _____________________________________________________________________________
6 6
 template <typename N, typename E>
7
-std::vector<std::set<Node<N, E>*> > Algorithm::connectedComponents(
7
+std::vector<std::set<Node<N, E>*>> Algorithm::connectedComponents(
8 8
     const UndirGraph<N, E>& g) {
9
+  return connectedComponents(g, EdgeCheckFunc<N, E>());
10
+}
11
+
12
+// _____________________________________________________________________________
13
+template <typename N, typename E>
14
+std::vector<std::set<Node<N, E>*>> Algorithm::connectedComponents(
15
+    const UndirGraph<N, E>& g, const EdgeCheckFunc<N, E>& checkFunc) {
9 16
   std::vector<std::set<Node<N, E>*>> ret;
10 17
   std::set<Node<N, E>*> visited;
11 18
 
@@ -22,6 +29,7 @@ std::vector<std::set<Node<N, E>*> > Algorithm::connectedComponents(
22 29
         visited.insert(cur);
23 30
 
24 31
         for (auto* e : cur->getAdjList()) {
32
+          if (!checkFunc(cur, e)) continue;
25 33
           if (!visited.count(e->getOtherNd(cur))) q.push(e->getOtherNd(cur));
26 34
         }
27 35
       }

+ 7 - 0
src/util/graph/BiDijkstra.cpp

@@ -0,0 +1,7 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include "util/graph/BiDijkstra.h"
6
+
7
+size_t util::graph::BiDijkstra::ITERS = 0;

+ 129 - 0
src/util/graph/BiDijkstra.h

@@ -0,0 +1,129 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_BIDIJKSTRA_H_
6
+#define UTIL_GRAPH_BIDIJKSTRA_H_
7
+
8
+#include <limits>
9
+#include <list>
10
+#include <queue>
11
+#include <set>
12
+#include <algorithm>
13
+#include <unordered_map>
14
+#include "util/graph/Edge.h"
15
+#include "util/graph/Graph.h"
16
+#include "util/graph/Node.h"
17
+#include "util/graph/ShortestPath.h"
18
+
19
+namespace util {
20
+namespace graph {
21
+
22
+using util::graph::Edge;
23
+using util::graph::Graph;
24
+using util::graph::Node;
25
+
26
+// bidirectional dijkstras algorithm for util graph
27
+class BiDijkstra : public ShortestPath<BiDijkstra> {
28
+ public:
29
+  template <typename N, typename E, typename C>
30
+  struct RouteNode {
31
+    RouteNode() : n(0), parent(0), d(), h() {}
32
+    RouteNode(Node<N, E>* n) : n(n), parent(0), d(), h() {}
33
+    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d)
34
+        : n(n), parent(parent), d(d), h() {}
35
+    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d, C h)
36
+        : n(n), parent(parent), d(d), h(h) {}
37
+
38
+    Node<N, E>* n;
39
+    Node<N, E>* parent;
40
+
41
+    // the cost so far
42
+    C d;
43
+
44
+    // the heuristical remaining cost + the cost so far
45
+    C h;
46
+
47
+    bool operator<(const RouteNode<N, E, C>& p) const { return h > p.h; }
48
+  };
49
+
50
+  template <typename N, typename E, typename C>
51
+  using Settled = std::unordered_map<Node<N, E>*, RouteNode<N, E, C> >;
52
+
53
+  template <typename N, typename E, typename C>
54
+  using PQ = std::priority_queue<RouteNode<N, E, C> >;
55
+
56
+  template <typename N, typename E, typename C>
57
+  struct CostFunc : public util::graph::CostFunc<N, E, C> {
58
+    virtual ~CostFunc() = default; C operator()(const Edge<N, E>* from, const Node<N, E>* n,
59
+                 const Edge<N, E>* to) const {
60
+      UNUSED(from);
61
+      UNUSED(n);
62
+      UNUSED(to);
63
+      return C();
64
+    };
65
+  };
66
+
67
+  template <typename N, typename E, typename C>
68
+  struct HeurFunc : public util::graph::HeurFunc<N, E, C> {
69
+    virtual ~HeurFunc() = default;
70
+    C operator()(const Edge<N, E>* from,
71
+                 const std::set<Edge<N, E>*>& to) const {
72
+      UNUSED(from);
73
+      UNUSED(to);
74
+      return C();
75
+    };
76
+  };
77
+
78
+  template <typename N, typename E, typename C>
79
+  static std::unordered_map<Node<N, E>*, C> shortestPathImpl(
80
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
81
+      const util::graph::CostFunc<N, E, C>& costFunc,
82
+      const util::graph::HeurFunc<N, E, C>&,
83
+      std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
84
+      std::unordered_map<Node<N, E>*, NList<N, E>*> resNode);
85
+
86
+  template <typename N, typename E, typename C>
87
+  static C shortestPathImpl(const std::set<Node<N, E>*> from,
88
+                            const std::set<Node<N, E>*>& to,
89
+                            const util::graph::CostFunc<N, E, C>& costFunc,
90
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
91
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
92
+
93
+  template <typename N, typename E, typename C>
94
+  static C shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
95
+                            const util::graph::CostFunc<N, E, C>& costFunc,
96
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
97
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
98
+
99
+  template <typename N, typename E, typename C>
100
+  static void relax(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
101
+                    const util::graph::CostFunc<N, E, C>& costFunc,
102
+                    const util::graph::HeurFunc<N, E, C>& heurFunc,
103
+                    PQ<N, E, C>& pq);
104
+
105
+  template <typename N, typename E, typename C>
106
+  static C relaxFwd(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
107
+                    const util::graph::CostFunc<N, E, C>& costFunc,
108
+                    const util::graph::HeurFunc<N, E, C>& heurFunc,
109
+                    PQ<N, E, C>& pq, const Settled<N, E, C>& settledBwd);
110
+
111
+  template <typename N, typename E, typename C>
112
+  static C relaxBwd(const std::set<Node<N, E>*>& froms, RouteNode<N, E, C>& cur,
113
+                    const util::graph::CostFunc<N, E, C>& costFunc,
114
+                    const util::graph::HeurFunc<N, E, C>& heurFunc,
115
+                    PQ<N, E, C>& pq, const Settled<N, E, C>& settledFwd);
116
+
117
+  template <typename N, typename E, typename C>
118
+  static void buildPath(Node<N, E>* curN, Settled<N, E, C>& settledFwd,
119
+                        Settled<N, E, C>& settledBwd, NList<N, E>* resNodes,
120
+                        EList<N, E>* resEdges);
121
+
122
+  static size_t ITERS;
123
+};
124
+
125
+#include "util/graph/BiDijkstra.tpp"
126
+}  // namespace graph
127
+}  // namespace util
128
+
129
+#endif  // UTIL_GRAPH_BIDIJKSTRA_H_

+ 283 - 0
src/util/graph/BiDijkstra.tpp

@@ -0,0 +1,283 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E, typename C>
7
+C BiDijkstra::shortestPathImpl(Node<N, E>* from,
8
+                               const std::set<Node<N, E>*>& to,
9
+                               const util::graph::CostFunc<N, E, C>& costFunc,
10
+                               const util::graph::HeurFunc<N, E, C>& heurFunc,
11
+                               EList<N, E>* resEdges, NList<N, E>* resNodes) {
12
+  if (from->getOutDeg() == 0) return costFunc.inf();
13
+
14
+  std::set<Node<N, E>*> froms;
15
+  froms.insert(from);
16
+
17
+  return shortestPathImpl(froms, to, costFunc, heurFunc, resEdges, resNodes);
18
+}
19
+
20
+// _____________________________________________________________________________
21
+template <typename N, typename E, typename C>
22
+C BiDijkstra::shortestPathImpl(const std::set<Node<N, E>*> from,
23
+                               const std::set<Node<N, E>*>& to,
24
+                               const util::graph::CostFunc<N, E, C>& costFunc,
25
+                               const util::graph::HeurFunc<N, E, C>& heurFunc,
26
+                               EList<N, E>* resEdges, NList<N, E>* resNodes) {
27
+  Settled<N, E, C> settledFwd, settledBwd;
28
+  PQ<N, E, C> pqFwd, pqBwd;
29
+  bool found = false;
30
+
31
+  // starter for forward search
32
+  for (auto n : from) pqFwd.emplace(n);
33
+
34
+  auto l = costFunc.inf();
35
+
36
+  // starter for backward search
37
+  for (auto n : to) pqBwd.emplace(n);
38
+
39
+  RouteNode<N, E, C> cur;
40
+
41
+  while (!pqFwd.empty() && !pqBwd.empty()) {
42
+    if (costFunc.inf() <= pqFwd.top().h && costFunc.inf() <= pqBwd.top().h)
43
+      return costFunc.inf();
44
+
45
+    if (pqFwd.top() < pqBwd.top()) {
46
+      auto se = settledBwd.find(pqBwd.top().n);
47
+      if (se != settledBwd.end()) {
48
+        // to allow non-consistent heuristics
49
+        if (se->second.d <= pqBwd.top().d) {
50
+          pqBwd.pop();
51
+          continue;
52
+        }
53
+      }
54
+    } else {
55
+      auto se = settledFwd.find(pqFwd.top().n);
56
+      if (se != settledFwd.end()) {
57
+        // to allow non-consistent heuristics
58
+        if (se->second.d <= pqFwd.top().d) {
59
+          pqFwd.pop();
60
+          continue;
61
+        }
62
+      }
63
+    }
64
+
65
+    BiDijkstra::ITERS++;
66
+
67
+    if (pqFwd.top() < pqBwd.top()) {
68
+      cur = pqBwd.top();
69
+      pqBwd.pop();
70
+      settledBwd[cur.n] = cur;
71
+      if (settledFwd.find(cur.n) != settledFwd.end()) {
72
+        auto newL = cur.d + settledFwd.find(cur.n)->second.d;
73
+
74
+        if (!(newL > l)) {
75
+          l = newL;
76
+          found = true;
77
+          break;
78
+        }
79
+      }
80
+      C bestCost = relaxBwd(from, cur, costFunc, heurFunc, pqBwd, settledFwd);
81
+      if (bestCost < l) l = bestCost;
82
+    } else {
83
+      cur = pqFwd.top();
84
+      pqFwd.pop();
85
+      settledFwd[cur.n] = cur;
86
+      if (settledBwd.find(cur.n) != settledBwd.end()) {
87
+        auto newL = cur.d + settledBwd.find(cur.n)->second.d;
88
+
89
+        if (!(newL > l)) {
90
+          l = newL;
91
+          found = true;
92
+          break;
93
+        }
94
+      }
95
+      C bestCost = relaxFwd(cur, to, costFunc, heurFunc, pqFwd, settledBwd);
96
+      if (bestCost < l) l = bestCost;
97
+    }
98
+  }
99
+
100
+  if (!found) return costFunc.inf();
101
+
102
+  buildPath(cur.n, settledFwd, settledBwd, resNodes, resEdges);
103
+
104
+  return l;
105
+}
106
+
107
+// _____________________________________________________________________________
108
+template <typename N, typename E, typename C>
109
+std::unordered_map<Node<N, E>*, C> BiDijkstra::shortestPathImpl(
110
+    Node<N, E>* from, const std::set<Node<N, E>*>& to,
111
+    const util::graph::CostFunc<N, E, C>& costFunc,
112
+    const util::graph::HeurFunc<N, E, C>& heurFunc,
113
+    std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
114
+    std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
115
+  assert(false);
116
+  // std::unordered_map<Node<N, E>*, C> costs;
117
+  // if (to.size() == 0) return costs;
118
+  // // init costs with inf
119
+  // for (auto n : to) costs[n] = costFunc.inf();
120
+
121
+  // if (from->getOutDeg() == 0) return costs;
122
+  // Settled<N, E, C> settled;
123
+  // PQ<N, E, C> pq;
124
+
125
+  // size_t found = 0;
126
+
127
+  // pq.emplace(from);
128
+  // RouteNode<N, E, C> cur;
129
+
130
+  // while (!pq.empty()) {
131
+  // if (costFunc.inf() <= pq.top().h) return costs;
132
+  // if (settled.find(pq.top().n) != settled.end()) {
133
+  // pq.pop();
134
+  // continue;
135
+  // }
136
+  // BiDijkstra::ITERS++;
137
+
138
+  // cur = pq.top();
139
+  // pq.pop();
140
+
141
+  // settled[cur.n] = cur;
142
+
143
+  // if (to.find(cur.n) != to.end()) {
144
+  // found++;
145
+  // }
146
+
147
+  // if (found == to.size()) break;
148
+
149
+  // relax(cur, to, costFunc, heurFunc, pq);
150
+  // }
151
+
152
+  // for (auto nto : to) {
153
+  // if (!settled.count(nto)) continue;
154
+  // Node<N, E>* curN = nto;
155
+  // costs[nto] = settled[curN].d;
156
+
157
+  // buildPath(nto, settled, resNodes[nto], resEdges[nto]);
158
+  // }
159
+
160
+  // return costs;
161
+}
162
+
163
+// _____________________________________________________________________________
164
+template <typename N, typename E, typename C>
165
+void BiDijkstra::relax(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
166
+                       const util::graph::CostFunc<N, E, C>& costFunc,
167
+                       const util::graph::HeurFunc<N, E, C>& heurFunc,
168
+                       PQ<N, E, C>& pq) {
169
+  for (auto edge : cur.n->getAdjListOut()) {
170
+    C newC = costFunc(cur.n, edge, edge->getOtherNd(cur.n));
171
+    newC = cur.d + newC;
172
+    if (costFunc.inf() <= newC) continue;
173
+
174
+    // addition done here to avoid it in the PQ
175
+    const C& newH = newC + heurFunc(edge->getOtherNd(cur.n), to);
176
+
177
+    pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH);
178
+  }
179
+}
180
+
181
+// _____________________________________________________________________________
182
+template <typename N, typename E, typename C>
183
+C BiDijkstra::relaxFwd(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
184
+                       const util::graph::CostFunc<N, E, C>& costFunc,
185
+                       const util::graph::HeurFunc<N, E, C>& heurFunc,
186
+                       PQ<N, E, C>& pq, const Settled<N, E, C>& settledBwd) {
187
+  C ret = costFunc.inf();
188
+  for (auto edge : cur.n->getAdjListOut()) {
189
+    C newC = costFunc(cur.n, edge, edge->getOtherNd(cur.n));
190
+    newC = cur.d + newC;
191
+    if (costFunc.inf() <= newC) continue;
192
+
193
+    // addition done here to avoid it in the PQ
194
+    // const C& newH = newC + heurFunc(froms, edge->getOtherNd(cur.n));
195
+
196
+    // TODO:
197
+    const C& newH = newC + 0;
198
+
199
+    // update new best found cost
200
+    if (settledBwd.find(edge->getOtherNd(cur.n)) != settledBwd.end()) {
201
+      C bwdCost = settledBwd.find(edge->getOtherNd(cur.n))->second.d + newC;
202
+      if (bwdCost < ret) ret = bwdCost;
203
+    }
204
+
205
+    pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH);
206
+  }
207
+
208
+  return ret;
209
+}
210
+
211
+// _____________________________________________________________________________
212
+template <typename N, typename E, typename C>
213
+C BiDijkstra::relaxBwd(const std::set<Node<N, E>*>& froms,
214
+                       RouteNode<N, E, C>& cur,
215
+                       const util::graph::CostFunc<N, E, C>& costFunc,
216
+                       const util::graph::HeurFunc<N, E, C>& heurFunc,
217
+                       PQ<N, E, C>& pq, const Settled<N, E, C>& settledFwd) {
218
+  C ret = costFunc.inf();
219
+  for (auto edge : cur.n->getAdjListIn()) {
220
+    C newC = costFunc(edge->getOtherNd(cur.n), edge, cur.n);
221
+    newC = cur.d + newC;
222
+    if (costFunc.inf() <= newC) continue;
223
+
224
+    // addition done here to avoid it in the PQ
225
+    // const C& newH = newC + heurFunc(froms, edge->getOtherNd(cur.n));
226
+
227
+    // TODO:
228
+    const C& newH = newC + 0;
229
+
230
+    // update new best found cost
231
+    if (settledFwd.find(edge->getOtherNd(cur.n)) != settledFwd.end()) {
232
+      C fwdCost = settledFwd.find(edge->getOtherNd(cur.n))->second.d + newC;
233
+      if (fwdCost < ret) ret = fwdCost;
234
+    }
235
+
236
+    pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH);
237
+  }
238
+
239
+  return ret;
240
+}
241
+
242
+// _____________________________________________________________________________
243
+template <typename N, typename E, typename C>
244
+void BiDijkstra::buildPath(Node<N, E>* curN, Settled<N, E, C>& settledFwd,
245
+                           Settled<N, E, C>& settledBwd, NList<N, E>* resNodes,
246
+                           EList<N, E>* resEdges) {
247
+  Node<N, E>* curNFwd = curN;
248
+  Node<N, E>* curNBwd = curN;
249
+
250
+  // the forward part
251
+  while (resNodes || resEdges) {
252
+    const RouteNode<N, E, C>& curNode = settledFwd[curNFwd];
253
+    if (resNodes) resNodes->push_back(curNode.n);
254
+    if (!curNode.parent) break;
255
+
256
+    if (resEdges) {
257
+      for (auto e : curNode.n->getAdjListIn()) {
258
+        if (e->getOtherNd(curNode.n) == curNode.parent) resEdges->push_back(e);
259
+      }
260
+    }
261
+    curNFwd = curNode.parent;
262
+  }
263
+
264
+  if (resNodes) std::reverse(resNodes->begin(), resNodes->end());
265
+  if (resEdges) std::reverse(resEdges->begin(), resEdges->end());
266
+
267
+  // the backward part
268
+  while (resNodes || resEdges) {
269
+    const RouteNode<N, E, C>& curNode = settledBwd[curNBwd];
270
+    if (resNodes && curNode.n != curN) resNodes->push_back(curNode.n);
271
+    if (!curNode.parent) break;
272
+
273
+    if (resEdges) {
274
+      for (auto e : curNode.n->getAdjListOut()) {
275
+        if (e->getOtherNd(curNode.n) == curNode.parent) resEdges->push_back(e);
276
+      }
277
+    }
278
+    curNBwd = curNode.parent;
279
+  }
280
+
281
+  if (resNodes) std::reverse(resNodes->begin(), resNodes->end());
282
+  if (resEdges) std::reverse(resEdges->begin(), resEdges->end());
283
+}

+ 1 - 0
src/util/graph/Dijkstra.cpp

@@ -5,3 +5,4 @@
5 5
 #include "util/graph/Dijkstra.h"
6 6
 
7 7
 size_t util::graph::Dijkstra::ITERS = 0;
8
+size_t util::graph::Dijkstra::DBL_VISITS = 0;

+ 29 - 25
src/util/graph/Dijkstra.h

@@ -9,7 +9,6 @@
9 9
 #include <list>
10 10
 #include <queue>
11 11
 #include <set>
12
-#include <set>
13 12
 #include <unordered_map>
14 13
 #include "util/graph/Edge.h"
15 14
 #include "util/graph/Graph.h"
@@ -19,33 +18,32 @@
19 18
 namespace util {
20 19
 namespace graph {
21 20
 
21
+using util::graph::Edge;
22 22
 using util::graph::Graph;
23 23
 using util::graph::Node;
24
-using util::graph::Edge;
25 24
 
26 25
 // dijkstras algorithm for util graph
27 26
 class Dijkstra : public ShortestPath<Dijkstra> {
28 27
  public:
29 28
   template <typename N, typename E, typename C>
30 29
   struct RouteNode {
31
-    RouteNode() : n(0), parent(0), d(), h(), e(0) {}
32
-    RouteNode(Node<N, E>* n) : n(n), parent(0), d(), h(), e(0) {}
33
-    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d, Edge<N, E>* e)
34
-        : n(n), parent(parent), d(d), h(), e(e) {}
35
-    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d, C h, Edge<N, E>* e)
36
-        : n(n), parent(parent), d(d), h(h), e(e) {}
30
+    RouteNode() : n(0), parent(0), d(), h() {}
31
+    RouteNode(Node<N, E>* n) : n(n), parent(0), d(), h() {}
32
+    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d)
33
+        : n(n), parent(parent), d(d), h() {}
34
+    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d, C h)
35
+        : n(n), parent(parent), d(d), h(h) {}
37 36
 
38 37
     Node<N, E>* n;
39 38
     Node<N, E>* parent;
40 39
 
40
+    // the cost so far
41 41
     C d;
42
-    C h;
43 42
 
44
-    Edge<N, E>* e;
43
+    // the heuristical remaining cost + the cost so far
44
+    C h;
45 45
 
46
-    bool operator<(const RouteNode<N, E, C>& p) const {
47
-      return h > p.h || (h == p.h && d > p.d);
48
-    }
46
+    bool operator<(const RouteNode<N, E, C>& p) const { return h > p.h; }
49 47
   };
50 48
 
51 49
   template <typename N, typename E, typename C>
@@ -55,7 +53,8 @@ class Dijkstra : public ShortestPath<Dijkstra> {
55 53
   using PQ = std::priority_queue<RouteNode<N, E, C> >;
56 54
 
57 55
   template <typename N, typename E, typename C>
58
-  struct CostFunc : public ShortestPath::CostFunc<N, E, C> {
56
+  struct CostFunc : public util::graph::CostFunc<N, E, C> {
57
+    virtual ~CostFunc() = default;
59 58
     C operator()(const Edge<N, E>* from, const Node<N, E>* n,
60 59
                  const Edge<N, E>* to) const {
61 60
       UNUSED(from);
@@ -66,7 +65,8 @@ class Dijkstra : public ShortestPath<Dijkstra> {
66 65
   };
67 66
 
68 67
   template <typename N, typename E, typename C>
69
-  struct HeurFunc : public ShortestPath::HeurFunc<N, E, C> {
68
+  struct HeurFunc : public util::graph::HeurFunc<N, E, C> {
69
+    virtual ~HeurFunc() = default;
70 70
     C operator()(const Edge<N, E>* from,
71 71
                  const std::set<Edge<N, E>*>& to) const {
72 72
       UNUSED(from);
@@ -78,36 +78,40 @@ class Dijkstra : public ShortestPath<Dijkstra> {
78 78
   template <typename N, typename E, typename C>
79 79
   static std::unordered_map<Node<N, E>*, C> shortestPathImpl(
80 80
       Node<N, E>* from, const std::set<Node<N, E>*>& to,
81
-      const ShortestPath::CostFunc<N, E, C>& costFunc, const ShortestPath::HeurFunc<N, E, C>&,
81
+      const util::graph::CostFunc<N, E, C>& costFunc,
82
+      const util::graph::HeurFunc<N, E, C>&,
82 83
       std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
83 84
       std::unordered_map<Node<N, E>*, NList<N, E>*> resNode);
84 85
 
85 86
   template <typename N, typename E, typename C>
86
-  static C shortestPathImpl(const std::set<Node<N, E>*> from, const std::set<Node<N, E>*>& to,
87
-                            const ShortestPath::CostFunc<N, E, C>& costFunc,
88
-                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
87
+  static C shortestPathImpl(const std::set<Node<N, E>*> from,
88
+                            const std::set<Node<N, E>*>& to,
89
+                            const util::graph::CostFunc<N, E, C>& costFunc,
90
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
89 91
                             EList<N, E>* resEdges, NList<N, E>* resNodes);
90 92
 
91 93
   template <typename N, typename E, typename C>
92 94
   static C shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
93
-                            const ShortestPath::CostFunc<N, E, C>& costFunc,
94
-                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
95
+                            const util::graph::CostFunc<N, E, C>& costFunc,
96
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
95 97
                             EList<N, E>* resEdges, NList<N, E>* resNodes);
96 98
 
97 99
   template <typename N, typename E, typename C>
98 100
   static void relax(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
99
-                    const ShortestPath::CostFunc<N, E, C>& costFunc,
100
-                    const ShortestPath::HeurFunc<N, E, C>& heurFunc, PQ<N, E, C>& pq);
101
+                    const util::graph::CostFunc<N, E, C>& costFunc,
102
+                    const util::graph::HeurFunc<N, E, C>& heurFunc,
103
+                    PQ<N, E, C>& pq);
101 104
 
102 105
   template <typename N, typename E, typename C>
103 106
   static void buildPath(Node<N, E>* curN, Settled<N, E, C>& settled,
104 107
                         NList<N, E>* resNodes, EList<N, E>* resEdges);
105 108
 
106 109
   static size_t ITERS;
110
+  static size_t DBL_VISITS;
107 111
 };
108 112
 
109 113
 #include "util/graph/Dijkstra.tpp"
110
-}
111
-}
114
+}  // namespace graph
115
+}  // namespace util
112 116
 
113 117
 #endif  // UTIL_GRAPH_DIJKSTRA_H_

+ 41 - 26
src/util/graph/Dijkstra.tpp

@@ -5,8 +5,8 @@
5 5
 // _____________________________________________________________________________
6 6
 template <typename N, typename E, typename C>
7 7
 C Dijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
8
-                             const ShortestPath::CostFunc<N, E, C>& costFunc,
9
-                             const ShortestPath::HeurFunc<N, E, C>& heurFunc,
8
+                             const util::graph::CostFunc<N, E, C>& costFunc,
9
+                             const util::graph::HeurFunc<N, E, C>& heurFunc,
10 10
                              EList<N, E>* resEdges, NList<N, E>* resNodes) {
11 11
   if (from->getOutDeg() == 0) return costFunc.inf();
12 12
 
@@ -18,12 +18,12 @@ C Dijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
18 18
   RouteNode<N, E, C> cur;
19 19
 
20 20
   while (!pq.empty()) {
21
-    Dijkstra::ITERS++;
22
-
21
+    if (costFunc.inf() <= pq.top().h) return costFunc.inf();
23 22
     if (settled.find(pq.top().n) != settled.end()) {
24 23
       pq.pop();
25 24
       continue;
26 25
     }
26
+    Dijkstra::ITERS++;
27 27
 
28 28
     cur = pq.top();
29 29
     pq.pop();
@@ -49,8 +49,8 @@ C Dijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
49 49
 template <typename N, typename E, typename C>
50 50
 C Dijkstra::shortestPathImpl(const std::set<Node<N, E>*> from,
51 51
                              const std::set<Node<N, E>*>& to,
52
-                             const ShortestPath::CostFunc<N, E, C>& costFunc,
53
-                             const ShortestPath::HeurFunc<N, E, C>& heurFunc,
52
+                             const util::graph::CostFunc<N, E, C>& costFunc,
53
+                             const util::graph::HeurFunc<N, E, C>& heurFunc,
54 54
                              EList<N, E>* resEdges, NList<N, E>* resNodes) {
55 55
   Settled<N, E, C> settled;
56 56
   PQ<N, E, C> pq;
@@ -61,12 +61,17 @@ C Dijkstra::shortestPathImpl(const std::set<Node<N, E>*> from,
61 61
   RouteNode<N, E, C> cur;
62 62
 
63 63
   while (!pq.empty()) {
64
-    Dijkstra::ITERS++;
65
-
66
-    if (settled.find(pq.top().n) != settled.end()) {
67
-      pq.pop();
68
-      continue;
64
+    if (costFunc.inf() <= pq.top().h) return costFunc.inf();
65
+    auto se = settled.find(pq.top().n);
66
+    if (se != settled.end()) {
67
+      // to allow non-consistent heuristics
68
+      if (se->second.d <= pq.top().d) {
69
+        pq.pop();
70
+        continue;
71
+      }
72
+      Dijkstra::DBL_VISITS++;
69 73
     }
74
+    Dijkstra::ITERS++;
70 75
 
71 76
     cur = pq.top();
72 77
     pq.pop();
@@ -92,8 +97,8 @@ C Dijkstra::shortestPathImpl(const std::set<Node<N, E>*> from,
92 97
 template <typename N, typename E, typename C>
93 98
 std::unordered_map<Node<N, E>*, C> Dijkstra::shortestPathImpl(
94 99
     Node<N, E>* from, const std::set<Node<N, E>*>& to,
95
-    const ShortestPath::CostFunc<N, E, C>& costFunc,
96
-    const ShortestPath::HeurFunc<N, E, C>& heurFunc,
100
+    const util::graph::CostFunc<N, E, C>& costFunc,
101
+    const util::graph::HeurFunc<N, E, C>& heurFunc,
97 102
     std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
98 103
     std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
99 104
   std::unordered_map<Node<N, E>*, C> costs;
@@ -112,12 +117,16 @@ std::unordered_map<Node<N, E>*, C> Dijkstra::shortestPathImpl(
112 117
   RouteNode<N, E, C> cur;
113 118
 
114 119
   while (!pq.empty()) {
115
-    Dijkstra::ITERS++;
116
-
117
-    if (settled.find(pq.top().n) != settled.end()) {
118
-      pq.pop();
119
-      continue;
120
+    if (costFunc.inf() <= pq.top().h) return costs;
121
+    auto se = settled.find(pq.top().n);
122
+    if (se != settled.end()) {
123
+      // to allow non-consistent heuristics
124
+      if (se->second.d <= pq.top().d) {
125
+        pq.pop();
126
+        continue;
127
+      }
120 128
     }
129
+    Dijkstra::ITERS++;
121 130
 
122 131
     cur = pq.top();
123 132
     pq.pop();
@@ -147,29 +156,35 @@ std::unordered_map<Node<N, E>*, C> Dijkstra::shortestPathImpl(
147 156
 // _____________________________________________________________________________
148 157
 template <typename N, typename E, typename C>
149 158
 void Dijkstra::relax(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
150
-                     const ShortestPath::CostFunc<N, E, C>& costFunc,
151
-                     const ShortestPath::HeurFunc<N, E, C>& heurFunc, PQ<N, E, C>& pq) {
159
+                     const util::graph::CostFunc<N, E, C>& costFunc,
160
+                     const util::graph::HeurFunc<N, E, C>& heurFunc,
161
+                     PQ<N, E, C>& pq) {
152 162
   for (auto edge : cur.n->getAdjListOut()) {
153 163
     C newC = costFunc(cur.n, edge, edge->getOtherNd(cur.n));
154 164
     newC = cur.d + newC;
155 165
     if (costFunc.inf() <= newC) continue;
156 166
 
167
+    // addition done here to avoid it in the PQ
157 168
     const C& newH = newC + heurFunc(edge->getOtherNd(cur.n), to);
158 169
 
159
-    pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH, &(*edge));
170
+    pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH);
160 171
   }
161 172
 }
162 173
 
163 174
 // _____________________________________________________________________________
164 175
 template <typename N, typename E, typename C>
165
-void Dijkstra::buildPath(Node<N, E>* curN,
166
-                         Settled<N, E, C>& settled, NList<N, E>* resNodes,
167
-                         EList<N, E>* resEdges) {
168
-  while (true) {
176
+void Dijkstra::buildPath(Node<N, E>* curN, Settled<N, E, C>& settled,
177
+                         NList<N, E>* resNodes, EList<N, E>* resEdges) {
178
+  while (resNodes || resEdges) {
169 179
     const RouteNode<N, E, C>& curNode = settled[curN];
170 180
     if (resNodes) resNodes->push_back(curNode.n);
171 181
     if (!curNode.parent) break;
172
-    if (resEdges) resEdges->push_back(curNode.e);
182
+
183
+    if (resEdges) {
184
+      for (auto e : curNode.n->getAdjListIn()) {
185
+        if (e->getOtherNd(curNode.n) == curNode.parent) resEdges->push_back(e);
186
+      }
187
+    }
173 188
     curN = curNode.parent;
174 189
   }
175 190
 }

+ 0 - 2
src/util/graph/DirGraph.h

@@ -21,8 +21,6 @@ using UndirEdge = Edge<N, E>;
21 21
 template <typename N, typename E>
22 22
 class DirGraph : public Graph<N, E> {
23 23
  public:
24
-  explicit DirGraph();
25
-
26 24
   using Graph<N, E>::addEdg;
27 25
 
28 26
   Node<N, E>* addNd();

+ 0 - 4
src/util/graph/DirGraph.tpp

@@ -4,10 +4,6 @@
4 4
 
5 5
 // _____________________________________________________________________________
6 6
 template <typename N, typename E>
7
-DirGraph<N, E>::DirGraph() {}
8
-
9
-// _____________________________________________________________________________
10
-template <typename N, typename E>
11 7
 Node<N, E>* DirGraph<N, E>::addNd(const N& pl) {
12 8
   return addNd(new DirNode<N, E>(pl));
13 9
 }

+ 20 - 17
src/util/graph/EDijkstra.h

@@ -37,18 +37,21 @@ class EDijkstra : public ShortestPath<EDijkstra> {
37 37
     Edge<N, E>* e;
38 38
     Edge<N, E>* parent;
39 39
 
40
+    // the cost so far
40 41
     C d;
42
+
43
+    // the heuristical remaining cost + the cost so far
41 44
     C h;
42 45
 
43 46
     Node<N, E>* n;
44 47
 
45 48
     bool operator<(const RouteEdge<N, E, C>& p) const {
46
-      return h > p.h || (h == p.h && d > p.d);
49
+      return h > p.h;
47 50
     }
48 51
   };
49 52
 
50 53
   template <typename N, typename E, typename C>
51
-  struct CostFunc : public ShortestPath::CostFunc<N, E, C> {
54
+  struct CostFunc : public util::graph::CostFunc<N, E, C> {
52 55
     C operator()(const Node<N, E>* from, const Edge<N, E>* e,
53 56
                  const Node<N, E>* to) const {
54 57
       UNUSED(from);
@@ -59,7 +62,7 @@ class EDijkstra : public ShortestPath<EDijkstra> {
59 62
   };
60 63
 
61 64
   template <typename N, typename E, typename C>
62
-  struct HeurFunc : public ShortestPath::HeurFunc<N, E, C> {
65
+  struct HeurFunc : public util::graph::HeurFunc<N, E, C> {
63 66
     C operator()(const Node<N, E>* from,
64 67
                  const std::set<Node<N, E>*>& to) const {
65 68
       UNUSED(from);
@@ -77,39 +80,39 @@ class EDijkstra : public ShortestPath<EDijkstra> {
77 80
   template <typename N, typename E, typename C>
78 81
   static C shortestPathImpl(const std::set<Edge<N, E>*> from,
79 82
                             const std::set<Edge<N, E>*>& to,
80
-                            const ShortestPath::CostFunc<N, E, C>& costFunc,
81
-                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
83
+                            const util::graph::CostFunc<N, E, C>& costFunc,
84
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
82 85
                             EList<N, E>* resEdges, NList<N, E>* resNodes);
83 86
 
84 87
   template <typename N, typename E, typename C>
85 88
   static C shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
86
-                            const ShortestPath::CostFunc<N, E, C>& costFunc,
87
-                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
89
+                            const util::graph::CostFunc<N, E, C>& costFunc,
90
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
88 91
                             EList<N, E>* resEdges, NList<N, E>* resNodes);
89 92
 
90 93
   template <typename N, typename E, typename C>
91 94
   static C shortestPathImpl(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
92
-                            const ShortestPath::CostFunc<N, E, C>& costFunc,
93
-                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
95
+                            const util::graph::CostFunc<N, E, C>& costFunc,
96
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
94 97
                             EList<N, E>* resEdges, NList<N, E>* resNodes);
95 98
 
96 99
   template <typename N, typename E, typename C>
97 100
   static C shortestPathImpl(const std::set<Edge<N, E>*>& from,
98 101
                             const std::set<Node<N, E>*>& to,
99
-                            const ShortestPath::CostFunc<N, E, C>& costFunc,
100
-                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
102
+                            const util::graph::CostFunc<N, E, C>& costFunc,
103
+                            const util::graph::HeurFunc<N, E, C>& heurFunc,
101 104
                             EList<N, E>* resEdges, NList<N, E>* resNodes);
102 105
 
103 106
   template <typename N, typename E, typename C>
104 107
   static std::unordered_map<Edge<N, E>*, C> shortestPathImpl(
105 108
       const std::set<Edge<N, E>*>& from,
106
-      const ShortestPath::CostFunc<N, E, C>& costFunc, bool rev);
109
+      const util::graph::CostFunc<N, E, C>& costFunc, bool rev);
107 110
 
108 111
   template <typename N, typename E, typename C>
109 112
   static std::unordered_map<Edge<N, E>*, C> shortestPathImpl(
110 113
       Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
111
-      const ShortestPath::CostFunc<N, E, C>& costFunc,
112
-      const ShortestPath::HeurFunc<N, E, C>& heurFunc,
114
+      const util::graph::CostFunc<N, E, C>& costFunc,
115
+      const util::graph::HeurFunc<N, E, C>& heurFunc,
113 116
       std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges,
114 117
       std::unordered_map<Edge<N, E>*, NList<N, E>*> resNodes);
115 118
 
@@ -120,13 +123,13 @@ class EDijkstra : public ShortestPath<EDijkstra> {
120 123
   template <typename N, typename E, typename C>
121 124
   static inline void relax(RouteEdge<N, E, C>& cur,
122 125
                            const std::set<Edge<N, E>*>& to,
123
-                           const ShortestPath::CostFunc<N, E, C>& costFunc,
124
-                           const ShortestPath::HeurFunc<N, E, C>& heurFunc,
126
+                           const util::graph::CostFunc<N, E, C>& costFunc,
127
+                           const util::graph::HeurFunc<N, E, C>& heurFunc,
125 128
                            PQ<N, E, C>& pq);
126 129
 
127 130
   template <typename N, typename E, typename C>
128 131
   static void relaxInv(RouteEdge<N, E, C>& cur,
129
-                      const ShortestPath::CostFunc<N, E, C>& costFunc,
132
+                      const util::graph::CostFunc<N, E, C>& costFunc,
130 133
                       PQ<N, E, C>& pq);
131 134
 
132 135
   static size_t ITERS;

+ 44 - 28
src/util/graph/EDijkstra.tpp

@@ -5,8 +5,8 @@
5 5
 // _____________________________________________________________________________
6 6
 template <typename N, typename E, typename C>
7 7
 C EDijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
8
-                              const ShortestPath::CostFunc<N, E, C>& costFunc,
9
-                              const ShortestPath::HeurFunc<N, E, C>& heurFunc,
8
+                              const util::graph::CostFunc<N, E, C>& costFunc,
9
+                              const util::graph::HeurFunc<N, E, C>& heurFunc,
10 10
                               EList<N, E>* resEdges, NList<N, E>* resNodes) {
11 11
   std::set<Edge<N, E>*> frEs;
12 12
   std::set<Edge<N, E>*> toEs;
@@ -28,8 +28,8 @@ C EDijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
28 28
 // _____________________________________________________________________________
29 29
 template <typename N, typename E, typename C>
30 30
 C EDijkstra::shortestPathImpl(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
31
-                              const ShortestPath::CostFunc<N, E, C>& costFunc,
32
-                              const ShortestPath::HeurFunc<N, E, C>& heurFunc,
31
+                              const util::graph::CostFunc<N, E, C>& costFunc,
32
+                              const util::graph::HeurFunc<N, E, C>& heurFunc,
33 33
                               EList<N, E>* resEdges, NList<N, E>* resNodes) {
34 34
   std::set<Edge<N, E>*> frEs;
35 35
   std::set<Edge<N, E>*> toEs;
@@ -49,8 +49,8 @@ C EDijkstra::shortestPathImpl(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
49 49
 template <typename N, typename E, typename C>
50 50
 C EDijkstra::shortestPathImpl(const std::set<Edge<N, E>*> from,
51 51
                               const std::set<Edge<N, E>*>& to,
52
-                              const ShortestPath::CostFunc<N, E, C>& costFunc,
53
-                              const ShortestPath::HeurFunc<N, E, C>& heurFunc,
52
+                              const util::graph::CostFunc<N, E, C>& costFunc,
53
+                              const util::graph::HeurFunc<N, E, C>& heurFunc,
54 54
                               EList<N, E>* resEdges, NList<N, E>* resNodes) {
55 55
   if (from.size() == 0 || to.size() == 0) return costFunc.inf();
56 56
 
@@ -69,13 +69,18 @@ C EDijkstra::shortestPathImpl(const std::set<Edge<N, E>*> from,
69 69
   RouteEdge<N, E, C> cur;
70 70
 
71 71
   while (!pq.empty()) {
72
-    EDijkstra::ITERS++;
73
-
74
-    if (settled.find(pq.top().e) != settled.end()) {
75
-      pq.pop();
76
-      continue;
72
+    if (costFunc.inf() <= pq.top().h) return costFunc.inf();
73
+    auto se = settled.find(pq.top().e);
74
+    if (se != settled.end()) {
75
+      // to allow non-consistent heuristics
76
+      if (se->second.d <= pq.top().d) {
77
+        pq.pop();
78
+        continue;
79
+      }
77 80
     }
78 81
 
82
+    EDijkstra::ITERS++;
83
+
79 84
     cur = pq.top();
80 85
     pq.pop();
81 86
 
@@ -99,7 +104,7 @@ C EDijkstra::shortestPathImpl(const std::set<Edge<N, E>*> from,
99 104
 // _____________________________________________________________________________
100 105
 template <typename N, typename E, typename C>
101 106
 std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
102
-    const std::set<Edge<N, E>*>& from, const ShortestPath::CostFunc<N, E, C>& costFunc,
107
+    const std::set<Edge<N, E>*>& from, const util::graph::CostFunc<N, E, C>& costFunc,
103 108
     bool rev) {
104 109
   std::unordered_map<Edge<N, E>*, C> costs;
105 110
 
@@ -115,13 +120,17 @@ std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
115 120
   RouteEdge<N, E, C> cur;
116 121
 
117 122
   while (!pq.empty()) {
118
-    EDijkstra::ITERS++;
119
-
120
-    if (settled.find(pq.top().e) != settled.end()) {
121
-      pq.pop();
122
-      continue;
123
+    auto se = settled.find(pq.top().e);
124
+    if (se != settled.end()) {
125
+      // to allow non-consistent heuristics
126
+      if (se->second.d <= pq.top().d) {
127
+        pq.pop();
128
+        continue;
129
+      }
123 130
     }
124 131
 
132
+    EDijkstra::ITERS++;
133
+
125 134
     cur = pq.top();
126 135
     pq.pop();
127 136
 
@@ -143,8 +152,8 @@ std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
143 152
 template <typename N, typename E, typename C>
144 153
 std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
145 154
     Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
146
-    const ShortestPath::CostFunc<N, E, C>& costFunc,
147
-    const ShortestPath::HeurFunc<N, E, C>& heurFunc,
155
+    const util::graph::CostFunc<N, E, C>& costFunc,
156
+    const util::graph::HeurFunc<N, E, C>& heurFunc,
148 157
     std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges,
149 158
     std::unordered_map<Edge<N, E>*, NList<N, E>*> resNodes) {
150 159
   std::unordered_map<Edge<N, E>*, C> costs;
@@ -165,13 +174,18 @@ std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
165 174
   RouteEdge<N, E, C> cur;
166 175
 
167 176
   while (!pq.empty()) {
168
-    EDijkstra::ITERS++;
169
-
170
-    if (settled.find(pq.top().e) != settled.end()) {
171
-      pq.pop();
172
-      continue;
177
+    if (costFunc.inf() <= pq.top().h) return costs;
178
+    auto se = settled.find(pq.top().e);
179
+    if (se != settled.end()) {
180
+      // to allow non-consistent heuristics
181
+      if (se->second.d <= pq.top().d) {
182
+        pq.pop();
183
+        continue;
184
+      }
173 185
     }
174 186
 
187
+    EDijkstra::ITERS++;
188
+
175 189
     cur = pq.top();
176 190
     pq.pop();
177 191
 
@@ -194,7 +208,7 @@ std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
194 208
 // _____________________________________________________________________________
195 209
 template <typename N, typename E, typename C>
196 210
 void EDijkstra::relaxInv(RouteEdge<N, E, C>& cur,
197
-                         const ShortestPath::CostFunc<N, E, C>& costFunc,
211
+                         const util::graph::CostFunc<N, E, C>& costFunc,
198 212
                          PQ<N, E, C>& pq) {
199 213
 
200 214
   // handling undirected graph makes no sense here
@@ -212,8 +226,8 @@ void EDijkstra::relaxInv(RouteEdge<N, E, C>& cur,
212 226
 // _____________________________________________________________________________
213 227
 template <typename N, typename E, typename C>
214 228
 void EDijkstra::relax(RouteEdge<N, E, C>& cur, const std::set<Edge<N, E>*>& to,
215
-                      const ShortestPath::CostFunc<N, E, C>& costFunc,
216
-                      const ShortestPath::HeurFunc<N, E, C>& heurFunc,
229
+                      const util::graph::CostFunc<N, E, C>& costFunc,
230
+                      const util::graph::HeurFunc<N, E, C>& heurFunc,
217 231
                       PQ<N, E, C>& pq) {
218 232
   if (cur.e->getFrom()->hasEdgeIn(cur.e)) {
219 233
     // for undirected graphs
@@ -224,6 +238,7 @@ void EDijkstra::relax(RouteEdge<N, E, C>& cur, const std::set<Edge<N, E>*>& to,
224 238
       if (costFunc.inf() <= newC) continue;
225 239
 
226 240
       const C& h = heurFunc(edge, to);
241
+      // addition done here to avoid it in the PQ
227 242
       const C& newH = newC + h;
228 243
 
229 244
       pq.emplace(edge, cur.e, cur.e->getFrom(), newC, newH);
@@ -237,6 +252,7 @@ void EDijkstra::relax(RouteEdge<N, E, C>& cur, const std::set<Edge<N, E>*>& to,
237 252
     if (costFunc.inf() <= newC) continue;
238 253
 
239 254
     const C& h = heurFunc(edge, to);
255
+    // addition done here to avoid it in the PQ
240 256
     const C& newH = newC + h;
241 257
 
242 258
     pq.emplace(edge, cur.e, cur.e->getTo(), newC, newH);
@@ -249,7 +265,7 @@ void EDijkstra::buildPath(Edge<N, E>* curE, const Settled<N, E, C>& settled,
249 265
                           NList<N, E>* resNodes, EList<N, E>* resEdges) {
250 266
   const RouteEdge<N, E, C>* curEdge = &settled.find(curE)->second;
251 267
   if (resNodes) resNodes->push_back(curEdge->e->getOtherNd(curEdge->n));
252
-  while (true) {
268
+  while (resNodes || resEdges) {
253 269
     if (resNodes && curEdge->n) resNodes->push_back(curEdge->n);
254 270
     if (resEdges) resEdges->push_back(curEdge->e);
255 271
     if (!curEdge->parent) break;

+ 0 - 3
src/util/graph/Edge.h

@@ -21,9 +21,6 @@ class Edge {
21 21
 
22 22
   Node<N, E>* getOtherNd(const Node<N, E>* notNode) const;
23 23
 
24
-  void setFrom(Node<N, E>* from);
25
-  void setTo(Node<N, E>* to);
26
-
27 24
   E& pl();
28 25
   const E& pl() const;
29 26
 

+ 2 - 0
src/util/graph/Graph.h

@@ -32,6 +32,8 @@ class Graph {
32 32
   const std::set<Node<N, E>*>& getNds() const;
33 33
   std::set<Node<N, E>*>* getNds();
34 34
 
35
+  static Node<N, E>* sharedNode(const Edge<N, E>* a, const Edge<N, E>* b);
36
+
35 37
   typename std::set<Node<N, E>*>::iterator delNd(Node<N, E>* n);
36 38
   typename std::set<Node<N, E>*>::iterator delNd(
37 39
       typename std::set<Node<N, E>*>::iterator i);

+ 11 - 0
src/util/graph/Graph.tpp

@@ -67,6 +67,17 @@ Edge<N, E>* Graph<N, E>::getEdg(Node<N, E>* from, Node<N, E>* to) {
67 67
 
68 68
 // _____________________________________________________________________________
69 69
 template <typename N, typename E>
70
+Node<N, E>* Graph<N, E>::sharedNode(const Edge<N, E>* a, const Edge<N, E>* b) {
71
+  Node<N, E>* r = 0;
72
+  if (a->getFrom() == b->getFrom() || a->getFrom() == b->getTo())
73
+    r = a->getFrom();
74
+  if (a->getTo() == b->getFrom() || a->getTo() == b->getTo()) r = a->getTo();
75
+  return r;
76
+}
77
+
78
+
79
+// _____________________________________________________________________________
80
+template <typename N, typename E>
70 81
 const Edge<N, E>* Graph<N, E>::getEdg(Node<N, E>* from, Node<N, E>* to) const {
71 82
   for (auto e : from->getAdjList()) {
72 83
     if (e->getOtherNd(from) == to) return e;

+ 89 - 59
src/util/graph/ShortestPath.h

@@ -19,9 +19,47 @@
19 19
 namespace util {
20 20
 namespace graph {
21 21
 
22
+using util::graph::Edge;
22 23
 using util::graph::Graph;
23 24
 using util::graph::Node;
24
-using util::graph::Edge;
25
+
26
+template <typename N, typename E>
27
+using EList = std::vector<Edge<N, E>*>;
28
+
29
+template <typename N, typename E>
30
+using NList = std::vector<Node<N, E>*>;
31
+
32
+template <typename N, typename E, typename C>
33
+struct CostFunc {
34
+  virtual C operator()(const Node<N, E>* from, const Edge<N, E>* e,
35
+                       const Node<N, E>* to) const = 0;
36
+  virtual C operator()(const Edge<N, E>* from, const Node<N, E>* n,
37
+                       const Edge<N, E>* to) const = 0;
38
+  virtual C inf() const = 0;
39
+};
40
+
41
+
42
+template <typename N, typename E, typename C>
43
+struct HeurFunc {
44
+  virtual C operator()(const Node<N, E>* a,
45
+                       const std::set<Node<N, E>*>& b) const = 0;
46
+  virtual C operator()(const Edge<N, E>* a,
47
+                       const std::set<Edge<N, E>*>& b) const = 0;
48
+};
49
+
50
+template <typename N, typename E, typename C>
51
+struct ZeroHeurFunc : public HeurFunc<N, E, C> {
52
+  C operator()(const Node<N, E>* a, const std::set<Node<N, E>*>& b) const {
53
+    UNUSED(a);
54
+    UNUSED(b);
55
+    return C();
56
+  }
57
+  C operator()(const Edge<N, E>* a, const std::set<Edge<N, E>*>& b) const {
58
+    UNUSED(a);
59
+    UNUSED(b);
60
+    return C();
61
+  }
62
+};
25 63
 
26 64
 // shortest path base class
27 65
 template <class D>
@@ -34,37 +72,6 @@ class ShortestPath {
34 72
   using NList = std::vector<Node<N, E>*>;
35 73
 
36 74
   template <typename N, typename E, typename C>
37
-  struct CostFunc {
38
-    virtual C operator()(const Node<N, E>* from, const Edge<N, E>* e,
39
-                         const Node<N, E>* to) const = 0;
40
-    virtual C operator()(const Edge<N, E>* from, const Node<N, E>* n,
41
-                         const Edge<N, E>* to) const = 0;
42
-    virtual C inf() const = 0;
43
-  };
44
-
45
-  template <typename N, typename E, typename C>
46
-  struct HeurFunc {
47
-    virtual C operator()(const Node<N, E>* a,
48
-                         const std::set<Node<N, E>*>& b) const = 0;
49
-    virtual C operator()(const Edge<N, E>* a,
50
-                         const std::set<Edge<N, E>*>& b) const = 0;
51
-  };
52
-
53
-  template <typename N, typename E, typename C>
54
-  struct ZeroHeurFunc : public HeurFunc<N, E, C> {
55
-    C operator()(const Node<N, E>* a, const std::set<Node<N, E>*>& b) const {
56
-      UNUSED(a);
57
-      UNUSED(b);
58
-      return C();
59
-    }
60
-    C operator()(const Edge<N, E>* a, const std::set<Edge<N, E>*>& b) const {
61
-      UNUSED(a);
62
-      UNUSED(b);
63
-      return C();
64
-    }
65
-  };
66
-
67
-  template <typename N, typename E, typename C>
68 75
   static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
69 76
                         const CostFunc<N, E, C>& costFunc,
70 77
                         const HeurFunc<N, E, C>& heurFunc,
@@ -74,7 +81,8 @@ class ShortestPath {
74 81
   }
75 82
 
76 83
   template <typename N, typename E, typename C>
77
-  static C shortestPath(const std::set<Node<N, E>*> from, const std::set<Node<N, E>*>& to,
84
+  static C shortestPath(const std::set<Node<N, E>*> from,
85
+                        const std::set<Node<N, E>*>& to,
78 86
                         const CostFunc<N, E, C>& costFunc,
79 87
                         const HeurFunc<N, E, C>& heurFunc,
80 88
                         EList<N, E>* resEdges, NList<N, E>* resNodes) {
@@ -83,6 +91,15 @@ class ShortestPath {
83 91
   }
84 92
 
85 93
   template <typename N, typename E, typename C>
94
+  static C shortestPath(const std::set<Node<N, E>*> from,
95
+                        const std::set<Node<N, E>*>& to,
96
+                        const CostFunc<N, E, C>& costFunc,
97
+                        EList<N, E>* resEdges, NList<N, E>* resNodes) {
98
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(),
99
+                               resEdges, resNodes);
100
+  }
101
+
102
+  template <typename N, typename E, typename C>
86 103
   static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
87 104
                         const CostFunc<N, E, C>& costFunc,
88 105
                         EList<N, E>* resEdges, NList<N, E>* resNodes) {
@@ -161,6 +178,14 @@ class ShortestPath {
161 178
   }
162 179
 
163 180
   template <typename N, typename E, typename C>
181
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& tos,
182
+                        const CostFunc<N, E, C>& costFunc) {
183
+    EList<N, E>* el = 0;
184
+    NList<N, E>* nl = 0;
185
+    return shortestPath(from, tos, costFunc, el, nl);
186
+  }
187
+
188
+  template <typename N, typename E, typename C>
164 189
   static C shortestPath(Node<N, E>* from, Node<N, E>* to,
165 190
                         const CostFunc<N, E, C>& costFunc) {
166 191
     if (to->getInDeg() == 0) return costFunc.inf();
@@ -266,7 +291,7 @@ class ShortestPath {
266 291
   template <typename N, typename E, typename C>
267 292
   static std::unordered_map<Edge<N, E>*, C> shortestPath(
268 293
       Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
269
-      const ShortestPath::CostFunc<N, E, C>& costFunc,
294
+      const CostFunc<N, E, C>& costFunc,
270 295
       const HeurFunc<N, E, C>& heurFunc,
271 296
       std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges,
272 297
       std::unordered_map<Edge<N, E>*, NList<N, E>*> resNodes) {
@@ -277,7 +302,7 @@ class ShortestPath {
277 302
   template <typename N, typename E, typename C>
278 303
   static std::unordered_map<Edge<N, E>*, C> shortestPath(
279 304
       Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
280
-      const ShortestPath::CostFunc<N, E, C>& costFunc,
305
+      const CostFunc<N, E, C>& costFunc,
281 306
       const HeurFunc<N, E, C>& heurFunc,
282 307
       std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges) {
283 308
     std::unordered_map<Edge<N, E>*, NList<N, E>*> dummyRet;
@@ -288,7 +313,7 @@ class ShortestPath {
288 313
   template <typename N, typename E, typename C>
289 314
   static std::unordered_map<Edge<N, E>*, C> shortestPath(
290 315
       Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
291
-      const ShortestPath::CostFunc<N, E, C>& costFunc,
316
+      const CostFunc<N, E, C>& costFunc,
292 317
       const HeurFunc<N, E, C>& heurFunc) {
293 318
     std::unordered_map<Edge<N, E>*, NList<N, E>*> dummyRet;
294 319
     std::unordered_map<Edge<N, E>*, EList<N, E>*> dummyRetE;
@@ -299,22 +324,21 @@ class ShortestPath {
299 324
   template <typename N, typename E, typename C>
300 325
   static C shortestPath(const std::set<Edge<N, E>*>& from,
301 326
                         const std::set<Edge<N, E>*>& to,
302
-                        const CostFunc<N, E, C>& costFunc,
303
-                        const HeurFunc<N, E, C>& heurFunc) {
327
+                        const CostFunc<N, E, C>& costFunc) {
304 328
     NList<N, E>* nl = 0;
305 329
     EList<N, E>* el = 0;
306
-    return D::shortestPathImpl(from, to, costFunc, heurFunc, el, nl);
330
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(), el,
331
+                               nl);
307 332
   }
308 333
 
309 334
   template <typename N, typename E, typename C>
310
-  static C shortestPath(Edge<N, E>* from,
311
-                        Edge<N, E>* to,
312
-                        const CostFunc<N, E, C>& costFunc ) {
335
+  static C shortestPath(const std::set<Edge<N, E>*>& from,
336
+                        const std::set<Edge<N, E>*>& to,
337
+                        const CostFunc<N, E, C>& costFunc,
338
+                        const HeurFunc<N, E, C>& heurFunc) {
313 339
     NList<N, E>* nl = 0;
314 340
     EList<N, E>* el = 0;
315
-    std::set<Edge<N, E>*> tos{to};
316
-    std::set<Edge<N, E>*> froms{from};
317
-    return D::shortestPathImpl(froms, tos, costFunc, ZeroHeurFunc<N, E, C>(), el, nl);
341
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, el, nl);
318 342
   }
319 343
 
320 344
   template <typename N, typename E, typename C>
@@ -327,6 +351,17 @@ class ShortestPath {
327 351
   }
328 352
 
329 353
   template <typename N, typename E, typename C>
354
+  static C shortestPath(Edge<N, E>* from, Edge<N, E>* to,
355
+                        const CostFunc<N, E, C>& costFunc) {
356
+    NList<N, E>* nl = 0;
357
+    EList<N, E>* el = 0;
358
+    std::set<Edge<N, E>*> tos{to};
359
+    std::set<Edge<N, E>*> froms{from};
360
+    return D::shortestPathImpl(froms, tos, costFunc, ZeroHeurFunc<N, E, C>(),
361
+                               el, nl);
362
+  }
363
+
364
+  template <typename N, typename E, typename C>
330 365
   static C shortestPath(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
331 366
                         const CostFunc<N, E, C>& costFunc,
332 367
                         const HeurFunc<N, E, C>& heurFunc, EList<N, E>* el,
@@ -336,8 +371,7 @@ class ShortestPath {
336 371
 
337 372
   template <typename N, typename E, typename C>
338 373
   static C shortestPath(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
339
-                        const CostFunc<N, E, C>& costFunc,
340
-                        EList<N, E>* el,
374
+                        const CostFunc<N, E, C>& costFunc, EList<N, E>* el,
341 375
                         NList<N, E>* nl) {
342 376
     return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(), el,
343 377
                                nl);
@@ -363,24 +397,21 @@ class ShortestPath {
363 397
 
364 398
   template <typename N, typename E, typename C>
365 399
   static std::unordered_map<Edge<N, E>*, C> shortestPath(
366
-      Edge<N, E>* from,
367
-      const ShortestPath::CostFunc<N, E, C>& costFunc) {
368
-    std::set<Edge<N, E>*> froms { from };
400
+      Edge<N, E>* from, const CostFunc<N, E, C>& costFunc) {
401
+    std::set<Edge<N, E>*> froms{from};
369 402
     return D::shortestPathImpl(froms, costFunc, false);
370 403
   }
371 404
 
372 405
   template <typename N, typename E, typename C>
373 406
   static std::unordered_map<Edge<N, E>*, C> shortestPathRev(
374
-      Edge<N, E>* from,
375
-      const ShortestPath::CostFunc<N, E, C>& costFunc) {
376
-    std::set<Edge<N, E>*> froms { from };
407
+      Edge<N, E>* from, const CostFunc<N, E, C>& costFunc) {
408
+    std::set<Edge<N, E>*> froms{from};
377 409
     return D::shortestPathImpl(froms, costFunc, true);
378 410
   }
379 411
 
380 412
   template <typename N, typename E, typename C>
381 413
   static std::unordered_map<Edge<N, E>*, C> shortestPath(
382
-      Node<N, E>* from,
383
-      const ShortestPath::CostFunc<N, E, C>& costFunc) {
414
+      Node<N, E>* from, const CostFunc<N, E, C>& costFunc) {
384 415
     std::set<Edge<N, E>*> froms;
385 416
     froms.insert(from->getAdjListOut().begin(), from->getAdjListOut().end());
386 417
     return D::shortestPathImpl(froms, costFunc, false);
@@ -388,14 +419,13 @@ class ShortestPath {
388 419
 
389 420
   template <typename N, typename E, typename C>
390 421
   static std::unordered_map<Edge<N, E>*, C> shortestPathRev(
391
-      Node<N, E>* from,
392
-      const ShortestPath::CostFunc<N, E, C>& costFunc) {
422
+      Node<N, E>* from, const CostFunc<N, E, C>& costFunc) {
393 423
     std::set<Edge<N, E>*> froms;
394 424
     froms.insert(from->getAdjListOut().begin(), from->getAdjListOut().end());
395 425
     return D::shortestPathImpl(froms, costFunc, true);
396 426
   }
397 427
 };
398
-}
399
-}
428
+}  // namespace graph
429
+}  // namespace util
400 430
 
401 431
 #endif  // UTIL_GRAPH_SHORTESTPATH_H_

+ 7 - 1
src/util/http/Server.cpp

@@ -22,6 +22,7 @@
22 22
 #include <vector>
23 23
 #include "Server.h"
24 24
 #include "util/String.h"
25
+#include "util/log/Log.h"
25 26
 
26 27
 using util::http::Socket;
27 28
 using util::http::Queue;
@@ -112,7 +113,12 @@ void HttpServer::handle() {
112 113
       answ = Answer("500 Internal Server Error", "500 Internal Server Error");
113 114
     }
114 115
 
115
-    send(connection, &answ);
116
+    try {
117
+      send(connection, &answ);
118
+    } catch (const std::runtime_error& err) {
119
+      LOG(WARN) << err.what();
120
+    }
121
+
116 122
     close(connection);
117 123
   }
118 124
 }

+ 7 - 2
src/util/log/Log.h

@@ -19,8 +19,12 @@
19 19
 #define LOGLEVEL 2
20 20
 #endif
21 21
 
22
+#define GET_MACRO(_1,_2,NAME,...) NAME
23
+#define LOG(...) GET_MACRO(__VA_ARGS__, LOGSTR, LOGAUTO)(__VA_ARGS__)
24
+
22 25
 // compiler will optimize statement away if x > LOGLEVEL
23
-#define LOG(x) if (x <= LOGLEVEL) util::Log<x>().log()
26
+#define LOGAUTO(x) if (x <= LOGLEVEL) util::Log<x>().log()
27
+#define LOGSTR(x, os) if (x <= LOGLEVEL) util::Log<x>(&os).log()
24 28
 
25 29
 using std::setfill;
26 30
 using std::setw;
@@ -33,7 +37,8 @@ static const char* LOGS[] = {"ERROR", "WARN ", "INFO ", "DEBUG", "DEBUG"};
33 37
 template <char LVL>
34 38
 class Log {
35 39
  public:
36
-  Log() { if (LVL == ERROR) os = &std::cerr; else os = &std::cout; }
40
+  Log() { if (LVL < INFO) os = &std::cerr; else os = &std::cout; }
41
+  Log(std::ostream* s) { os = s; }
37 42
   ~Log() { (*os) << std::endl; }
38 43
   std::ostream& log() { return ts() << LOGS[(size_t)LVL] << ": "; }
39 44
 

+ 38 - 0
src/util/tests/QuadTreeTest.cpp

@@ -0,0 +1,38 @@
1
+// Copyright 2016
2
+// Author: Patrick Brosi
3
+
4
+#include "util/Misc.h"
5
+#include "util/geo/QuadTree.h"
6
+#include "util/tests/QuadTreeTest.h"
7
+
8
+using util::approx;
9
+using util::geo::QuadTree;
10
+using util::geo::DPoint;
11
+using util::geo::DBox;
12
+
13
+// _____________________________________________________________________________
14
+void QuadTreeTest::run() {
15
+  // ___________________________________________________________________________
16
+  {
17
+    QuadTree<int, double> qt(4, 4, DBox(DPoint(0, 0), DPoint(10, 10)));
18
+
19
+    qt.insert(0, {2, 2});
20
+    TEST(qt.size(), ==, 1);
21
+
22
+    qt.insert(666, {-1, 0});
23
+    TEST(qt.size(), ==, 1);
24
+
25
+    qt.insert(1, {0, 0});
26
+    TEST(qt.size(), ==, 2);
27
+
28
+    qt.insert(2, {0, 1});
29
+    TEST(qt.size(), ==, 3);
30
+
31
+    qt.insert(3, {6, 9});
32
+    TEST(qt.size(), ==, 4);
33
+
34
+    qt.insert(4, {9, 0});
35
+    TEST(qt.size(), ==, 5);
36
+  }
37
+
38
+}

+ 12 - 0
src/util/tests/QuadTreeTest.h

@@ -0,0 +1,12 @@
1
+// Copyright 2016
2
+// Author: Patrick Brosi
3
+
4
+#ifndef UTIL_TEST_QUADTTREETEST_H_
5
+#define UTIL_TEST_QUADTREETEST_H_
6
+
7
+class QuadTreeTest {
8
+  public:
9
+    void run();
10
+};
11
+
12
+#endif

Plik diff jest za duży
+ 603 - 525
src/util/tests/TestMain.cpp


Plik diff jest za duży
+ 98 - 1
web/index.html


+ 110 - 20
web/script.js

@@ -187,12 +187,6 @@ function renderStat(stat) {
187 187
         suggList.appendChild(suggDiv);
188 188
     }
189 189
 
190
-    if (map.getZoom() < 18) {
191
-        map.setView(ll, 18, {
192
-            animate: true
193
-        });
194
-    }
195
-
196 190
     L.popup({
197 191
             opacity: 0.8
198 192
         })
@@ -347,15 +341,8 @@ function renderGroup(grp, ll) {
347 341
 
348 342
     content.appendChild(suggD);
349 343
 
350
-    if (map.getZoom() < 18) {
351
-        map.setView(ll, 18, {
352
-            animate: true
353
-        });
354
-    }
355 344
 
356
-    L.popup({
357
-            opacity: 0.8
358
-        })
345
+    L.popup({opacity: 0.8})
359 346
         .setLatLng(ll)
360 347
         .setContent(content)
361 348
         .openOn(map)
@@ -411,7 +398,7 @@ function nodeUnHl(id) {
411 398
 
412 399
     if (map.getZoom() > 15) {
413 400
         document.nodeIdx[id].setStyle({
414
-            'weight': 1,
401
+            'weight': map.getZoom() > 17 ? 1.5 : 1,
415 402
             'color': "black"
416 403
         });
417 404
     } else {
@@ -431,6 +418,12 @@ map.addControl(L.control.attribution({
431 418
     prefix: '&copy; <a href="http://ad.cs.uni-freiburg.de">University of Freiburg, Chair of Algorithms and Data Structures</a>'
432 419
 }));
433 420
 
421
+map.on('popupopen', function(e) {
422
+    var px = map.project(e.target._popup._latlng);
423
+    px.y -= e.target._popup._container.clientHeight/2;
424
+    map.panTo(map.unproject(px),{animate: true});
425
+});
426
+
434 427
 L.tileLayer('http://{s}.tile.stamen.com/toner-lite/{z}/{x}/{y}.png', {
435 428
     maxZoom: 20,
436 429
     attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
@@ -480,7 +473,6 @@ function render() {
480 473
                     blur: blur - 3,
481 474
                     radius: Math.min(12, rad - 3)
482 475
                 }));
483
-
484 476
                 layer.addLayer(L.heatLayer(content.err, {
485 477
                     max: 500,
486 478
                     gradient: {
@@ -538,6 +530,10 @@ function render() {
538 530
                     }));
539 531
                 }
540 532
 
533
+                layer.addLayer(L.featureGroup(stations).on('click', function(a) {
534
+                    openStat(a.layer.options.id);
535
+                }));
536
+
541 537
                 if (map.getZoom() > 15) {
542 538
                     labelLayer.addLayer(L.featureGroup(labels));
543 539
                     layer.addLayer(L.featureGroup(suggs).on('click', function(a) {
@@ -545,10 +541,6 @@ function render() {
545 541
                     }));
546 542
                 }
547 543
 
548
-                layer.addLayer(L.featureGroup(stations).on('click', function(a) {
549
-                    openStat(a.layer.options.id);
550
-                }));
551
-
552 544
                 groupHl(openGr);
553 545
                 nodeHl(openSt);
554 546
             }
@@ -559,4 +551,102 @@ function render() {
559 551
     }
560 552
 }
561 553
 
554
+function rowClick(row) {    
555
+    if (!isSearchOpen()) return;
556
+    openGroup(row.gid, row.latlng);
557
+    document.getElementById('searchinput').value = "";
558
+    search();
559
+}
560
+
561
+function select(row) {
562
+    if (!isSearchOpen()) return;
563
+    if (window.selectedRes) window.selectedRes.className = "searchres";    
564
+    row.className = "searchres selected-res";
565
+    window.selectedRes = row;
566
+}
567
+
568
+function unselect(row) {    
569
+    window.selectedRes = undefined;
570
+    if (row) row.className = "searchres";
571
+}
572
+
573
+function isSearchOpen() {
574
+    return document.getElementById("searchresults").className == "res-open";
575
+}
576
+
577
+function search(q) {
578
+    var delay = 0;
579
+    if (q == window.prevSearch) return;
580
+    clearTimeout(window.delayTimer);
581
+    window.prevSearch = q;
582
+    if (!q) {
583
+        unselect(window.selectedRes);
584
+        var res = document.getElementById("searchresults");
585
+        res.className = "";
586
+        return;
587
+    }
588
+
589
+    window.delayTimer = setTimeout(function() {
590
+        window.searchhttp = new XMLHttpRequest();
591
+        window.searchhttp.open("GET", backend + "/search?q=" + q, true);
592
+        window.searchhttp.send();
593
+
594
+        window.searchhttp.onreadystatechange = function() {
595
+            if (this.readyState == 4 && this.status == 200 && this == window.searchhttp) {
596
+                var content = JSON.parse(this.responseText);
597
+                var res = document.getElementById("searchresults");
598
+                res.className = "res-open";        
599
+                res.innerHTML = "";
600
+                for (var i = 0; i < content.length; i++) {
601
+                    stat = content[i];
602
+                    var row = document.createElement('span');
603
+                    row.className="searchres";
604
+                    row.innerHTML = stat.name;
605
+                    row.gid = stat.gid;
606
+                    row.latlng = stat.latlng;
607
+                    row.onmouseover = function(){select(this)};
608
+                    row.onclick = function(){rowClick(this)};
609
+                    if (stat.via && stat.via != stat.name) {
610
+                        var via = document.createElement('span');
611
+                        via.className="via";
612
+                        via.innerHTML = stat.via;
613
+                        row.appendChild(via);
614
+                    }
615
+                    res.appendChild(row);
616
+                }
617
+            }
618
+        }
619
+    }, delay);
620
+}
621
+
622
+function keypress(e) {
623
+    if (e.keyCode == 40) {
624
+        var sels = document.getElementsByClassName('selected-res')
625
+        if (sels.length) {
626
+            var selected = sels[0];
627
+            if (selected.nextSibling) select(selected.nextSibling);
628
+        } else {
629
+           var res = document.getElementsByClassName('searchres') 
630
+           if (res.length) select(res[0]);
631
+        }
632
+    } else if (e.keyCode == 38) {
633
+        var sels = document.getElementsByClassName('selected-res')
634
+        if (sels.length) {
635
+            var selected = sels[0];
636
+            if (selected.previousSibling) select(selected.previousSibling);
637
+            else unselect(selected);
638
+        }
639
+    }
640
+
641
+    if (e.keyCode == 13) {
642
+        var sels = document.getElementsByClassName('selected-res');
643
+        if (sels.length) rowClick(sels[0]);
644
+    }
645
+}
646
+
647
+document.getElementById('del').onclick = function() {
648
+    document.getElementById('searchinput').value = "";
649
+    search();
650
+}
651
+
562 652
 render();