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