LCOV - code coverage report
Current view: top level - app/src/data/SUMO - Network.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 358 429 83.4 %
Date: 2023-08-17 16:45:52 Functions: 32 47 68.1 %

          Line data    Source code
       1             : #include "data/SUMO/Network.hpp"
       2             : 
       3             : #include <algorithm>
       4             : #include <cassert>
       5             : #include <cstring>
       6             : #include <fstream>
       7             : #include <ios>
       8             : #include <iostream>
       9             : #include <iterator>
      10             : #include <list>
      11             : #include <memory>
      12             : #include <rapidxml_utils.hpp>
      13             : #include <set>
      14             : #include <sstream>
      15             : #include <stdexcept>
      16             : 
      17             : #include "utils/stringify.hpp"
      18             : 
      19             : using namespace std;
      20             : using namespace rapidxml;
      21             : using namespace SUMO;
      22             : using namespace utils::stringify;
      23             : 
      24             : typedef Network::Junction          Junction;
      25             : typedef Network::Junction::Request Request;
      26             : typedef Network::Edge              Edge;
      27             : typedef Network::Edge::Lane        Lane;
      28             : typedef Network::TrafficLightLogic TrafficLightLogic;
      29             : typedef Network::TrafficLights     TrafficLights;
      30             : typedef Network::Connection        Connection;
      31             : 
      32      170464 : Vector2 Lane::getIncomingDirection() const {
      33      170464 :     const Coord &p1 = edge.from.value().get().pos;
      34      170464 :     const Coord &p2 = shape.front();
      35      170464 :     return (p2 - p1);
      36             : }
      37             : 
      38      116005 : Vector2 Lane::getOutgoingDirection() const {
      39      116005 :     const Coord &p1 = shape.back();
      40      116005 :     const Coord &p2 = edge.to.value().get().pos;
      41             : 
      42      116005 :     return (p2 - p1);
      43             : }
      44             : 
      45           0 : Shape Lane::getShape() const {
      46           0 :     if(!shape.empty())
      47           0 :         return shape;
      48             : 
      49           0 :     return edge.getShape();
      50             : }
      51             : 
      52       30966 : bool Lane::operator==(const Lane &other) const {
      53       27450 :     return edge == other.edge && index == other.index;
      54             : }
      55             : 
      56           0 : bool Lane::operator<(const Lane &other) const {
      57           0 :     return edge < other.edge || (edge == other.edge && index < other.index);
      58             : }
      59             : 
      60      170464 : double calculateAngle(const Vector2 &v1, const Vector2 &v2) {
      61      170464 :     double theta1, r1;
      62      170464 :     Vector2::ToPolar(v1, r1, theta1);
      63      170464 :     double theta2, r2;
      64      170464 :     Vector2::ToPolar(v2, r2, theta2);
      65             : 
      66      170464 :     double theta = theta2 - theta1;
      67      204125 :     while(theta > M_PI) theta -= 2 * M_PI;
      68      176792 :     while(theta < -M_PI) theta += 2 * M_PI;
      69      170464 :     return theta;
      70             : }
      71             : 
      72      116005 : vector<reference_wrapper<const Connection>> Lane::getOutgoing() const {
      73      116005 :     const Vector2 inLaneDir = getOutgoingDirection();
      74             : 
      75      116005 :     multimap<double, reference_wrapper<const Connection>> outConnections;
      76             : 
      77      116005 :     if(net.connections.count(edge.id)) {
      78      114913 :         const auto &connectionsFromEdge = net.connections.at(edge.id);
      79      114913 :         if(connectionsFromEdge.count(index)) {
      80      113852 :             const auto &connectionsFrom = connectionsFromEdge.at(index);
      81      280473 :             for(const auto &[_, connectionsFromTo]: connectionsFrom) {
      82      337085 :                 for(const auto &[toLaneIndex, conn]: connectionsFromTo) {
      83      170464 :                     const Vector2 outLaneDir = conn.toLane().getIncomingDirection();
      84      170464 :                     const double  angle      = calculateAngle(inLaneDir, outLaneDir) * 180.0 / M_PI;
      85      170464 :                     outConnections.emplace(angle, conn);
      86             :                 }
      87             :             }
      88             :         }
      89             :     }
      90             : 
      91      116005 :     vector<reference_wrapper<const Connection>> ret;
      92      286469 :     for(const auto &[_, conn]: outConnections)
      93      170464 :         ret.push_back(conn);
      94             : 
      95      116005 :     return ret;
      96             : }
      97             : 
      98      538259 : const Lane &Connection::fromLane() const {
      99      538259 :     return from.lanes.at(fromLaneIndex);
     100             : }
     101             : 
     102      694248 : const Lane &Connection::toLane() const {
     103      694248 :     try {
     104      694248 :         return to.lanes.at(toLaneIndex);
     105           0 :     } catch(const out_of_range &e) {
     106             :         // clang-format off
     107           0 :         throw out_of_range(
     108           0 :             "No such lane " + to_string(toLaneIndex) +
     109           0 :             " in junction " + to.id +
     110           0 :             " (from lane " + fromLane().id + ")"
     111           0 :         );
     112             :         // clang-format on
     113             :     }
     114             : }
     115             : 
     116       23372 : const Junction &Connection::getJunction() const {
     117       23372 :     return from.to.value();
     118             : }
     119             : 
     120             : /*
     121             :  * This implementation is based on Node#getLinkIndex(conn):
     122             :  * https://github.com/eclipse/sumo/blob/main/tools/sumolib/net/node.py
     123             :  */
     124       11686 : size_t Connection::getJunctionIndex() const {
     125       11686 :     size_t ret = 0;
     126             : 
     127       11686 :     const Junction &junction = getJunction();
     128       22239 :     for(const Edge::Lane &lane: junction.incLanes) {
     129       32792 :         const vector<reference_wrapper<const Connection>> outConnections = lane.getOutgoing();
     130       22239 :         if(lane.id != fromLane().id) {
     131       10553 :             ret += outConnections.size();
     132             :         } else {
     133       15483 :             for(const Connection &connection: outConnections) {
     134       15483 :                 if(connection == *this) {
     135       23372 :                     return ret;
     136             :                 }
     137        3797 :                 ++ret;
     138             :             }
     139             :         }
     140             :     }
     141             : 
     142           0 :     throw logic_error(
     143           0 :         "This connection comes from lane " + fromLane().id + " but that lane is not in the incLanes of junction " + junction.id
     144           0 :     );
     145             : }
     146             : 
     147        4314 : Time Connection::getGreenTime() const {
     148        4314 :     return tl.value().get().getGreenTime(linkIndex.value());
     149             : }
     150             : 
     151        4314 : Time Connection::getCycleTime() const {
     152        4314 :     return tl.value().get().getCycleTime();
     153             : }
     154             : 
     155        4314 : size_t Connection::getNumberStops() const {
     156        4314 :     return tl.value().get().getNumberStops(linkIndex.value());
     157             : }
     158             : 
     159       11686 : const Request &Connection::getRequest() const {
     160       11686 :     return getJunction().requests.at(getJunctionIndex());
     161             : }
     162             : 
     163       15483 : bool Connection::operator==(const Connection &other) const {
     164       30966 :     return fromLane() == other.fromLane() && toLane() == other.toLane();
     165             : }
     166             : 
     167           0 : const TrafficLightLogic::Phase::State &Connection::getTrafficLightState(Time t) const {
     168           0 :     const TrafficLightLogic::Phase &phase = tl.value().get().getPhase(t);
     169             : 
     170           0 :     return phase.state.at(linkIndex.value());
     171             : }
     172             : 
     173        7534 : Length Edge::length() const {
     174        7534 :     Length length = 0;
     175       17655 :     for(const Lane &lane: lanes) {
     176       10121 :         length += lane.length;
     177             :     }
     178        7534 :     length /= (Length)lanes.size();
     179        7534 :     return length;
     180             : }
     181             : 
     182       37856 : Speed Edge::speed() const {
     183       37856 :     Speed speed = 0;
     184       88966 :     for(const Lane &lane: lanes) {
     185       51110 :         speed += lane.speed;
     186             :     }
     187       37856 :     speed /= (Speed)lanes.size();
     188       37856 :     return speed;
     189             : }
     190             : 
     191           0 : Shape Edge::getShape() const {
     192           0 :     if(!shape.empty()) {
     193           0 :         list<Coord> ret(shape.begin(), shape.end());
     194             : 
     195           0 :         SUMO::Coord first(0, 0), last(0, 0);
     196           0 :         for(const Lane &lane: lanes) {
     197           0 :             first += lane.shape.front() / (double)lanes.size();
     198           0 :             last += lane.shape.back() / (double)lanes.size();
     199             :         }
     200             : 
     201           0 :         ret.push_front(first);
     202           0 :         ret.push_back(last);
     203             : 
     204           0 :         return Shape(ret.begin(), ret.end());
     205             :     }
     206             : 
     207           0 :     if(lanes.size() == 1) {
     208           0 :         return lanes.at(0).shape;
     209             :     }
     210             : 
     211           0 :     SUMO::Coord p1 = from.value().get().pos;
     212           0 :     SUMO::Coord p2 = to.value().get().pos;
     213             : 
     214           0 :     return {p1, p2};
     215             : }
     216             : 
     217        7534 : vector<reference_wrapper<const Edge>> Edge::getOutgoing() const {
     218        7534 :     vector<reference_wrapper<const Edge>> ret;
     219             : 
     220        7534 :     if(net.edgesByJunctions.count(to.value().get().id)) {
     221       22590 :         for(const auto &[nextJunctionID, outEdges]: net.edgesByJunctions.at(to.value().get().id)) {
     222       30254 :             for(const Edge &edge: outEdges) {
     223       15134 :                 if(edge.from.value().get() == to.value()) {
     224       15134 :                     ret.push_back(edge);
     225             :                 }
     226             :             }
     227             :         }
     228             :     }
     229             : 
     230        7534 :     return ret;
     231             : }
     232             : 
     233       45148 : vector<reference_wrapper<const Connection>> Edge::getOutgoingConnections() const {
     234       45148 :     vector<reference_wrapper<const Connection>> ret;
     235      105790 :     for(const Lane &lane: lanes) {
     236      121284 :         vector<reference_wrapper<const Connection>> conns = lane.getOutgoing();
     237       60642 :         ret.insert(ret.end(), conns.begin(), conns.end());
     238             :     }
     239       45148 :     return ret;
     240             : }
     241             : 
     242       30966 : bool Edge::operator==(const Edge &other) const {
     243       30966 :     return id == other.id;
     244             : }
     245             : 
     246           0 : bool Edge::operator<(const Edge &other) const {
     247           0 :     return id < other.id;
     248             : }
     249             : 
     250       11686 : const Junction &Request::junction() const {
     251       11686 :     try {
     252       11686 :         return net.junctions.at(junctionID);
     253           0 :     } catch(const out_of_range &e) {
     254           0 :         throw out_of_range("No such junction " + junctionID);
     255             :     }
     256             : }
     257             : 
     258       11686 : vector<reference_wrapper<const Connection>> Request::getResponse() const {
     259       11686 :     vector<reference_wrapper<const Connection>> ret;
     260             : 
     261       11686 :     vector<reference_wrapper<const Connection>> allConnections = junction().getConnections();
     262             : 
     263       11686 :     assert(allConnections.size() == response.size());
     264             : 
     265       63605 :     for(size_t i = 0; i < allConnections.size(); ++i) {
     266       51919 :         if(response.at(i))
     267        7221 :             ret.push_back(allConnections.at(i));
     268             :     }
     269             : 
     270       23372 :     return ret;
     271             : }
     272             : 
     273       11686 : vector<reference_wrapper<const Connection>> Junction::getConnections() const {
     274       11686 :     vector<reference_wrapper<const Connection>> ret;
     275       44810 :     for(const Lane &lane: incLanes) {
     276       66248 :         vector<reference_wrapper<const Connection>> conns = lane.getOutgoing();
     277       33124 :         ret.insert(ret.end(), conns.begin(), conns.end());
     278             :     }
     279       11686 :     return ret;
     280             : }
     281             : 
     282           0 : vector<reference_wrapper<const Lane>> Junction::outLanes() const {
     283           0 :     set<reference_wrapper<const Lane>, less<Lane>> ret;
     284           0 :     for(const Connection &conn: getConnections()) {
     285           0 :         ret.insert(conn.toLane());
     286             :     }
     287           0 :     return vector<reference_wrapper<const Lane>>(ret.begin(), ret.end());
     288             : }
     289             : 
     290       15134 : bool Junction::operator==(const Junction &other) const {
     291       15134 :     return id == other.id;
     292             : }
     293             : 
     294        4314 : Time TrafficLightLogic::getGreenTime(size_t linkIndex) const {
     295        4314 :     Time t = 0.0;
     296       22940 :     for(const auto &p: phases) {
     297       18626 :         const TrafficLightLogic::Phase &phase = p.second;
     298       18626 : #pragma GCC diagnostic push
     299       18626 : #pragma GCC diagnostic ignored "-Wswitch-enum"
     300       18626 :         switch(phase.state.at(linkIndex)) {
     301        9872 :             case Phase::YELLOW_STOP:
     302        9872 :             case Phase::GREEN_NOPRIORITY:
     303        9872 :             case Phase::GREEN_PRIORITY:
     304        9872 :             case Phase::GREEN_RIGHT:
     305        9872 :             case Phase::OFF_YIELD:
     306        9872 :             case Phase::OFF:
     307        9872 :                 t += phase.duration;
     308        9872 :                 break;
     309             :             default:
     310             :                 break;
     311             :         }
     312       18626 : #pragma GCC diagnostic pop
     313             :     }
     314        4314 :     return t;
     315             : }
     316        4314 : Time TrafficLightLogic::getCycleTime() const {
     317        4314 :     Time t = 0.0;
     318       22940 :     for(const auto &p: phases) {
     319       18626 :         const TrafficLightLogic::Phase &phase = p.second;
     320       18626 :         t += phase.duration;
     321             :     }
     322        4314 :     return t;
     323             : }
     324        4314 : size_t TrafficLightLogic::getNumberStops(size_t linkIndex) const {
     325        4314 :     size_t n = 0;
     326             : 
     327        4314 :     bool previousStateGo = (phases.rbegin()->second.state.at(linkIndex) != Phase::RED);
     328             : 
     329       22940 :     for(const auto &[t, phase]: phases) {
     330       18626 :         bool currentStateGo = (phase.state.at(linkIndex) != Phase::RED);
     331       18626 :         if(!previousStateGo && currentStateGo)
     332        3166 :             ++n;
     333       18626 :         previousStateGo = currentStateGo;
     334             :     }
     335        4314 :     return n;
     336             : }
     337             : 
     338           0 : const TrafficLightLogic::Phase &TrafficLightLogic::getPhase(Time time) const {
     339           0 :     assert(!phases.empty());
     340             : 
     341           0 :     time -= offset;
     342           0 :     time = fmod(time, getCycleTime());
     343             : 
     344           0 :     auto it = phases.upper_bound(time);
     345             : 
     346           0 :     assert(it != phases.begin());
     347             : 
     348           0 :     --it;
     349             : 
     350           0 :     return it->second;
     351             : }
     352             : 
     353       38658 : Edge &Network::loadEdge(const xml_node<> *it) {
     354       77316 :     Edge::ID id = it->first_attribute("id")->value();
     355       77316 :     auto     p  = edges.emplace(id, Edge{*this, id});
     356       38658 :     assert(p.second);
     357       38658 :     Edge &edge = p.first->second;
     358             : 
     359             :     // Edge edge{
     360             :     //     *this,
     361             :     //     it->first_attribute("id")->value()};
     362             : 
     363       38658 :     {
     364       38658 :         auto *fromAttr = it->first_attribute("from");
     365       38658 :         if(fromAttr) edge.fromID = fromAttr->value();
     366             :     }
     367       38658 :     {
     368       38658 :         auto *toAttr = it->first_attribute("to");
     369       38658 :         if(toAttr) edge.toID = toAttr->value();
     370             :     }
     371       38658 :     {
     372       38658 :         auto *priorityAttr = it->first_attribute("priority");
     373       38658 :         if(priorityAttr) edge.priority = stringify<Edge::Priority>::fromString(priorityAttr->value());
     374             :     }
     375       38658 :     {
     376       38658 :         auto *functionAttr = it->first_attribute("function");
     377       38658 :         if(functionAttr) edge.function = stringify<Edge::Function>::fromString(functionAttr->value());
     378             :     }
     379       38658 :     {
     380       38658 :         auto *shapeAttr = it->first_attribute("shape");
     381       46778 :         if(shapeAttr) edge.shape = stringify<Shape>::fromString(shapeAttr->value());
     382             :     }
     383             : 
     384       86826 :     for(auto it2 = it->first_node("lane"); it2; it2 = it2->next_sibling("lane")) {
     385             :         // clang-format off
     386       48168 :         Lane lane {
     387             :             *this,
     388             :             edge,
     389       48168 :             it2->first_attribute("id")->value(),
     390       48168 :             stringify<Lane::Index>::fromString(it2->first_attribute("index")->value()),
     391       48168 :             stringify<Speed>::fromString(it2->first_attribute("speed")->value()),
     392       48168 :             stringify<Length>::fromString(it2->first_attribute("length")->value()),
     393       48168 :             stringify<Shape>::fromString(it2->first_attribute("shape")->value())
     394      240840 :         };
     395             :         // clang-format on
     396             : 
     397       48168 :         assert(edge.lanes.size() == lane.index);
     398             : 
     399       48168 :         edge.lanes.emplace_back(lane);
     400             :     }
     401             : 
     402       86826 :     for(const Lane &lane: edge.lanes) {
     403       48168 :         lanes[lane.id] = make_pair(edge.id, lane.index);
     404             :     }
     405       38658 :     if(!edge.fromID.has_value() || !edge.toID.has_value()) return edge;
     406       15052 :     edgesByJunctions[edge.fromID.value()][edge.toID.value()].push_back(edge);
     407             : 
     408       15052 :     return edge;
     409             : }
     410             : 
     411        8487 : Junction &Network::loadJunction(const xml_node<> *it) {
     412        8487 :     Junction::ID id = it->first_attribute("id")->value();
     413             : 
     414        8487 :     double x = stringify<double>::fromString(it->first_attribute("x")->value());
     415        8487 :     double y = stringify<double>::fromString(it->first_attribute("y")->value());
     416             : 
     417        8487 :     double z = 0.0;
     418             : 
     419        8487 :     xml_attribute<> *zAttr = it->first_attribute("z");
     420        8487 :     if(zAttr)
     421           0 :         z = stringify<double>::fromString(zAttr->value());
     422             : 
     423             :     // clang-format off
     424        8487 :     auto junctionEmplace = junctions.emplace(id, Junction{
     425             :         id,
     426             :         Coord(
     427             :             x,
     428             :             y,
     429             :             z
     430             :         )
     431       16974 :     });
     432             :     // clang-format on
     433        8487 :     assert(junctionEmplace.second);
     434        8487 :     Junction &junction = junctionEmplace.first->second;
     435             : 
     436        8487 :     {
     437        8487 :         auto *typeAttr = it->first_attribute("type");
     438       14927 :         if(typeAttr) junction.type = stringify<Junction::Type>::fromString(typeAttr->value());
     439             :     }
     440             : 
     441       16974 :     const vector<Lane::ID> incLanes = stringify<vector<Lane::ID>>::fromString(it->first_attribute("incLanes")->value());
     442        8487 :     const vector<Lane::ID> intLanes = stringify<vector<Lane::ID>>::fromString(it->first_attribute("intLanes")->value());
     443             : 
     444       49777 :     auto f = [this](const Lane::ID &laneID) -> const Lane & {
     445       49777 :         const auto &[edgeID, laneIndex] = lanes.at(laneID);
     446       49777 :         return edges.at(edgeID).lanes.at(laneIndex);
     447        8487 :     };
     448             : 
     449        8487 :     junction.incLanes.clear();
     450        8487 :     junction.incLanes.reserve(incLanes.size());
     451        8487 :     transform(incLanes.begin(), incLanes.end(), back_inserter(junction.incLanes), f);
     452             : 
     453        8487 :     junction.intLanes.clear();
     454        8487 :     junction.intLanes.reserve(intLanes.size());
     455        8487 :     transform(intLanes.begin(), intLanes.end(), back_inserter(junction.intLanes), f);
     456             : 
     457        8487 :     {
     458        8487 :         auto *shapeAttr = it->first_attribute("shape");
     459       16677 :         if(shapeAttr) junction.shape = stringify<Shape>::fromString(it->first_attribute("shape")->value());
     460             :     }
     461             : 
     462       36140 :     for(auto it2 = it->first_node("request"); it2; it2 = it2->next_sibling("request")) {
     463       27653 :         size_t requestIndex = stringify<Index>::fromString(it2->first_attribute("index")->value());
     464             : 
     465             :         // clang-format off
     466      110612 :         auto requestEmplace = junction.requests.emplace(requestIndex, Request{
     467             :             *this,
     468       27653 :             junction.id,
     469             :             requestIndex,
     470       27653 :             stringify<vector<bool>>::fromString(it2->first_attribute("response")->value()),
     471       27653 :             stringify<vector<bool>>::fromString(it2->first_attribute("foes")->value()),
     472       55306 :             stringify<bool>::fromString(it2->first_attribute("cont")->value())
     473       55306 :         });
     474             :         // clang-format on
     475       27653 :         assert(requestEmplace.second);
     476       27653 :         Request &request = requestEmplace.first->second;
     477             : 
     478       27653 :         reverse(request.response.begin(), request.response.end());
     479       27653 :         reverse(request.foes.begin(), request.foes.end());
     480             :     }
     481             : 
     482        8487 :     assert(
     483             :         junction.type == Junction::Type::INTERNAL || junction.requests.size() == junction.intLanes.size()
     484             :     );
     485             : 
     486       16974 :     return junction;
     487             : }
     488             : 
     489        1016 : TrafficLightLogic &Network::loadTrafficLightLogic(const xml_node<> *it) {
     490        1016 :     TrafficLightLogic::ID id = it->first_attribute("id")->value();
     491             : 
     492             :     // clang-format off
     493        3048 :     auto p = trafficLights.emplace(id, TrafficLightLogic{
     494             :         id,
     495        1016 :         stringify<TrafficLightLogic::Type>::fromString(it->first_attribute("type")->value()),
     496        1016 :         it->first_attribute("programID")->value(),
     497        2032 :         stringify<Time>::fromString(it->first_attribute("offset")->value())
     498        2032 :     });
     499             :     // clang-format on
     500        1016 :     assert(p.second);
     501        1016 :     TrafficLightLogic &tlLogic = p.first->second;
     502             : 
     503        4668 :     for(auto it2 = it->first_node("phase"); it2; it2 = it2->next_sibling("phase")) {
     504             :         // clang-format off
     505        3652 :         TrafficLightLogic::Phase phase{
     506        3652 :             stringify<Time>::fromString(it2->first_attribute("duration")->value()),
     507        3652 :             stringify<vector<TrafficLightLogic::Phase::State>>::fromString(it2->first_attribute("state")->value())
     508        7304 :         };
     509             :         // clang-format on
     510             : 
     511        3652 :         Time tPrev;
     512        3652 :         if(tlLogic.phases.empty())
     513        1016 :             tPrev = 0;
     514             :         else {
     515        2636 :             tPrev = tlLogic.phases.rbegin()->first + tlLogic.phases.rbegin()->second.duration;
     516             :         }
     517             : 
     518        3652 :         tlLogic.phases.emplace(tPrev, phase);
     519             :     }
     520             : 
     521        1016 :     return tlLogic;
     522             : }
     523             : 
     524       55603 : Connection &Network::loadConnection(const xml_node<> *it) {
     525       55603 :     Edge::ID          fromID        = it->first_attribute("from")->value();
     526      111206 :     Edge::ID          toID          = it->first_attribute("to")->value();
     527       55603 :     Edge::Lane::Index fromLaneIndex = stringify<Edge::Lane::Index>::fromString(it->first_attribute("fromLane")->value());
     528       55603 :     Edge::Lane::Index toLaneIndex   = stringify<Edge::Lane::Index>::fromString(it->first_attribute("toLane")->value());
     529             : 
     530             :     // clang-format off
     531      111206 :     auto p = connections[fromID][fromLaneIndex][toID].emplace(toLaneIndex, Connection{
     532       55603 :         edges.at(fromID),
     533       55603 :         edges.at(toID),
     534             :         fromLaneIndex,
     535             :         toLaneIndex,
     536       55603 :         stringify<Connection::Direction>::fromString(it->first_attribute("dir")->value()),
     537      111206 :         stringify<Connection::State>::fromString(it->first_attribute("state")->value())
     538       55603 :     });
     539             :     // clang-format on
     540       55603 :     assert(p.second);
     541       55603 :     Connection &connection = p.first->second;
     542             : 
     543       55603 :     connection.fromLane();
     544       55603 :     connection.toLane();
     545             : 
     546       55603 :     {
     547       55603 :         auto *viaAttr = it->first_attribute("via");
     548       55603 :         if(viaAttr) {
     549       55900 :             const auto &[edgeID, laneIndex] = lanes.at(it->first_attribute("via")->value());
     550       27950 :             connection.via                  = edges.at(edgeID).lanes.at(laneIndex);
     551             :         }
     552             :     }
     553       55603 :     {
     554       55603 :         auto *tlAttr        = it->first_attribute("tl");
     555       55603 :         auto *linkIndexAttr = it->first_attribute("linkIndex");
     556       55603 :         if(tlAttr && linkIndexAttr) {
     557       12861 :             connection.tl        = trafficLights.at(tlAttr->value());
     558        8574 :             connection.linkIndex = stringify<int>::fromString(linkIndexAttr->value());
     559             :             // clang-format off
     560        4287 :             if(!(
     561        4287 :                 0 <= connection.linkIndex && 
     562        4287 :                 connection.linkIndex < connection.tl.value().get().phases.begin()->second.state.size()
     563             :             )){
     564           0 :                 throw logic_error(
     565           0 :                     "linkIndex " + to_string(connection.linkIndex.value()) + 
     566           0 :                     " out of bounds [0," + to_string(connection.tl.value().get().phases.begin()->second.state.size()) + ")" +
     567           0 :                     ", connection " + connection.fromLane().id + " → " + connection.toLane().id
     568           0 :                 );
     569             :             }
     570             :             // clang-format on
     571       51316 :         } else if(tlAttr || linkIndexAttr) {
     572           0 :             throw runtime_error("Connection has only one of tl and linkIndex");
     573             :         }
     574             :     }
     575      111206 :     return connection;
     576             : }
     577             : 
     578           4 : shared_ptr<Network> Network::loadFromFile(const string &path) {
     579           4 :     shared_ptr<Network> networkPtr = make_shared<Network>();
     580             : 
     581           4 :     Network &network = *networkPtr;
     582             : 
     583             :     // Parse XML
     584           4 :     shared_ptr<file<>> xmlFilePointer = nullptr;
     585           4 :     try {
     586           4 :         xmlFilePointer = make_shared<file<>>(path.c_str());
     587           0 :     } catch(const ios_base::failure &e) {
     588           0 :         throw ios_base::failure("Could not open file " + path);
     589             :     }
     590           4 :     file<> &xmlFile = *xmlFilePointer;
     591             : 
     592           8 :     xml_document<> doc;
     593           4 :     doc.parse<0>(xmlFile.data());
     594             : 
     595             :     // Get data from XML parser
     596           4 :     const auto &net = *doc.first_node();
     597             : 
     598             :     // Location
     599           4 :     const xml_node<> &locationEl = *net.first_node("location");
     600             : 
     601           4 :     network.location.loadFromXMLNode(locationEl);
     602             : 
     603             :     // Edges
     604       38662 :     for(auto it = net.first_node("edge"); it; it = it->next_sibling("edge")) {
     605       38658 :         network.loadEdge(it);
     606             :     }
     607             : 
     608             :     // Junctions
     609        8491 :     for(auto it = net.first_node("junction"); it; it = it->next_sibling("junction")) {
     610        8487 :         network.loadJunction(it);
     611             :     }
     612             : 
     613             :     // Correct edge.from/to
     614       38662 :     for(auto &[edgeID, edge]: network.edges) {
     615       38658 :         if(edge.fromID.has_value()) edge.from = network.junctions.at(edge.fromID.value());
     616       53710 :         if(edge.toID.has_value()) edge.to = network.junctions.at(edge.toID.value());
     617             :     }
     618             : 
     619             :     // Traffic lights
     620        1020 :     for(auto it = net.first_node("tlLogic"); it; it = it->next_sibling("tlLogic")) {
     621        1016 :         network.loadTrafficLightLogic(it);
     622             :     }
     623             : 
     624             :     // Connections
     625       55607 :     for(auto it = net.first_node("connection"); it; it = it->next_sibling("connection")) {
     626       55603 :         network.loadConnection(it);
     627             :     }
     628             : 
     629           8 :     return networkPtr;
     630             : }
     631             : 
     632           0 : vector<Junction> Network::getJunctions() const {
     633           0 :     vector<Junction> ret;
     634           0 :     ret.reserve(junctions.size());
     635           0 :     for(const auto &p: junctions)
     636           0 :         ret.push_back(p.second);
     637           0 :     return ret;
     638             : }
     639             : 
     640           0 : const Junction &Network::getJunction(const Junction::ID &id) const {
     641           0 :     return junctions.at(id);
     642             : }
     643             : 
     644           6 : vector<Edge> Network::getEdges() const {
     645           6 :     vector<Edge> ret;
     646           6 :     ret.reserve(edges.size());
     647       38714 :     for(const auto &p: edges)
     648       38708 :         ret.push_back(p.second);
     649           6 :     return ret;
     650             : }
     651             : 
     652      188598 : const Edge &Network::getEdge(const Edge::ID &id) const {
     653      188598 :     return edges.at(id);
     654             : }
     655             : 
     656       90626 : vector<reference_wrapper<const Connection>> Network::getConnections(const Edge &e1, const Edge &e2) const {
     657       90626 :     vector<reference_wrapper<const Connection>> ret;
     658             : 
     659       90626 :     if(!connections.count(e1.id)) return ret;
     660      210913 :     for(const auto &[laneIndex1, conns1]: connections.at(e1.id)) {
     661      120369 :         if(!conns1.count(e2.id)) continue;
     662      208814 :         for(const auto &[laneIndex2, conn]: conns1.at(e2.id)) {
     663      105548 :             ret.push_back(conn);
     664             :         }
     665             :     }
     666             : 
     667             :     return ret;
     668             : }
     669             : 
     670           3 : unordered_map<SUMO::Network::Edge::ID, unordered_map<SUMO::Network::Edge::ID, list<reference_wrapper<const SUMO::Network::Connection>>>> Network::getConnections() const {
     671           3 :     unordered_map<SUMO::Network::Edge::ID, unordered_map<SUMO::Network::Edge::ID, list<reference_wrapper<const SUMO::Network::Connection>>>> ret;
     672             : 
     673       19211 :     for(const auto &[fromID, conns1]: connections)
     674       43026 :         for(const auto &[fromLaneIndex, conns2]: conns1)
     675       51344 :             for(const auto &[toID, conns3]: conns2)
     676       55364 :                 for(const auto &[toLaneIndex, conn]: conns3)
     677       27838 :                     ret[fromID][toID].push_back(conn);
     678             : 
     679           3 :     return ret;
     680             : }
     681             : 
     682           0 : const TrafficLights &Network::getTrafficLights() const {
     683           0 :     return trafficLights;
     684             : }
     685             : 
     686           1 : void Network::saveStatsToFile(const string &path) const {
     687           1 :     xml_document<> doc;
     688           1 :     auto           meandata = doc.allocate_node(node_element, "meandata");
     689           1 :     doc.append_node(meandata);
     690           1 :     auto interval = doc.allocate_node(node_element, "interval");
     691           1 :     interval->append_attribute(doc.allocate_attribute("begin", "0.0"));
     692           1 :     interval->append_attribute(doc.allocate_attribute("end", "1.0"));
     693           1 :     meandata->append_node(interval);
     694             : 
     695           2 :     list<string> strs;
     696       19305 :     for(const auto &[eid, e]: edges) {
     697       38608 :         string &ps  = (strs.emplace_back() = stringify<Edge::Priority>::toString(e.priority));
     698       38608 :         string &fs  = (strs.emplace_back() = stringify<Edge::Function>::toString(e.function));
     699       38608 :         string &lns = (strs.emplace_back() = stringify<size_t>::toString(e.lanes.size()));
     700             : 
     701       19304 :         Length length = 0;
     702       19304 :         Speed  speed  = 0;
     703       43356 :         for(const Lane &lane: e.lanes) {
     704       24052 :             length += lane.length;
     705       24052 :             speed += lane.speed;
     706             :         }
     707       19304 :         length /= (Length)e.lanes.size();
     708       19304 :         speed /= (Speed)e.lanes.size();
     709       19304 :         Speed speed_kmh = speed * 3.6;
     710             : 
     711       38608 :         string &ls   = (strs.emplace_back() = stringify<Length>::toString(length));
     712       38608 :         string &ss   = (strs.emplace_back() = stringify<Speed>::toString(speed));
     713       38608 :         string &kmhs = (strs.emplace_back() = stringify<Speed>::toString(speed_kmh));
     714             : 
     715       19304 :         auto edge = doc.allocate_node(node_element, "edge");
     716       19304 :         edge->append_attribute(doc.allocate_attribute("id", eid.c_str()));
     717       19304 :         edge->append_attribute(doc.allocate_attribute("priority", ps.c_str()));
     718       19304 :         edge->append_attribute(doc.allocate_attribute("function", fs.c_str()));
     719       19304 :         edge->append_attribute(doc.allocate_attribute("lanes", lns.c_str()));
     720       19304 :         edge->append_attribute(doc.allocate_attribute("length", ls.c_str()));
     721       19304 :         edge->append_attribute(doc.allocate_attribute("speed", ss.c_str()));
     722       19304 :         edge->append_attribute(doc.allocate_attribute("speed_kmh", kmhs.c_str()));
     723       19304 :         interval->append_node(edge);
     724             :     }
     725             : 
     726           2 :     ofstream os;
     727           1 :     os.exceptions(ios_base::failbit | ios_base::badbit);
     728           1 :     try {
     729           1 :         os.open(path);
     730           0 :     } catch(const ios_base::failure &e) {
     731           0 :         throw ios_base::failure("Could not open file " + path);
     732             :     }
     733           1 :     os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
     734           1 :     os << doc;
     735           1 : }

Generated by: LCOV version 1.14