Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file NLHandler.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Clemens Honomichl
18 : /// @author Sascha Krieg
19 : /// @author Michael Behrisch
20 : /// @author Felix Brack
21 : /// @date Mon, 9 Jul 2001
22 : ///
23 : // The XML-Handler for network loading
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <string>
28 : #include "NLHandler.h"
29 : #include "NLEdgeControlBuilder.h"
30 : #include "NLJunctionControlBuilder.h"
31 : #include "NLDetectorBuilder.h"
32 : #include "NLTriggerBuilder.h"
33 : #include <utils/xml/SUMOXMLDefinitions.h>
34 : #include <utils/xml/SUMOSAXHandler.h>
35 : #include <utils/common/MsgHandler.h>
36 : #include <utils/common/SUMOTime.h>
37 : #include <utils/common/StringUtils.h>
38 : #include <utils/common/StringTokenizer.h>
39 : #include <utils/common/RGBColor.h>
40 : #include <utils/geom/GeomConvHelper.h>
41 : #include <microsim/MSGlobals.h>
42 : #include <microsim/MSLane.h>
43 : #include <microsim/MSJunction.h>
44 : #include <microsim/MSJunctionLogic.h>
45 : #include <microsim/MSStoppingPlace.h>
46 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
47 : #include <microsim/traffic_lights/MSRailSignal.h>
48 : #include <microsim/traffic_lights/MSRailSignalControl.h>
49 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
50 : #include <mesosim/MESegment.h>
51 : #include <utils/iodevices/OutputDevice.h>
52 : #include <utils/common/UtilExceptions.h>
53 : #include <utils/geom/GeoConvHelper.h>
54 : #include <utils/shapes/ShapeContainer.h>
55 : #include <utils/shapes/Shape.h>
56 :
57 :
58 : // ===========================================================================
59 : // method definitions
60 : // ===========================================================================
61 43998 : NLHandler::NLHandler(const std::string& file, MSNet& net,
62 : NLDetectorBuilder& detBuilder,
63 : NLTriggerBuilder& triggerBuilder,
64 : NLEdgeControlBuilder& edgeBuilder,
65 43998 : NLJunctionControlBuilder& junctionBuilder) :
66 : MSRouteHandler(file, true),
67 43998 : myNet(net), myActionBuilder(net),
68 43998 : myCurrentIsInternalToSkip(false),
69 43998 : myDetectorBuilder(detBuilder), myTriggerBuilder(triggerBuilder),
70 43998 : myEdgeControlBuilder(edgeBuilder), myJunctionControlBuilder(junctionBuilder),
71 43998 : myAmParsingTLLogicOrJunction(false), myCurrentIsBroken(false),
72 43998 : myHaveWarnedAboutInvalidTLType(false),
73 43998 : myHaveSeenInternalEdge(false),
74 43998 : myHaveJunctionHigherSpeeds(false),
75 43998 : myHaveSeenDefaultLength(false),
76 43998 : myHaveSeenNeighs(false),
77 43998 : myHaveSeenAdditionalSpeedRestrictions(false),
78 43998 : myHaveSeenMesoEdgeType(false),
79 : myNetworkVersion(0, 0),
80 43998 : myNetIsLoaded(false) {
81 43998 : }
82 :
83 :
84 43998 : NLHandler::~NLHandler() {}
85 :
86 :
87 : void
88 10463408 : NLHandler::myStartElement(int element,
89 : const SUMOSAXAttributes& attrs) {
90 : try {
91 10463408 : switch (element) {
92 43901 : case SUMO_TAG_NET: {
93 : bool ok;
94 43901 : MSGlobals::gLefthand = attrs.getOpt<bool>(SUMO_ATTR_LEFTHAND, nullptr, ok, false);
95 43901 : myHaveJunctionHigherSpeeds = attrs.getOpt<bool>(SUMO_ATTR_HIGHER_SPEED, nullptr, ok, false);
96 87802 : myNetworkVersion = StringUtils::toVersion(attrs.get<std::string>(SUMO_ATTR_VERSION, nullptr, ok, false));
97 : break;
98 : }
99 1808397 : case SUMO_TAG_EDGE:
100 1808397 : beginEdgeParsing(attrs);
101 : break;
102 2240544 : case SUMO_TAG_LANE:
103 2240544 : addLane(attrs);
104 : break;
105 7967 : case SUMO_TAG_NEIGH:
106 7967 : if (!myCurrentIsInternalToSkip) {
107 15934 : myEdgeControlBuilder.addNeigh(attrs.getString(SUMO_ATTR_LANE));
108 : }
109 7967 : myHaveSeenNeighs = true;
110 7967 : break;
111 579847 : case SUMO_TAG_JUNCTION:
112 579847 : openJunction(attrs);
113 579847 : initJunctionLogic(attrs);
114 : break;
115 520196 : case SUMO_TAG_PHASE:
116 520196 : addPhase(attrs);
117 : break;
118 94 : case SUMO_TAG_CONDITION:
119 94 : addCondition(attrs);
120 : break;
121 60 : case SUMO_TAG_ASSIGNMENT:
122 60 : addAssignment(attrs);
123 : break;
124 4 : case SUMO_TAG_FUNCTION:
125 4 : addFunction(attrs);
126 : break;
127 3028172 : case SUMO_TAG_CONNECTION:
128 3028172 : addConnection(attrs);
129 : break;
130 6 : case SUMO_TAG_CONFLICT:
131 6 : addConflict(attrs);
132 : break;
133 111311 : case SUMO_TAG_TLLOGIC:
134 111311 : initTrafficLightLogic(attrs);
135 : break;
136 1656543 : case SUMO_TAG_REQUEST:
137 1656543 : addRequest(attrs);
138 : break;
139 92 : case SUMO_TAG_WAUT:
140 92 : openWAUT(attrs);
141 : break;
142 175 : case SUMO_TAG_WAUT_SWITCH:
143 175 : addWAUTSwitch(attrs);
144 : break;
145 93 : case SUMO_TAG_WAUT_JUNCTION:
146 93 : addWAUTJunction(attrs);
147 : break;
148 21296 : case SUMO_TAG_E1DETECTOR:
149 : case SUMO_TAG_INDUCTION_LOOP:
150 21296 : addE1Detector(attrs);
151 : break;
152 3124 : case SUMO_TAG_E2DETECTOR:
153 : case SUMO_TAG_LANE_AREA_DETECTOR:
154 3124 : addE2Detector(attrs);
155 : break;
156 1548 : case SUMO_TAG_E3DETECTOR:
157 : case SUMO_TAG_ENTRY_EXIT_DETECTOR:
158 1548 : beginE3Detector(attrs);
159 : break;
160 1873 : case SUMO_TAG_DET_ENTRY:
161 1873 : addE3Entry(attrs);
162 : break;
163 1837 : case SUMO_TAG_DET_EXIT:
164 1837 : addE3Exit(attrs);
165 : break;
166 1089 : case SUMO_TAG_INSTANT_INDUCTION_LOOP:
167 1089 : addInstantE1Detector(attrs);
168 : break;
169 551 : case SUMO_TAG_VSS:
170 551 : myTriggerBuilder.parseAndBuildLaneSpeedTrigger(myNet, attrs, getFileName());
171 : break;
172 1081 : case SUMO_TAG_CALIBRATOR:
173 1081 : myTriggerBuilder.parseAndBuildCalibrator(myNet, attrs, getFileName());
174 : break;
175 3514 : case SUMO_TAG_REROUTER:
176 3514 : myTriggerBuilder.parseAndBuildRerouter(myNet, attrs);
177 : break;
178 39800 : case SUMO_TAG_BUS_STOP:
179 : case SUMO_TAG_TRAIN_STOP:
180 : case SUMO_TAG_CONTAINER_STOP:
181 39800 : myTriggerBuilder.parseAndBuildStoppingPlace(myNet, attrs, (SumoXMLTag)element);
182 39789 : myLastParameterised.push_back(myTriggerBuilder.getCurrentStop());
183 39789 : break;
184 765 : case SUMO_TAG_PARKING_SPACE:
185 765 : myTriggerBuilder.parseAndAddLotEntry(attrs);
186 : break;
187 13712 : case SUMO_TAG_PARKING_AREA:
188 13712 : myTriggerBuilder.parseAndBeginParkingArea(myNet, attrs);
189 13711 : myLastParameterised.push_back(myTriggerBuilder.getCurrentStop());
190 13711 : break;
191 2108 : case SUMO_TAG_ACCESS:
192 2108 : myTriggerBuilder.addAccess(myNet, attrs);
193 : break;
194 12023 : case SUMO_TAG_CHARGING_STATION:
195 12023 : myTriggerBuilder.parseAndBuildChargingStation(myNet, attrs);
196 12022 : myLastParameterised.push_back(myTriggerBuilder.getCurrentStop());
197 12022 : break;
198 58 : case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
199 58 : myTriggerBuilder.parseAndBuildOverheadWireSegment(myNet, attrs);
200 : break;
201 8 : case SUMO_TAG_OVERHEAD_WIRE_SECTION:
202 8 : myTriggerBuilder.parseAndBuildOverheadWireSection(myNet, attrs);
203 : break;
204 8 : case SUMO_TAG_TRACTION_SUBSTATION:
205 8 : myTriggerBuilder.parseAndBuildTractionSubstation(myNet, attrs);
206 : break;
207 11 : case SUMO_TAG_OVERHEAD_WIRE_CLAMP:
208 11 : myTriggerBuilder.parseAndBuildOverheadWireClamp(myNet, attrs);
209 : break;
210 144 : case SUMO_TAG_VTYPEPROBE:
211 144 : addVTypeProbeDetector(attrs);
212 : break;
213 614 : case SUMO_TAG_ROUTEPROBE:
214 614 : addRouteProbeDetector(attrs);
215 : break;
216 10424 : case SUMO_TAG_MEANDATA_EDGE:
217 10424 : addEdgeLaneMeanData(attrs, SUMO_TAG_MEANDATA_EDGE);
218 : break;
219 9456 : case SUMO_TAG_MEANDATA_LANE:
220 9456 : addEdgeLaneMeanData(attrs, SUMO_TAG_MEANDATA_LANE);
221 : break;
222 965 : case SUMO_TAG_TIMEDEVENT:
223 965 : myActionBuilder.addAction(attrs, getFileName());
224 : break;
225 634 : case SUMO_TAG_VAPORIZER:
226 634 : myTriggerBuilder.buildVaporizer(attrs);
227 : break;
228 43923 : case SUMO_TAG_LOCATION:
229 43923 : setLocation(attrs);
230 : break;
231 23610 : case SUMO_TAG_TAZ:
232 23610 : addDistrict(attrs);
233 : break;
234 20109 : case SUMO_TAG_TAZSOURCE:
235 20109 : addDistrictEdge(attrs, true);
236 : break;
237 20116 : case SUMO_TAG_TAZSINK:
238 20116 : addDistrictEdge(attrs, false);
239 : break;
240 375 : case SUMO_TAG_ROUNDABOUT:
241 375 : addRoundabout(attrs);
242 : break;
243 11522 : case SUMO_TAG_TYPE: {
244 11522 : bool ok = true;
245 23044 : myCurrentTypeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
246 : break;
247 : }
248 197 : case SUMO_TAG_RESTRICTION: {
249 197 : bool ok = true;
250 394 : const SUMOVehicleClass svc = getVehicleClassID(attrs.get<std::string>(SUMO_ATTR_VCLASS, myCurrentTypeID.c_str(), ok));
251 197 : const double speed = attrs.get<double>(SUMO_ATTR_SPEED, myCurrentTypeID.c_str(), ok);
252 197 : if (ok) {
253 197 : myNet.addRestriction(myCurrentTypeID, svc, speed);
254 : }
255 197 : if (myNetIsLoaded) {
256 189 : myHaveSeenAdditionalSpeedRestrictions = true;
257 : }
258 : break;
259 : }
260 22 : case SUMO_TAG_MESO: {
261 22 : addMesoEdgeType(attrs);
262 : break;
263 : }
264 2178 : case SUMO_TAG_STOPOFFSET: {
265 2178 : bool ok = true;
266 2178 : const StopOffset stopOffset(attrs, ok);
267 2178 : if (!ok) {
268 0 : WRITE_ERROR(myEdgeControlBuilder.reportCurrentEdgeOrLane());
269 : } else {
270 2178 : myEdgeControlBuilder.addStopOffsets(stopOffset);
271 : }
272 : break;
273 : }
274 488 : case SUMO_TAG_RAILSIGNAL_CONSTRAINTS: {
275 488 : bool ok = true;
276 488 : const std::string signalID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
277 488 : if (!MSNet::getInstance()->getTLSControl().knows(signalID)) {
278 0 : throw InvalidArgument("Rail signal '" + signalID + "' in railSignalConstraints is not known");
279 : }
280 488 : myConstrainedSignal = dynamic_cast<MSRailSignal*>(MSNet::getInstance()->getTLSControl().get(signalID).getDefault());
281 488 : if (myConstrainedSignal == nullptr) {
282 0 : throw InvalidArgument("Traffic light '" + signalID + "' is not a rail signal");
283 : }
284 : break;
285 : }
286 642 : case SUMO_TAG_PREDECESSOR: // intended fall-through
287 : case SUMO_TAG_FOE_INSERTION: // intended fall-through
288 : case SUMO_TAG_INSERTION_PREDECESSOR: // intended fall-through
289 : case SUMO_TAG_INSERTION_ORDER: // intended fall-through
290 : case SUMO_TAG_BIDI_PREDECESSOR:
291 642 : myLastParameterised.push_back(addPredecessorConstraint(element, attrs, myConstrainedSignal));
292 642 : break;
293 15 : case SUMO_TAG_DEADLOCK:
294 15 : addDeadlock(attrs);
295 : break;
296 : default:
297 : break;
298 : }
299 86 : } catch (InvalidArgument& e) {
300 86 : myCurrentIsBroken = true;
301 86 : WRITE_ERROR(e.what());
302 86 : }
303 10463398 : MSRouteHandler::myStartElement(element, attrs);
304 10463314 : if (element == SUMO_TAG_PARAM && !myCurrentIsBroken) {
305 42760 : addParam(attrs);
306 : }
307 10463314 : }
308 :
309 :
310 : void
311 10459145 : NLHandler::myEndElement(int element) {
312 10459145 : switch (element) {
313 1808337 : case SUMO_TAG_EDGE:
314 1808337 : closeEdge();
315 1808337 : break;
316 2240544 : case SUMO_TAG_LANE:
317 2240544 : myEdgeControlBuilder.closeLane();
318 2240544 : if (!myCurrentIsInternalToSkip && !myCurrentIsBroken) {
319 : myLastParameterised.pop_back();
320 : }
321 : break;
322 579847 : case SUMO_TAG_JUNCTION:
323 579847 : if (!myCurrentIsBroken) {
324 : try {
325 579718 : myJunctionControlBuilder.closeJunction(getFileName());
326 6 : } catch (InvalidArgument& e) {
327 6 : WRITE_ERROR(e.what());
328 6 : }
329 : }
330 579847 : myAmParsingTLLogicOrJunction = false;
331 579847 : break;
332 111311 : case SUMO_TAG_TLLOGIC:
333 111311 : if (!myCurrentIsBroken) {
334 : try {
335 111310 : myJunctionControlBuilder.closeTrafficLightLogic(getFileName());
336 2 : } catch (InvalidArgument& e) {
337 10 : for (MSPhaseDefinition* const phase : myJunctionControlBuilder.getLoadedPhases()) {
338 8 : delete phase;
339 : }
340 2 : WRITE_ERROR(e.what());
341 2 : }
342 : }
343 111305 : myAmParsingTLLogicOrJunction = false;
344 111305 : break;
345 4 : case SUMO_TAG_FUNCTION:
346 4 : closeFunction();
347 4 : break;
348 92 : case SUMO_TAG_WAUT:
349 92 : closeWAUT();
350 92 : break;
351 488 : case SUMO_TAG_RAILSIGNAL_CONSTRAINTS:
352 488 : myConstrainedSignal = nullptr;
353 488 : break;
354 25499 : case SUMO_TAG_E1DETECTOR:
355 : case SUMO_TAG_INDUCTION_LOOP:
356 : case SUMO_TAG_INSTANT_INDUCTION_LOOP:
357 : case SUMO_TAG_E2DETECTOR:
358 : case SUMO_TAG_LANE_AREA_DETECTOR:
359 25499 : if (!myCurrentIsBroken) {
360 : myLastParameterised.pop_back();
361 : }
362 : break;
363 1548 : case SUMO_TAG_E3DETECTOR:
364 : case SUMO_TAG_ENTRY_EXIT_DETECTOR:
365 1548 : endE3Detector();
366 1540 : if (!myCurrentIsBroken) {
367 : myLastParameterised.pop_back();
368 : }
369 : break;
370 13712 : case SUMO_TAG_PARKING_AREA:
371 13712 : myTriggerBuilder.updateParkingAreaDefaultCapacity();
372 13712 : myTriggerBuilder.endParkingArea();
373 : myLastParameterised.pop_back();
374 : break;
375 51823 : case SUMO_TAG_BUS_STOP:
376 : case SUMO_TAG_TRAIN_STOP:
377 : case SUMO_TAG_CONTAINER_STOP:
378 : case SUMO_TAG_CHARGING_STATION:
379 51823 : myTriggerBuilder.endStoppingPlace();
380 : myLastParameterised.pop_back();
381 : break;
382 642 : case SUMO_TAG_PREDECESSOR: // intended fall-through
383 : case SUMO_TAG_FOE_INSERTION: // intended fall-through
384 : case SUMO_TAG_INSERTION_PREDECESSOR: // intended fall-through
385 : case SUMO_TAG_INSERTION_ORDER: // intended fall-through
386 : case SUMO_TAG_BIDI_PREDECESSOR:
387 : myLastParameterised.pop_back();
388 : break;
389 43816 : case SUMO_TAG_NET:
390 : // build junction graph
391 1839176 : for (JunctionGraph::iterator it = myJunctionGraph.begin(); it != myJunctionGraph.end(); ++it) {
392 1795504 : MSEdge* edge = MSEdge::dictionary(it->first);
393 3591008 : MSJunction* from = myJunctionControlBuilder.retrieve(it->second.first);
394 3591008 : MSJunction* to = myJunctionControlBuilder.retrieve(it->second.second);
395 1795504 : if (from == nullptr) {
396 78 : WRITE_ERRORF(TL("Unknown from-node '%' for edge '%'."), it->second.first, it->first);
397 26 : return;
398 : }
399 1795478 : if (to == nullptr) {
400 354 : WRITE_ERRORF(TL("Unknown to-node '%' for edge '%'."), it->second.second, it->first);
401 118 : return;
402 : }
403 1795360 : if (edge != nullptr) {
404 1795356 : edge->setJunctions(from, to);
405 1795356 : from->addOutgoing(edge);
406 1795356 : to->addIncoming(edge);
407 : }
408 : }
409 43672 : myNetIsLoaded = true;
410 43672 : break;
411 : default:
412 : break;
413 : }
414 10458974 : MSRouteHandler::myEndElement(element);
415 : }
416 :
417 :
418 :
419 : // ---- the root/edge - element
420 : void
421 1808397 : NLHandler::beginEdgeParsing(const SUMOSAXAttributes& attrs) {
422 1808397 : bool ok = true;
423 1808397 : myCurrentIsBroken = false;
424 : // get the id, report an error if not given or empty...
425 1808397 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
426 1808397 : if (!ok) {
427 4 : myCurrentIsBroken = true;
428 4 : return;
429 : }
430 : // parse the function
431 1808393 : const SumoXMLEdgeFunc func = attrs.getOpt<SumoXMLEdgeFunc>(SUMO_ATTR_FUNCTION, id.c_str(), ok, SumoXMLEdgeFunc::NORMAL);
432 1808393 : if (!ok) {
433 2 : myCurrentIsBroken = true;
434 2 : return;
435 : }
436 : // omit internal edges if not wished
437 1808391 : if (id[0] == ':') {
438 1128852 : myHaveSeenInternalEdge = true;
439 1128852 : if (!MSGlobals::gUsingInternalLanes && (func == SumoXMLEdgeFunc::CROSSING || func == SumoXMLEdgeFunc::WALKINGAREA)) {
440 12678 : myCurrentIsInternalToSkip = true;
441 12678 : return;
442 : }
443 2232348 : std::string junctionID = SUMOXMLDefinitions::getJunctionIDFromInternalEdge(id);
444 2232348 : myJunctionGraph[id] = std::make_pair(junctionID, junctionID);
445 : } else {
446 679539 : myHaveSeenDefaultLength |= !attrs.hasAttribute(SUMO_ATTR_LENGTH);
447 679539 : myJunctionGraph[id] = std::make_pair(
448 1359078 : attrs.get<std::string>(SUMO_ATTR_FROM, id.c_str(), ok),
449 1359078 : attrs.get<std::string>(SUMO_ATTR_TO, id.c_str(), ok));
450 : }
451 1795713 : if (!ok) {
452 16 : myCurrentIsBroken = true;
453 16 : return;
454 : }
455 1795697 : myCurrentIsInternalToSkip = false;
456 : // get the street name
457 1795697 : const std::string streetName = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
458 : // get the edge type
459 3591394 : const std::string edgeType = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
460 : // get the edge priority (only for visualization)
461 1795697 : const int priority = attrs.getOpt<int>(SUMO_ATTR_PRIORITY, id.c_str(), ok, -1); // default taken from netbuild/NBFrame option 'default.priority'
462 : // get the bidi-edge
463 3591394 : const std::string bidi = attrs.getOpt<std::string>(SUMO_ATTR_BIDI, id.c_str(), ok, "");
464 : // get the kilometrage/mileage (for visualization and output)
465 1795697 : const double distance = attrs.getOpt<double>(SUMO_ATTR_DISTANCE, id.c_str(), ok, 0);
466 :
467 1795697 : if (!ok) {
468 0 : myCurrentIsBroken = true;
469 : return;
470 : }
471 : //
472 : try {
473 1795697 : myEdgeControlBuilder.beginEdgeParsing(id, func, streetName, edgeType, priority, bidi, distance);
474 4 : } catch (InvalidArgument& e) {
475 4 : WRITE_ERROR(e.what());
476 4 : myCurrentIsBroken = true;
477 4 : }
478 :
479 1795697 : if (func == SumoXMLEdgeFunc::CROSSING) {
480 : //get the crossingEdges attribute (to implement the other side of the road pushbutton)
481 32452 : const std::string crossingEdges = attrs.getOpt<std::string>(SUMO_ATTR_CROSSING_EDGES, id.c_str(), ok, "");
482 16226 : if (!crossingEdges.empty()) {
483 : std::vector<std::string> crossingEdgesVector;
484 16226 : StringTokenizer edges(crossingEdges);
485 47470 : while (edges.hasNext()) {
486 62488 : crossingEdgesVector.push_back(edges.next());
487 : }
488 16226 : myEdgeControlBuilder.addCrossingEdges(crossingEdgesVector);
489 16226 : }
490 : }
491 1795697 : myLastEdgeParameters.clearParameter();
492 1795697 : myLastParameterised.push_back(&myLastEdgeParameters);
493 : }
494 :
495 :
496 : void
497 1808337 : NLHandler::closeEdge() {
498 : myLastParameterised.clear();
499 : // omit internal edges if not wished and broken edges
500 1808337 : if (myCurrentIsInternalToSkip || myCurrentIsBroken) {
501 : return;
502 : }
503 : try {
504 1795565 : MSEdge* e = myEdgeControlBuilder.closeEdge();
505 1795565 : MSEdge::dictionary(e->getID(), e);
506 1795565 : e->updateParameters(myLastEdgeParameters.getParametersMap());
507 0 : } catch (InvalidArgument& e) {
508 0 : WRITE_ERROR(e.what());
509 0 : }
510 : }
511 :
512 :
513 : // ---- the root/edge/lanes/lane - element
514 : void
515 2240544 : NLHandler::addLane(const SUMOSAXAttributes& attrs) {
516 : // omit internal edges if not wished and broken edges
517 2240544 : if (myCurrentIsInternalToSkip || myCurrentIsBroken) {
518 12804 : return;
519 : }
520 2227780 : bool ok = true;
521 : // get the id, report an error if not given or empty...
522 2227780 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
523 2227780 : if (!ok) {
524 8 : myCurrentIsBroken = true;
525 8 : return;
526 : }
527 2227772 : const double maxSpeed = attrs.get<double>(SUMO_ATTR_SPEED, id.c_str(), ok);
528 2227772 : const double friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, id.c_str(), ok, (double)(1.), false);
529 2227772 : const double length = attrs.get<double>(SUMO_ATTR_LENGTH, id.c_str(), ok);
530 2227772 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, id.c_str(), ok, "", false);
531 2227772 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, id.c_str(), ok, "");
532 2227772 : const std::string changeLeftS = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_LEFT, id.c_str(), ok, "");
533 4455544 : const std::string changeRightS = attrs.getOpt<std::string>(SUMO_ATTR_CHANGE_RIGHT, id.c_str(), ok, "");
534 2227772 : const double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, id.c_str(), ok, SUMO_const_laneWidth);
535 2227772 : const PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok);
536 2227772 : const PositionVector outlineShape = attrs.getOpt<PositionVector>(SUMO_ATTR_OUTLINESHAPE, id.c_str(), ok, PositionVector());
537 2227772 : const int index = attrs.get<int>(SUMO_ATTR_INDEX, id.c_str(), ok);
538 2227772 : const bool isRampAccel = attrs.getOpt<bool>(SUMO_ATTR_ACCELERATION, id.c_str(), ok, false);
539 4455544 : const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
540 2227772 : if (shape.size() < 2) {
541 96 : WRITE_ERRORF(TL("Shape of lane '%' is broken.\n Can not build according edge."), id);
542 32 : myCurrentIsBroken = true;
543 : return;
544 : }
545 2227740 : const SVCPermissions permissions = parseVehicleClasses(allow, disallow, myNetworkVersion);
546 2227740 : SVCPermissions changeLeft = parseVehicleClasses(changeLeftS, "", myNetworkVersion);
547 2227740 : SVCPermissions changeRight = parseVehicleClasses(changeRightS, "", myNetworkVersion);
548 2227740 : if (MSGlobals::gLefthand) {
549 : // internally, changeLeft always checks for the higher lane index
550 : // even though the higher lane index is to the right in a left-hand network
551 : std::swap(changeLeft, changeRight);
552 : }
553 2227740 : if (permissions != SVCAll || changeLeft != SVCAll || changeRight != SVCAll) {
554 777539 : myNet.setPermissionsFound();
555 : }
556 2227740 : myCurrentIsBroken |= !ok;
557 2227740 : if (!myCurrentIsBroken) {
558 : try {
559 2227720 : MSLane* lane = myEdgeControlBuilder.addLane(id, maxSpeed, friction, length, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape);
560 : // insert the lane into the lane-dictionary, checking
561 2227720 : if (!MSLane::dictionary(id, lane)) {
562 8 : delete lane;
563 24 : WRITE_ERRORF(TL("Another lane with the id '%' exists."), id);
564 8 : myCurrentIsBroken = true;
565 8 : myLastParameterised.push_back(nullptr);
566 : } else {
567 2227712 : myLastParameterised.push_back(lane);
568 : }
569 0 : } catch (InvalidArgument& e) {
570 0 : WRITE_ERROR(e.what());
571 0 : }
572 : }
573 2227772 : }
574 :
575 :
576 : // ---- the root/junction - element
577 : void
578 579847 : NLHandler::openJunction(const SUMOSAXAttributes& attrs) {
579 579847 : myCurrentIsBroken = false;
580 579847 : bool ok = true;
581 : // get the id, report an error if not given or empty...
582 579847 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
583 579847 : if (!ok) {
584 6 : myCurrentIsBroken = true;
585 : return;
586 : }
587 579841 : PositionVector shape;
588 579841 : if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
589 : // inner junctions have no shape
590 773266 : shape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, id.c_str(), ok, PositionVector());
591 386633 : if (shape.size() > 2) {
592 346793 : shape.closePolygon();
593 : }
594 : }
595 579841 : double x = attrs.get<double>(SUMO_ATTR_X, id.c_str(), ok);
596 579841 : double y = attrs.get<double>(SUMO_ATTR_Y, id.c_str(), ok);
597 579841 : double z = attrs.getOpt<double>(SUMO_ATTR_Z, id.c_str(), ok, 0);
598 579841 : const SumoXMLNodeType type = attrs.get<SumoXMLNodeType>(SUMO_ATTR_TYPE, id.c_str(), ok);
599 579841 : std::string key = attrs.getOpt<std::string>(SUMO_ATTR_KEY, id.c_str(), ok, "");
600 1159682 : std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
601 : // incoming lanes
602 : std::vector<MSLane*> incomingLanes;
603 1159682 : parseLanes(id, attrs.getStringSecure(SUMO_ATTR_INCLANES, ""), incomingLanes, ok);
604 : // internal lanes
605 : std::vector<MSLane*> internalLanes;
606 579841 : if (MSGlobals::gUsingInternalLanes) {
607 981520 : parseLanes(id, attrs.getStringSecure(SUMO_ATTR_INTLANES, ""), internalLanes, ok);
608 : }
609 579841 : if (!ok) {
610 123 : myCurrentIsBroken = true;
611 : } else {
612 : try {
613 579718 : myJunctionControlBuilder.openJunction(id, key, type, Position(x, y, z), shape, incomingLanes, internalLanes, name);
614 0 : } catch (InvalidArgument& e) {
615 0 : WRITE_ERROR(e.what() + std::string("\n Can not build according junction."));
616 0 : myCurrentIsBroken = true;
617 0 : }
618 : }
619 1159682 : }
620 :
621 :
622 : void
623 1070601 : NLHandler::parseLanes(const std::string& junctionID,
624 : const std::string& def, std::vector<MSLane*>& into, bool& ok) {
625 3211803 : StringTokenizer st(def, " ");
626 4183338 : while (ok && st.hasNext()) {
627 3112737 : std::string laneID = st.next();
628 3112737 : MSLane* lane = MSLane::dictionary(laneID);
629 3112737 : if (!MSGlobals::gUsingInternalLanes && laneID[0] == ':') {
630 35969 : continue;
631 : }
632 3076768 : if (lane == nullptr) {
633 342 : WRITE_ERRORF(TL("An unknown lane ('%') was tried to be set as incoming to junction '%'."), laneID, junctionID);
634 114 : ok = false;
635 114 : continue;
636 : }
637 3076654 : into.push_back(lane);
638 : }
639 1070601 : }
640 : // ----
641 :
642 : void
643 42760 : NLHandler::addParam(const SUMOSAXAttributes& attrs) {
644 42760 : bool ok = true;
645 42760 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
646 : // circumventing empty string test
647 42760 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
648 42760 : if (myLastParameterised.size() > 0 && myLastParameterised.back() != nullptr) {
649 29443 : myLastParameterised.back()->setParameter(key, val);
650 : }
651 : // set
652 42760 : if (ok && myAmParsingTLLogicOrJunction) {
653 : assert(key != "");
654 10311 : myJunctionControlBuilder.addParam(key, val);
655 : }
656 42760 : }
657 :
658 :
659 : void
660 92 : NLHandler::openWAUT(const SUMOSAXAttributes& attrs) {
661 92 : myCurrentIsBroken = false;
662 92 : bool ok = true;
663 : // get the id, report an error if not given or empty...
664 92 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
665 92 : if (!ok) {
666 1 : myCurrentIsBroken = true;
667 : return;
668 : }
669 91 : SUMOTime refTime = attrs.getOptSUMOTimeReporting(SUMO_ATTR_REF_TIME, id.c_str(), ok, 0);
670 91 : SUMOTime period = attrs.getOptSUMOTimeReporting(SUMO_ATTR_PERIOD, id.c_str(), ok, 0);
671 91 : std::string startProg = attrs.get<std::string>(SUMO_ATTR_START_PROG, id.c_str(), ok);
672 91 : if (!ok) {
673 1 : myCurrentIsBroken = true;
674 : }
675 91 : if (!myCurrentIsBroken) {
676 90 : myCurrentWAUTID = id;
677 : try {
678 90 : myJunctionControlBuilder.getTLLogicControlToUse().addWAUT(refTime, id, startProg, period);
679 0 : } catch (InvalidArgument& e) {
680 0 : WRITE_ERROR(e.what());
681 0 : myCurrentIsBroken = true;
682 0 : }
683 : }
684 : }
685 :
686 :
687 : void
688 175 : NLHandler::addWAUTSwitch(const SUMOSAXAttributes& attrs) {
689 175 : bool ok = true;
690 175 : SUMOTime t = attrs.getSUMOTimeReporting(SUMO_ATTR_TIME, myCurrentWAUTID.c_str(), ok);
691 175 : std::string to = attrs.get<std::string>(SUMO_ATTR_TO, myCurrentWAUTID.c_str(), ok);
692 175 : if (!ok) {
693 2 : myCurrentIsBroken = true;
694 : }
695 175 : if (!myCurrentIsBroken) {
696 : try {
697 171 : myJunctionControlBuilder.getTLLogicControlToUse().addWAUTSwitch(myCurrentWAUTID, t, to);
698 0 : } catch (InvalidArgument& e) {
699 0 : WRITE_ERROR(e.what());
700 0 : myCurrentIsBroken = true;
701 0 : }
702 : }
703 175 : }
704 :
705 :
706 : void
707 93 : NLHandler::addWAUTJunction(const SUMOSAXAttributes& attrs) {
708 93 : bool ok = true;
709 93 : std::string wautID = attrs.get<std::string>(SUMO_ATTR_WAUT_ID, nullptr, ok);
710 93 : std::string junctionID = attrs.get<std::string>(SUMO_ATTR_JUNCTION_ID, nullptr, ok);
711 93 : std::string procedure = attrs.getOpt<std::string>(SUMO_ATTR_PROCEDURE, nullptr, ok, "");
712 93 : bool synchron = attrs.getOpt<bool>(SUMO_ATTR_SYNCHRON, nullptr, ok, false);
713 93 : if (!ok) {
714 0 : myCurrentIsBroken = true;
715 : }
716 : try {
717 93 : if (!myCurrentIsBroken) {
718 89 : myJunctionControlBuilder.getTLLogicControlToUse().addWAUTJunction(wautID, junctionID, procedure, synchron);
719 : }
720 3 : } catch (InvalidArgument& e) {
721 3 : WRITE_ERROR(e.what());
722 3 : myCurrentIsBroken = true;
723 3 : }
724 93 : }
725 :
726 :
727 : void
728 1656543 : NLHandler::addRequest(const SUMOSAXAttributes& attrs) {
729 1656543 : if (myCurrentIsBroken) {
730 124 : return;
731 : }
732 1656419 : bool ok = true;
733 1656419 : int request = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
734 : bool cont = false;
735 1656419 : cont = attrs.getOpt<bool>(SUMO_ATTR_CONT, nullptr, ok, false);
736 1656419 : std::string response = attrs.get<std::string>(SUMO_ATTR_RESPONSE, nullptr, ok);
737 1656419 : std::string foes = attrs.get<std::string>(SUMO_ATTR_FOES, nullptr, ok);
738 1656419 : if (!ok) {
739 : return;
740 : }
741 : // store received information
742 1656419 : if (request >= 0 && response.length() > 0) {
743 : try {
744 1656419 : myJunctionControlBuilder.addLogicItem(request, response, foes, cont);
745 0 : } catch (InvalidArgument& e) {
746 0 : WRITE_ERROR(e.what());
747 0 : }
748 : }
749 : }
750 :
751 :
752 : void
753 579847 : NLHandler::initJunctionLogic(const SUMOSAXAttributes& attrs) {
754 579847 : if (myCurrentIsBroken) {
755 129 : return;
756 : }
757 579718 : myAmParsingTLLogicOrJunction = true;
758 579718 : bool ok = true;
759 : // we either a have a junction or a legacy network with ROWLogic
760 579718 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
761 579718 : if (ok) {
762 579718 : myJunctionControlBuilder.initJunctionLogic(id);
763 : }
764 : }
765 :
766 :
767 : void
768 111311 : NLHandler::initTrafficLightLogic(const SUMOSAXAttributes& attrs) {
769 111311 : myCurrentIsBroken = false;
770 111311 : myAmParsingTLLogicOrJunction = true;
771 111311 : bool ok = true;
772 111311 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
773 111311 : std::string programID = attrs.getOpt<std::string>(SUMO_ATTR_PROGRAMID, id.c_str(), ok, "<unknown>");
774 111311 : TrafficLightType type = TrafficLightType::STATIC;
775 : std::string typeS;
776 111311 : if (myJunctionControlBuilder.getTLLogicControlToUse().get(id, programID) == nullptr) {
777 : // SUMO_ATTR_TYPE is not needed when only modifying the offset of an
778 : // existing program
779 111181 : typeS = attrs.get<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok);
780 111181 : if (!ok) {
781 1 : myCurrentIsBroken = true;
782 1 : return;
783 : }
784 : if (SUMOXMLDefinitions::TrafficLightTypes.hasString(typeS)) {
785 111180 : type = SUMOXMLDefinitions::TrafficLightTypes.get(typeS);
786 : } else {
787 0 : WRITE_ERRORF(TL("Traffic light '%' has unknown type '%'."), id, typeS);
788 : }
789 111180 : if (MSGlobals::gUseMesoSim && (type == TrafficLightType::ACTUATED || type == TrafficLightType::NEMA)) {
790 23 : if (!myHaveWarnedAboutInvalidTLType) {
791 46 : WRITE_WARNINGF(TL("Traffic light type '%' cannot be used in mesoscopic simulation. Using '%' as fallback."), toString(type), toString(TrafficLightType::STATIC));
792 23 : myHaveWarnedAboutInvalidTLType = true;
793 : }
794 23 : type = TrafficLightType::STATIC;
795 : }
796 : }
797 111310 : SUMOTime offset = attrs.getOptOffsetReporting(SUMO_ATTR_OFFSET, id.c_str(), ok, 0);
798 111310 : if (offset == SUMOTime_MAX) {
799 2 : offset = string2time(OptionsCont::getOptions().getString("begin"));
800 : }
801 111310 : if (!ok) {
802 0 : myCurrentIsBroken = true;
803 0 : return;
804 : }
805 111310 : myJunctionControlBuilder.initTrafficLightLogic(id, programID, type, offset);
806 : }
807 :
808 :
809 : void
810 520196 : NLHandler::addPhase(const SUMOSAXAttributes& attrs) {
811 : // try to get the phase definition
812 520196 : bool ok = true;
813 520196 : const std::string& id = myJunctionControlBuilder.getActiveKey();
814 : const SUMOTime tDefault = MSPhaseDefinition::UNSPECIFIED_DURATION;
815 :
816 520196 : const SUMOTime duration = attrs.getSUMOTimeReporting(SUMO_ATTR_DURATION, myJunctionControlBuilder.getActiveKey().c_str(), ok);
817 520196 : const std::string state = attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok);
818 520196 : if (duration == 0) {
819 2 : WRITE_ERROR("Duration of phase " + toString(myJunctionControlBuilder.getLoadedPhases().size())
820 : + " for tlLogic '" + myJunctionControlBuilder.getActiveKey()
821 : + "' program '" + myJunctionControlBuilder.getActiveSubKey() + "' is zero.");
822 1 : return;
823 : }
824 520195 : if (!ok) {
825 : return;
826 : }
827 1040390 : MSPhaseDefinition* phase = new MSPhaseDefinition(duration, state);
828 :
829 : // if the traffic light is an actuated traffic light, try to get
830 : // the minimum and maximum durations
831 520195 : phase->minDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MINDURATION, id.c_str(), ok, duration);
832 : // if minDur is set but not maxDur, assume high maxDur (avoid using the absolute max in case we do some arithmetic later)
833 520195 : SUMOTime defaultMaxDur = attrs.hasAttribute(SUMO_ATTR_MINDURATION) ? std::numeric_limits<int>::max() : duration;
834 520195 : phase->maxDuration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MAXDURATION, id.c_str(), ok, defaultMaxDur);
835 520195 : phase->earliestEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_EARLIEST_END, id.c_str(), ok, tDefault);
836 520195 : phase->latestEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_LATEST_END, id.c_str(), ok, tDefault);
837 520195 : phase->nextPhases = attrs.getOpt<std::vector<int> >(SUMO_ATTR_NEXT, id.c_str(), ok);
838 1040390 : phase->earlyTarget = attrs.getOpt<std::string>(SUMO_ATTR_EARLY_TARGET, id.c_str(), ok);
839 1040390 : phase->finalTarget = attrs.getOpt<std::string>(SUMO_ATTR_FINAL_TARGET, id.c_str(), ok);
840 1040390 : phase->name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok);
841 :
842 520195 : phase->vehext = attrs.getOptSUMOTimeReporting(SUMO_ATTR_VEHICLEEXTENSION, id.c_str(), ok, tDefault);
843 520195 : phase->yellow = attrs.getOptSUMOTimeReporting(SUMO_ATTR_YELLOW, id.c_str(), ok, tDefault);
844 520195 : phase->red = attrs.getOptSUMOTimeReporting(SUMO_ATTR_RED, id.c_str(), ok, tDefault);
845 :
846 520195 : if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
847 : //SOTL attributes
848 : //If the type attribute is not present, the parsed phase is of type "undefined" (MSPhaseDefinition constructor),
849 : //in this way SOTL traffic light logic can recognize the phase as unsuitable or decides other
850 : //behaviors. See SOTL traffic light logic implementations.
851 : std::string phaseTypeString;
852 : try {
853 1536 : phaseTypeString = attrs.get<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, false);
854 0 : } catch (EmptyData&) {
855 0 : MsgHandler::getWarningInstance()->inform("Empty type definition. Assuming phase type as SUMOSOTL_TagAttrDefinitions::SOTL_ATTL_TYPE_TRANSIENT");
856 0 : phase->myTransientNotDecisional = false;
857 0 : }
858 768 : if (phaseTypeString.find("decisional") != std::string::npos) {
859 256 : phase->myTransientNotDecisional = false;
860 512 : } else if (phaseTypeString.find("transient") != std::string::npos) {
861 512 : phase->myTransientNotDecisional = true;
862 : } else {
863 0 : MsgHandler::getWarningInstance()->inform("SOTL_ATTL_TYPE_DECISIONAL nor SOTL_ATTL_TYPE_TRANSIENT. Assuming phase type as SUMOSOTL_TagAttrDefinitions::SOTL_ATTL_TYPE_TRANSIENT");
864 0 : phase->myTransientNotDecisional = false;
865 : }
866 768 : phase->myCommit = (phaseTypeString.find("commit") != std::string::npos);
867 :
868 768 : if (phaseTypeString.find("target") != std::string::npos) {
869 256 : std::string delimiter(" ,;");
870 : //Phase declared as target, getting targetLanes attribute
871 : try {
872 512 : phase->myTargetLaneSet = StringTokenizer(attrs.getStringSecure(SUMO_ATTR_TARGETLANE, ""), " ,;", true).getVector();
873 0 : } catch (EmptyData&) {
874 0 : MsgHandler::getErrorInstance()->inform("Missing targetLane definition for the target phase.");
875 0 : delete phase;
876 : return;
877 0 : }
878 : }
879 : }
880 :
881 520195 : if (phase->maxDuration < phase->minDuration) {
882 9 : WRITE_WARNINGF(TL("maxDur % should not be smaller than minDir % in phase of tlLogic %"), phase->maxDuration, phase->minDuration, id);
883 3 : phase->maxDuration = phase->duration;
884 : }
885 :
886 520195 : phase->myLastSwitch = string2time(OptionsCont::getOptions().getString("begin")) - 1; // SUMOTime-option
887 520195 : myJunctionControlBuilder.addPhase(phase);
888 : }
889 :
890 :
891 : void
892 94 : NLHandler::addCondition(const SUMOSAXAttributes& attrs) {
893 94 : bool ok = true;
894 94 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
895 94 : const std::string value = attrs.get<std::string>(SUMO_ATTR_VALUE, id.c_str(), ok);
896 94 : if (!myJunctionControlBuilder.addCondition(id, value)) {
897 0 : WRITE_ERRORF(TL("Duplicate condition '%' in tlLogic '%'"), id, myJunctionControlBuilder.getActiveKey());
898 : }
899 94 : }
900 :
901 :
902 : void
903 60 : NLHandler::addAssignment(const SUMOSAXAttributes& attrs) {
904 60 : bool ok = true;
905 60 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
906 60 : const std::string check = attrs.get<std::string>(SUMO_ATTR_CHECK, nullptr, ok);
907 60 : const std::string value = attrs.get<std::string>(SUMO_ATTR_VALUE, id.c_str(), ok);
908 60 : myJunctionControlBuilder.addAssignment(id, check, value);
909 60 : }
910 :
911 :
912 : void
913 4 : NLHandler::addFunction(const SUMOSAXAttributes& attrs) {
914 4 : bool ok = true;
915 4 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
916 4 : const int nArgs = attrs.get<int>(SUMO_ATTR_NARGS, nullptr, ok);
917 4 : myJunctionControlBuilder.addFunction(id, nArgs);
918 4 : }
919 :
920 : void
921 4 : NLHandler::closeFunction() {
922 4 : myJunctionControlBuilder.closeFunction();
923 4 : }
924 :
925 : void
926 21296 : NLHandler::addE1Detector(const SUMOSAXAttributes& attrs) {
927 21296 : myCurrentIsBroken = false;
928 21296 : bool ok = true;
929 : // get the id, report an error if not given or empty...
930 21296 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
931 21296 : if (!ok) {
932 12 : myCurrentIsBroken = true;
933 12 : return;
934 : }
935 21284 : const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, SUMOTime_MAX_PERIOD);
936 21284 : const double position = attrs.get<double>(SUMO_ATTR_POSITION, id.c_str(), ok);
937 21284 : const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, 0);
938 21284 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
939 21290 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
940 21290 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
941 42574 : const std::string nextEdges = attrs.getOpt<std::string>(SUMO_ATTR_NEXT_EDGES, id.c_str(), ok, "");
942 21284 : const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, id.c_str(), ok);
943 21284 : const std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
944 42574 : const std::string detectPersonsString = attrs.getOpt<std::string>(SUMO_ATTR_DETECT_PERSONS, id.c_str(), ok, "");
945 : int detectPersons = 0;
946 42783 : for (std::string mode : StringTokenizer(detectPersonsString).getVector()) {
947 : if (SUMOXMLDefinitions::PersonModeValues.hasString(mode)) {
948 209 : detectPersons |= (int)SUMOXMLDefinitions::PersonModeValues.get(mode);
949 : } else {
950 0 : WRITE_ERRORF(TL("Invalid person mode '%' in E1 detector definition '%'"), mode, id);
951 0 : myCurrentIsBroken = true;
952 : return;
953 : }
954 21284 : }
955 21284 : if (!ok) {
956 54 : myCurrentIsBroken = true;
957 54 : return;
958 : }
959 : try {
960 42460 : Parameterised* det = myDetectorBuilder.buildInductLoop(id, lane, position, length, period,
961 42460 : FileHelpers::checkForRelativity(file, getFileName()),
962 21187 : friendlyPos, name, vTypes, nextEdges, detectPersons);
963 21187 : myLastParameterised.push_back(det);
964 43 : } catch (InvalidArgument& e) {
965 31 : myCurrentIsBroken = true;
966 31 : WRITE_ERROR(e.what());
967 37 : } catch (IOError& e) {
968 6 : myCurrentIsBroken = true;
969 6 : WRITE_ERROR(e.what());
970 6 : }
971 : }
972 :
973 :
974 : void
975 1089 : NLHandler::addInstantE1Detector(const SUMOSAXAttributes& attrs) {
976 1089 : myCurrentIsBroken = false;
977 1089 : bool ok = true;
978 : // get the id, report an error if not given or empty...
979 1089 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
980 1089 : if (!ok) {
981 8 : myCurrentIsBroken = true;
982 8 : return;
983 : }
984 1081 : const double position = attrs.get<double>(SUMO_ATTR_POSITION, id.c_str(), ok);
985 1081 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
986 1081 : const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, id.c_str(), ok);
987 1081 : const std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
988 1081 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
989 1081 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
990 1081 : const std::string nextEdges = attrs.getOpt<std::string>(SUMO_ATTR_NEXT_EDGES, id.c_str(), ok, "");
991 1081 : if (!ok) {
992 28 : myCurrentIsBroken = true;
993 : return;
994 : }
995 : try {
996 2118 : Parameterised* det = myDetectorBuilder.buildInstantInductLoop(id, lane, position, FileHelpers::checkForRelativity(file, getFileName()), friendlyPos, name, vTypes, nextEdges);
997 1041 : myLastParameterised.push_back(det);
998 12 : } catch (InvalidArgument& e) {
999 8 : WRITE_ERROR(e.what());
1000 12 : } catch (IOError& e) {
1001 4 : WRITE_ERROR(e.what());
1002 4 : }
1003 1053 : myCurrentIsBroken = true;
1004 : }
1005 :
1006 :
1007 : void
1008 144 : NLHandler::addVTypeProbeDetector(const SUMOSAXAttributes& attrs) {
1009 144 : WRITE_WARNING(TL("VTypeProbes are deprecated. Use fcd-output devices (assigned to the vType) instead."));
1010 144 : bool ok = true;
1011 144 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1012 144 : SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, SUMOTime_MAX_PERIOD);
1013 288 : std::string type = attrs.getStringSecure(SUMO_ATTR_TYPE, "");
1014 144 : std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
1015 144 : if (!ok) {
1016 : return;
1017 : }
1018 : try {
1019 198 : myDetectorBuilder.buildVTypeProbe(id, type, period, FileHelpers::checkForRelativity(file, getFileName()));
1020 18 : } catch (InvalidArgument& e) {
1021 12 : WRITE_ERROR(e.what());
1022 18 : } catch (IOError& e) {
1023 6 : WRITE_ERROR(e.what());
1024 6 : }
1025 : }
1026 :
1027 :
1028 : void
1029 614 : NLHandler::addRouteProbeDetector(const SUMOSAXAttributes& attrs) {
1030 614 : bool ok = true;
1031 614 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1032 614 : SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, SUMOTime_MAX_PERIOD);
1033 614 : SUMOTime begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, id.c_str(), ok, -1);
1034 614 : std::string edge = attrs.get<std::string>(SUMO_ATTR_EDGE, id.c_str(), ok);
1035 614 : std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
1036 614 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
1037 614 : if (!ok) {
1038 : return;
1039 : }
1040 : try {
1041 614 : myDetectorBuilder.buildRouteProbe(id, edge, period, begin,
1042 1228 : FileHelpers::checkForRelativity(file, getFileName()), vTypes);
1043 0 : } catch (InvalidArgument& e) {
1044 0 : WRITE_ERROR(e.what());
1045 0 : } catch (IOError& e) {
1046 0 : WRITE_ERROR(e.what());
1047 0 : }
1048 : }
1049 :
1050 :
1051 :
1052 : void
1053 3124 : NLHandler::addE2Detector(const SUMOSAXAttributes& attrs) {
1054 3124 : myCurrentIsBroken = false;
1055 : // check whether this is a detector connected to a tls and optionally to a link
1056 3124 : bool ok = true;
1057 3124 : const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1058 3155 : const std::string lsaid = attrs.getOpt<std::string>(SUMO_ATTR_TLID, id.c_str(), ok, "");
1059 6279 : const std::string toLane = attrs.getOpt<std::string>(SUMO_ATTR_TO, id.c_str(), ok, "");
1060 3124 : const SUMOTime haltingTimeThreshold = attrs.getOptSUMOTimeReporting(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, TIME2STEPS(1));
1061 3124 : const double haltingSpeedThreshold = attrs.getOpt<double>(SUMO_ATTR_HALTING_SPEED_THRESHOLD, id.c_str(), ok, 5.0f / 3.6f);
1062 3124 : const double jamDistThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, id.c_str(), ok, 10.0f);
1063 3124 : double position = attrs.getOpt<double>(SUMO_ATTR_POSITION, id.c_str(), ok, std::numeric_limits<double>::max());
1064 3124 : const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, id.c_str(), ok, std::numeric_limits<double>::max());
1065 3124 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, id.c_str(), ok, false);
1066 3124 : const bool showDetector = attrs.getOpt<bool>(SUMO_ATTR_SHOW_DETECTOR, id.c_str(), ok, true);
1067 6279 : const std::string contStr = attrs.getOpt<std::string>(SUMO_ATTR_CONT, id.c_str(), ok, "");
1068 3124 : if (contStr != "") {
1069 0 : WRITE_WARNINGF(TL("Ignoring deprecated argument 'cont' for E2 detector '%'"), id);
1070 : }
1071 6279 : std::string lane = attrs.getOpt<std::string>(SUMO_ATTR_LANE, id.c_str(), ok, "");
1072 3124 : const std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
1073 3155 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
1074 3155 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
1075 6279 : const std::string nextEdges = attrs.getOpt<std::string>(SUMO_ATTR_NEXT_EDGES, id.c_str(), ok, "");
1076 :
1077 3124 : double endPosition = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok, std::numeric_limits<double>::max());
1078 3155 : const std::string lanes = attrs.getOpt<std::string>(SUMO_ATTR_LANES, id.c_str(), ok, ""); // lanes has priority to lane
1079 6279 : const std::string detectPersonsString = attrs.getOpt<std::string>(SUMO_ATTR_DETECT_PERSONS, id.c_str(), ok, "");
1080 : int detectPersons = 0;
1081 6366 : for (std::string mode : StringTokenizer(detectPersonsString).getVector()) {
1082 : if (SUMOXMLDefinitions::PersonModeValues.hasString(mode)) {
1083 118 : detectPersons |= (int)SUMOXMLDefinitions::PersonModeValues.get(mode);
1084 : } else {
1085 0 : WRITE_ERRORF(TL("Invalid person mode '%' in E2 detector definition '%'"), mode, id);
1086 0 : myCurrentIsBroken = true;
1087 : return;
1088 : }
1089 3124 : }
1090 3124 : if (!ok) {
1091 36 : myCurrentIsBroken = true;
1092 36 : return;
1093 : }
1094 :
1095 : bool lanesGiven = lanes != "";
1096 : bool laneGiven = lane != "";
1097 3088 : if (!(lanesGiven || laneGiven)) {
1098 : // in absence of any lane-specification assume specification by id
1099 39 : WRITE_WARNING(TL("Trying to specify detector's lane by the given id since the argument 'lane' is missing."))
1100 : lane = id;
1101 : laneGiven = true;
1102 : }
1103 3088 : bool lengthGiven = length != std::numeric_limits<double>::max();
1104 : bool posGiven = position != std::numeric_limits<double>::max();
1105 3088 : bool endPosGiven = endPosition != std::numeric_limits<double>::max();
1106 : bool lsaGiven = lsaid != "";
1107 : bool toLaneGiven = toLane != "";
1108 :
1109 3088 : MSLane* clane = nullptr;
1110 : std::vector<MSLane*> clanes;
1111 3088 : if (lanesGiven) {
1112 : // If lanes is given, endPos and startPos are required. lane, and length are ignored
1113 317 : std::string seps = " ,\t\n";
1114 635 : StringTokenizer st = StringTokenizer(lanes, seps, true);
1115 : // std::cout << "Parsing lanes..." << std::endl;
1116 1049 : while (st.hasNext()) {
1117 733 : std::string nextLaneID = st.next();
1118 : // std::cout << "Next: " << nextLaneID << std::endl;
1119 733 : if (nextLaneID.find_first_of(seps) != nextLaneID.npos) {
1120 : continue;
1121 : }
1122 733 : clane = myDetectorBuilder.getLaneChecking(nextLaneID, SUMO_TAG_E2DETECTOR, id);
1123 732 : clanes.push_back(clane);
1124 : }
1125 316 : if (clanes.size() == 0) {
1126 0 : throw InvalidArgument("Malformed argument 'lanes' for E2Detector '" + id + "'.\nSpecify 'lanes' as a sequence of lane-IDs separated by whitespace or comma (',')");
1127 : }
1128 316 : if (laneGiven) {
1129 0 : WRITE_WARNING("Ignoring argument 'lane' for E2Detector '" + id + "' since argument 'lanes' was given.\n"
1130 : "Usage combinations for positional specification: [lane, pos, length], [lane, endPos, length], or [lanes, pos, endPos]");
1131 : }
1132 316 : if (lengthGiven) {
1133 0 : WRITE_WARNING("Ignoring argument 'length' for E2Detector '" + id + "' since argument 'lanes' was given.\n"
1134 : "Usage combinations for positional specification: [lane, pos, length], [lane, endPos, length], or [lanes, pos, endPos]");
1135 : }
1136 316 : if (!posGiven) {
1137 : // assuming start pos == lane start
1138 : position = 0;
1139 0 : WRITE_WARNINGF(TL("Missing argument 'pos' for E2Detector '%'. Assuming detector start == lane start of lane '%'."), id, clanes[0]->getID());
1140 : }
1141 316 : if (!endPosGiven) {
1142 : // assuming end pos == lane end
1143 0 : endPosition = clanes[clanes.size() - 1]->getLength();
1144 0 : WRITE_WARNINGF(TL("Missing argument 'endPos' for E2Detector '%'. Assuming detector end == lane end of lane '%'."), id, clanes[clanes.size() - 1]->getID());
1145 : }
1146 :
1147 317 : } else {
1148 2771 : if (!laneGiven) {
1149 0 : std::stringstream ss;
1150 : ss << "Missing argument 'lane' for E2Detector '" << id << "'."
1151 0 : << "\nUsage combinations for positional specification: [lane, pos, length], [lane, endPos, length], or [lanes, pos, endPos]";
1152 0 : throw InvalidArgument(ss.str());
1153 0 : }
1154 2771 : clane = myDetectorBuilder.getLaneChecking(lane, SUMO_TAG_E2DETECTOR, id);
1155 :
1156 2763 : if (posGiven) {
1157 : // start pos is given
1158 2658 : if (endPosGiven && lengthGiven) {
1159 0 : std::stringstream ss;
1160 : ss << "Ignoring argument 'endPos' for E2Detector '" << id << "' since argument 'pos' was given."
1161 0 : << "\nUsage combinations for positional specification: [lane, pos, length], [lane, endPos, length], or [lanes, pos, endPos]";
1162 0 : WRITE_WARNING(ss.str());
1163 : endPosition = std::numeric_limits<double>::max();
1164 0 : }
1165 2658 : if (!lengthGiven && !endPosGiven) {
1166 4 : std::stringstream ss;
1167 4 : ss << "Missing arguments 'length'/'endPos' for E2Detector '" << id << "'. Assuming detector end == lane end of lane '" << lane << "'.";
1168 8 : WRITE_WARNING(ss.str());
1169 : endPosition = clane->getLength();
1170 4 : }
1171 105 : } else if (endPosGiven) {
1172 : // endPos is given, pos is not given
1173 101 : if (!lengthGiven) {
1174 0 : std::stringstream ss;
1175 0 : ss << "Missing arguments 'length'/'pos' for E2Detector '" << id << "'. Assuming detector start == lane start of lane '" << lane << "'.";
1176 0 : WRITE_WARNING(ss.str());
1177 0 : }
1178 : } else {
1179 4 : std::stringstream ss;
1180 4 : if (lengthGiven && fabs(length - clane->getLength()) > NUMERICAL_EPS) {
1181 : ss << "Incomplete positional specification for E2Detector '" << id << "'."
1182 4 : << "\nUsage combinations for positional specification: [lane, pos, length], [lane, endPos, length], or [lanes, pos, endPos]";
1183 8 : throw InvalidArgument(ss.str());
1184 : }
1185 : endPosition = clane->getLength();
1186 : position = 0;
1187 0 : ss << "Missing arguments 'pos'/'endPos' for E2Detector '" << id << "'. Assuming that the detector covers the whole lane '" << lane << "'.";
1188 0 : WRITE_WARNING(ss.str());
1189 4 : }
1190 : }
1191 :
1192 : // Period
1193 :
1194 : SUMOTime period;
1195 3075 : if (!lsaGiven) {
1196 2516 : period = attrs.getOptPeriod(id.c_str(), ok, SUMOTime_MAX_PERIOD);
1197 2516 : if (!ok) {
1198 8 : myCurrentIsBroken = true;
1199 : return;
1200 : }
1201 : } else {
1202 559 : period = attrs.getPeriod(id.c_str(), ok, false);
1203 : }
1204 :
1205 : // TLS
1206 : MSTLLogicControl::TLSLogicVariants* tlls = nullptr;
1207 3067 : if (lsaGiven) {
1208 559 : tlls = &myJunctionControlBuilder.getTLLogic(lsaid);
1209 559 : if (tlls->getActive() == nullptr) {
1210 0 : throw InvalidArgument("The detector '" + id + "' refers to an unknown lsa '" + lsaid + "'.");
1211 : }
1212 559 : if (period != -1) {
1213 75 : WRITE_WARNINGF(TL("Ignoring argument 'period' for E2Detector '%' since argument 'tl' was given."), id);
1214 : period = -1;
1215 : }
1216 : }
1217 :
1218 : // Link
1219 : MSLane* cToLane = nullptr;
1220 3067 : if (toLaneGiven) {
1221 8 : cToLane = myDetectorBuilder.getLaneChecking(toLane, SUMO_TAG_E2DETECTOR, id);
1222 : }
1223 :
1224 : // File
1225 : std::string filename;
1226 : try {
1227 6134 : filename = FileHelpers::checkForRelativity(file, getFileName());
1228 0 : } catch (IOError& e) {
1229 0 : WRITE_ERROR(e.what());
1230 0 : }
1231 :
1232 : Parameterised* det;
1233 : // Build detector
1234 3067 : if (lanesGiven) {
1235 : // specification by a lane sequence
1236 638 : det = myDetectorBuilder.buildE2Detector(id, clanes, position, endPosition, filename, period,
1237 : haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold,
1238 : name, vTypes, nextEdges, detectPersons, friendlyPos, showDetector,
1239 : tlls, cToLane);
1240 : } else {
1241 : // specification by start or end lane
1242 5520 : det = myDetectorBuilder.buildE2Detector(id, clane, position, endPosition, length, filename, period,
1243 : haltingTimeThreshold, haltingSpeedThreshold, jamDistThreshold,
1244 : name, vTypes, nextEdges, detectPersons, friendlyPos, showDetector,
1245 : tlls, cToLane);
1246 : }
1247 3049 : myLastParameterised.push_back(det);
1248 3088 : }
1249 :
1250 :
1251 : void
1252 1548 : NLHandler::beginE3Detector(const SUMOSAXAttributes& attrs) {
1253 1548 : myCurrentIsBroken = false;
1254 1548 : bool ok = true;
1255 1548 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1256 1548 : const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, SUMOTime_MAX_PERIOD);
1257 1548 : const SUMOTime haltingTimeThreshold = attrs.getOptSUMOTimeReporting(SUMO_ATTR_HALTING_TIME_THRESHOLD, id.c_str(), ok, TIME2STEPS(1));
1258 1548 : const double haltingSpeedThreshold = attrs.getOpt<double>(SUMO_ATTR_HALTING_SPEED_THRESHOLD, id.c_str(), ok, 5.0f / 3.6f);
1259 1548 : const std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
1260 1548 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
1261 1548 : const std::string vTypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
1262 3096 : const std::string nextEdges = attrs.getOpt<std::string>(SUMO_ATTR_NEXT_EDGES, id.c_str(), ok, "");
1263 1548 : const bool openEntry = attrs.getOpt<bool>(SUMO_ATTR_OPEN_ENTRY, id.c_str(), ok, false);
1264 1548 : const bool expectArrival = attrs.getOpt<bool>(SUMO_ATTR_EXPECT_ARRIVAL, id.c_str(), ok, false);
1265 3096 : const std::string detectPersonsString = attrs.getOpt<std::string>(SUMO_ATTR_DETECT_PERSONS, id.c_str(), ok, "");
1266 : int detectPersons = 0;
1267 3165 : for (std::string mode : StringTokenizer(detectPersonsString).getVector()) {
1268 : if (SUMOXMLDefinitions::PersonModeValues.hasString(mode)) {
1269 69 : detectPersons |= (int)SUMOXMLDefinitions::PersonModeValues.get(mode);
1270 : } else {
1271 0 : WRITE_ERRORF(TL("Invalid person mode '%' in E3 detector definition '%'"), mode, id);
1272 0 : myCurrentIsBroken = true;
1273 : return;
1274 : }
1275 1548 : }
1276 1548 : if (!ok) {
1277 24 : myCurrentIsBroken = true;
1278 24 : return;
1279 : }
1280 : try {
1281 3048 : Parameterised* det = myDetectorBuilder.beginE3Detector(id,
1282 3048 : FileHelpers::checkForRelativity(file, getFileName()),
1283 1520 : period, haltingSpeedThreshold, haltingTimeThreshold, name, vTypes, nextEdges, detectPersons, openEntry, expectArrival);
1284 1520 : myLastParameterised.push_back(det);
1285 4 : } catch (InvalidArgument& e) {
1286 4 : myCurrentIsBroken = true;
1287 4 : WRITE_ERROR(e.what());
1288 4 : } catch (IOError& e) {
1289 0 : myCurrentIsBroken = true;
1290 0 : WRITE_ERROR(e.what());
1291 0 : }
1292 : }
1293 :
1294 :
1295 : void
1296 1873 : NLHandler::addE3Entry(const SUMOSAXAttributes& attrs) {
1297 1873 : bool ok = true;
1298 1873 : const double position = attrs.get<double>(SUMO_ATTR_POSITION, myDetectorBuilder.getCurrentE3ID().c_str(), ok);
1299 1873 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, myDetectorBuilder.getCurrentE3ID().c_str(), ok, false);
1300 1873 : const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, myDetectorBuilder.getCurrentE3ID().c_str(), ok);
1301 1873 : if (!ok) {
1302 : return;
1303 : }
1304 1853 : myDetectorBuilder.addE3Entry(lane, position, friendlyPos);
1305 : }
1306 :
1307 :
1308 : void
1309 1837 : NLHandler::addE3Exit(const SUMOSAXAttributes& attrs) {
1310 1837 : bool ok = true;
1311 1837 : const double position = attrs.get<double>(SUMO_ATTR_POSITION, myDetectorBuilder.getCurrentE3ID().c_str(), ok);
1312 1837 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, myDetectorBuilder.getCurrentE3ID().c_str(), ok, false);
1313 1837 : const std::string lane = attrs.get<std::string>(SUMO_ATTR_LANE, myDetectorBuilder.getCurrentE3ID().c_str(), ok);
1314 1837 : if (!ok) {
1315 : return;
1316 : }
1317 1817 : myDetectorBuilder.addE3Exit(lane, position, friendlyPos);
1318 : }
1319 :
1320 :
1321 : void
1322 19880 : NLHandler::addEdgeLaneMeanData(const SUMOSAXAttributes& attrs, int objecttype) {
1323 19880 : bool ok = true;
1324 19880 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1325 19880 : const double maxTravelTime = attrs.getOpt<double>(SUMO_ATTR_MAX_TRAVELTIME, id.c_str(), ok, 100000);
1326 19880 : const double minSamples = attrs.getOpt<double>(SUMO_ATTR_MIN_SAMPLES, id.c_str(), ok, 0);
1327 19880 : const double haltingSpeedThreshold = attrs.getOpt<double>(SUMO_ATTR_HALTING_SPEED_THRESHOLD, id.c_str(), ok, POSITION_EPS);
1328 39760 : const std::string excludeEmpty = attrs.getOpt<std::string>(SUMO_ATTR_EXCLUDE_EMPTY, id.c_str(), ok, "false");
1329 19880 : const bool withInternal = attrs.getOpt<bool>(SUMO_ATTR_WITH_INTERNAL, id.c_str(), ok, false);
1330 19880 : const bool trackVehicles = attrs.getOpt<bool>(SUMO_ATTR_TRACK_VEHICLES, id.c_str(), ok, false);
1331 39760 : const std::string detectPersonsString = attrs.getOpt<std::string>(SUMO_ATTR_DETECT_PERSONS, id.c_str(), ok, "");
1332 19880 : const std::string file = attrs.get<std::string>(SUMO_ATTR_FILE, id.c_str(), ok);
1333 19880 : const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "performance");
1334 19880 : std::string vtypes = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id.c_str(), ok, "");
1335 39760 : const std::string writeAttributes = attrs.getOpt<std::string>(SUMO_ATTR_WRITE_ATTRIBUTES, id.c_str(), ok, "");
1336 19880 : const SUMOTime period = attrs.getOptPeriod(id.c_str(), ok, -1);
1337 19880 : const SUMOTime begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, id.c_str(), ok, string2time(OptionsCont::getOptions().getString("begin")));
1338 39760 : const SUMOTime end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, id.c_str(), ok, string2time(OptionsCont::getOptions().getString("end")));
1339 19880 : std::vector<std::string> edgeIDs = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EDGES, id.c_str(), ok);
1340 39760 : const std::string edgesFile = attrs.getOpt<std::string>(SUMO_ATTR_EDGESFILE, id.c_str(), ok, "");
1341 19880 : const bool aggregate = attrs.getOpt<bool>(SUMO_ATTR_AGGREGATE, id.c_str(), ok, false);
1342 19880 : if (!ok) {
1343 : return;
1344 : }
1345 : int detectPersons = 0;
1346 39722 : for (std::string mode : StringTokenizer(detectPersonsString).getVector()) {
1347 : if (SUMOXMLDefinitions::PersonModeValues.hasString(mode)) {
1348 34 : detectPersons |= (int)SUMOXMLDefinitions::PersonModeValues.get(mode);
1349 : } else {
1350 0 : WRITE_ERRORF(TL("Invalid person mode '%' in edgeData definition '%'"), mode, id);
1351 : return;
1352 : }
1353 19844 : }
1354 19844 : if (edgesFile != "") {
1355 6 : std::ifstream strm(edgesFile.c_str());
1356 6 : if (!strm.good()) {
1357 0 : throw ProcessError("Could not load names of edges for edgeData definition '" + id + "' from '" + edgesFile + "'.");
1358 : }
1359 24 : while (strm.good()) {
1360 : std::string name;
1361 18 : strm >> name;
1362 : // maybe we're loading an edge-selection
1363 36 : if (StringUtils::startsWith(name, "edge:")) {
1364 12 : edgeIDs.push_back(name.substr(5));
1365 12 : } else if (name != "") {
1366 6 : edgeIDs.push_back(name);
1367 : }
1368 : }
1369 6 : }
1370 : std::vector<MSEdge*> edges;
1371 19941 : for (const std::string& edgeID : edgeIDs) {
1372 97 : MSEdge* edge = MSEdge::dictionary(edgeID);
1373 97 : if (edge == nullptr) {
1374 0 : WRITE_ERRORF(TL("Unknown edge '%' in edgeData definition '%'"), edgeID, id);
1375 0 : return;
1376 : }
1377 97 : edges.push_back(edge);
1378 : }
1379 19844 : bool useLanes = objecttype == SUMO_TAG_MEANDATA_LANE;
1380 20214 : if (useLanes && MSGlobals::gUseMesoSim && !OptionsCont::getOptions().getBool("meso-lane-queue")) {
1381 1098 : WRITE_WARNINGF(TL("LaneData '%' requested for mesoscopic simulation but --meso-lane-queue is not active. Falling back to edgeData."), id);
1382 : useLanes = false;
1383 : }
1384 : try {
1385 39760 : myDetectorBuilder.createEdgeLaneMeanData(id, period, begin, end,
1386 : type, useLanes,
1387 : // equivalent to TplConvert::_2bool used in SUMOSAXAttributes::getBool
1388 19844 : excludeEmpty[0] != 't' && excludeEmpty[0] != 'T' && excludeEmpty[0] != '1' && excludeEmpty[0] != 'x',
1389 19844 : excludeEmpty == "defaults", withInternal, trackVehicles, detectPersons,
1390 : maxTravelTime, minSamples, haltingSpeedThreshold, vtypes, writeAttributes, edges, aggregate,
1391 39616 : FileHelpers::checkForRelativity(file, getFileName()));
1392 72 : } catch (InvalidArgument& e) {
1393 72 : WRITE_ERROR(e.what());
1394 72 : } catch (IOError& e) {
1395 0 : WRITE_ERROR(e.what());
1396 0 : }
1397 39724 : }
1398 :
1399 :
1400 : void
1401 3028172 : NLHandler::addConnection(const SUMOSAXAttributes& attrs) {
1402 3028172 : bool ok = true;
1403 3028172 : const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
1404 3028172 : const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
1405 3028172 : if (!MSGlobals::gUsingInternalLanes && (fromID[0] == ':' || toID[0] == ':')) {
1406 387798 : std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
1407 193899 : if (tlID != "") {
1408 850 : int tlLinkIdx = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);
1409 850 : myJunctionControlBuilder.getTLLogic(tlID).ignoreLinkIndex(tlLinkIdx);
1410 : }
1411 : return;
1412 : }
1413 :
1414 2834273 : myCurrentLink = nullptr;
1415 : try {
1416 2834273 : const int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
1417 2834273 : const int toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
1418 2834273 : LinkDirection dir = parseLinkDir(attrs.get<std::string>(SUMO_ATTR_DIR, nullptr, ok));
1419 2834273 : LinkState state = parseLinkState(attrs.get<std::string>(SUMO_ATTR_STATE, nullptr, ok));
1420 5668044 : const double foeVisibilityDistance = attrs.getOpt<double>(SUMO_ATTR_VISIBILITY_DISTANCE, nullptr, ok, state == LINKSTATE_ZIPPER ? 100 : 4.5);
1421 2834273 : const bool keepClear = attrs.getOpt<bool>(SUMO_ATTR_KEEP_CLEAR, nullptr, ok, true);
1422 2834273 : const bool indirect = attrs.getOpt<bool>(SUMO_ATTR_INDIRECT, nullptr, ok, false);
1423 2834273 : std::string tlID = attrs.getOpt<std::string>(SUMO_ATTR_TLID, nullptr, ok, "");
1424 2834277 : std::string viaID = attrs.getOpt<std::string>(SUMO_ATTR_VIA, nullptr, ok, "");
1425 :
1426 2834273 : MSEdge* from = MSEdge::dictionaryHint(fromID, myPreviousEdgeIdx);
1427 2834273 : if (from == nullptr) {
1428 324 : WRITE_ERRORF(TL("Unknown from-edge '%' in connection."), fromID);
1429 108 : return;
1430 : }
1431 2834165 : myPreviousEdgeIdx = from->getNumericalID();
1432 2834165 : MSEdge* to = MSEdge::dictionary(toID);
1433 2834165 : if (to == nullptr) {
1434 324 : WRITE_ERRORF(TL("Unknown to-edge '%' in connection."), toID);
1435 108 : return;
1436 : }
1437 2834057 : if (fromLaneIdx < 0 || fromLaneIdx >= (int)from->getLanes().size() ||
1438 5668110 : toLaneIdx < 0 || toLaneIdx >= (int)to->getLanes().size()) {
1439 24 : WRITE_ERRORF(TL("Invalid lane index in connection from '%' to '%'."), from->getID(), to->getID());
1440 8 : return;
1441 : }
1442 2834049 : MSLane* fromLane = from->getLanes()[fromLaneIdx];
1443 2834049 : MSLane* toLane = to->getLanes()[toLaneIdx];
1444 : assert(fromLane);
1445 : assert(toLane);
1446 :
1447 : MSTrafficLightLogic* logic = nullptr;
1448 2834049 : int tlLinkIdx = -1;
1449 2834049 : if (tlID != "") {
1450 808346 : tlLinkIdx = attrs.get<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok);
1451 : // make sure that the index is in range
1452 808346 : logic = myJunctionControlBuilder.getTLLogic(tlID).getActive();
1453 808023 : if ((tlLinkIdx < 0 || tlLinkIdx >= (int)logic->getCurrentPhaseDef().getState().size())
1454 325 : && logic->getLogicType() != TrafficLightType::RAIL_SIGNAL
1455 808667 : && logic->getLogicType() != TrafficLightType::RAIL_CROSSING) {
1456 24 : WRITE_ERROR("Invalid " + toString(SUMO_ATTR_TLLINKINDEX) + " '" + toString(tlLinkIdx) +
1457 : "' in connection controlled by '" + tlID + "'");
1458 6 : return;
1459 : }
1460 808336 : if (!ok) {
1461 : return;
1462 : }
1463 : }
1464 : double length;
1465 : // build the link
1466 : MSLane* via = nullptr;
1467 2834039 : if (viaID != "" && MSGlobals::gUsingInternalLanes) {
1468 950514 : via = MSLane::dictionary(viaID);
1469 950514 : if (via == nullptr) {
1470 4 : WRITE_ERROR("An unknown lane ('" + viaID +
1471 : "') should be set as a via-lane for lane '" + toLane->getID() + "'.");
1472 0 : return;
1473 : }
1474 : length = via->getLength();
1475 1883525 : } else if (toLane->getEdge().isCrossing()) {
1476 : length = toLane->getLength();
1477 : } else {
1478 1867303 : length = fromLane->getShape()[-1].distanceTo(toLane->getShape()[0]);
1479 : }
1480 2834039 : myCurrentLink = new MSLink(fromLane, toLane, via, dir, state, length, foeVisibilityDistance, keepClear, logic, tlLinkIdx, indirect);
1481 2834039 : if (via != nullptr) {
1482 950514 : via->addIncomingLane(fromLane, myCurrentLink);
1483 : } else {
1484 1883525 : toLane->addIncomingLane(fromLane, myCurrentLink);
1485 : }
1486 2834039 : toLane->addApproachingLane(fromLane, myNetworkVersion < MMVersion(0, 25));
1487 :
1488 : // if a traffic light is responsible for it, inform the traffic light
1489 : // check whether this link is controlled by a traffic light
1490 : // we can not reuse logic here because it might be an inactive one
1491 2834039 : if (tlID != "") {
1492 808336 : myJunctionControlBuilder.getTLLogic(tlID).addLink(myCurrentLink, fromLane, tlLinkIdx);
1493 : }
1494 : // add the link
1495 2834039 : fromLane->addLink(myCurrentLink);
1496 :
1497 4 : } catch (InvalidArgument& e) {
1498 4 : WRITE_ERROR(e.what());
1499 4 : }
1500 : }
1501 :
1502 :
1503 : void
1504 6 : NLHandler::addConflict(const SUMOSAXAttributes& attrs) {
1505 6 : if (myCurrentLink == nullptr) {
1506 0 : throw InvalidArgument(toString(SUMO_TAG_CONFLICT) + " must occur within a " + toString(SUMO_TAG_CONNECTION) + " element");
1507 : }
1508 6 : if (!MSGlobals::gUsingInternalLanes) {
1509 2 : return;
1510 : }
1511 4 : bool ok = true;
1512 4 : const std::string fromID = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
1513 4 : const std::string toID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
1514 4 : const int fromLaneIdx = attrs.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
1515 4 : const int toLaneIdx = attrs.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
1516 4 : double startPos = attrs.get<double>(SUMO_ATTR_STARTPOS, nullptr, ok);
1517 4 : double endPos = attrs.get<double>(SUMO_ATTR_ENDPOS, nullptr, ok);
1518 4 : MSEdge* from = MSEdge::dictionary(fromID);
1519 4 : if (from == nullptr) {
1520 0 : WRITE_ERRORF(TL("Unknown from-edge '%' in conflict."), fromID);
1521 0 : return;
1522 : }
1523 4 : MSEdge* to = MSEdge::dictionary(toID);
1524 4 : if (to == nullptr) {
1525 0 : WRITE_ERRORF(TL("Unknown to-edge '%' in conflict."), toID);
1526 0 : return;
1527 : }
1528 4 : if (fromLaneIdx < 0 || fromLaneIdx >= (int)from->getLanes().size() ||
1529 8 : toLaneIdx < 0 || toLaneIdx >= (int)to->getLanes().size()) {
1530 0 : WRITE_ERRORF(TL("Invalid lane index in conflict with '%' to '%'."), from->getID(), to->getID());
1531 0 : return;
1532 : }
1533 4 : MSLane* fromLane = from->getLanes()[fromLaneIdx];
1534 4 : MSLane* toLane = to->getLanes()[toLaneIdx];
1535 : assert(fromLane);
1536 : assert(toLane);
1537 4 : myCurrentLink->addCustomConflict(fromLane, toLane, startPos, endPos);
1538 : }
1539 :
1540 :
1541 : LinkDirection
1542 2834273 : NLHandler::parseLinkDir(const std::string& dir) {
1543 : if (SUMOXMLDefinitions::LinkDirections.hasString(dir)) {
1544 2834273 : return SUMOXMLDefinitions::LinkDirections.get(dir);
1545 : } else {
1546 0 : throw InvalidArgument("Unrecognised link direction '" + dir + "'.");
1547 : }
1548 : }
1549 :
1550 :
1551 : LinkState
1552 2834273 : NLHandler::parseLinkState(const std::string& state) {
1553 : if (SUMOXMLDefinitions::LinkStates.hasString(state)) {
1554 2834273 : return SUMOXMLDefinitions::LinkStates.get(state);
1555 : } else {
1556 0 : if (state == "t") { // legacy networks
1557 : // WRITE_WARNING(TL("Obsolete link state 't'. Use 'o' instead"));
1558 : return LINKSTATE_TL_OFF_BLINKING;
1559 : } else {
1560 0 : throw InvalidArgument("Unrecognised link state '" + state + "'.");
1561 : }
1562 : }
1563 : }
1564 :
1565 :
1566 : // ----------------------------------
1567 : void
1568 43923 : NLHandler::setLocation(const SUMOSAXAttributes& attrs) {
1569 43923 : if (myNetIsLoaded) {
1570 : //WRITE_WARNING(TL("POIs and Polygons should be loaded using option --po-files"))
1571 22 : return;
1572 : }
1573 43901 : bool ok = true;
1574 43901 : PositionVector s = attrs.get<PositionVector>(SUMO_ATTR_NET_OFFSET, nullptr, ok);
1575 43901 : Boundary convBoundary = attrs.get<Boundary>(SUMO_ATTR_CONV_BOUNDARY, nullptr, ok);
1576 43901 : Boundary origBoundary = attrs.get<Boundary>(SUMO_ATTR_ORIG_BOUNDARY, nullptr, ok);
1577 43901 : std::string proj = attrs.get<std::string>(SUMO_ATTR_ORIG_PROJ, nullptr, ok);
1578 43901 : if (ok) {
1579 43901 : Position networkOffset = s[0];
1580 43901 : GeoConvHelper::init(proj, networkOffset, origBoundary, convBoundary);
1581 87802 : if (OptionsCont::getOptions().getBool("fcd-output.geo") && !GeoConvHelper::getFinal().usingGeoProjection()) {
1582 0 : WRITE_WARNING(TL("no valid geo projection loaded from network. fcd-output.geo will not work"));
1583 : }
1584 : }
1585 43901 : }
1586 :
1587 :
1588 : void
1589 23610 : NLHandler::addDistrict(const SUMOSAXAttributes& attrs) {
1590 23610 : bool ok = true;
1591 23610 : myCurrentIsBroken = false;
1592 : // get the id, report an error if not given or empty...
1593 23610 : myCurrentDistrictID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1594 23610 : if (!ok) {
1595 0 : myCurrentIsBroken = true;
1596 0 : return;
1597 : }
1598 : try {
1599 23610 : const std::string sinkID = myCurrentDistrictID + "-sink";
1600 23610 : const std::string sourceID = myCurrentDistrictID + "-source";
1601 :
1602 23610 : MSEdge* sink = MSEdge::dictionary(sinkID);
1603 23610 : if (sink == nullptr) {
1604 47178 : sink = myEdgeControlBuilder.buildEdge(sinkID, SumoXMLEdgeFunc::CONNECTOR, "", "", -1, 0);
1605 23589 : MSEdge::dictionary(sinkID, sink);
1606 23589 : sink->initialize(new std::vector<MSLane*>());
1607 : } else {
1608 42 : if (OptionsCont::getOptions().getBool("junction-taz")
1609 21 : && myNet.getJunctionControl().get(myCurrentDistrictID) != nullptr) {
1610 : // overwrite junction taz
1611 42 : sink->resetTAZ(myNet.getJunctionControl().get(myCurrentDistrictID));
1612 63 : WRITE_WARNINGF(TL("Replacing junction-taz '%' with loaded TAZ."), myCurrentDistrictID);
1613 : } else {
1614 0 : throw InvalidArgument("Another edge with the id '" + sinkID + "' exists.");
1615 : }
1616 : }
1617 23610 : MSEdge* source = MSEdge::dictionary(sourceID);
1618 23610 : if (source == nullptr) {
1619 47178 : source = myEdgeControlBuilder.buildEdge(sourceID, SumoXMLEdgeFunc::CONNECTOR, "", "", -1, 0);
1620 23589 : MSEdge::dictionary(sourceID, source);
1621 23589 : source->initialize(new std::vector<MSLane*>());
1622 : } else {
1623 42 : if (OptionsCont::getOptions().getBool("junction-taz")
1624 21 : && myNet.getJunctionControl().get(myCurrentDistrictID) != nullptr) {
1625 : // overwrite junction taz
1626 42 : source->resetTAZ(myNet.getJunctionControl().get(myCurrentDistrictID));
1627 : } else {
1628 0 : throw InvalidArgument("Another edge with the id '" + sourceID + "' exists.");
1629 : }
1630 : }
1631 : sink->setOtherTazConnector(source);
1632 : source->setOtherTazConnector(sink);
1633 23610 : const std::vector<std::string>& desc = attrs.getOpt<std::vector<std::string> >(SUMO_ATTR_EDGES, myCurrentDistrictID.c_str(), ok);
1634 44489 : for (const std::string& eID : desc) {
1635 20879 : MSEdge* edge = MSEdge::dictionary(eID);
1636 : // check whether the edge exists
1637 20879 : if (edge == nullptr) {
1638 0 : throw InvalidArgument("The edge '" + eID + "' within district '" + myCurrentDistrictID + "' is not known.");
1639 : }
1640 20879 : source->addSuccessor(edge);
1641 20879 : edge->addSuccessor(sink);
1642 : }
1643 23610 : source->setParameter("taz", myCurrentDistrictID);
1644 23610 : sink->setParameter("taz", myCurrentDistrictID);
1645 23610 : RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, myCurrentDistrictID.c_str(), ok, RGBColor::parseColor("1.0,.33,.33"));
1646 23610 : const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, myCurrentDistrictID.c_str(), ok, "");
1647 47220 : source->setParameter("tazColor", toString(color));
1648 47220 : sink->setParameter("tazColor", toString(color));
1649 :
1650 23610 : if (attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
1651 10141 : PositionVector shape = attrs.get<PositionVector>(SUMO_ATTR_SHAPE, myCurrentDistrictID.c_str(), ok);
1652 10141 : const bool fill = attrs.getOpt<bool>(SUMO_ATTR_FILL, myCurrentDistrictID.c_str(), ok, false);
1653 10141 : if (shape.size() != 0) {
1654 20282 : if (!myNet.getShapeContainer().addPolygon(myCurrentDistrictID, "taz", color, 0, 0, "", shape, false, fill, 1.0, false, name)) {
1655 0 : WRITE_WARNINGF(TL("Skipping visualization of taz '%', polygon already exists."), myCurrentDistrictID);
1656 : } else {
1657 10141 : myLastParameterised.push_back(myNet.getShapeContainer().getPolygons().get(myCurrentDistrictID));
1658 10141 : myCurrentIsBroken = false;
1659 : }
1660 : }
1661 10141 : }
1662 23610 : } catch (InvalidArgument& e) {
1663 0 : WRITE_ERROR(e.what());
1664 0 : myCurrentIsBroken = true;
1665 0 : }
1666 : }
1667 :
1668 :
1669 : void
1670 40225 : NLHandler::addDistrictEdge(const SUMOSAXAttributes& attrs, bool isSource) {
1671 40225 : if (myCurrentIsBroken) {
1672 : // earlier error
1673 0 : return;
1674 : }
1675 40225 : bool ok = true;
1676 40225 : std::string id = attrs.get<std::string>(SUMO_ATTR_ID, myCurrentDistrictID.c_str(), ok);
1677 40225 : MSEdge* succ = MSEdge::dictionary(id);
1678 40225 : if (succ != nullptr) {
1679 : // connect edge
1680 40225 : if (isSource) {
1681 40218 : MSEdge::dictionary(myCurrentDistrictID + "-source")->addSuccessor(succ);
1682 : } else {
1683 40232 : succ->addSuccessor(MSEdge::dictionary(myCurrentDistrictID + "-sink"));
1684 : }
1685 : } else {
1686 0 : WRITE_ERRORF(TL("At district '%': succeeding edge '%' does not exist."), myCurrentDistrictID, id);
1687 : }
1688 : }
1689 :
1690 :
1691 : void
1692 375 : NLHandler::addRoundabout(const SUMOSAXAttributes& attrs) {
1693 375 : bool ok = true;
1694 375 : const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
1695 375 : if (ok) {
1696 1868 : for (const std::string& eID : edgeIDs) {
1697 1493 : MSEdge* edge = MSEdge::dictionary(eID);
1698 1493 : if (edge == nullptr) {
1699 0 : WRITE_ERRORF(TL("Unknown edge '%' in roundabout"), eID);
1700 : } else {
1701 : edge->markAsRoundabout();
1702 : }
1703 : }
1704 : }
1705 375 : }
1706 :
1707 :
1708 : void
1709 22 : NLHandler::addMesoEdgeType(const SUMOSAXAttributes& attrs) {
1710 22 : bool ok = true;
1711 22 : MESegment::MesoEdgeType edgeType = myNet.getMesoType(""); // init defaults
1712 22 : edgeType.tauff = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MESO_TAUFF, myCurrentTypeID.c_str(), ok, edgeType.tauff);
1713 22 : edgeType.taufj = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MESO_TAUFJ, myCurrentTypeID.c_str(), ok, edgeType.taufj);
1714 22 : edgeType.taujf = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MESO_TAUJF, myCurrentTypeID.c_str(), ok, edgeType.taujf);
1715 22 : edgeType.taujj = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MESO_TAUJJ, myCurrentTypeID.c_str(), ok, edgeType.taujj);
1716 22 : edgeType.jamThreshold = attrs.getOpt<double>(SUMO_ATTR_JAM_DIST_THRESHOLD, myCurrentTypeID.c_str(), ok, edgeType.jamThreshold);
1717 22 : edgeType.junctionControl = attrs.getOpt<bool>(SUMO_ATTR_MESO_JUNCTION_CONTROL, myCurrentTypeID.c_str(), ok, edgeType.junctionControl);
1718 22 : edgeType.tlsPenalty = attrs.getOpt<double>(SUMO_ATTR_MESO_TLS_PENALTY, myCurrentTypeID.c_str(), ok, edgeType.tlsPenalty);
1719 22 : edgeType.tlsFlowPenalty = attrs.getOpt<double>(SUMO_ATTR_MESO_TLS_FLOW_PENALTY, myCurrentTypeID.c_str(), ok, edgeType.tlsFlowPenalty);
1720 22 : edgeType.minorPenalty = attrs.getOptSUMOTimeReporting(SUMO_ATTR_MESO_MINOR_PENALTY, myCurrentTypeID.c_str(), ok, edgeType.minorPenalty);
1721 22 : edgeType.overtaking = attrs.getOpt<bool>(SUMO_ATTR_MESO_OVERTAKING, myCurrentTypeID.c_str(), ok, edgeType.overtaking);
1722 :
1723 22 : if (ok) {
1724 22 : myNet.addMesoType(myCurrentTypeID, edgeType);
1725 : }
1726 22 : if (myNetIsLoaded) {
1727 22 : myHaveSeenMesoEdgeType = true;
1728 : }
1729 22 : }
1730 :
1731 : void
1732 15 : NLHandler::addDeadlock(const SUMOSAXAttributes& attrs) {
1733 15 : bool ok = true;
1734 15 : std::vector<std::string> signalIDs = attrs.get<std::vector<std::string>>(SUMO_ATTR_SIGNALS, nullptr, ok);
1735 : std::vector<const MSRailSignal*> signals;
1736 78 : for (const std::string& id : signalIDs) {
1737 63 : const MSTrafficLightLogic* tll = myJunctionControlBuilder.getTLLogicControlToUse().getActive(id);
1738 63 : const MSRailSignal* rs = dynamic_cast<const MSRailSignal*>(tll);
1739 63 : if (rs != nullptr) {
1740 63 : signals.push_back(rs);
1741 : } else {
1742 0 : throw InvalidArgument("Rail signal '" + toString(id) + "' in " + toString(SUMO_TAG_DEADLOCK) + " is not known");
1743 : }
1744 : }
1745 15 : MSRailSignalControl::getInstance().addDeadlockCheck(signals);
1746 15 : }
1747 :
1748 : // ----------------------------------
1749 : void
1750 1548 : NLHandler::endE3Detector() {
1751 : try {
1752 1548 : myDetectorBuilder.endE3Detector();
1753 0 : } catch (InvalidArgument& e) {
1754 0 : WRITE_ERROR(e.what());
1755 0 : }
1756 1540 : }
1757 :
1758 :
1759 : void
1760 92 : NLHandler::closeWAUT() {
1761 92 : if (!myCurrentIsBroken) {
1762 : try {
1763 88 : myJunctionControlBuilder.getTLLogicControlToUse().closeWAUT(myCurrentWAUTID);
1764 0 : } catch (InvalidArgument& e) {
1765 0 : WRITE_ERROR(e.what());
1766 0 : myCurrentIsBroken = true;
1767 0 : }
1768 : }
1769 92 : myCurrentWAUTID = "";
1770 92 : }
1771 :
1772 :
1773 : Position
1774 833 : NLShapeHandler::getLanePos(const std::string& poiID, const std::string& laneID, double lanePos, bool friendlyPos, double lanePosLat) {
1775 833 : MSLane* lane = MSLane::dictionary(laneID);
1776 833 : if (lane == nullptr) {
1777 0 : WRITE_ERRORF(TL("Lane '%' to place poi '%' on is not known."), laneID, poiID);
1778 0 : return Position::INVALID;
1779 : }
1780 833 : if (lanePos < 0) {
1781 0 : lanePos = lane->getLength() + lanePos;
1782 : }
1783 833 : if ((lanePos < 0) && friendlyPos) {
1784 0 : lanePos = 0;
1785 : }
1786 833 : if ((lanePos > lane->getLength()) && friendlyPos) {
1787 0 : lanePos = lane->getLength();
1788 : }
1789 833 : if (lanePos < 0 || lanePos > lane->getLength()) {
1790 0 : WRITE_WARNINGF(TL("lane position % for poi '%' is not valid."), toString(lanePos), poiID);
1791 : }
1792 833 : return lane->geometryPositionAtOffset(lanePos, -lanePosLat);
1793 : }
1794 :
1795 :
1796 : Parameterised*
1797 662 : NLHandler::addPredecessorConstraint(int element, const SUMOSAXAttributes& attrs, MSRailSignal* rs) {
1798 662 : if (rs == nullptr) {
1799 0 : throw InvalidArgument("Rail signal '" + toString((SumoXMLTag)element) + "' constraint must occur within a railSignalConstraints element");
1800 : }
1801 662 : bool ok = true;
1802 662 : const std::string tripId = attrs.get<std::string>(SUMO_ATTR_TRIP_ID, nullptr, ok);
1803 662 : const std::string signalID = attrs.get<std::string>(SUMO_ATTR_TLID, nullptr, ok);
1804 662 : const std::string foesString = attrs.get<std::string>(SUMO_ATTR_FOES, nullptr, ok);
1805 1324 : const std::vector<std::string> foes = StringTokenizer(foesString).getVector();
1806 662 : const int limit = attrs.getOpt<int>(SUMO_ATTR_LIMIT, nullptr, ok, (int)foes.size());
1807 662 : const bool active = attrs.getOpt<bool>(SUMO_ATTR_ACTIVE, nullptr, ok, true);
1808 :
1809 662 : if (!MSNet::getInstance()->getTLSControl().knows(signalID)) {
1810 0 : throw InvalidArgument("Rail signal '" + signalID + "' in railSignalConstraints is not known");
1811 : }
1812 662 : MSRailSignal* signal = dynamic_cast<MSRailSignal*>(MSNet::getInstance()->getTLSControl().get(signalID).getDefault());
1813 662 : if (signal == nullptr) {
1814 0 : throw InvalidArgument("Traffic light '" + signalID + "' is not a rail signal");
1815 : }
1816 : MSRailSignalConstraint::ConstraintType type;
1817 662 : switch (element) {
1818 : case SUMO_TAG_PREDECESSOR:
1819 : type = MSRailSignalConstraint::ConstraintType::PREDECESSOR;
1820 : break;
1821 : case SUMO_TAG_INSERTION_PREDECESSOR:
1822 : type = MSRailSignalConstraint::ConstraintType::INSERTION_PREDECESSOR;
1823 : break;
1824 : case SUMO_TAG_FOE_INSERTION:
1825 : type = MSRailSignalConstraint::ConstraintType::FOE_INSERTION;
1826 : break;
1827 : case SUMO_TAG_INSERTION_ORDER:
1828 : type = MSRailSignalConstraint::ConstraintType::INSERTION_ORDER;
1829 : break;
1830 : case SUMO_TAG_BIDI_PREDECESSOR:
1831 : type = MSRailSignalConstraint::ConstraintType::BIDI_PREDECESSOR;
1832 : break;
1833 0 : default:
1834 0 : throw InvalidArgument("Unsupported rail signal constraint '" + toString((SumoXMLTag)element) + "'");
1835 : }
1836 : Parameterised* result = nullptr;
1837 662 : if (ok) {
1838 1334 : for (const std::string& foe : foes) {
1839 672 : MSRailSignalConstraint* c = new MSRailSignalConstraint_Predecessor(type, signal, foe, limit, active);
1840 672 : rs->addConstraint(tripId, c);
1841 : // XXX if there are multiple foes, only one constraint will receive the parameters
1842 : result = c;
1843 : }
1844 : }
1845 662 : return result;
1846 662 : }
1847 :
1848 :
1849 : /****************************************************************************/
|