diff options
Diffstat (limited to 'server/src/datex2.cppm')
| -rw-r--r-- | server/src/datex2.cppm | 142 |
1 files changed, 71 insertions, 71 deletions
diff --git a/server/src/datex2.cppm b/server/src/datex2.cppm index b4c795f..7c20347 100644 --- a/server/src/datex2.cppm +++ b/server/src/datex2.cppm | |||
| @@ -31,7 +31,7 @@ export struct situation | |||
| 31 | { | 31 | { |
| 32 | std::string id; | 32 | std::string id; |
| 33 | std::optional<geo::point> location = | 33 | std::optional<geo::point> location = |
| 34 | std::nullopt; // as shown on the map, not used for querying | 34 | std::nullopt; // as shown on the map, not used for querying |
| 35 | std::vector<std::string> comments = {}; | 35 | std::vector<std::string> comments = {}; |
| 36 | std::vector<std::shared_ptr<road_closure>> road_closures = {}; | 36 | std::vector<std::shared_ptr<road_closure>> road_closures = {}; |
| 37 | }; | 37 | }; |
| @@ -54,13 +54,13 @@ export class loader | |||
| 54 | { | 54 | { |
| 55 | // ETRS 89 (EPSG:4258) -> WGS 84 (EPSG:4326) | 55 | // ETRS 89 (EPSG:4258) -> WGS 84 (EPSG:4326) |
| 56 | bgeo::srs::transformation< | 56 | bgeo::srs::transformation< |
| 57 | bgeo::srs::static_epsg<4258>, bgeo::srs::static_epsg<4326>> | 57 | bgeo::srs::static_epsg<4258>, bgeo::srs::static_epsg<4326>> |
| 58 | etrs89_to_wgs84_{}; | 58 | etrs89_to_wgs84_{}; |
| 59 | 59 | ||
| 60 | std::multiset<std::string> warnings_; | 60 | std::multiset<std::string> warnings_; |
| 61 | 61 | ||
| 62 | auto add_location_from_xml(road_closure& rc, pugi::xml_node const& loc_xml) | 62 | auto add_location_from_xml(road_closure& rc, pugi::xml_node const& loc_xml) |
| 63 | -> void | 63 | -> void |
| 64 | { | 64 | { |
| 65 | auto loc_xml_type = std::string_view{loc_xml.attribute("xsi:type").value()}; | 65 | auto loc_xml_type = std::string_view{loc_xml.attribute("xsi:type").value()}; |
| 66 | if (loc_xml_type == "loc:ItineraryByIndexedLocations") | 66 | if (loc_xml_type == "loc:ItineraryByIndexedLocations") |
| @@ -79,15 +79,15 @@ export class loader | |||
| 79 | return; | 79 | return; |
| 80 | 80 | ||
| 81 | auto const srs_name = | 81 | auto const srs_name = |
| 82 | std::string_view{loc_gml_xml.attribute("srsName").value()}; | 82 | std::string_view{loc_gml_xml.attribute("srsName").value()}; |
| 83 | if (srs_name != "WGS 84"sv) | 83 | if (srs_name != "WGS 84"sv) |
| 84 | { | 84 | { |
| 85 | warnings_.insert( | 85 | warnings_.insert( |
| 86 | std::format("don't now how to handle the CRS {}", srs_name)); | 86 | std::format("don't now how to handle the CRS {}", srs_name)); |
| 87 | return; | 87 | return; |
| 88 | } | 88 | } |
| 89 | auto const pos_list_str = | 89 | auto const pos_list_str = |
| 90 | std::string_view{loc_gml_xml.child_value("loc:posList")}; | 90 | std::string_view{loc_gml_xml.child_value("loc:posList")}; |
| 91 | // lat1 long1 lat2 long2 ... lat(n-1) long(n-1) latn longn | 91 | // lat1 long1 lat2 long2 ... lat(n-1) long(n-1) latn longn |
| 92 | 92 | ||
| 93 | auto ls = std::make_shared<geo::linestring>(); | 93 | auto ls = std::make_shared<geo::linestring>(); |
| @@ -97,13 +97,13 @@ export class loader | |||
| 97 | for (auto const lat_or_long_str : std::views::split(pos_list_str, " "sv)) | 97 | for (auto const lat_or_long_str : std::views::split(pos_list_str, " "sv)) |
| 98 | { | 98 | { |
| 99 | auto mlat_or_long = | 99 | auto mlat_or_long = |
| 100 | util::parse_double(std::string_view{lat_or_long_str}); | 100 | util::parse_double(std::string_view{lat_or_long_str}); |
| 101 | if (!mlat_or_long) | 101 | if (!mlat_or_long) |
| 102 | { | 102 | { |
| 103 | warnings_.insert( | 103 | warnings_.insert( |
| 104 | std::format( | 104 | std::format( |
| 105 | "failed to parse coordinate {:?}", | 105 | "failed to parse coordinate {:?}", |
| 106 | std::string_view{lat_or_long_str})); | 106 | std::string_view{lat_or_long_str})); |
| 107 | return; | 107 | return; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| @@ -131,7 +131,7 @@ export class loader | |||
| 131 | else if (loc_xml_type == "loc:PointLocation") | 131 | else if (loc_xml_type == "loc:PointLocation") |
| 132 | { | 132 | { |
| 133 | auto const& coords_xml = | 133 | auto const& coords_xml = |
| 134 | loc_xml.child("loc:pointByCoordinates").child("loc:pointCoordinates"); | 134 | loc_xml.child("loc:pointByCoordinates").child("loc:pointCoordinates"); |
| 135 | if (!coords_xml) | 135 | if (!coords_xml) |
| 136 | return; | 136 | return; |
| 137 | 137 | ||
| @@ -157,28 +157,28 @@ export class loader | |||
| 157 | else | 157 | else |
| 158 | { | 158 | { |
| 159 | warnings_.insert( | 159 | warnings_.insert( |
| 160 | std::format( | 160 | std::format( |
| 161 | "don't know how to hande location of type {}, ignoring", | 161 | "don't know how to hande location of type {}, ignoring", |
| 162 | loc_xml.attribute("xsi:type").value())); | 162 | loc_xml.attribute("xsi:type").value())); |
| 163 | return; | 163 | return; |
| 164 | } | 164 | } |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | auto handle_road_or_carriageway_or_lane_management( | 167 | auto handle_road_or_carriageway_or_lane_management( |
| 168 | pugi::xml_node const& record_xml, std::weak_ptr<situation> parent) | 168 | pugi::xml_node const& record_xml, std::weak_ptr<situation> parent) |
| 169 | -> std::optional<std::shared_ptr<road_closure>> | 169 | -> std::optional<std::shared_ptr<road_closure>> |
| 170 | { | 170 | { |
| 171 | auto const type = | 171 | auto const type = |
| 172 | std::string_view{record_xml | 172 | std::string_view{record_xml |
| 173 | .child("sit:roadOrCarriagewayOrLaneManagementType") | 173 | .child("sit:roadOrCarriagewayOrLaneManagementType") |
| 174 | .child_value()}; | 174 | .child_value()}; |
| 175 | if (type != "carriagewayClosures" && type != "roadClosed") | 175 | if (type != "carriagewayClosures" && type != "roadClosed") |
| 176 | // TODO: checken of er nog andere types fietsers de doorgang zouden | 176 | // TODO: checken of er nog andere types fietsers de doorgang zouden |
| 177 | // kunnen blokkeren? | 177 | // kunnen blokkeren? |
| 178 | return std::nullopt; | 178 | return std::nullopt; |
| 179 | 179 | ||
| 180 | auto const& restricted_vehicle_types_xml = | 180 | auto const& restricted_vehicle_types_xml = |
| 181 | record_xml.child("sit:forVehiclesWithCharacteristicsOf"); | 181 | record_xml.child("sit:forVehiclesWithCharacteristicsOf"); |
| 182 | bool likely_restriction_for_bikes = restricted_vehicle_types_xml.empty(); | 182 | bool likely_restriction_for_bikes = restricted_vehicle_types_xml.empty(); |
| 183 | for (auto const vehicle_type_xml : | 183 | for (auto const vehicle_type_xml : |
| 184 | restricted_vehicle_types_xml.children("com:vehicleType")) | 184 | restricted_vehicle_types_xml.children("com:vehicleType")) |
| @@ -199,20 +199,20 @@ export class loader | |||
| 199 | auto const& validity_xml = record_xml.child("sit:validity"); | 199 | auto const& validity_xml = record_xml.child("sit:validity"); |
| 200 | if (validity_xml | 200 | if (validity_xml |
| 201 | && validity_xml.child_value("com:validityStatus") | 201 | && validity_xml.child_value("com:validityStatus") |
| 202 | == "definedByValidityTimeSpec"sv) | 202 | == "definedByValidityTimeSpec"sv) |
| 203 | { | 203 | { |
| 204 | auto const& validity_spec_xml = | 204 | auto const& validity_spec_xml = |
| 205 | validity_xml.child("com:validityTimeSpecification"); | 205 | validity_xml.child("com:validityTimeSpecification"); |
| 206 | 206 | ||
| 207 | auto valid_periods = std::vector<time::period>{}; | 207 | auto valid_periods = std::vector<time::period>{}; |
| 208 | auto exception_periods = std::vector<time::period>{}; | 208 | auto exception_periods = std::vector<time::period>{}; |
| 209 | 209 | ||
| 210 | // TODO: com:overallEndTime may be missing (according to the DATEX | 210 | // TODO: com:overallEndTime may be missing (according to the DATEX |
| 211 | // II v3 data model) | 211 | // II v3 data model) |
| 212 | auto const overall_start_time = parse_timestamp( | 212 | auto const overall_start_time = |
| 213 | validity_spec_xml.child_value("com:overallStartTime")); | 213 | parse_timestamp(validity_spec_xml.child_value("com:overallStartTime")); |
| 214 | auto const overall_end_time = | 214 | auto const overall_end_time = |
| 215 | parse_timestamp(validity_spec_xml.child_value("com:overallEndTime")); | 215 | parse_timestamp(validity_spec_xml.child_value("com:overallEndTime")); |
| 216 | if (overall_start_time && overall_end_time | 216 | if (overall_start_time && overall_end_time |
| 217 | && *overall_start_time < *overall_end_time) | 217 | && *overall_start_time < *overall_end_time) |
| 218 | { | 218 | { |
| @@ -221,10 +221,10 @@ export class loader | |||
| 221 | for (auto const valid_period_xml : | 221 | for (auto const valid_period_xml : |
| 222 | validity_xml.children("com:validPeriod")) | 222 | validity_xml.children("com:validPeriod")) |
| 223 | { | 223 | { |
| 224 | auto const start_of_period = parse_timestamp( | 224 | auto const start_of_period = |
| 225 | valid_period_xml.child_value("com:startOfPeriod")); | 225 | parse_timestamp(valid_period_xml.child_value("com:startOfPeriod")); |
| 226 | auto const end_of_period = | 226 | auto const end_of_period = |
| 227 | parse_timestamp(valid_period_xml.child_value("com:endOfPeriod")); | 227 | parse_timestamp(valid_period_xml.child_value("com:endOfPeriod")); |
| 228 | if (start_of_period && end_of_period | 228 | if (start_of_period && end_of_period |
| 229 | && *start_of_period < *end_of_period) | 229 | && *start_of_period < *end_of_period) |
| 230 | { | 230 | { |
| @@ -235,9 +235,9 @@ export class loader | |||
| 235 | validity_xml.children("com:exceptionPeriod")) | 235 | validity_xml.children("com:exceptionPeriod")) |
| 236 | { | 236 | { |
| 237 | auto const start_of_period = parse_timestamp( | 237 | auto const start_of_period = parse_timestamp( |
| 238 | exception_period_xml.child_value("com:startOfPeriod")); | 238 | exception_period_xml.child_value("com:startOfPeriod")); |
| 239 | auto const end_of_period = parse_timestamp( | 239 | auto const end_of_period = parse_timestamp( |
| 240 | exception_period_xml.child_value("com:endOfPeriod")); | 240 | exception_period_xml.child_value("com:endOfPeriod")); |
| 241 | if (start_of_period && end_of_period | 241 | if (start_of_period && end_of_period |
| 242 | && *start_of_period < *end_of_period) | 242 | && *start_of_period < *end_of_period) |
| 243 | { | 243 | { |
| @@ -246,19 +246,19 @@ export class loader | |||
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | validity = | 248 | validity = |
| 249 | time::period_seq{valid_periods.begin(), valid_periods.end()}.except( | 249 | time::period_seq{valid_periods.begin(), valid_periods.end()}.except( |
| 250 | time::period_seq{ | 250 | time::period_seq{ |
| 251 | exception_periods.begin(), exception_periods.end() | 251 | exception_periods.begin(), exception_periods.end() |
| 252 | }); | 252 | }); |
| 253 | } | 253 | } |
| 254 | else | 254 | else |
| 255 | { | 255 | { |
| 256 | warnings_.insert( | 256 | warnings_.insert( |
| 257 | std::format( | 257 | std::format( |
| 258 | "invalid overall start / end time (start time: {}, end " | 258 | "invalid overall start / end time (start time: {}, end " |
| 259 | "time: {})", | 259 | "time: {})", |
| 260 | validity_spec_xml.child_value("com:overallStartTime"), | 260 | validity_spec_xml.child_value("com:overallStartTime"), |
| 261 | validity_spec_xml.child_value("com:overallEndTime"))); | 261 | validity_spec_xml.child_value("com:overallEndTime"))); |
| 262 | return std::nullopt; | 262 | return std::nullopt; |
| 263 | } | 263 | } |
| 264 | } | 264 | } |
| @@ -272,7 +272,7 @@ export class loader | |||
| 272 | 272 | ||
| 273 | public: | 273 | public: |
| 274 | [[nodiscard]] auto load_situation_publication(std::string const& filename) | 274 | [[nodiscard]] auto load_situation_publication(std::string const& filename) |
| 275 | -> situation_publication | 275 | -> situation_publication |
| 276 | { | 276 | { |
| 277 | auto doc = pugi::xml_document{}; | 277 | auto doc = pugi::xml_document{}; |
| 278 | if (auto result = doc.load_file(filename.c_str()); !result) | 278 | if (auto result = doc.load_file(filename.c_str()); !result) |
| @@ -281,10 +281,10 @@ public: | |||
| 281 | } | 281 | } |
| 282 | auto payload_xml = doc.child("mc:messageContainer").child("mc:payload"); | 282 | auto payload_xml = doc.child("mc:messageContainer").child("mc:payload"); |
| 283 | auto mpublication_time = | 283 | auto mpublication_time = |
| 284 | parse_timestamp(payload_xml.child_value("com:publicationTime")); | 284 | parse_timestamp(payload_xml.child_value("com:publicationTime")); |
| 285 | if (!mpublication_time) | 285 | if (!mpublication_time) |
| 286 | throw std::runtime_error{ | 286 | throw std::runtime_error{ |
| 287 | "provided publication does not name publication time" | 287 | "provided publication does not name publication time" |
| 288 | }; | 288 | }; |
| 289 | 289 | ||
| 290 | auto situations = std::vector<std::shared_ptr<situation>>{}; | 290 | auto situations = std::vector<std::shared_ptr<situation>>{}; |
| @@ -302,26 +302,26 @@ public: | |||
| 302 | for (auto const record_xml : sit_xml.children("sit:situationRecord")) | 302 | for (auto const record_xml : sit_xml.children("sit:situationRecord")) |
| 303 | { | 303 | { |
| 304 | auto const record_type = | 304 | auto const record_type = |
| 305 | std::string_view{record_xml.attribute("xsi:type").value()}; | 305 | std::string_view{record_xml.attribute("xsi:type").value()}; |
| 306 | auto const primary_record_types = std::unordered_set<std::string_view>{ | 306 | auto const primary_record_types = std::unordered_set<std::string_view>{ |
| 307 | "sit:Roadworks", | 307 | "sit:Roadworks", |
| 308 | /* { */ "sit:MaintenanceWorks", | 308 | /* { */ "sit:MaintenanceWorks", |
| 309 | /* | */ "sit:ConstructionWorks", | 309 | /* | */ "sit:ConstructionWorks", |
| 310 | /* } */ | 310 | /* } */ |
| 311 | "sit:Obstruction", | 311 | "sit:Obstruction", |
| 312 | /* { */ "sit:EnvironmentalObstruction", | 312 | /* { */ "sit:EnvironmentalObstruction", |
| 313 | /* | */ "sit:GeneralObstruction", | 313 | /* | */ "sit:GeneralObstruction", |
| 314 | /* | */ "sit:InfrastructureDamageObstruction", | 314 | /* | */ "sit:InfrastructureDamageObstruction", |
| 315 | /* } */ | 315 | /* } */ |
| 316 | "sit:Activity", | 316 | "sit:Activity", |
| 317 | /* { */ "sit:PublicEvent", | 317 | /* { */ "sit:PublicEvent", |
| 318 | /* } */ | 318 | /* } */ |
| 319 | }; | 319 | }; |
| 320 | 320 | ||
| 321 | if (record_type == "sit:RoadOrCarriagewayOrLaneManagement") | 321 | if (record_type == "sit:RoadOrCarriagewayOrLaneManagement") |
| 322 | { | 322 | { |
| 323 | if (auto rc = handle_road_or_carriageway_or_lane_management( | 323 | if (auto rc = |
| 324 | record_xml, sit)) | 324 | handle_road_or_carriageway_or_lane_management(record_xml, sit)) |
| 325 | { | 325 | { |
| 326 | sit->road_closures.push_back(*rc); | 326 | sit->road_closures.push_back(*rc); |
| 327 | } | 327 | } |
| @@ -335,10 +335,10 @@ public: | |||
| 335 | // (comment_xml.child_value("sit:commentType") | 335 | // (comment_xml.child_value("sit:commentType") |
| 336 | // == "internalNote"sv) { | 336 | // == "internalNote"sv) { |
| 337 | auto candidate = std::optional<std::pair< | 337 | auto candidate = std::optional<std::pair< |
| 338 | std::string_view, std::string_view>>{}; // (text, language) | 338 | std::string_view, std::string_view>>{}; // (text, language) |
| 339 | for (auto const comment_value_xml : comment_xml.child("sit:comment") | 339 | for (auto const comment_value_xml : comment_xml.child("sit:comment") |
| 340 | .child("com:values") | 340 | .child("com:values") |
| 341 | .children("com:value")) | 341 | .children("com:value")) |
| 342 | { | 342 | { |
| 343 | if (!candidate | 343 | if (!candidate |
| 344 | || comment_value_xml.attribute("lang").value() == "nl"sv | 344 | || comment_value_xml.attribute("lang").value() == "nl"sv |
| @@ -346,8 +346,8 @@ public: | |||
| 346 | && comment_value_xml.attribute("lang").value() == "nl"sv)) | 346 | && comment_value_xml.attribute("lang").value() == "nl"sv)) |
| 347 | { | 347 | { |
| 348 | candidate = std::make_pair( | 348 | candidate = std::make_pair( |
| 349 | comment_value_xml.child_value(), | 349 | comment_value_xml.child_value(), |
| 350 | comment_value_xml.attribute("lang").value()); | 350 | comment_value_xml.attribute("lang").value()); |
| 351 | } | 351 | } |
| 352 | } | 352 | } |
| 353 | if (candidate) | 353 | if (candidate) |
| @@ -355,7 +355,7 @@ public: | |||
| 355 | auto already_present = false; | 355 | auto already_present = false; |
| 356 | for (auto const& comment : sit->comments) | 356 | for (auto const& comment : sit->comments) |
| 357 | already_present = | 357 | already_present = |
| 358 | already_present || comment == candidate->first; | 358 | already_present || comment == candidate->first; |
| 359 | if (!already_present) | 359 | if (!already_present) |
| 360 | { | 360 | { |
| 361 | sit->comments.emplace_back(candidate->first); | 361 | sit->comments.emplace_back(candidate->first); |
| @@ -365,19 +365,19 @@ public: | |||
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | if (auto const location_ref_xml = | 367 | if (auto const location_ref_xml = |
| 368 | record_xml.child("sit:locationReference")) | 368 | record_xml.child("sit:locationReference")) |
| 369 | { | 369 | { |
| 370 | if (location_ref_xml.attribute("xsi:type").value() | 370 | if (location_ref_xml.attribute("xsi:type").value() |
| 371 | == "loc:PointLocation"sv) | 371 | == "loc:PointLocation"sv) |
| 372 | { | 372 | { |
| 373 | if (auto const coords_xml = | 373 | if (auto const coords_xml = |
| 374 | location_ref_xml.child("loc:pointByCoordinates") | 374 | location_ref_xml.child("loc:pointByCoordinates") |
| 375 | .child("loc:pointCoordinates")) | 375 | .child("loc:pointCoordinates")) |
| 376 | { | 376 | { |
| 377 | auto const mlat = | 377 | auto const mlat = |
| 378 | util::parse_double(coords_xml.child_value("loc:latitude")); | 378 | util::parse_double(coords_xml.child_value("loc:latitude")); |
| 379 | auto const mlon = | 379 | auto const mlon = |
| 380 | util::parse_double(coords_xml.child_value("loc:longitude")); | 380 | util::parse_double(coords_xml.child_value("loc:longitude")); |
| 381 | if (mlat && mlon) | 381 | if (mlat && mlon) |
| 382 | { | 382 | { |
| 383 | // Vaag genoeg zegt NDW dat het hier om WGS | 383 | // Vaag genoeg zegt NDW dat het hier om WGS |
| @@ -404,8 +404,8 @@ public: | |||
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | return { | 406 | return { |
| 407 | .publication_time = *mpublication_time, | 407 | .publication_time = *mpublication_time, |
| 408 | .situations = situations, | 408 | .situations = situations, |
| 409 | }; | 409 | }; |
| 410 | } | 410 | } |
| 411 | 411 | ||