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 : }
|