From d6d21a9c7c5acbe5b37daa9f6307d8498bc1a97b Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Sun, 30 Aug 2026 14:52:18 +0200 Subject: Buffer situation line segments when indexing --- server/src/api.cpp | 93 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 34 deletions(-) (limited to 'server/src/api.cpp') diff --git a/server/src/api.cpp b/server/src/api.cpp index 18fbc91..9953675 100644 --- a/server/src/api.cpp +++ b/server/src/api.cpp @@ -100,9 +100,36 @@ auto tag_invoke(json::value_from_tag, json::value& jv, sysinfo const& info) handler::handler(log::logger const& l, datex2::situation_publication pub) : l_{l.sub("handler")}, pub_{std::move(pub)} { - l_.info("Building indices"); + auto const nsit = pub_.situations.size(); + auto progress_percent = + [nsit](decltype(pub_.situations)::difference_type i) -> int + { + return static_cast( + static_cast(i) / static_cast(nsit) * 100.0f); + }; + + l_.info("Building indices for {} situations", nsit); + + auto const buffer_distance = min_distance_; + auto const points_per_circle = 8; + // Note: thomas strategy does not work for geographic_join_round; + // need to use andoyer for that. + using formula = bgeo::strategy::andoyer; + bgeo::strategy::buffer::distance_symmetric distance_strategy{ + buffer_distance + }; + bgeo::strategy::buffer::geographic_join_round join_strategy{ + points_per_circle + }; + bgeo::strategy::buffer::geographic_end_round end_strategy{4}; + bgeo::strategy::buffer::geographic_point_circle circle_strategy{ + points_per_circle + }; + bgeo::strategy::buffer::geographic_side_straight side_strategy; + + l_.info("Progress: 0%"); auto const before_build = chrono::steady_clock::now(); - for (auto const& sit : pub_.situations) + for (auto const& [i, sit] : pub_.situations | std::views::enumerate) { for (auto const& rc : sit->road_closures) { @@ -110,18 +137,30 @@ handler::handler(log::logger const& l, datex2::situation_publication pub) { auto box = geo::box{}; bgeo::envelope(*ls, box); - lse_index_.insert(std::make_tuple(box, ls, rc)); + auto buffered_ls = geo::multi_polygon{}; + bgeo::buffer( + *ls, buffered_ls, distance_strategy, side_strategy, join_strategy, + end_strategy, circle_strategy); + lse_index_.insert(std::make_tuple(box, buffered_ls, rc)); } for (auto p : rc->relevant_points) { p_index_.insert(std::make_pair(p, rc)); } } + + auto prev_prog = progress_percent(i); + auto cur_prog = progress_percent(i + 1); + if (cur_prog > prev_prog && cur_prog % 5 == 0 && cur_prog != 100) + { + l_.info("Progress: {}%", cur_prog); + } } + l_.info("Progress: 100%"); + auto const after_build = chrono::steady_clock::now(); - auto const dur_build = - chrono::duration_cast(after_build - before_build); - l_.info("Indices built in {}", dur_build); + auto const dur_build_s = chrono::duration{after_build - before_build}; + l_.info("Indices built in {}", dur_build_s); l_.info("LSE index size: {}", lse_index_.size()); l_.info("Point index size: {}", p_index_.size()); } @@ -129,8 +168,6 @@ handler::handler(log::logger const& l, datex2::situation_publication pub) auto handler::process_gpx(gpx::file&& gpx_file) -> std::optional { - const auto min_distance = 5.0; - auto const now = chrono::utc_clock::now(); auto const relevant = std::initializer_list{ time::period{now - chrono::days(7), now + chrono::days(7)} @@ -149,26 +186,6 @@ auto handler::process_gpx(gpx::file&& gpx_file) auto vincenty_strategy = geo::vincenty_strategy{}; - const auto buffer_distance = min_distance; - const auto points_per_circle = 8; - // Note: thomas strategy does not work for geographic_join_round; - // need to use andoyer for that. - using formula = bgeo::strategy::thomas; - bgeo::strategy::buffer::distance_symmetric distance_strategy{ - buffer_distance - }; - bgeo::strategy::buffer::geographic_join_miter join_strategy{ - buffer_distance - }; - bgeo::strategy::buffer::geographic_end_round end_strategy{4}; - bgeo::strategy::buffer::geographic_point_circle circle_strategy{ - points_per_circle - }; - bgeo::strategy::buffer::geographic_side_straight side_strategy; - - using polygon = bgeo::model::polygon; - auto buffered_ls = bgeo::model::multi_polygon{}; - l_.debug("Querying for relevant situations"); auto relevant_road_closures = std::unordered_set>{}; @@ -179,7 +196,7 @@ auto handler::process_gpx(gpx::file&& gpx_file) { l_.debug("Checking part [{}/{}]", ++i, splits_with_overlap_segments.size()); - // TODO: consider buffering with min_distance + // TODO: consider buffering with min_distance_ auto part_box = geo::box{}; bgeo::envelope(part, part_box); @@ -193,16 +210,24 @@ auto handler::process_gpx(gpx::file&& gpx_file) // boost::geometry::model::linestring is part of the // whole tuple type (lse_index_value) that is the value_type of the // iterator. - std::shared_ptr const& ls = std::get<1>(*it); + + // geo::box const& lse = std::get<0>(*it); + geo::multi_polygon const& buffered_ls = std::get<1>(*it); std::shared_ptr const& rc = std::get<2>(*it); if (rc->validity && rc->validity->intersect(check_periods).periods().empty()) continue; - bgeo::buffer( - *ls, buffered_ls, distance_strategy, side_strategy, join_strategy, - end_strategy, circle_strategy); + + // auto small_parts = bgeo::model::multi_linestring{}; + // bgeo::intersection(part, lse, small_parts); + if (bgeo::intersects(buffered_ls, part)) relevant_road_closures.emplace(rc); + + // if (!bgeo::is_empty(small_parts)) + // if (bgeo::distance(*ls, small_parts, vincenty_strategy) < + // min_distance_) + // relevant_road_closures.emplace(rc); ls_checked++; } for (auto it = p_index_.qbegin(bgeo::index::intersects(part_box)); @@ -214,7 +239,7 @@ auto handler::process_gpx(gpx::file&& gpx_file) if (rc->validity && rc->validity->intersect(check_periods).periods().empty()) continue; - if (bgeo::distance(p, part, vincenty_strategy) < min_distance) + if (bgeo::distance(p, part, vincenty_strategy) < min_distance_) relevant_road_closures.emplace(rc); p_checked++; } -- cgit v1.3