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