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