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