diff --git a/include/soro/infrastructure/graph/element.h b/include/soro/infrastructure/graph/element.h index 7c3fa34b..548f9e6b 100644 --- a/include/soro/infrastructure/graph/element.h +++ b/include/soro/infrastructure/graph/element.h @@ -10,6 +10,8 @@ #include "soro/si/units.h" #include "soro/infrastructure/graph/type.h" +#include "soro/infrastructure/kilometrage.h" +#include "soro/infrastructure/line.h" namespace soro::infra { @@ -29,8 +31,7 @@ auto const INVALID_ELEMENT_ID = std::numeric_limits::max(); using kilometrage = si::length; -using line_id = uint32_t; -constexpr auto const INVALID_LINE_ID = std::numeric_limits::max(); +constexpr auto const INVALID_LINE_ID = std::numeric_limits::max(); struct end_element { #if !(defined(SERIALIZE) || defined(__EMSCRIPTEN__)) @@ -66,7 +67,7 @@ struct end_element { soro::array neighbours_{nullptr, nullptr}; kilometrage km_{si::INVALID}; - line_id line_{INVALID_LINE_ID}; + line::id line_{INVALID_LINE_ID}; }; struct simple_element { @@ -108,8 +109,8 @@ struct simple_element { kilometrage end_km_{si::INVALID}; kilometrage start_km_{si::INVALID}; - line_id end_line_{INVALID_LINE_ID}; - line_id start_line_{INVALID_LINE_ID}; + line::id end_line_{INVALID_LINE_ID}; + line::id start_line_{INVALID_LINE_ID}; bool end_rising_{false}; }; @@ -144,7 +145,7 @@ struct track_element { soro::array neighbours_{nullptr, nullptr}; kilometrage km_{si::INVALID}; - line_id line_{INVALID_LINE_ID}; + line::id line_{INVALID_LINE_ID}; }; struct undirected_track_element { @@ -185,7 +186,7 @@ struct undirected_track_element { soro::array neighbours_{nullptr, nullptr, nullptr, nullptr}; kilometrage km_{si::INVALID}; - line_id line_{INVALID_LINE_ID}; + line::id line_{INVALID_LINE_ID}; }; struct simple_switch { @@ -230,7 +231,7 @@ struct simple_switch { soro::array neighbours_{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; - line_id start_line_{INVALID_LINE_ID}, stem_line_{INVALID_LINE_ID}, + line::id start_line_{INVALID_LINE_ID}, stem_line_{INVALID_LINE_ID}, branch_line_{INVALID_LINE_ID}; kilometrage start_km_{si::INVALID}, stem_km_{si::INVALID}, branch_km_{si::INVALID}; @@ -291,8 +292,8 @@ struct cross { bool start_left_end_right_arc_{false}; bool start_right_end_left_arc_{false}; - line_id start_left_line_{INVALID_LINE_ID}, end_left_line_{INVALID_LINE_ID}; - line_id start_right_line_{INVALID_LINE_ID}, end_right_line_{INVALID_LINE_ID}; + line::id start_left_line_{INVALID_LINE_ID}, end_left_line_{INVALID_LINE_ID}; + line::id start_right_line_{INVALID_LINE_ID}, end_right_line_{INVALID_LINE_ID}; kilometrage start_left_km_{si::INVALID}, end_left_km_{si::INVALID}; kilometrage start_right_km_{si::INVALID}, diff --git a/include/soro/infrastructure/graph/graph_creation.h b/include/soro/infrastructure/graph/graph_creation.h index 2c51b02e..7d27fe42 100644 --- a/include/soro/infrastructure/graph/graph_creation.h +++ b/include/soro/infrastructure/graph/graph_creation.h @@ -57,7 +57,7 @@ element* get_or_create_element(graph& network, station& station, bool const rising); void set_km_point_and_line(element& e, std::string const& node_name, - kilometrage km_point, line_id line); + kilometrage km_point, line::id line); void set_neighbour(element& e, std::string const& name, element* neigh, bool const rising); diff --git a/include/soro/infrastructure/graph/section.h b/include/soro/infrastructure/graph/section.h index 5fef6c12..e49285c5 100644 --- a/include/soro/infrastructure/graph/section.h +++ b/include/soro/infrastructure/graph/section.h @@ -48,7 +48,7 @@ struct section { soro::vector falling_order_; si::length length_{si::ZERO}; - line_id line_id_{INVALID_LINE_ID}; + line::id line_id_{INVALID_LINE_ID}; }; } // namespace soro::infra diff --git a/include/soro/infrastructure/graph/type.h b/include/soro/infrastructure/graph/type.h index e12be5b4..6f06be48 100644 --- a/include/soro/infrastructure/graph/type.h +++ b/include/soro/infrastructure/graph/type.h @@ -29,7 +29,12 @@ enum class type : type_id { SPEED_LIMIT, POINT_SPEED, BRAKE_PATH, - CTC, + LZB_START, + LZB_END, + LZB_BLOCK_SIGN, + ETCS_START, + ETCS_END, + ETCS_BLOCK_SIGN, FORCED_HALT, HALT, // undirected track elements @@ -103,4 +108,12 @@ constexpr bool is_runtime_checkpoint(type const type) { constexpr bool is_halt(type const type) { return type == type::HALT; } +constexpr bool is_lzb(type const type) { + return type >= type::LZB_START && type <= type::LZB_BLOCK_SIGN; +} + +constexpr bool is_etcs(type const type) { + return type >= type::ETCS_START && type <= type::ETCS_BLOCK_SIGN; +} + } // namespace soro::infra diff --git a/include/soro/infrastructure/infrastructure_t.h b/include/soro/infrastructure/infrastructure_t.h index 30633a72..66846613 100644 --- a/include/soro/infrastructure/infrastructure_t.h +++ b/include/soro/infrastructure/infrastructure_t.h @@ -5,6 +5,7 @@ #include "soro/infrastructure/graph/graph.h" #include "soro/infrastructure/infrastructure_options.h" #include "soro/infrastructure/interlocking/interlocking_subsystem.h" +#include "soro/infrastructure/line.h" #include "soro/infrastructure/station/station.h" #include "soro/infrastructure/station/station_route_graph.h" #include "soro/rolling_stock/rolling_stock.h" @@ -42,6 +43,8 @@ struct infrastructure_t { soro::vector station_positions_{}; soro::vector element_positions_{}; + lines lines_{}; + soro::vector> station_store_{}; soro::vector> station_route_store_{}; soro::vector> diff --git a/include/soro/infrastructure/kilometrage.h b/include/soro/infrastructure/kilometrage.h new file mode 100644 index 00000000..53c1c28d --- /dev/null +++ b/include/soro/infrastructure/kilometrage.h @@ -0,0 +1,9 @@ +#pragma once + +#include "soro/si/units.h" + +namespace soro::infra { + +using kilometrage = si::length; + +} // namespace soro::infra \ No newline at end of file diff --git a/include/soro/infrastructure/line.h b/include/soro/infrastructure/line.h new file mode 100644 index 00000000..44f519b1 --- /dev/null +++ b/include/soro/infrastructure/line.h @@ -0,0 +1,30 @@ +#pragma once + +#include "soro/base/soro_types.h" +#include "soro/infrastructure/kilometrage.h" + +namespace soro::infra { + +struct line { + using id = uint16_t; + + struct segment { + kilometrage from_{si::INVALID}; + kilometrage to_{si::INVALID}; + bool etcs_{false}; + bool lzb_{false}; + bool signalling_{false}; + }; + + bool has_signalling(kilometrage const km) const; + bool has_etcs(kilometrage const km) const; + + id id_; + + // ordered w.r.t. distance + soro::vector segments_; +}; + +using lines = soro::map; + +} // namespace soro::infra diff --git a/include/soro/infrastructure/parsers/iss/iss_string_literals.h b/include/soro/infrastructure/parsers/iss/iss_string_literals.h index 7ce1431a..b210c718 100644 --- a/include/soro/infrastructure/parsers/iss/iss_string_literals.h +++ b/include/soro/infrastructure/parsers/iss/iss_string_literals.h @@ -34,14 +34,17 @@ constexpr const char* const ETCS_START_FALLING = "ETCSAnfangF"; constexpr const char* const ETCS_END_RISING = "ETCSEndeS"; constexpr const char* const ETCS_END_FALLING = "ETCSEndeF"; -constexpr const char* const CTC_START_FALLING = "LZBAnfangF"; -constexpr const char* const CTC_END_FALLING = "LZBEndeF"; +constexpr const char* const ETCS_BLOCK_SIGN_RISING = "ETCSBlockkennzeichenS"; +constexpr const char* const ETCS_BLOCK_SIGN_FALLING = "ETCSBlockkennzeichenF"; -constexpr const char* const CTC_START_RISING = "LZBAnfangS"; -constexpr const char* const CTC_END_RISING = "LZBEndeS"; +constexpr const char* const LZB_START_FALLING = "LZBAnfangF"; +constexpr const char* const LZB_END_FALLING = "LZBEndeF"; -constexpr const char* const CTC_BLOCK_SIGN_RISING = "LZBBlockkennzeichenS"; -constexpr const char* const CTC_BLOCK_SIGN_FALLING = "LZBBlockkennzeichenF"; +constexpr const char* const LZB_START_RISING = "LZBAnfangS"; +constexpr const char* const LZB_END_RISING = "LZBEndeS"; + +constexpr const char* const LZB_BLOCK_SIGN_RISING = "LZBBlockkennzeichenS"; +constexpr const char* const LZB_BLOCK_SIGN_FALLING = "LZBBlockkennzeichenF"; constexpr const char* const SPEED_LIMIT_RISING = "GeschwZulaessigS"; constexpr const char* const SPEED_LIMIT_FALLING = "GeschwZulaessigF"; diff --git a/include/soro/infrastructure/parsers/iss/parse_helpers.h b/include/soro/infrastructure/parsers/iss/parse_helpers.h index 24350e62..90dea08f 100644 --- a/include/soro/infrastructure/parsers/iss/parse_helpers.h +++ b/include/soro/infrastructure/parsers/iss/parse_helpers.h @@ -7,7 +7,7 @@ namespace soro::infra { -kilometrage parse_kilometrage(pugi::xml_node const& node); +kilometrage parse_kilometrage(std::string_view const kmp); rail_plan_node_id parse_rp_node_id(pugi::xml_node const& node); diff --git a/include/soro/infrastructure/parsers/iss/parse_track_element.h b/include/soro/infrastructure/parsers/iss/parse_track_element.h index f2e022ab..2ec98b3d 100644 --- a/include/soro/infrastructure/parsers/iss/parse_track_element.h +++ b/include/soro/infrastructure/parsers/iss/parse_track_element.h @@ -9,7 +9,7 @@ namespace soro::infra { element* parse_track_element(pugi::xml_node const& track_node, type const type, - bool const rising, line_id const line, + bool const rising, line::id const line, graph& network, station& station, construction_materials& mats); diff --git a/include/soro/infrastructure/regulatory_data.h b/include/soro/infrastructure/regulatory_data.h index 6354e9ef..06ea7a6f 100644 --- a/include/soro/infrastructure/regulatory_data.h +++ b/include/soro/infrastructure/regulatory_data.h @@ -1,6 +1,7 @@ #pragma once #include "soro/base/soro_types.h" +#include "soro/infrastructure/line.h" #include "soro/utls/file/loaded_file.h" namespace soro::infra { @@ -9,12 +10,10 @@ struct regulatory_station_data { soro::map ds100_to_full_name_{}; }; -struct regulatory_line_data {}; - regulatory_station_data parse_regulatory_stations( std::vector const& regulatory_station_files); -regulatory_line_data parse_regulatory_line_data( - std::vector const&); +soro::map parse_lines( + std::vector const& regulatory_line_files); } // namespace soro::infra \ No newline at end of file diff --git a/include/soro/infrastructure/station/station.h b/include/soro/infrastructure/station/station.h index 6f1f0f84..74d64b4f 100644 --- a/include/soro/infrastructure/station/station.h +++ b/include/soro/infrastructure/station/station.h @@ -44,7 +44,7 @@ struct border { std::numeric_limits::max(); // minimum information to uniquely identify a border pair - using id_tuple = std::tuple; + using id_tuple = std::tuple; auto get_id_tuple() const { return id_tuple{std::min(station_->id_, neighbour_->id_), @@ -62,7 +62,7 @@ struct border { station::ptr neighbour_{nullptr}; element::ptr neighbour_element_{nullptr}; - line_id line_{INVALID_LINE_ID}; + line::id line_{INVALID_LINE_ID}; track_sign track_sign_{INVALID_TRACK_SIGN}; bool low_border_{false}; diff --git a/include/soro/infrastructure/station/station_route.h b/include/soro/infrastructure/station/station_route.h index c63aee49..084fe23e 100644 --- a/include/soro/infrastructure/station/station_route.h +++ b/include/soro/infrastructure/station/station_route.h @@ -50,6 +50,9 @@ struct station_route { soro::vector nodes_{}; soro::vector main_signals_{}; + + soro::vector etcs_starts_{}; + soro::vector etcs_ends_{}; }; node::idx size() const noexcept; @@ -69,6 +72,8 @@ struct station_route { bool can_start_an_interlocking(station_route_graph const& srg) const; bool can_end_an_interlocking(station_route_graph const&) const; + bool requires_etcs(lines const& lines) const; + bool operator==(station_route const& o) const; bool operator!=(station_route const& o) const; diff --git a/include/soro/utls/sassert.h b/include/soro/utls/sassert.h index d74fdd2d..fc80a966 100644 --- a/include/soro/utls/sassert.h +++ b/include/soro/utls/sassert.h @@ -46,8 +46,11 @@ struct bool_with_loc { }; #if !defined(NDEBUG) + template -inline void sassert(bool_with_loc assert_this, Msg&& msg, Args... args) { +inline void sassert_impl(bool_with_loc assert_this, + std::string_view failure_type, Msg&& msg, + Args... args) { if (!assert_this) { using clock = std::chrono::system_clock; @@ -62,7 +65,7 @@ inline void sassert(bool_with_loc assert_this, Msg&& msg, Args... args) { std::stringstream ss; - fmt::print(ss, "[ASSERT FAIL][{}] ", std::put_time(&tmp, "%FT%TZ")); + fmt::print(ss, "[{}][{}] ", failure_type, std::put_time(&tmp, "%FT%TZ")); fmt::print(ss, std::forward(msg), std::forward(args)...); fmt::print(ss, "\n"); fmt::print(ss, "[FAILED HERE] {}:{}:{} in {}", @@ -79,12 +82,27 @@ inline void sassert(bool_with_loc assert_this, Msg&& msg, Args... args) { #else template -inline void sassert(bool const, Msg&&, Args...) {} +inline void sassert_impl(bool const, Msg&&, Args...) {} #endif +template +inline void sassert(bool_with_loc assert_this, Msg&& msg, Args... args) { + sassert_impl(assert_this, "ASSERT", msg, args...); +} + +template +inline void expects(bool_with_loc assert_this, Msg&& msg, Args... args) { + sassert_impl(assert_this, "PRECONDITION", msg, args...); +} + +template +inline void ensures(bool_with_loc assert_this, Msg&& msg, Args... args) { + sassert_impl(assert_this, "POSTCONDITION", msg, args...); +} + inline void sassert(bool const assert_this) { - sassert(assert_this, "I didn't specify a error message :("); + sassert_impl(assert_this, "Unknown", "I didn't specify a error message :("); } #if !defined(NDEBUG) @@ -92,9 +110,26 @@ template inline void sasserts(F&& f) { f(); } + +template +inline void expects(F&& f) { + f(); +} + +template +inline void ensures(F&& f) { + f(); +} + #else template inline void sasserts(F&&) {} + +template +inline void expects(F&&) {} + +template +inline void ensures(F&&) {} #endif } // namespace soro::utls \ No newline at end of file diff --git a/include/soro/utls/std_wrapper/std_wrapper.h b/include/soro/utls/std_wrapper/std_wrapper.h index bb91db07..7ed11eee 100644 --- a/include/soro/utls/std_wrapper/std_wrapper.h +++ b/include/soro/utls/std_wrapper/std_wrapper.h @@ -156,8 +156,8 @@ inline void append_move(C1& dest, C2&& src) { } template -inline auto any_of(Iteratable const& i, Pred&& p) { - return std::any_of(std::cbegin(i), std::cend(i), p); +inline auto any_of(Iteratable&& i, Pred&& p) { + return std::any_of(std::begin(i), std::end(i), p); } template diff --git a/src/infrastructure/graph/graph_creation.cc b/src/infrastructure/graph/graph_creation.cc index 097e3526..d2811fd4 100644 --- a/src/infrastructure/graph/graph_creation.cc +++ b/src/infrastructure/graph/graph_creation.cc @@ -48,13 +48,13 @@ element* get_or_create_element(graph& network, station& station, } void set_km_point_and_line(end_element& e, std::string const&, - kilometrage const km_point, line_id const line) { + kilometrage const km_point, line::id const line) { e.km_ = km_point; e.line_ = line; } void set_km_point_and_line(simple_element& e, std::string const& node_name, - kilometrage const km_point, line_id const line) { + kilometrage const km_point, line::id const line) { switch (str_hash(node_name)) { case str_hash(KM_JUMP_START): case str_hash(LINE_SWITCH_ZERO): { @@ -83,19 +83,19 @@ void set_km_point_and_line(simple_element& e, std::string const& node_name, } void set_km_point_and_line(track_element& e, std::string const&, - kilometrage const km_point, line_id const line) { + kilometrage const km_point, line::id const line) { e.km_ = km_point; e.line_ = line; } void set_km_point_and_line(undirected_track_element& e, std::string const&, - kilometrage const km_point, line_id const line) { + kilometrage const km_point, line::id const line) { e.km_ = km_point; e.line_ = line; } void set_km_point_and_line(simple_switch& e, std::string const& node_name, - kilometrage const km_point, line_id const line) { + kilometrage const km_point, line::id const line) { switch (str_hash(node_name)) { case str_hash(SWITCH_START): { e.start_km_ = km_point; @@ -119,7 +119,7 @@ void set_km_point_and_line(simple_switch& e, std::string const& node_name, } void set_km_point_and_line(cross& e, std::string const& node_name, - kilometrage const km_point, line_id const line) { + kilometrage const km_point, line::id const line) { switch (str_hash(node_name)) { case str_hash(CROSS_SWITCH_START_LEFT): case str_hash(CROSS_START_LEFT): { @@ -150,7 +150,7 @@ void set_km_point_and_line(cross& e, std::string const& node_name, } void set_km_point_and_line(element& e, std::string const& node_name, - kilometrage km_point, line_id line) { + kilometrage km_point, line::id line) { e.apply( [&](auto&& x) { set_km_point_and_line(x, node_name, km_point, line); }); } diff --git a/src/infrastructure/graph/type.cc b/src/infrastructure/graph/type.cc index bb3a544f..13b210c5 100644 --- a/src/infrastructure/graph/type.cc +++ b/src/infrastructure/graph/type.cc @@ -80,18 +80,19 @@ type get_type(const char* const str) { case str_hash(CROSS_SWITCH_END_LEFT): case str_hash(CROSS_SWITCH_START_RIGHT): case str_hash(CROSS_SWITCH_END_RIGHT): return type::CROSS; - case str_hash(CTC_BLOCK_SIGN_RISING): - // ct - case str_hash(CTC_BLOCK_SIGN_FALLING): - case str_hash(CTC_START_FALLING): - case str_hash(CTC_END_FALLING): - case str_hash(CTC_START_RISING): - case str_hash(CTC_END_RISING): - case str_hash(ETCS_END_RISING): - case str_hash(ETCS_END_FALLING): + case str_hash(LZB_START_RISING): + case str_hash(LZB_START_FALLING): return type::LZB_START; + case str_hash(LZB_END_RISING): + case str_hash(LZB_END_FALLING): return type::LZB_END; + case str_hash(LZB_BLOCK_SIGN_RISING): + case str_hash(LZB_BLOCK_SIGN_FALLING): return type::LZB_BLOCK_SIGN; case str_hash(ETCS_START_RISING): - case str_hash(ETCS_START_FALLING): - return type::CTC; + case str_hash(ETCS_START_FALLING): return type::ETCS_START; + case str_hash(ETCS_END_RISING): + case str_hash(ETCS_END_FALLING): return type::ETCS_END; + case str_hash(ETCS_BLOCK_SIGN_RISING): + case str_hash(ETCS_BLOCK_SIGN_FALLING): + return type::ETCS_BLOCK_SIGN; // ignore these for the moment default: case str_hash(PICTURE_POINT): @@ -127,7 +128,12 @@ std::string get_type_str(type const& t) { case type::SLOPE: return "slope"; case type::LEVEL_CROSSING: return "level_crossing"; case type::CROSS: return "cross"; - case type::CTC: return "ctc"; + case type::LZB_END: return "lzb_end"; + case type::LZB_START: return "lzb_start"; + case type::LZB_BLOCK_SIGN: return "lzb_block_sign"; + case type::ETCS_END: return "etcs_end"; + case type::ETCS_START: return "etcs_start"; + case type::ETCS_BLOCK_SIGN: return "etcs_block_sign"; } throw utl::fail("No type string found in infrastructure element"); } diff --git a/src/infrastructure/interlocking/get_interlocking_subsystem.cc b/src/infrastructure/interlocking/get_interlocking_subsystem.cc index c9498c91..71e8dafc 100644 --- a/src/infrastructure/interlocking/get_interlocking_subsystem.cc +++ b/src/infrastructure/interlocking/get_interlocking_subsystem.cc @@ -137,37 +137,11 @@ interlocking_route get_trailing_interlocking_route( .station_routes_ = {sr->id_}}; } -std::string generate_dot_tree(station_route::ptr const route, - station_route_graph const& srg) { - std::set ids; - - auto const generate_graphviz = [&](station_route::ptr const sr, - auto&& generate_ref) { - ids.insert(sr->id_); - - if (sr->can_end_an_interlocking(srg) && sr->id_ != route->id_) { - return; - } - - for (auto const& neighbour : srg.successors_[sr->id_]) { - generate_ref(neighbour, generate_ref); - } - }; - - generate_graphviz(route, generate_graphviz); - - std::string dot; - for (auto const& id : ids) { - for (auto const& neigh : srg.successors_[id]) { - dot += std::to_string(id) + " -> " + std::to_string(neigh->id_) + ";\n"; - } - } - - return dot; -} - soro::vector get_interlocking_routes_from_sr( station_route::ptr sr, station_route_graph const& srg) { + utls::expects(sr->can_start_an_interlocking(srg), + "SR {} cannot start an interlocking route.", sr->id_); + soro::vector routes; // reserve 2^16 elements as around there is the maximum of interlocking @@ -215,7 +189,10 @@ soro::vector get_interlocking_routes( interlocking_routes.reserve(infra.station_routes_.size() * 30); for (auto const& sr : infra.station_routes_) { - if (sr->can_start_an_interlocking(infra.station_route_graph_)) { + // add all interlocking routes that start with this station route. + // do not generate them when etcs is required to use the station route. + if (sr->can_start_an_interlocking(infra.station_route_graph_) && + !sr->requires_etcs(infra.lines_)) { utl::concat(interlocking_routes, get_interlocking_routes_from_sr( sr, infra.station_route_graph_)); } diff --git a/src/infrastructure/line.cc b/src/infrastructure/line.cc new file mode 100644 index 00000000..4c192365 --- /dev/null +++ b/src/infrastructure/line.cc @@ -0,0 +1,46 @@ +#include "soro/infrastructure/line.h" + +#include "utl/logging.h" + +namespace soro::infra { + +line::segment const& get_segment(line const& l, kilometrage const km) { + utls::expects(!l.segments_.empty(), "Segments of line {} are empty.", l.id_); + + // ideally these would be a precondition, alas + if (km < l.segments_.front().from_) { + uLOG(utl::warn) << "Requesting line segment with kilometrage " << km + << ", but first line segment only starts at " + << l.segments_.front().from_ << ". Serving first segment."; + return l.segments_.front(); + } + + if (km > l.segments_.back().to_) { + uLOG(utl::warn) << "Requesting line segment with kilometrage " << km + << ", but last line segment only goes to " + << l.segments_.back().to_ << ". Serving last segment."; + return l.segments_.back(); + } + + auto const it = + std::lower_bound( + std::begin(l.segments_), std::end(l.segments_), km, + [](auto&& segment, auto&& v) { return segment.from_ <= v; }) - + 1; + + utls::sassert(it->from_ <= km && km <= it->to_, + "Segment of line {} does not contain kilometrage {}.", l.id_, + km); + + return *it; +} + +bool line::has_signalling(kilometrage const km) const { + return get_segment(*this, km).signalling_; +} + +bool line::has_etcs(kilometrage const km) const { + return get_segment(*this, km).etcs_; +} + +} // namespace soro::infra \ No newline at end of file diff --git a/src/infrastructure/parsers/iss/iss_files.cc b/src/infrastructure/parsers/iss/iss_files.cc index 8c687a25..e77414c7 100644 --- a/src/infrastructure/parsers/iss/iss_files.cc +++ b/src/infrastructure/parsers/iss/iss_files.cc @@ -21,6 +21,7 @@ void add_iss_file(iss_files& iss_fs, std::filesystem::path const& fp) { } else if (fp.filename().string().starts_with("Ordnungsrahmen_ORStr")) { iss_fs.regulatory_line_files_.emplace_back(fp); } else if (fp.filename().string().starts_with("BaubetrieblicheMassnahmen")) { + // ignore for now } else { uLOG(utl::warn) << "Found file " << fp diff --git a/src/infrastructure/parsers/iss/parse_helpers.cc b/src/infrastructure/parsers/iss/parse_helpers.cc index a02498fb..1bf51ef2 100644 --- a/src/infrastructure/parsers/iss/parse_helpers.cc +++ b/src/infrastructure/parsers/iss/parse_helpers.cc @@ -8,9 +8,7 @@ namespace soro::infra { using namespace soro::utls; -kilometrage parse_kilometrage(pugi::xml_node const& node) { - std::string_view const kmp(node.child_value(KILOMETER_POINT)); - +kilometrage parse_kilometrage(std::string_view kmp) { if (auto const pos = kmp.find('+'); pos != std::string::npos) { auto const base_km = parse_fp( diff --git a/src/infrastructure/parsers/iss/parse_iss.cc b/src/infrastructure/parsers/iss/parse_iss.cc index 1d2663d2..63c1f851 100644 --- a/src/infrastructure/parsers/iss/parse_iss.cc +++ b/src/infrastructure/parsers/iss/parse_iss.cc @@ -16,6 +16,7 @@ #include "soro/utls/execute_if.h" #include "soro/utls/parse_fp.h" +#include "soro/utls/parse_int.h" #include "soro/utls/sassert.h" #include "soro/utls/string.h" @@ -45,14 +46,16 @@ using namespace soro::utls; length get_section_length(xml_node const& section_start, xml_node const& section_end) { - auto const start_km = parse_kilometrage(section_start); - auto const end_km = parse_kilometrage(section_end); + auto const start_km = + parse_kilometrage(section_start.child_value(KILOMETER_POINT)); + auto const end_km = + parse_kilometrage(section_end.child_value(KILOMETER_POINT)); return abs(start_km - end_km); } border parse_border(xml_node const& xml_rp_border, element* border_element, - line_id const line, bool const is_start) { + line::id const line, bool const is_start) { border b; b.neighbour_name_ = xml_rp_border.child_value(PARTNER_STATION); @@ -104,12 +107,17 @@ constexpr type_order_key get_type_order_key(type const t, bool const rising) { case type::APPROACH_SIGNAL: return rising ? 130 : 131; case type::PROTECTION_SIGNAL: return rising ? 140 : 141; case type::EOTD: return rising ? 150 : 151; - case type::CTC: return rising ? 160 : 161; - case type::SPEED_LIMIT: return rising ? 170 : 171; - case type::FORCED_HALT: return rising ? 180 : 181; - case type::POINT_SPEED: return rising ? 190 : 191; + case type::LZB_START: return rising ? 160 : 161; + case type::LZB_BLOCK_SIGN: return rising ? 170 : 171; + case type::LZB_END: return rising ? 180 : 181; + case type::ETCS_START: return rising ? 190 : 191; + case type::ETCS_BLOCK_SIGN: return rising ? 200 : 201; + case type::ETCS_END: return rising ? 210 : 211; + case type::SPEED_LIMIT: return rising ? 220 : 221; + case type::FORCED_HALT: return rising ? 230 : 231; + case type::POINT_SPEED: return rising ? 240 : 241; case type::BRAKE_PATH: - return rising ? 200 : 201; + return rising ? 250 : 251; // undirected track elements part 2 case type::TRACK_NAME: return 300; @@ -158,8 +166,8 @@ bool order_impl(kilometrage const km1, type const t1, bool const r1, template bool element_order_from_nodes(xml_node const n1, xml_node const n2) { - auto const km1 = parse_kilometrage(n1); - auto const km2 = parse_kilometrage(n2); + auto const km1 = parse_kilometrage(n1.child_value(KILOMETER_POINT)); + auto const km2 = parse_kilometrage(n2.child_value(KILOMETER_POINT)); auto const r1 = has_rising_name(n1); auto const r2 = has_rising_name(n2); @@ -197,8 +205,8 @@ bool element_order(element::ptr e1, element::ptr e2) { section::id parse_section_into_network(xml_node const& xml_rp_section, station& station, graph& network, construction_materials& mats) { - line_id const line = - static_cast(std::stoul(xml_rp_section.child_value(LINE))); + auto const line_id = + utls::parse_int(xml_rp_section.child_value(LINE)); auto const& section_start = xml_rp_section.child(RAIL_PLAN_NODE).children().begin(); auto const& section_end = @@ -207,7 +215,7 @@ section::id parse_section_into_network(xml_node const& xml_rp_section, auto const section_id = create_section(network); auto& sec = network.sections_[section_id]; sec.length_ = get_section_length(*section_start, *section_end); - sec.line_id_ = line; + sec.line_id_ = line_id; auto get_main_rp_node_id = [](auto const& node) -> rail_plan_node_id { switch (str_hash(node.name())) { @@ -309,20 +317,23 @@ section::id parse_section_into_network(xml_node const& xml_rp_section, } if (utls::equal(node.name(), BORDER)) { - station.borders_.push_back(parse_border(node, element, line, is_start)); + station.borders_.push_back( + parse_border(node, element, line_id, is_start)); } return element; }; auto start_element = emplace_into_network(*section_start, true); - set_km_point_and_line(*start_element, section_start->name(), - parse_kilometrage(*section_start), line); + set_km_point_and_line( + *start_element, section_start->name(), + parse_kilometrage(section_start->child_value(KILOMETER_POINT)), line_id); network.element_id_to_section_ids_[start_element->id()].push_back(section_id); auto end_element = emplace_into_network(*section_end, false); - set_km_point_and_line(*end_element, section_end->name(), - parse_kilometrage(*section_end), line); + set_km_point_and_line( + *end_element, section_end->name(), + parse_kilometrage(section_end->child_value(KILOMETER_POINT)), line_id); network.element_id_to_section_ids_[end_element->id()].push_back(section_id); std::map undirected_track_elements; @@ -335,7 +346,7 @@ section::id parse_section_into_network(xml_node const& xml_rp_section, auto const rising_element = has_rising_name(node); auto const track_element = parse_track_element( - node, type, rising_element, line, network, station, mats); + node, type, rising_element, line_id, network, station, mats); if (dir || prev_element->is_track_element()) { set_neighbour(*prev_element, prev_node.name(), track_element, true); @@ -361,7 +372,7 @@ section::id parse_section_into_network(xml_node const& xml_rp_section, auto const track_element = utl::get_or_create(undirected_track_elements, node, [&]() { - return parse_track_element(node, type, false, line, network, + return parse_track_element(node, type, false, line_id, network, station, mats); }); @@ -582,6 +593,24 @@ deduplicated_paths get_station_route_paths(infrastructure_t const& infra, return main_signals; }; + auto const get_etcs = [&](soro::vector const& nodes) + -> std::pair, soro::vector> { + soro::vector etcs_starts, etcs_ends; + + for (node::idx idx = 0; idx < static_cast(nodes.size()); ++idx) { + auto const& node = nodes[idx]; + if (node->is(type::ETCS_START)) { + etcs_starts.emplace_back(idx); + } + + if (node->is(type::ETCS_END)) { + etcs_ends.emplace_back(idx); + } + } + + return {etcs_starts, etcs_ends}; + }; + auto const& graph = infra.graph_; deduplicated_paths result; @@ -613,6 +642,7 @@ deduplicated_paths get_station_route_paths(infrastructure_t const& infra, auto nodes = get_path(i_sr, get_node(start, true), get_node(end, false)->id_); auto main_signals = get_main_signals(i_sr, nodes); + auto [etcs_starts, etcs_ends] = get_etcs(nodes); result.path_store_.emplace_back(); result.path_store_.back() = soro::make_unique( @@ -620,7 +650,9 @@ deduplicated_paths get_station_route_paths(infrastructure_t const& infra, .end_ = end, .course_ = i_sr.course_, .nodes_ = std::move(nodes), - .main_signals_ = std::move(main_signals)}); + .main_signals_ = std::move(main_signals), + .etcs_starts_ = std::move(etcs_starts), + .etcs_ends_ = std::move(etcs_ends)}); auto const path_ptr = result.path_store_.back().get(); result.paths_.emplace_back(path_ptr); @@ -1151,6 +1183,8 @@ infrastructure_t parse_iss(infrastructure_options const& options) { iss.full_station_names_ = get_full_station_names(iss, regulatory_station_data); + iss.lines_ = parse_lines(iss_files.regulatory_line_files_); + iss.station_route_graph_ = get_station_route_graph(iss.station_routes_, iss.graph_); diff --git a/src/infrastructure/parsers/iss/parse_track_element.cc b/src/infrastructure/parsers/iss/parse_track_element.cc index c58e8be8..d2166db7 100644 --- a/src/infrastructure/parsers/iss/parse_track_element.cc +++ b/src/infrastructure/parsers/iss/parse_track_element.cc @@ -173,14 +173,15 @@ void add_element_data(pugi::xml_node const& xml_node, element* element, } element* parse_track_element(xml_node const& track_node, type const type, - bool const rising, line_id const line, + bool const rising, line::id const line, graph& network, station& station, construction_materials& mats) { auto element = create_element(network, station, mats, type, parse_rp_node_id(track_node), rising); - set_km_point_and_line(*element, track_node.name(), - parse_kilometrage(track_node), line); + set_km_point_and_line( + *element, track_node.name(), + parse_kilometrage(track_node.child_value(KILOMETER_POINT)), line); add_element_data(track_node, element, network); diff --git a/src/infrastructure/regulatory_data.cc b/src/infrastructure/regulatory_data.cc index cb626de4..8a3355c8 100644 --- a/src/infrastructure/regulatory_data.cc +++ b/src/infrastructure/regulatory_data.cc @@ -2,10 +2,15 @@ #include "pugixml.hpp" +#include "utl/concat.h" #include "utl/logging.h" #include "utl/timer.h" +#include "soro/utls/parse_fp.h" +#include "soro/utls/parse_int.h" + #include "soro/infrastructure/parsers/iss/iss_string_literals.h" +#include "soro/infrastructure/parsers/iss/parse_helpers.h" namespace soro::infra { @@ -35,10 +40,83 @@ regulatory_station_data parse_regulatory_stations( return station_data; } -regulatory_line_data parse_regulatory_line_data( - std::vector const&) { - regulatory_line_data line_data; - return line_data; +using line_type_key = uint32_t; + +static const std::map HAS_SIGNALLING = { + {1, true}, {2, true}, {3, false}, {6, true}, {8, true}, + {9, true}, {12, true}, {13, false}, {14, false}, {15, true}, + {18, true}, {20, true}, {21, true}, {23, true}, {24, false}, +}; + +static const std::map HAS_LZB = { + {1, false}, {2, true}, {3, true}, {6, false}, {8, false}, + {9, false}, {12, false}, {13, false}, {14, false}, {15, false}, + {18, false}, {20, false}, {21, false}, {23, false}, {24, false}, +}; + +static const std::map HAS_ETCS = { + {1, false}, {2, false}, {3, false}, {6, false}, {8, true}, + {9, true}, {12, true}, {13, true}, {14, false}, {15, false}, + {18, true}, {20, false}, {21, false}, {23, true}, {24, false}, +}; + +soro::vector parse_lines_from_file( + utls::loaded_file const& regulatory_line_file) { + soro::vector lines; + + pugi::xml_document d; + auto success = + d.load_buffer(reinterpret_cast(regulatory_line_file.data()), + regulatory_line_file.size()); + utl::verify(success, "Bad xml: {}", success.description()); + + for (auto const& line_xml : + d.child(XML_ISS_DATA).child("Ordnungsrahmen").child("Strecken")) { + + line l; + + l.id_ = utls::parse_int(line_xml.child_value("Nr")); + + for (auto const line_segment_xml : line_xml.child("Streckenabschnitte")) { + line::segment s; + + s.from_ = + parse_kilometrage(line_segment_xml.child_value("KilometrierungVon")); + s.to_ = + parse_kilometrage(line_segment_xml.child_value("KilometrierungBis")); + + if (auto type = line_segment_xml.child("Art"); static_cast(type)) { + auto const line_key = utls::parse_int( + type.attribute("Schluessel").value()); + + s.signalling_ = HAS_SIGNALLING.at(line_key); + s.lzb_ = HAS_LZB.at(line_key); + s.etcs_ = HAS_ETCS.at(line_key); + } + + l.segments_.push_back(s); + } + + lines.push_back(l); + } + + return lines; +} + +soro::map parse_lines( + std::vector const& regulatory_line_files) { + soro::vector lines; + + for (auto const& f : regulatory_line_files) { + utl::concat(lines, parse_lines_from_file(f)); + } + + soro::map result; + for (auto const& l : lines) { + result.emplace(l.id_, l); + } + + return result; } } // namespace soro::infra \ No newline at end of file diff --git a/src/infrastructure/station/station_route.cc b/src/infrastructure/station/station_route.cc index 78f60132..2b671100 100644 --- a/src/infrastructure/station/station_route.cc +++ b/src/infrastructure/station/station_route.cc @@ -54,6 +54,17 @@ bool station_route::is_contained_route() const { return !starts_at_boundary(*this) && !ends_at_boundary(*this); } +bool station_route::requires_etcs(lines const& lines) const { + if (!path_->etcs_starts_.empty()) { + auto const& etcs_start = + nodes(path_->etcs_starts_.back())->element_->as(); + auto const& line = lines.at(etcs_start.line_); + return !line.has_signalling(etcs_start.km_); + } + + return false; +} + bool station_route::can_start_an_interlocking( station_route_graph const& srg) const { return !this->path_->main_signals_.empty() || srg.predeccesors_[id_].empty(); diff --git a/test/src/infrastructure/graph_test.cc b/test/src/infrastructure/graph_test.cc index 5a92c61f..5ad16149 100644 --- a/test/src/infrastructure/graph_test.cc +++ b/test/src/infrastructure/graph_test.cc @@ -29,7 +29,12 @@ constexpr std::array, {type::SPEED_LIMIT, 1}, {type::POINT_SPEED, 1}, {type::BRAKE_PATH, 1}, - {type::CTC, 1}, + {type::LZB_START, 1}, + {type::LZB_END, 1}, + {type::LZB_BLOCK_SIGN, 1}, + {type::ETCS_START, 1}, + {type::ETCS_END, 1}, + {type::ETCS_BLOCK_SIGN, 1}, {type::FORCED_HALT, 1}, {type::HALT, 1}, // undirected track elements diff --git a/test/src/infrastructure/section_test.cc b/test/src/infrastructure/section_test.cc index 9c80e266..c757f799 100644 --- a/test/src/infrastructure/section_test.cc +++ b/test/src/infrastructure/section_test.cc @@ -169,13 +169,18 @@ void check_track_elements_are_ordered_correctly(section const& section) { {type::APPROACH_SIGNAL, 7}, {type::PROTECTION_SIGNAL, 8}, {type::EOTD, 9}, - {type::CTC, 10}, - {type::SPEED_LIMIT, 11}, - {type::FORCED_HALT, 12}, - {type::POINT_SPEED, 13}, - {type::BRAKE_PATH, 14}, - {type::TRACK_NAME, 15}, - {type::LEVEL_CROSSING, 16}, + {type::LZB_START, 10}, + {type::LZB_END, 11}, + {type::LZB_BLOCK_SIGN, 12}, + {type::ETCS_START, 13}, + {type::ETCS_END, 14}, + {type::ETCS_BLOCK_SIGN, 15}, + {type::SPEED_LIMIT, 16}, + {type::FORCED_HALT, 17}, + {type::POINT_SPEED, 18}, + {type::BRAKE_PATH, 19}, + {type::TRACK_NAME, 20}, + {type::LEVEL_CROSSING, 21}, }; auto const check_order = [&](struct section const& sec) {