summaryrefslogtreecommitdiffstats
path: root/server/src/api.cpp
diff options
context:
space:
mode:
authorRutger Broekhoff2026-09-08 01:36:38 +0200
committerRutger Broekhoff2026-09-08 01:37:34 +0200
commit3e8ce840c70ee00925210b96738696d1dc445f8f (patch)
tree4eb6b30b1d571daa596394c36e7769f6ee0af956 /server/src/api.cpp
parent15bcf23f2e75f9c710eee3753d530ebefc5f78f1 (diff)
downloadroutemon-3e8ce840c70ee00925210b96738696d1dc445f8f.tar.gz
routemon-3e8ce840c70ee00925210b96738696d1dc445f8f.zip
UTM projection
Diffstat (limited to 'server/src/api.cpp')
-rw-r--r--server/src/api.cpp86
1 files changed, 26 insertions, 60 deletions
diff --git a/server/src/api.cpp b/server/src/api.cpp
index 5dd3fc5..137666b 100644
--- a/server/src/api.cpp
+++ b/server/src/api.cpp
@@ -17,12 +17,14 @@ namespace views = std::views;
17 17
18namespace routemon::api { 18namespace routemon::api {
19 19
20auto json_value_from_point(geo::point const& p) -> json::value 20auto json_value_from_point(geo::utm::zonable_wgs84_point const& p)
21 -> json::value
21{ 22{
22 return json::array{bgeo::get<1>(p), bgeo::get<0>(p)}; 23 return json::array{p.lat(), p.lon()};
23} 24}
24 25
25auto json_value_from_linestring(geo::linestring const& ls) -> json::value 26auto json_value_from_linestring(geo::utm::zonable_wgs84_linestring const& ls)
27 -> json::value
26{ 28{
27 json::array a; 29 json::array a;
28 for (auto const& p : ls) 30 for (auto const& p : ls)
@@ -30,8 +32,8 @@ auto json_value_from_linestring(geo::linestring const& ls) -> json::value
30 return a; 32 return a;
31} 33}
32 34
33auto json_value_from_linestrings(std::vector<geo::linestring> const& lss) 35auto json_value_from_linestrings(
34 -> json::value 36 std::vector<geo::utm::zonable_wgs84_linestring> const& lss) -> json::value
35{ 37{
36 json::array a; 38 json::array a;
37 for (auto const& ls : lss) 39 for (auto const& ls : lss)
@@ -108,24 +110,7 @@ handler::handler(log::logger const& l, datex2::situation_publication pub)
108 static_cast<float>(i) / static_cast<float>(nsit) * 100.0f); 110 static_cast<float>(i) / static_cast<float>(nsit) * 100.0f);
109 }; 111 };
110 112
111 l_.info("Building indices for {} situations", nsit); 113 l_.info("Building indexes for {} situations", nsit);
112
113 auto const buffer_distance = min_distance_;
114 auto const points_per_circle = 8;
115 // Note: thomas strategy does not work for geographic_join_round;
116 // need to use andoyer for that.
117 using formula = bgeo::strategy::andoyer;
118 bgeo::strategy::buffer::distance_symmetric<double> distance_strategy{
119 buffer_distance
120 };
121 bgeo::strategy::buffer::geographic_join_round<formula> join_strategy{
122 points_per_circle
123 };
124 bgeo::strategy::buffer::geographic_end_round<formula> end_strategy{4};
125 bgeo::strategy::buffer::geographic_point_circle<formula> circle_strategy{
126 points_per_circle
127 };
128 bgeo::strategy::buffer::geographic_side_straight<formula> side_strategy;
129 114
130 l_.info("Progress: 0%"); 115 l_.info("Progress: 0%");
131 auto const before_build = chrono::steady_clock::now(); 116 auto const before_build = chrono::steady_clock::now();
@@ -135,17 +120,11 @@ handler::handler(log::logger const& l, datex2::situation_publication pub)
135 { 120 {
136 for (auto const& ls : rc->relevant_line_strings) 121 for (auto const& ls : rc->relevant_line_strings)
137 { 122 {
138 auto buffered_ls = geo::multi_polygon{}; 123 blse_index_.insert(*ls, rc);
139 bgeo::buffer(
140 *ls, buffered_ls, distance_strategy, side_strategy, join_strategy,
141 end_strategy, circle_strategy);
142 auto blse = geo::box{};
143 bgeo::envelope(buffered_ls, blse);
144 blse_index_.insert(std::make_tuple(blse, buffered_ls, rc));
145 } 124 }
146 for (auto p : rc->relevant_points) 125 for (auto p : rc->relevant_points)
147 { 126 {
148 p_index_.insert(std::make_pair(p, rc)); 127 p_index_.insert(p_index_value{p, rc});
149 } 128 }
150 } 129 }
151 130
@@ -160,7 +139,7 @@ handler::handler(log::logger const& l, datex2::situation_publication pub)
160 139
161 auto const after_build = chrono::steady_clock::now(); 140 auto const after_build = chrono::steady_clock::now();
162 auto const dur_build_s = chrono::duration<double>{after_build - before_build}; 141 auto const dur_build_s = chrono::duration<double>{after_build - before_build};
163 l_.info("Indices built in {}", dur_build_s); 142 l_.info("Indexes built in {}", dur_build_s);
164 l_.info("BLSE index size: {}", blse_index_.size()); 143 l_.info("BLSE index size: {}", blse_index_.size());
165 l_.info("Point index size: {}", p_index_.size()); 144 l_.info("Point index size: {}", p_index_.size());
166} 145}
@@ -175,16 +154,13 @@ auto handler::process_gpx(gpx::file&& gpx_file)
175 auto const check_periods = time::period_seq{relevant.begin(), relevant.end()}; 154 auto const check_periods = time::period_seq{relevant.begin(), relevant.end()};
176 155
177 // TODO: eliminate use of overlap segments 156 // TODO: eliminate use of overlap segments
178 auto splits_with_overlap_segments = std::vector<geo::linestring>{}; 157 auto segments = std::vector<geo::utm::zonable_wgs84_linestring>{};
179 for (auto const& track : gpx_file.tracks) 158 for (auto const& track : gpx_file.tracks)
180 for (auto const& seg : track.segments) 159 for (auto const& seg : track.segments)
181 geo::split_linestring_with_overlap_segments( 160 segments.push_back(seg.waypoints);
182 seg.waypoints,
183 5000 /* meters max total dist until a new split is forced */,
184 splits_with_overlap_segments);
185 auto const before_query = chrono::steady_clock::now(); 161 auto const before_query = chrono::steady_clock::now();
186 162
187 auto vincenty_strategy = geo::vincenty_strategy{}; 163 auto vincenty_strategy = geo::wgs84::vincenty_strategy{};
188 164
189 l_.debug("Querying for relevant situations"); 165 l_.debug("Querying for relevant situations");
190 auto relevant_road_closures = 166 auto relevant_road_closures =
@@ -192,28 +168,17 @@ auto handler::process_gpx(gpx::file&& gpx_file)
192 auto ls_checked = 0uz; 168 auto ls_checked = 0uz;
193 auto p_checked = 0uz; 169 auto p_checked = 0uz;
194 auto i = 0; 170 auto i = 0;
195 for (geo::linestring const& part : splits_with_overlap_segments) 171 for (auto const& part : segments)
196 { 172 {
197 l_.debug("Checking part [{}/{}]", ++i, splits_with_overlap_segments.size()); 173 l_.debug("Checking part [{}/{}]", ++i, segments.size());
198 174
175 auto part_zone_lss = geo::multizonal::zoned_linestring_seg_seq{part};
199 // TODO: consider buffering with min_distance_ 176 // TODO: consider buffering with min_distance_
200 auto part_box = geo::box{}; 177 auto part_box = geo::wgs84::box{};
201 bgeo::envelope(part, part_box); 178 bgeo::envelope(part, part_box);
202 179
203 for (auto it = blse_index_.qbegin(bgeo::index::intersects(part_box)); 180 for (auto const& rc : blse_index_.intersection(part_zone_lss))
204 it != blse_index_.qend(); it++)
205 { 181 {
206 // Cannot use structured bindings here, as boost::geometry::get
207 // interferes with ADL. It is a candidate as the namespace
208 // boost::geometry is part of the associated namespace set, which
209 // happens because geo::linestring ≡
210 // boost::geometry::model::linestring<geo::point> is part of the
211 // whole tuple type (blse_index_value) that is the value_type of the
212 // iterator.
213
214 geo::box const& blse = std::get<0>(*it);
215 geo::multi_polygon const& bls = std::get<1>(*it);
216 std::shared_ptr<datex2::road_closure> const& rc = std::get<2>(*it);
217 if (rc->validity 182 if (rc->validity
218 && rc->validity->intersect(check_periods).periods().empty()) 183 && rc->validity->intersect(check_periods).periods().empty())
219 continue; 184 continue;
@@ -221,8 +186,7 @@ auto handler::process_gpx(gpx::file&& gpx_file)
221 // auto small_parts = bgeo::model::multi_linestring<geo::linestring>{}; 186 // auto small_parts = bgeo::model::multi_linestring<geo::linestring>{};
222 // bgeo::intersection(part, lse, small_parts); 187 // bgeo::intersection(part, lse, small_parts);
223 188
224 if (bgeo::intersects(blse, part) && bgeo::intersects(bls, part)) 189 relevant_road_closures.emplace(rc);
225 relevant_road_closures.emplace(rc);
226 190
227 // if (!bgeo::is_empty(small_parts)) 191 // if (!bgeo::is_empty(small_parts))
228 // if (bgeo::distance(*ls, small_parts, vincenty_strategy) < 192 // if (bgeo::distance(*ls, small_parts, vincenty_strategy) <
@@ -234,7 +198,7 @@ auto handler::process_gpx(gpx::file&& gpx_file)
234 it != p_index_.qend(); it++) 198 it != p_index_.qend(); it++)
235 { 199 {
236 // Cannot use structured bindings here for the same reason as above. 200 // Cannot use structured bindings here for the same reason as above.
237 geo::point const& p = std::get<0>(*it); 201 geo::utm::zonable_wgs84_point const& p = std::get<0>(*it);
238 std::shared_ptr<datex2::road_closure> const& rc = std::get<1>(*it); 202 std::shared_ptr<datex2::road_closure> const& rc = std::get<1>(*it);
239 if (rc->validity 203 if (rc->validity
240 && rc->validity->intersect(check_periods).periods().empty()) 204 && rc->validity->intersect(check_periods).periods().empty())
@@ -301,10 +265,12 @@ auto handler::process_gpx(gpx::file&& gpx_file)
301 .relevant_lss = 265 .relevant_lss =
302 rc->relevant_line_strings 266 rc->relevant_line_strings
303 | views::transform( 267 | views::transform(
304 [](auto const& lsp) -> geo::linestring 268 [](auto const& lsp)
269 -> geo::utm::zonable_wgs84_linestring
305 { return *lsp; }) 270 { return *lsp; })
306 | std::ranges:: 271 | std::ranges::to<std::vector<
307 to<std::vector<geo::linestring>>(), 272 geo::utm::zonable_wgs84_linestring
273 >>(),
308 }; 274 };
309 }) 275 })
310 | std::ranges::to<std::vector<relevant_road_closure>>(), 276 | std::ranges::to<std::vector<relevant_road_closure>>(),