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