Patrick Brosi 5 years ago
parent
commit
cdc8fef405

+ 195 - 0
.ycm_extra_conf.py

@@ -0,0 +1,195 @@
1
+# This file is NOT licensed under the GPLv3, which is the license for the rest
2
+# of YouCompleteMe.
3
+#
4
+# Here's the license text for this file:
5
+#
6
+# This is free and unencumbered software released into the public domain.
7
+#
8
+# Anyone is free to copy, modify, publish, use, compile, sell, or
9
+# distribute this software, either in source code form or as a compiled
10
+# binary, for any purpose, commercial or non-commercial, and by any
11
+# means.
12
+#
13
+# In jurisdictions that recognize copyright laws, the author or authors
14
+# of this software dedicate any and all copyright interest in the
15
+# software to the public domain. We make this dedication for the benefit
16
+# of the public at large and to the detriment of our heirs and
17
+# successors. We intend this dedication to be an overt act of
18
+# relinquishment in perpetuity of all present and future rights to this
19
+# software under copyright law.
20
+#
21
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27
+# OTHER DEALINGS IN THE SOFTWARE.
28
+#
29
+# For more information, please refer to <http://unlicense.org/>
30
+
31
+import os
32
+import ycm_core
33
+
34
+# These are the compilation flags that will be used in case there's no
35
+# compilation database set (by default, one is not set).
36
+# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
37
+flags = [
38
+'-Wall',
39
+'-Wextra',
40
+'-Werror',
41
+'-Wno-c++98-compat',
42
+'-Wno-long-long',
43
+'-Wno-variadic-macros',
44
+'-fexceptions',
45
+'-DNDEBUG',
46
+# You 100% do NOT need -DUSE_CLANG_COMPLETER in your flags; only the YCM
47
+# source code needs it.
48
+'-DUSE_CLANG_COMPLETER',
49
+# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
50
+# language to use when compiling headers. So it will guess. Badly. So C++
51
+# headers will be compiled as C headers. You don't want that so ALWAYS specify
52
+# a "-std=<something>".
53
+# For a C project, you would set this to something like 'c99' instead of
54
+# 'c++11'.
55
+'-std=c++11',
56
+# ...and the same thing goes for the magic -x option which specifies the
57
+# language that the files to be compiled are written in. This is mostly
58
+# relevant for c++ headers.
59
+# For a C project, you would set this to 'c' instead of 'c++'.
60
+'-x',
61
+'c++',
62
+'-isystem',
63
+'../BoostParts',
64
+'-isystem',
65
+# This path will only work on OS X, but extra paths that don't exist are not
66
+# harmful
67
+'/System/Library/Frameworks/Python.framework/Headers',
68
+'-isystem',
69
+'../llvm/include',
70
+'-isystem',
71
+'../llvm/tools/clang/include',
72
+'-I',
73
+'.',
74
+'-I',
75
+'./ClangCompleter',
76
+'-isystem',
77
+'./tests/gmock/gtest',
78
+'-isystem',
79
+'./tests/gmock/gtest/include',
80
+'-isystem',
81
+'./tests/gmock',
82
+'-isystem',
83
+'./tests/gmock/include'
84
+'-I',
85
+'/usr/lib/gcc/x86_64-linux-gnu/4.8/include/',
86
+'-I',
87
+'/usr/lib/gcc/x86_64-linux-gnu/5/include/',
88
+'-I',
89
+'/usr/lib/gcc/x86_64-linux-gnu/6/include/',
90
+'-fopenmp'
91
+]
92
+
93
+
94
+# Set this to the absolute path to the folder (NOT the file!) containing the
95
+# compile_commands.json file to use that instead of 'flags'. See here for
96
+# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
97
+#
98
+# You can get CMake to generate this file for you by adding:
99
+#   set( CMAKE_EXPORT_COMPILE_COMMANDS 1 )
100
+# to your CMakeLists.txt file.
101
+#
102
+# Most projects will NOT need to set this to anything; you can just change the
103
+# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
104
+compilation_database_folder = 'build'
105
+
106
+if os.path.exists( compilation_database_folder ):
107
+  database = ycm_core.CompilationDatabase( compilation_database_folder )
108
+else:
109
+  database = None
110
+
111
+SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]
112
+
113
+def DirectoryOfThisScript():
114
+  return os.path.dirname( os.path.abspath( __file__ ) )
115
+
116
+
117
+def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
118
+  if not working_directory:
119
+    return list( flags )
120
+  new_flags = []
121
+  make_next_absolute = False
122
+  path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
123
+  for flag in flags:
124
+    new_flag = flag
125
+
126
+    if make_next_absolute:
127
+      make_next_absolute = False
128
+      if not flag.startswith( '/' ):
129
+        new_flag = os.path.join( working_directory, flag )
130
+
131
+    for path_flag in path_flags:
132
+      if flag == path_flag:
133
+        make_next_absolute = True
134
+        break
135
+
136
+      if flag.startswith( path_flag ):
137
+        path = flag[ len( path_flag ): ]
138
+        new_flag = path_flag + os.path.join( working_directory, path )
139
+        break
140
+
141
+    if new_flag:
142
+      new_flags.append( new_flag )
143
+  return new_flags
144
+
145
+
146
+def IsHeaderFile( filename ):
147
+  extension = os.path.splitext( filename )[ 1 ]
148
+  return extension in [ '.h', '.hxx', '.hpp', '.hh' ]
149
+
150
+
151
+def GetCompilationInfoForFile( filename ):
152
+  # The compilation_commands.json file generated by CMake does not have entries
153
+  # for header files. So we do our best by asking the db for flags for a
154
+  # corresponding source file, if any. If one exists, the flags for that file
155
+  # should be good enough.
156
+  if IsHeaderFile( filename ):
157
+    basename = os.path.splitext( filename )[ 0 ]
158
+    for extension in SOURCE_EXTENSIONS:
159
+      replacement_file = basename + extension
160
+      if os.path.exists( replacement_file ):
161
+        compilation_info = database.GetCompilationInfoForFile(
162
+          replacement_file )
163
+        if compilation_info.compiler_flags_:
164
+          return compilation_info
165
+    return None
166
+  return database.GetCompilationInfoForFile( filename )
167
+
168
+
169
+def FlagsForFile( filename, **kwargs ):
170
+  if database:
171
+    # Bear in mind that compilation_info.compiler_flags_ does NOT return a
172
+    # python list, but a "list-like" StringVec object
173
+    compilation_info = GetCompilationInfoForFile( filename )
174
+    if not compilation_info:
175
+      return None
176
+
177
+    final_flags = MakeRelativePathsInFlagsAbsolute(
178
+      compilation_info.compiler_flags_,
179
+      compilation_info.compiler_working_dir_ )
180
+
181
+    # NOTE: This is just for YouCompleteMe; it's highly likely that your project
182
+    # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
183
+    # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
184
+    try:
185
+      final_flags.remove( '-stdlib=libc++' )
186
+    except ValueError:
187
+      pass
188
+  else:
189
+    relative_to = DirectoryOfThisScript()
190
+    final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
191
+
192
+  return {
193
+    'flags': final_flags,
194
+    'do_cache': True
195
+  }

+ 87 - 10
src/osmfixer/index/StatIdx.cpp

@@ -12,6 +12,7 @@
12
 using osmfixer::StatIdx;
12
 using osmfixer::StatIdx;
13
 using osmfixer::OsmAttrs;
13
 using osmfixer::OsmAttrs;
14
 using osmfixer::Station;
14
 using osmfixer::Station;
15
+using osmfixer::Group;
15
 
16
 
16
 // _____________________________________________________________________________
17
 // _____________________________________________________________________________
17
 void StatIdx::readFromFile(const std::string& path) {
18
 void StatIdx::readFromFile(const std::string& path) {
@@ -25,41 +26,117 @@ void StatIdx::readFromFile(const std::string& path) {
25
     if (line.size() == 0) break;
26
     if (line.size() == 0) break;
26
 
27
 
27
     std::stringstream rec(line);
28
     std::stringstream rec(line);
28
-    size_t osmid;
29
+    size_t osmid, group;
29
     double lat, lng;
30
     double lat, lng;
30
     OsmAttrs attrs;
31
     OsmAttrs attrs;
31
 
32
 
32
     rec >> osmid;
33
     rec >> osmid;
33
     rec >> lat;
34
     rec >> lat;
34
     rec >> lng;
35
     rec >> lng;
36
+    rec >> group;
35
 
37
 
36
-    addStation(osmid, lat, lng, attrs);
38
+    addStation(osmid, lat, lng, group, attrs);
37
   }
39
   }
38
 
40
 
39
-  initIndex();
41
+  // second, parse groups
42
+  while (std::getline(f, line)) {
43
+    // empty line is separator between blocks
44
+    if (line.size() == 0) break;
45
+
46
+    std::stringstream rec(line);
47
+    size_t osmid;
48
+    OsmAttrs attrs;
49
+
50
+    rec >> osmid;
40
 
51
 
41
-  std::cout << util::geo::getWKT(_bbox) << std::endl;
52
+    addGroup(osmid, attrs);
53
+  }
54
+
55
+  initGroups();
56
+  initIndex();
42
 }
57
 }
43
 
58
 
44
 // _____________________________________________________________________________
59
 // _____________________________________________________________________________
45
-void StatIdx::addStation(size_t osmid, double lat, double lng,
60
+void StatIdx::addStation(size_t osmid, double lat, double lng, size_t group,
46
                          const OsmAttrs& attrs) {
61
                          const OsmAttrs& attrs) {
47
   std::cout << "Record: " << osmid << " " << lat << " " << lng << std::endl;
62
   std::cout << "Record: " << osmid << " " << lat << " " << lng << std::endl;
48
   auto point = util::geo::latLngToWebMerc<double>(lat, lng);
63
   auto point = util::geo::latLngToWebMerc<double>(lat, lng);
49
 
64
 
50
-  _stations.emplace_back(Station{osmid, point, attrs});
65
+  _stations.emplace_back(Station{osmid, group, point, attrs});
51
 
66
 
52
   // extend bounding box
67
   // extend bounding box
53
   _bbox = util::geo::extendBox(point, _bbox);
68
   _bbox = util::geo::extendBox(point, _bbox);
54
 }
69
 }
55
 
70
 
56
 // _____________________________________________________________________________
71
 // _____________________________________________________________________________
72
+void StatIdx::addGroup(size_t osmid, const OsmAttrs& attrs) {
73
+  std::cout << osmid << std::endl;
74
+  Group g;
75
+  g.osmid = osmid;
76
+  g.attrs = attrs;
77
+  _groups.emplace_back(g);
78
+}
79
+
80
+// _____________________________________________________________________________
81
+void StatIdx::initGroups() {
82
+  for (size_t i = 0; i < _stations.size(); i++) {
83
+    // this should be ensured by the input file
84
+    assert(_stations[i].group < _groups.size());
85
+    _groups[_stations[i].group].stations.push_back(i);
86
+  }
87
+
88
+  for (size_t i = 0; i < _groups.size(); i++) {
89
+    util::geo::MultiPoint<double> mp;
90
+    for (size_t stid : _groups[i].stations) {
91
+      double rad = 11.0;
92
+      int n = 50.0;
93
+      for (int i = 0; i <= n; i++) {
94
+        double x = rad * cos((2.0 * M_PI / static_cast<double>(n)) *
95
+                             static_cast<double>(i));
96
+        double y = rad * sin((2.0 * M_PI / static_cast<double>(n)) *
97
+                             static_cast<double>(i));
98
+
99
+        mp.push_back(util::geo::DPoint(_stations[stid].pos.getX() + x,
100
+                                       _stations[stid].pos.getY() + y));
101
+      }
102
+    }
103
+    _groups[i].poly = util::geo::convexHull(mp);
104
+  }
105
+}
106
+
107
+// _____________________________________________________________________________
57
 void StatIdx::initIndex() {
108
 void StatIdx::initIndex() {
58
-  _grid = util::geo::Grid<size_t, util::geo::Point, double>(5000, 5000, _bbox,
59
-                                                            false);
109
+  _sgrid = util::geo::Grid<size_t, util::geo::Point, double>(5000, 5000, _bbox,
110
+                                                             false);
111
+  _ggrid = util::geo::Grid<size_t, util::geo::Polygon, double>(5000, 5000,
112
+                                                               _bbox, false);
60
   for (size_t i = 0; i < _stations.size(); i++) {
113
   for (size_t i = 0; i < _stations.size(); i++) {
61
-    _grid.add(_stations[i].pos, i);
114
+    _sgrid.add(_stations[i].pos, i);
115
+  }
116
+
117
+  for (size_t i = 0; i < _groups.size(); i++) {
118
+    _ggrid.add(_groups[i].poly, i);
119
+  }
120
+}
121
+
122
+// _____________________________________________________________________________
123
+std::vector<const Group*> StatIdx::getGroups(const util::geo::DBox bbox) const {
124
+  std::vector<const Group*> ret;
125
+  auto ll = util::geo::latLngToWebMerc<double>(bbox.getLowerLeft().getX(),
126
+                                               bbox.getLowerLeft().getY());
127
+  auto ur = util::geo::latLngToWebMerc<double>(bbox.getUpperRight().getX(),
128
+                                               bbox.getUpperRight().getY());
129
+
130
+  std::set<size_t> tmp;
131
+  auto reqBox = util::geo::DBox(ll, ur);
132
+  _ggrid.get(reqBox, &tmp);
133
+
134
+  for (auto i : tmp) {
135
+    if (util::geo::intersects(_groups[i].poly, reqBox))
136
+      ret.push_back(&_groups[i]);
62
   }
137
   }
138
+
139
+  return ret;
63
 }
140
 }
64
 
141
 
65
 // _____________________________________________________________________________
142
 // _____________________________________________________________________________
@@ -73,7 +150,7 @@ std::vector<const Station*> StatIdx::getStations(
73
 
150
 
74
   std::set<size_t> tmp;
151
   std::set<size_t> tmp;
75
   auto reqBox = util::geo::DBox(ll, ur);
152
   auto reqBox = util::geo::DBox(ll, ur);
76
-  _grid.get(reqBox, &tmp);
153
+  _sgrid.get(reqBox, &tmp);
77
 
154
 
78
   for (auto i : tmp) {
155
   for (auto i : tmp) {
79
     if (util::geo::contains(_stations[i].pos, reqBox))
156
     if (util::geo::contains(_stations[i].pos, reqBox))

+ 18 - 4
src/osmfixer/index/StatIdx.h

@@ -17,10 +17,18 @@ typedef std::map<std::string, std::vector<std::string>> OsmAttrs;
17
 
17
 
18
 struct Station {
18
 struct Station {
19
   size_t osmid;
19
   size_t osmid;
20
+  size_t group;
20
   util::geo::DPoint pos;
21
   util::geo::DPoint pos;
21
   OsmAttrs attrs;
22
   OsmAttrs attrs;
22
 };
23
 };
23
 
24
 
25
+struct Group {
26
+  size_t osmid;
27
+  util::geo::DPolygon poly;
28
+  OsmAttrs attrs;
29
+  std::vector<size_t> stations;
30
+};
31
+
24
 class StatIdx {
32
 class StatIdx {
25
  public:
33
  public:
26
   StatIdx() {}
34
   StatIdx() {}
@@ -28,17 +36,23 @@ class StatIdx {
28
   void readFromFile(const std::string& path);
36
   void readFromFile(const std::string& path);
29
 
37
 
30
   std::vector<const Station*> getStations(const util::geo::DBox bbox) const;
38
   std::vector<const Station*> getStations(const util::geo::DBox bbox) const;
39
+  std::vector<const Group*> getGroups(const util::geo::DBox bbox) const;
31
 
40
 
32
  private:
41
  private:
33
-  void addStation(size_t id, double lat, double lng, const OsmAttrs& attrs);
42
+  void addStation(size_t id, double lat, double lng, size_t group,
43
+                  const OsmAttrs& attrs);
44
+  void addGroup(size_t id, const OsmAttrs& attrs);
34
 
45
 
35
   void initIndex();
46
   void initIndex();
47
+  void initGroups();
36
 
48
 
37
   std::vector<Station> _stations;
49
   std::vector<Station> _stations;
50
+  std::vector<Group> _groups;
38
   util::geo::DBox _bbox;
51
   util::geo::DBox _bbox;
39
 
52
 
40
-  util::geo::Grid<size_t, util::geo::Point, double> _grid;
53
+  util::geo::Grid<size_t, util::geo::Point, double> _sgrid;
54
+  util::geo::Grid<size_t, util::geo::Polygon, double> _ggrid;
41
 };
55
 };
42
-}
56
+}  // namespace osmfixer
43
 
57
 
44
-#endif
58
+#endif  // OSMFIXER_INDEX_STATIDX_H_

+ 49 - 7
src/osmfixer/server/StatServer.cpp

@@ -2,12 +2,12 @@
2
 // Chair of Algorithms and Data Structures.
2
 // Chair of Algorithms and Data Structures.
3
 // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
3
 // Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
 
4
 
5
+#include <vector>
5
 #include "osmfixer/server/StatServer.h"
6
 #include "osmfixer/server/StatServer.h"
6
 #include "util/Misc.h"
7
 #include "util/Misc.h"
7
 #include "util/String.h"
8
 #include "util/String.h"
8
 #include "util/geo/Geo.h"
9
 #include "util/geo/Geo.h"
9
 #include "util/log/Log.h"
10
 #include "util/log/Log.h"
10
-#include "util/String.h"
11
 
11
 
12
 using osmfixer::StatServer;
12
 using osmfixer::StatServer;
13
 using osmfixer::Params;
13
 using osmfixer::Params;
@@ -51,8 +51,7 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
51
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
51
   if (pars.count("cb")) cb = pars.find("cb")->second.c_str();
52
   auto box = util::split(pars.find("bbox")->second, ',');
52
   auto box = util::split(pars.find("bbox")->second, ',');
53
 
53
 
54
-  if (box.size() != 4)
55
-    throw std::invalid_argument("Invalid request.");
54
+  if (box.size() != 4) throw std::invalid_argument("Invalid request.");
56
 
55
 
57
   double lat1 = atof(box[0].c_str());
56
   double lat1 = atof(box[0].c_str());
58
   double lng1 = atof(box[1].c_str());
57
   double lng1 = atof(box[1].c_str());
@@ -61,18 +60,37 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
61
 
60
 
62
   std::cout << pars.find("bbox")->second << std::endl;
61
   std::cout << pars.find("bbox")->second << std::endl;
63
 
62
 
64
-  util::geo::DBox bbox(util::geo::DPoint(lng1, lat1), util::geo::DPoint(lng2, lat2));
63
+  util::geo::DBox bbox(util::geo::DPoint(lat1, lng1),
64
+                       util::geo::DPoint(lat2, lng2));
65
 
65
 
66
   LOG(INFO) << "Request for bounding box " << util::geo::getWKT(bbox);
66
   LOG(INFO) << "Request for bounding box " << util::geo::getWKT(bbox);
67
 
67
 
68
   std::stringstream json;
68
   std::stringstream json;
69
 
69
 
70
+  json << std::setprecision(10);
71
+
70
   if (cb.size()) json << cb << "(";
72
   if (cb.size()) json << cb << "(";
71
-  json << "[";
73
+  json << "{\"stats\":[";
74
+
75
+  auto ret = _idx->getStations(bbox);
76
+  char sep = ' ';
77
+  for (auto stat : ret) {
78
+    json << sep;
79
+    sep = ',';
80
+    printStation(stat, &json);
81
+  }
72
 
82
 
73
-  // TODO: query index
83
+  json << "], \"groups\":[";
84
+  auto gret = _idx->getGroups(bbox);
85
+  sep = ' ';
86
+  for (auto group : gret) {
87
+    json << sep;
88
+    sep = ',';
89
+    printGroup(group, &json);
90
+  }
91
+
92
+  json << "]}";
74
 
93
 
75
-  json << "]";
76
   if (cb.size()) json << ")";
94
   if (cb.size()) json << ")";
77
 
95
 
78
   auto answ = util::http::Answer("200 OK", json.str(), true);
96
   auto answ = util::http::Answer("200 OK", json.str(), true);
@@ -82,6 +100,30 @@ util::http::Answer StatServer::handleMapReq(const Params& pars) const {
82
 }
100
 }
83
 
101
 
84
 // _____________________________________________________________________________
102
 // _____________________________________________________________________________
103
+void StatServer::printStation(const Station* stat, std::ostream* out) {
104
+  auto latLng =
105
+      util::geo::webMercToLatLng<double>(stat->pos.getX(), stat->pos.getY());
106
+  (*out) << "{\"id\":" << stat->osmid << ",\"lat\":"
107
+         << latLng.getY() << ",\"lon\":" << latLng.getX() << "}";
108
+}
109
+
110
+// _____________________________________________________________________________
111
+void StatServer::printGroup(const Group* group, std::ostream* out) {
112
+  std::vector<util::geo::DPoint> projPoly;
113
+
114
+  for (auto p : group->poly.getOuter()) {
115
+    projPoly.push_back(util::geo::webMercToLatLng<double>(p.getX(), p.getY()));
116
+  }
117
+  (*out) << "{\"id\":" << group->osmid << ",\"poly\":[";
118
+  char sep = ' ';
119
+  for (auto p : projPoly) {
120
+    (*out) << sep << "[" << p.getY() << "," << p.getX() << "]";
121
+    sep = ',';
122
+  }
123
+  (*out) << "]}";
124
+}
125
+
126
+// _____________________________________________________________________________
85
 std::string StatServer::parseUrl(std::string u, std::string pl,
127
 std::string StatServer::parseUrl(std::string u, std::string pl,
86
                                  std::map<std::string, std::string>* params) {
128
                                  std::map<std::string, std::string>* params) {
87
   auto parts = util::split(u, '?');
129
   auto parts = util::split(u, '?');

+ 8 - 3
src/osmfixer/server/StatServer.h

@@ -5,6 +5,8 @@
5
 #ifndef OSMFIXER_SERVER_STATSERVER_H_
5
 #ifndef OSMFIXER_SERVER_STATSERVER_H_
6
 #define OSMFIXER_SERVER_STATSERVER_H_
6
 #define OSMFIXER_SERVER_STATSERVER_H_
7
 
7
 
8
+#include <map>
9
+#include <string>
8
 #include "osmfixer/index/StatIdx.h"
10
 #include "osmfixer/index/StatIdx.h"
9
 #include "util/http/Server.h"
11
 #include "util/http/Server.h"
10
 
12
 
@@ -14,7 +16,7 @@ typedef std::map<std::string, std::string> Params;
14
 
16
 
15
 class StatServer : public util::http::Handler {
17
 class StatServer : public util::http::Handler {
16
  public:
18
  public:
17
-  StatServer(const osmfixer::StatIdx* idx) : _idx(idx) {}
19
+  explicit StatServer(const osmfixer::StatIdx* idx) : _idx(idx) {}
18
 
20
 
19
   virtual util::http::Answer handle(const util::http::Req& request,
21
   virtual util::http::Answer handle(const util::http::Req& request,
20
                                     int connection) const;
22
                                     int connection) const;
@@ -24,8 +26,11 @@ class StatServer : public util::http::Handler {
24
 
26
 
25
   util::http::Answer handleMapReq(const Params& pars) const;
27
   util::http::Answer handleMapReq(const Params& pars) const;
26
 
28
 
29
+  static void printStation(const Station* stat, std::ostream* out);
30
+  static void printGroup(const Group* stat, std::ostream* out);
31
+
27
   const osmfixer::StatIdx* _idx;
32
   const osmfixer::StatIdx* _idx;
28
 };
33
 };
29
-}
34
+}  // namespace osmfixer
30
 
35
 
31
-#endif
36
+#endif  // OSMFIXER_SERVER_STATSERVER_H_

BIN
src/util/geo/.PolyLine.h.swp


+ 100 - 17
src/util/geo/Geo.h

@@ -243,15 +243,21 @@ inline bool doubleEq(double a, double b) { return fabs(a - b) < EPSILON; }
243
 // _____________________________________________________________________________
243
 // _____________________________________________________________________________
244
 template <typename T>
244
 template <typename T>
245
 inline bool contains(const Point<T>& p, const Box<T>& box) {
245
 inline bool contains(const Point<T>& p, const Box<T>& box) {
246
-  return p.getX() >= box.getLowerLeft().getX() &&
247
-         p.getX() <= box.getUpperRight().getX() &&
248
-         p.getY() >= box.getLowerLeft().getY() &&
249
-         p.getY() <= box.getUpperRight().getY();
246
+  // check if point lies in box
247
+  return (fabs(p.getX() - box.getLowerLeft().getX()) < EPSILON ||
248
+          p.getX() > box.getLowerLeft().getX()) &&
249
+         (fabs(p.getX() - box.getUpperRight().getX()) < EPSILON ||
250
+          p.getX() < box.getUpperRight().getX()) &&
251
+         (fabs(p.getY() - box.getLowerLeft().getY()) < EPSILON ||
252
+          p.getY() > box.getLowerLeft().getY()) &&
253
+         (fabs(p.getY() - box.getUpperRight().getY()) < EPSILON ||
254
+          p.getY() < box.getUpperRight().getY());
250
 }
255
 }
251
 
256
 
252
 // _____________________________________________________________________________
257
 // _____________________________________________________________________________
253
 template <typename T>
258
 template <typename T>
254
 inline bool contains(const Line<T>& l, const Box<T>& box) {
259
 inline bool contains(const Line<T>& l, const Box<T>& box) {
260
+  // check if line lies in box
255
   for (const auto& p : l)
261
   for (const auto& p : l)
256
     if (!contains(p, box)) return false;
262
     if (!contains(p, box)) return false;
257
   return true;
263
   return true;
@@ -260,24 +266,35 @@ inline bool contains(const Line<T>& l, const Box<T>& box) {
260
 // _____________________________________________________________________________
266
 // _____________________________________________________________________________
261
 template <typename T>
267
 template <typename T>
262
 inline bool contains(const LineSegment<T>& l, const Box<T>& box) {
268
 inline bool contains(const LineSegment<T>& l, const Box<T>& box) {
269
+  // check if line segment lies in box
263
   return contains(l.first, box) && contains(l.second, box);
270
   return contains(l.first, box) && contains(l.second, box);
264
 }
271
 }
265
 
272
 
266
 // _____________________________________________________________________________
273
 // _____________________________________________________________________________
267
 template <typename T>
274
 template <typename T>
268
 inline bool contains(const Box<T>& b, const Box<T>& box) {
275
 inline bool contains(const Box<T>& b, const Box<T>& box) {
276
+  // check if box b lies in box
269
   return contains(b.getLowerLeft(), box) && contains(b.getUpperRight(), box);
277
   return contains(b.getLowerLeft(), box) && contains(b.getUpperRight(), box);
270
 }
278
 }
271
 
279
 
272
 // _____________________________________________________________________________
280
 // _____________________________________________________________________________
273
 template <typename T>
281
 template <typename T>
274
 inline bool contains(const Point<T>& p, const LineSegment<T>& ls) {
282
 inline bool contains(const Point<T>& p, const LineSegment<T>& ls) {
283
+  // check if point p lies in (on) line segment ls
275
   return fabs(crossProd(p, ls)) < EPSILON && contains(p, getBoundingBox(ls));
284
   return fabs(crossProd(p, ls)) < EPSILON && contains(p, getBoundingBox(ls));
276
 }
285
 }
277
 
286
 
278
 // _____________________________________________________________________________
287
 // _____________________________________________________________________________
279
 template <typename T>
288
 template <typename T>
289
+inline bool contains(const LineSegment<T>& a, const LineSegment<T>& b) {
290
+  // check if line segment a is contained in line segment b
291
+  return contains(a.first, b) && contains(a.second, b);
292
+}
293
+
294
+// _____________________________________________________________________________
295
+template <typename T>
280
 inline bool contains(const Point<T>& p, const Line<T>& l) {
296
 inline bool contains(const Point<T>& p, const Line<T>& l) {
297
+  // check if point p lies in line l
281
   for (size_t i = 1; i < l.size(); i++) {
298
   for (size_t i = 1; i < l.size(); i++) {
282
     if (contains(p, LineSegment<T>(l[i - 1], l[i]))) return true;
299
     if (contains(p, LineSegment<T>(l[i - 1], l[i]))) return true;
283
   }
300
   }
@@ -287,6 +304,8 @@ inline bool contains(const Point<T>& p, const Line<T>& l) {
287
 // _____________________________________________________________________________
304
 // _____________________________________________________________________________
288
 template <typename T>
305
 template <typename T>
289
 inline bool contains(const Point<T>& p, const Polygon<T>& poly) {
306
 inline bool contains(const Point<T>& p, const Polygon<T>& poly) {
307
+  // check if point p lies in polygon
308
+
290
   // see https://de.wikipedia.org/wiki/Punkt-in-Polygon-Test_nach_Jordan
309
   // see https://de.wikipedia.org/wiki/Punkt-in-Polygon-Test_nach_Jordan
291
   int8_t c = -1;
310
   int8_t c = -1;
292
 
311
 
@@ -328,19 +347,53 @@ inline int8_t polyContCheck(const Point<T>& a, Point<T> b, Point<T> c) {
328
 // _____________________________________________________________________________
347
 // _____________________________________________________________________________
329
 template <typename T>
348
 template <typename T>
330
 inline bool contains(const Polygon<T>& polyC, const Polygon<T>& poly) {
349
 inline bool contains(const Polygon<T>& polyC, const Polygon<T>& poly) {
331
-  for (const auto& p : polyC.getOuter()) {
332
-    if (!contains(p, poly)) {
350
+  // check if polygon polyC lies in polygon poly
351
+
352
+  for (size_t i = 1; i < polyC.getOuter().size(); i++) {
353
+    if (!contains(LineSegment<T>(polyC.getOuter()[i - 1], polyC.getOuter()[i]),
354
+                  poly))
355
+      return false;
356
+  }
357
+
358
+  // also check the last hop
359
+  if (!contains(LineSegment<T>(polyC.getOuter().back(), polyC.getOuter().front()),
360
+                poly))
361
+    return false;
362
+
363
+  return true;
364
+}
365
+
366
+// _____________________________________________________________________________
367
+template <typename T>
368
+inline bool contains(const LineSegment<T>& ls, const Polygon<T>& p) {
369
+  // check if linesegment ls lies in polygon poly
370
+
371
+  // if one of the endpoints lies outside, abort
372
+  if (!contains(ls.first, p)) return false;
373
+  if (!contains(ls.second, p)) return false;
374
+
375
+  for (size_t i = 1; i < p.getOuter().size(); i++) {
376
+    auto seg = LineSegment<T>(p.getOuter()[i - 1], p.getOuter()[i]);
377
+    if (!(contains(ls.first, seg) || contains(ls.second, seg)) &&
378
+        intersects(seg, ls)) {
333
       return false;
379
       return false;
334
     }
380
     }
335
   }
381
   }
382
+
383
+  auto seg = LineSegment<T>(p.getOuter().back(), p.getOuter().front());
384
+  if (!(contains(ls.first, seg) || contains(ls.second, seg)) &&
385
+      intersects(seg, ls)) {
386
+    return false;
387
+  }
388
+
336
   return true;
389
   return true;
337
 }
390
 }
338
 
391
 
339
 // _____________________________________________________________________________
392
 // _____________________________________________________________________________
340
 template <typename T>
393
 template <typename T>
341
 inline bool contains(const Line<T>& l, const Polygon<T>& poly) {
394
 inline bool contains(const Line<T>& l, const Polygon<T>& poly) {
342
-  for (const auto& p : l) {
343
-    if (!contains(p, poly)) {
395
+  for (size_t i = 1; i < l.size(); i++) {
396
+    if (!contains(LineSegment<T>(l[i - 1], l[i]), poly)) {
344
       return false;
397
       return false;
345
     }
398
     }
346
   }
399
   }
@@ -351,9 +404,7 @@ inline bool contains(const Line<T>& l, const Polygon<T>& poly) {
351
 template <typename T>
404
 template <typename T>
352
 inline bool contains(const Line<T>& l, const Line<T>& other) {
405
 inline bool contains(const Line<T>& l, const Line<T>& other) {
353
   for (const auto& p : l) {
406
   for (const auto& p : l) {
354
-    if (!contains(p, other)) {
355
-      return false;
356
-    }
407
+    if (!contains(p, other)) return false;
357
   }
408
   }
358
   return true;
409
   return true;
359
 }
410
 }
@@ -361,17 +412,13 @@ inline bool contains(const Line<T>& l, const Line<T>& other) {
361
 // _____________________________________________________________________________
412
 // _____________________________________________________________________________
362
 template <typename T>
413
 template <typename T>
363
 inline bool contains(const Box<T>& b, const Polygon<T>& poly) {
414
 inline bool contains(const Box<T>& b, const Polygon<T>& poly) {
364
-  return contains(b.getLowerLeft(), poly) &&
365
-         contains(b.getUpperRight(), poly) &&
366
-         contains(Point<T>(b.getUpperRight().getX(), b.getLowerLeft().getY()),
367
-                  poly) &&
368
-         contains(Point<T>(b.getLowerLeft().getX(), b.getUpperRight().getY()),
369
-                  poly);
415
+  return contains(convexHull(b), poly);
370
 }
416
 }
371
 
417
 
372
 // _____________________________________________________________________________
418
 // _____________________________________________________________________________
373
 template <typename T>
419
 template <typename T>
374
 inline bool contains(const Polygon<T>& poly, const Box<T>& b) {
420
 inline bool contains(const Polygon<T>& poly, const Box<T>& b) {
421
+  // check of poly lies in box
375
   for (const auto& p : poly.getOuter()) {
422
   for (const auto& p : poly.getOuter()) {
376
     if (!contains(p, b)) return false;
423
     if (!contains(p, b)) return false;
377
   }
424
   }
@@ -400,6 +447,8 @@ inline bool contains(const std::vector<GeometryA<T>>& multigeo,
400
 // _____________________________________________________________________________
447
 // _____________________________________________________________________________
401
 template <typename T>
448
 template <typename T>
402
 inline bool intersects(const LineSegment<T>& ls1, const LineSegment<T>& ls2) {
449
 inline bool intersects(const LineSegment<T>& ls1, const LineSegment<T>& ls2) {
450
+  // check if two linesegments intersect
451
+
403
   // two line segments intersect of there is a single, well-defined intersection
452
   // two line segments intersect of there is a single, well-defined intersection
404
   // point between them. If more than 1 endpoint is colinear with any line,
453
   // point between them. If more than 1 endpoint is colinear with any line,
405
   // the segments have infinite intersections. We handle this case as non-
454
   // the segments have infinite intersections. We handle this case as non-
@@ -470,6 +519,39 @@ inline bool intersects(const Box<T>& b1, const Box<T>& b2) {
470
 
519
 
471
 // _____________________________________________________________________________
520
 // _____________________________________________________________________________
472
 template <typename T>
521
 template <typename T>
522
+inline bool intersects(const Box<T>& b, const Polygon<T>& poly) {
523
+  return intersects(b, poly);
524
+}
525
+
526
+// _____________________________________________________________________________
527
+template <typename T>
528
+inline bool intersects(const Polygon<T>& poly, const Box<T>& b) {
529
+  if (intersects(
530
+          LineSegment<T>(b.getLowerLeft(), Point<T>(b.getUpperRight().getX(),
531
+                                                    b.getLowerLeft().getY())),
532
+          poly))
533
+    return true;
534
+  if (intersects(
535
+          LineSegment<T>(b.getLowerLeft(), Point<T>(b.getLowerLeft().getX(),
536
+                                                    b.getUpperRight().getY())),
537
+          poly))
538
+    return true;
539
+  if (intersects(
540
+          LineSegment<T>(b.getUpperRight(), Point<T>(b.getLowerLeft().getX(),
541
+                                                     b.getUpperRight().getY())),
542
+          poly))
543
+    return true;
544
+  if (intersects(
545
+          LineSegment<T>(b.getUpperRight(), Point<T>(b.getUpperRight().getX(),
546
+                                                     b.getLowerLeft().getY())),
547
+          poly))
548
+    return true;
549
+
550
+  return contains(poly, b) || contains(b, poly);
551
+}
552
+
553
+// _____________________________________________________________________________
554
+template <typename T>
473
 inline bool intersects(const LineSegment<T>& ls, const Box<T>& b) {
555
 inline bool intersects(const LineSegment<T>& ls, const Box<T>& b) {
474
   if (intersects(ls, LineSegment<T>(b.getLowerLeft(),
556
   if (intersects(ls, LineSegment<T>(b.getLowerLeft(),
475
                                     Point<T>(b.getUpperRight().getX(),
557
                                     Point<T>(b.getUpperRight().getX(),
@@ -499,6 +581,7 @@ inline bool intersects(const LineSegment<T>& ls, const Polygon<T>& p) {
499
       return true;
581
       return true;
500
   }
582
   }
501
 
583
 
584
+  // also check the last hop
502
   if (intersects(LineSegment<T>(p.getOuter().back(), p.getOuter().front()), ls))
585
   if (intersects(LineSegment<T>(p.getOuter().back(), p.getOuter().front()), ls))
503
     return true;
586
     return true;
504
 
587
 

+ 20 - 0
src/util/tests/TestMain.cpp

@@ -1446,6 +1446,26 @@ CASE("geometry") {
1446
   EXPECT(geo::dist(Line<double>{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, Point<double>{7, 4}) == approx(0));
1446
   EXPECT(geo::dist(Line<double>{{7, 7}, {7, -7}, {-7, -7}, {-7, 7}, {9, 0}, {-9, 0}, {0, 9}, {0, -9}}, Point<double>{7, 4}) == approx(0));
1447
   EXPECT(geo::dist(Line<double>{{0, 0}, {1, 1}, {2, 0}}, Line<double>{{1.5, 0.5}, {1.5, 100}}) == approx(0));
1447
   EXPECT(geo::dist(Line<double>{{0, 0}, {1, 1}, {2, 0}}, Line<double>{{1.5, 0.5}, {1.5, 100}}) == approx(0));
1448
   EXPECT(geo::dist(Line<double>{{0, 0}, {1, 1}, {2, 0}}, Line<double>{{2, 0.5}, {2, 100}}) == approx(0.353553));
1448
   EXPECT(geo::dist(Line<double>{{0, 0}, {1, 1}, {2, 0}}, Line<double>{{2, 0.5}, {2, 100}}) == approx(0.353553));
1449
+
1450
+  EXPECT(geo::contains(util::geo::Point<double>{1.5, 0.5}, util::geo::LineSegment<double>{{1, 1},{1.5, 0.5}}));
1451
+  EXPECT(geo::contains(util::geo::Point<double>{1.5, 0.5}, util::geo::LineSegment<double>{{1, 1},{1.5, 0.5}}));
1452
+
1453
+  auto polyTest = geo::Polygon<double>({{1, 1}, {3, 1}, {2, 2}, {3, 3}, {1, 3}});
1454
+  EXPECT(!geo::contains(util::geo::LineSegment<double>({2.5, 1.3}, {2.5, 2.6}), polyTest));
1455
+
1456
+  EXPECT(!geo::contains(util::geo::LineSegment<double>{{2.5, 1.3}, {2.5, 2.6}}, polyTest));
1457
+  EXPECT(geo::contains(util::geo::LineSegment<double>{{2.5, 2.6}, {1.5, 2}}, polyTest));
1458
+  EXPECT(!geo::contains(util::geo::Line<double>{{2.5, 1.3}, {2.5, 2.6}, {1.5, 2}}, polyTest));
1459
+  EXPECT(geo::contains(util::geo::Line<double>{{2.5, 1.3}, {1.5, 2}, {2.5, 2.6}}, polyTest));
1460
+
1461
+  EXPECT(!geo::contains(util::geo::Box<double>{{1, 1},{2.5, 2.6}}, polyTest));
1462
+
1463
+  EXPECT(geo::intersects(Box<double>(Point<double>(0, 0), Point<double>(10, 10)), Box<double>(Point<double>(2, 2), Point<double>(8, 8))));
1464
+  EXPECT(geo::intersects(Box<double>(Point<double>(0, 0), Point<double>(10, 10)), Box<double>(Point<double>(-2, -2), Point<double>(8, 8))));
1465
+  EXPECT(geo::intersects(Box<double>(Point<double>(0, 0), Point<double>(10, 10)), Box<double>(Point<double>(-2, -2), Point<double>(12, 12))));
1466
+  EXPECT(geo::intersects(Box<double>(Point<double>(0, 0), Point<double>(10, 10)), Box<double>(Point<double>(5, 5), Point<double>(12, 12))));
1467
+
1468
+  EXPECT(!geo::intersects(Box<double>(Point<double>(0, 0), Point<double>(10, 10)), Box<double>(Point<double>(15, 15), Point<double>(12, 12))));
1449
 }
1469
 }
1450
 
1470
 
1451
 }};
1471
 }};