Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIXMLConnectionsHandler.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 NIXMLConnectionsHandler.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Laura Bieker
19
/// @date Thu, 17 Oct 2002
20
///
21
// Importer for edge connections stored in XML
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <string>
26
#include <iostream>
27
#include <netbuild/NBEdge.h>
28
#include <netbuild/NBEdgeCont.h>
29
#include <netbuild/NBNodeCont.h>
30
#include <netbuild/NBTrafficLightLogicCont.h>
31
#include <netbuild/NBNode.h>
32
#include <netbuild/NBNetBuilder.h>
33
#include <utils/geom/GeoConvHelper.h>
34
#include <utils/xml/SUMOSAXHandler.h>
35
#include <utils/xml/SUMOXMLDefinitions.h>
36
#include <utils/common/StringTokenizer.h>
37
#include <utils/common/ToString.h>
38
#include <utils/common/StringUtils.h>
39
#include <utils/common/UtilExceptions.h>
40
#include <utils/common/MsgHandler.h>
41
#include <utils/options/OptionsCont.h>
42
#include "NIImporter_SUMO.h"
43
#include "NIXMLConnectionsHandler.h"
44
45
46
// ===========================================================================
47
// method definitions
48
// ===========================================================================
49
NIXMLConnectionsHandler::NIXMLConnectionsHandler(NBEdgeCont& ec, NBNodeCont& nc, NBTrafficLightLogicCont& tlc) :
50
SUMOSAXHandler("xml-connection-description"),
51
myEdgeCont(ec),
52
myNodeCont(nc),
53
myTLLogicCont(tlc),
54
myHaveWarnedAboutDeprecatedLanes(false),
55
myErrorMsgHandler(OptionsCont::getOptions().getBool("ignore-errors.connections") ?
56
MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
57
myLocation(nullptr),
58
myLastParameterised(nullptr) {
59
}
60
61
62
NIXMLConnectionsHandler::~NIXMLConnectionsHandler() {
63
delete myLocation;
64
}
65
66
67
void
68
NIXMLConnectionsHandler::myStartElement(int element,
69
const SUMOSAXAttributes& attrs) {
70
switch (element) {
71
case SUMO_TAG_CONNECTIONS:
72
// infer location for legacy networks that don't have location information
73
myLocation = GeoConvHelper::getLoadedPlain(getFileName(), ".con.xml");
74
break;
75
case SUMO_TAG_LOCATION:
76
delete myLocation;
77
myLocation = NIImporter_SUMO::loadLocation(attrs, false);
78
break;
79
case SUMO_TAG_DEL:
80
delConnection(attrs);
81
break;
82
case SUMO_TAG_CONNECTION:
83
parseConnection(attrs);
84
break;
85
case SUMO_TAG_PROHIBITION:
86
addProhibition(attrs);
87
break;
88
case SUMO_TAG_CROSSING:
89
addCrossing(attrs);
90
break;
91
case SUMO_TAG_WALKINGAREA:
92
addWalkingArea(attrs);
93
break;
94
case SUMO_TAG_PARAM:
95
if (myLastParameterised != nullptr) {
96
bool ok = true;
97
const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
98
// circumventing empty string test
99
const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
100
myLastParameterised->setParameter(key, val);
101
}
102
break;
103
default:
104
break;
105
}
106
}
107
108
109
void
110
NIXMLConnectionsHandler::myEndElement(int element) {
111
switch (element) {
112
case SUMO_TAG_CONNECTION:
113
case SUMO_TAG_CROSSING:
114
myLastParameterised = nullptr;
115
break;
116
default:
117
break;
118
}
119
}
120
121
122
123
NBConnection
124
NIXMLConnectionsHandler::parseConnectionDef(const std::string& defRole, const std::string& def) {
125
// split from/to
126
const std::string::size_type div = def.find("->");
127
if (div == std::string::npos) {
128
myErrorMsgHandler->inform("Missing connection divider in " + defRole + " '" + def + "'");
129
return NBConnection::InvalidConnection;
130
}
131
std::string fromDef = def.substr(0, div);
132
std::string toDef = def.substr(div + 2);
133
134
// retrieve them now
135
NBEdge* fromE = myEdgeCont.retrieve(fromDef);
136
NBEdge* toE = myEdgeCont.retrieve(toDef);
137
// check
138
if (fromE == nullptr) {
139
myErrorMsgHandler->inform("Could not find edge '" + fromDef + "' in " + defRole + " '" + def + "'");
140
return NBConnection::InvalidConnection;
141
}
142
if (toE == nullptr) {
143
myErrorMsgHandler->inform("Could not find edge '" + toDef + "' in " + defRole + " '" + def + "'");
144
return NBConnection::InvalidConnection;
145
}
146
return NBConnection(fromE, toE);
147
}
148
149
150
void
151
NIXMLConnectionsHandler::parseLaneBound(const SUMOSAXAttributes& attrs, NBEdge* from, NBEdge* to) {
152
if (to == nullptr) {
153
// do nothing if it's a dead end
154
return;
155
}
156
bool ok = true;
157
// get the begin and the end lane
158
int fromLane;
159
int toLane;
160
try {
161
if (!parseLaneInfo(attrs, from, to, &fromLane, &toLane)) {
162
return;
163
}
164
if (fromLane < 0) {
165
myErrorMsgHandler->informf("Invalid value '%' for " + toString(SUMO_ATTR_FROM_LANE) +
166
" in connection from '%' to '%'.", fromLane, from->getID(), to->getID());
167
return;
168
}
169
if (toLane < 0) {
170
myErrorMsgHandler->informf("Invalid value '%' for " + toString(SUMO_ATTR_TO_LANE) +
171
" in connection from '%' to '%'.", toLane, from->getID(), to->getID());
172
return;
173
}
174
175
NBEdge::Connection defaultCon(fromLane, to, toLane);
176
if (from->getStep() == NBEdge::EdgeBuildingStep::LANES2LANES_USER) {
177
// maybe we are patching an existing connection
178
std::vector<NBEdge::Connection> existing = from->getConnectionsFromLane(fromLane, to, toLane);
179
if (existing.size() > 0) {
180
assert(existing.size() == 1);
181
defaultCon = existing.front();
182
// remove the original so we can insert the replacement
183
from->removeFromConnections(defaultCon);
184
} else {
185
from->getToNode()->invalidateTLS(myTLLogicCont, true, false);
186
}
187
}
188
if (OptionsCont::getOptions().isSet("default.connection.cont-pos")) {
189
defaultCon.contPos = OptionsCont::getOptions().getFloat("default.connection.cont-pos");
190
}
191
const bool mayDefinitelyPass = attrs.getOpt<bool>(SUMO_ATTR_PASS, nullptr, ok, defaultCon.mayDefinitelyPass);
192
KeepClear keepClear = defaultCon.keepClear;
193
if (attrs.hasAttribute(SUMO_ATTR_KEEP_CLEAR)) {
194
keepClear = attrs.get<bool>(SUMO_ATTR_KEEP_CLEAR, nullptr, ok) ? KEEPCLEAR_TRUE : KEEPCLEAR_FALSE;
195
}
196
const double contPos = attrs.getOpt<double>(SUMO_ATTR_CONTPOS, nullptr, ok, defaultCon.contPos);
197
const double visibility = attrs.getOpt<double>(SUMO_ATTR_VISIBILITY_DISTANCE, nullptr, ok, defaultCon.visibility);
198
const double speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, nullptr, ok, defaultCon.speed);
199
const double friction = attrs.getOpt<double>(SUMO_ATTR_FRICTION, nullptr, ok, defaultCon.friction);
200
const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, nullptr, ok, defaultCon.customLength);
201
const bool uncontrolled = attrs.getOpt<bool>(SUMO_ATTR_UNCONTROLLED, nullptr, ok, defaultCon.uncontrolled);
202
const bool indirectLeft = attrs.getOpt<bool>(SUMO_ATTR_INDIRECT, nullptr, ok, false);
203
const std::string edgeType = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, nullptr, ok, "");
204
PositionVector customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, defaultCon.customShape);
205
std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, nullptr, ok, "");
206
std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, nullptr, ok, "");
207
SVCPermissions permissions;
208
if (allow == "" && disallow == "") {
209
permissions = SVC_UNSPECIFIED;
210
} else {
211
permissions = parseVehicleClasses(allow, disallow);
212
}
213
SVCPermissions changeLeft = SVC_UNSPECIFIED;
214
SVCPermissions changeRight = SVC_UNSPECIFIED;
215
if (attrs.hasAttribute(SUMO_ATTR_CHANGE_LEFT)) {
216
changeLeft = parseVehicleClasses(attrs.get<std::string>(SUMO_ATTR_CHANGE_LEFT, nullptr, ok), "");
217
}
218
if (attrs.hasAttribute(SUMO_ATTR_CHANGE_RIGHT)) {
219
changeRight = parseVehicleClasses(attrs.get<std::string>(SUMO_ATTR_CHANGE_RIGHT, nullptr, ok), "");
220
}
221
if (attrs.hasAttribute(SUMO_ATTR_SHAPE) && !NBNetBuilder::transformCoordinates(customShape, true, myLocation)) {
222
WRITE_ERRORF(TL("Unable to project shape for connection from edge '%' to edge '%'."), from->getID(), to->getID());
223
}
224
if (!ok) {
225
return;
226
}
227
if (!from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::Lane2LaneInfoType::USER, true, mayDefinitelyPass,
228
keepClear, contPos, visibility, speed, friction, length, customShape, uncontrolled, permissions, indirectLeft, edgeType, changeLeft, changeRight)) {
229
if (OptionsCont::getOptions().getBool("show-errors.connections-first-try")) {
230
WRITE_WARNINGF(TL("Could not set loaded connection from lane '%' to lane '%'."), from->getLaneID(fromLane), to->getLaneID(toLane));
231
}
232
// set as to be re-applied after network processing
233
myEdgeCont.addPostProcessConnection(from->getID(), fromLane, to->getID(), toLane, mayDefinitelyPass, keepClear, contPos, visibility,
234
speed, friction, length, customShape, uncontrolled, false, permissions, indirectLeft, edgeType, changeLeft, changeRight);
235
}
236
} catch (NumberFormatException&) {
237
myErrorMsgHandler->inform("At least one of the defined lanes was not numeric");
238
}
239
}
240
241
bool
242
NIXMLConnectionsHandler::parseLaneInfo(const SUMOSAXAttributes& attributes, NBEdge* fromEdge, NBEdge* toEdge,
243
int* fromLane, int* toLane) {
244
if (attributes.hasAttribute(SUMO_ATTR_LANE)) {
245
return parseDeprecatedLaneDefinition(attributes, fromEdge, toEdge, fromLane, toLane);
246
} else {
247
return parseLaneDefinition(attributes, fromLane, toLane);
248
}
249
}
250
251
252
inline bool
253
NIXMLConnectionsHandler::parseDeprecatedLaneDefinition(const SUMOSAXAttributes& attributes,
254
NBEdge* from, NBEdge* to,
255
int* fromLane, int* toLane) {
256
bool ok = true;
257
if (!myHaveWarnedAboutDeprecatedLanes) {
258
myHaveWarnedAboutDeprecatedLanes = true;
259
WRITE_WARNING("'" + toString(SUMO_ATTR_LANE) + "' is deprecated, please use '" +
260
toString(SUMO_ATTR_FROM_LANE) + "' and '" + toString(SUMO_ATTR_TO_LANE) +
261
"' instead.");
262
}
263
264
std::string laneConn = attributes.get<std::string>(SUMO_ATTR_LANE, nullptr, ok);
265
StringTokenizer st(laneConn, ':');
266
if (!ok || st.size() != 2) {
267
myErrorMsgHandler->inform("Invalid lane to lane connection from '" +
268
from->getID() + "' to '" + to->getID() + "'.");
269
return false; // There was an error.
270
}
271
272
*fromLane = StringUtils::toIntSecure(st.next(), -1);
273
*toLane = StringUtils::toIntSecure(st.next(), -1);
274
275
return true; // We succeeded.
276
}
277
278
279
inline bool
280
NIXMLConnectionsHandler::parseLaneDefinition(const SUMOSAXAttributes& attributes,
281
int* fromLane,
282
int* toLane) {
283
bool ok = true;
284
*fromLane = attributes.get<int>(SUMO_ATTR_FROM_LANE, nullptr, ok);
285
*toLane = attributes.get<int>(SUMO_ATTR_TO_LANE, nullptr, ok);
286
return ok;
287
}
288
289
void
290
NIXMLConnectionsHandler::delConnection(const SUMOSAXAttributes& attrs) {
291
bool ok = true;
292
std::string from = attrs.get<std::string>(SUMO_ATTR_FROM, nullptr, ok);
293
std::string to = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
294
if (!ok) {
295
return;
296
}
297
// these connections were removed when the edge was deleted
298
if (myEdgeCont.wasRemoved(from) || myEdgeCont.wasRemoved(to)) {
299
return;
300
}
301
NBEdge* fromEdge = myEdgeCont.retrieve(from);
302
NBEdge* toEdge = myEdgeCont.retrieve(to);
303
if (fromEdge == nullptr) {
304
myErrorMsgHandler->informf("The connection-source edge '%' to reset is not known.", from);
305
return;
306
}
307
if (toEdge == nullptr) {
308
myErrorMsgHandler->informf("The connection-destination edge '%' to reset is not known.", to);
309
return;
310
}
311
if (!fromEdge->isConnectedTo(toEdge) && fromEdge->getStep() >= NBEdge::EdgeBuildingStep::EDGE2EDGES) {
312
WRITE_WARNINGF(TL("Target edge '%' is not connected with '%'; the connection cannot be reset."), toEdge->getID(), fromEdge->getID());
313
return;
314
}
315
int fromLane = -1; // Assume all lanes are to be reset.
316
int toLane = -1;
317
if (attrs.hasAttribute(SUMO_ATTR_LANE)
318
|| attrs.hasAttribute(SUMO_ATTR_FROM_LANE)
319
|| attrs.hasAttribute(SUMO_ATTR_TO_LANE)) {
320
if (!parseLaneInfo(attrs, fromEdge, toEdge, &fromLane, &toLane)) {
321
return;
322
}
323
// we could be trying to reset a connection loaded from a sumo net and which has become obsolete.
324
// In this case it's ok to encounter invalid lance indices
325
if (!fromEdge->hasConnectionTo(toEdge, toLane) && fromEdge->getStep() >= NBEdge::EdgeBuildingStep::LANES2EDGES) {
326
WRITE_WARNINGF(TL("Edge '%' has no connection to lane '%'; the connection cannot be reset."), fromEdge->getID(), toEdge->getLaneID(toLane));
327
}
328
}
329
fromEdge->removeFromConnections(toEdge, fromLane, toLane, true);
330
}
331
332
void
333
NIXMLConnectionsHandler::parseConnection(const SUMOSAXAttributes& attrs) {
334
bool ok = true;
335
std::string from = attrs.get<std::string>(SUMO_ATTR_FROM, "connection", ok);
336
std::string to = attrs.getOpt<std::string>(SUMO_ATTR_TO, "connection", ok, "");
337
if (!ok || myEdgeCont.wasIgnored(from) || myEdgeCont.wasIgnored(to)) {
338
return;
339
}
340
// extract edges
341
NBEdge* fromEdge = myEdgeCont.retrieve(from);
342
NBEdge* toEdge = to.length() != 0 ? myEdgeCont.retrieve(to) : nullptr;
343
// check whether they are valid
344
if (fromEdge == nullptr) {
345
myErrorMsgHandler->inform("The connection-source edge '" + from + "' is not known.");
346
return;
347
}
348
if (toEdge == nullptr && to.length() != 0) {
349
myErrorMsgHandler->inform("The connection-destination edge '" + to + "' is not known.");
350
return;
351
}
352
// parse optional lane information
353
if (attrs.hasAttribute(SUMO_ATTR_LANE) || attrs.hasAttribute(SUMO_ATTR_FROM_LANE) || attrs.hasAttribute(SUMO_ATTR_TO_LANE)) {
354
parseLaneBound(attrs, fromEdge, toEdge);
355
} else {
356
fromEdge->addEdge2EdgeConnection(toEdge);
357
fromEdge->getToNode()->invalidateTLS(myTLLogicCont, true, false);
358
if (attrs.hasAttribute(SUMO_ATTR_PASS)
359
|| attrs.hasAttribute(SUMO_ATTR_KEEP_CLEAR)
360
|| attrs.hasAttribute(SUMO_ATTR_CONTPOS)
361
|| attrs.hasAttribute(SUMO_ATTR_VISIBILITY_DISTANCE)
362
|| attrs.hasAttribute(SUMO_ATTR_SPEED)
363
|| attrs.hasAttribute(SUMO_ATTR_LENGTH)
364
|| attrs.hasAttribute(SUMO_ATTR_UNCONTROLLED)
365
|| attrs.hasAttribute(SUMO_ATTR_SHAPE)
366
|| attrs.hasAttribute(SUMO_ATTR_ALLOW)
367
|| attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
368
WRITE_ERROR("No additional connection attributes are permitted in connection from edge '" + fromEdge->getID() + "' unless '"
369
+ toString(SUMO_ATTR_FROM_LANE) + "' and '" + toString(SUMO_ATTR_TO_LANE) + "' are set.");
370
}
371
}
372
}
373
374
void
375
NIXMLConnectionsHandler::addCrossing(const SUMOSAXAttributes& attrs) {
376
bool ok = true;
377
EdgeVector edges;
378
const std::string nodeID = attrs.get<std::string>(SUMO_ATTR_NODE, nullptr, ok);
379
double width = attrs.getOpt<double>(SUMO_ATTR_WIDTH, nodeID.c_str(), ok, NBEdge::UNSPECIFIED_WIDTH, true);
380
const bool discard = attrs.getOpt<bool>(SUMO_ATTR_DISCARD, nodeID.c_str(), ok, false, true);
381
int tlIndex = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX, nullptr, ok, -1);
382
int tlIndex2 = attrs.getOpt<int>(SUMO_ATTR_TLLINKINDEX2, nullptr, ok, -1);
383
NBNode* node = myNodeCont.retrieve(nodeID);
384
if (node == nullptr) {
385
if (!discard && myNodeCont.wasRemoved(nodeID)) {
386
WRITE_ERRORF(TL("Node '%' in crossing is not known."), nodeID);
387
}
388
return;
389
}
390
if (!attrs.hasAttribute(SUMO_ATTR_EDGES)) {
391
if (discard) {
392
node->discardAllCrossings(true);
393
return;
394
} else {
395
WRITE_ERRORF(TL("No edges specified for crossing at node '%'."), nodeID);
396
return;
397
}
398
}
399
for (const std::string& id : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nodeID.c_str(), ok)) {
400
NBEdge* edge = myEdgeCont.retrieve(id);
401
if (edge == nullptr) {
402
if (!(discard && myEdgeCont.wasRemoved(id))) {
403
WRITE_ERRORF(TL("Edge '%' for crossing at node '%' is not known."), id, nodeID);
404
return;
405
} else {
406
edge = myEdgeCont.retrieve(id, true);
407
}
408
} else {
409
if (edge->getToNode() != node && edge->getFromNode() != node) {
410
if (!discard) {
411
WRITE_ERRORF(TL("Edge '%' does not touch node '%'."), id, nodeID);
412
return;
413
}
414
}
415
}
416
edges.push_back(edge);
417
}
418
if (!ok) {
419
return;
420
}
421
bool priority = attrs.getOpt<bool>(SUMO_ATTR_PRIORITY, nodeID.c_str(), ok, node->isTLControlled(), true);
422
if (node->isTLControlled() && !priority) {
423
// traffic_light nodes should always have priority crossings
424
WRITE_WARNINGF(TL("Crossing at controlled node '%' must be prioritized"), nodeID);
425
priority = true;
426
}
427
PositionVector customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, PositionVector::EMPTY);
428
if (!NBNetBuilder::transformCoordinates(customShape, true, myLocation)) {
429
WRITE_ERRORF(TL("Unable to project shape for crossing at node '%'."), node->getID());
430
}
431
if (discard) {
432
node->removeCrossing(edges);
433
} else {
434
if (node->checkCrossingDuplicated(edges)) {
435
// possibly a diff
436
NBNode::Crossing* existing = node->getCrossing(edges);
437
if (!(
438
(attrs.hasAttribute(SUMO_ATTR_WIDTH) && width != existing->width)
439
|| (attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX) && tlIndex != existing->customTLIndex)
440
|| (attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX2) && tlIndex2 != existing->customTLIndex2)
441
|| (attrs.hasAttribute(SUMO_ATTR_PRIORITY) && priority != existing->priority))) {
442
WRITE_ERRORF(TL("Crossing with edges '%' already exists at node '%'."), toString(edges), node->getID());
443
return;
444
} else {
445
// replace existing, keep old attributes
446
if (!attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
447
width = existing->width;
448
}
449
if (!attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX)) {
450
tlIndex = existing->customTLIndex;
451
}
452
if (!attrs.hasAttribute(SUMO_ATTR_TLLINKINDEX2)) {
453
tlIndex2 = existing->customTLIndex2;
454
}
455
if (!attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
456
priority = existing->priority;
457
}
458
node->removeCrossing(edges);
459
}
460
}
461
NBNode::Crossing* c = node->addCrossing(edges, width, priority, tlIndex, tlIndex2, customShape);
462
myLastParameterised = c;
463
}
464
}
465
466
467
void
468
NIXMLConnectionsHandler::addWalkingArea(const SUMOSAXAttributes& attrs) {
469
bool ok = true;
470
NBNode* node = nullptr;
471
EdgeVector edges;
472
const std::string nodeID = attrs.get<std::string>(SUMO_ATTR_NODE, nullptr, ok);
473
std::vector<std::string> edgeIDs;
474
if (!attrs.hasAttribute(SUMO_ATTR_EDGES)) {
475
WRITE_ERRORF(TL("No edges specified for walkingArea at node '%'."), nodeID);
476
return;
477
}
478
for (const std::string& id : attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nodeID.c_str(), ok)) {
479
NBEdge* edge = myEdgeCont.retrieve(id);
480
if (edge == nullptr) {
481
WRITE_ERRORF(TL("Edge '%' for walkingArea at node '%' is not known."), id, nodeID);
482
return;
483
}
484
if (node == nullptr) {
485
if (edge->getToNode()->getID() == nodeID) {
486
node = edge->getToNode();
487
} else if (edge->getFromNode()->getID() == nodeID) {
488
node = edge->getFromNode();
489
} else {
490
WRITE_ERRORF(TL("Edge '%' does not touch node '%'."), id, nodeID);
491
return;
492
}
493
} else {
494
if (edge->getToNode() != node && edge->getFromNode() != node) {
495
WRITE_ERRORF(TL("Edge '%' does not touch node '%'."), id, nodeID);
496
return;
497
}
498
}
499
edges.push_back(edge);
500
}
501
if (!ok) {
502
return;
503
}
504
PositionVector customShape = attrs.getOpt<PositionVector>(SUMO_ATTR_SHAPE, nullptr, ok, PositionVector::EMPTY);
505
double customWidth = attrs.getOpt<double>(SUMO_ATTR_WIDTH, nullptr, ok, NBEdge::UNSPECIFIED_WIDTH);
506
if (!NBNetBuilder::transformCoordinates(customShape, true, myLocation)) {
507
WRITE_ERRORF(TL("Unable to project shape for walkingArea at node '%'."), node->getID());
508
}
509
node->addWalkingAreaShape(edges, customShape, customWidth);
510
}
511
512
void
513
NIXMLConnectionsHandler::addProhibition(const SUMOSAXAttributes& attrs) {
514
bool ok = true;
515
std::string prohibitor = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITOR, nullptr, ok, "");
516
std::string prohibited = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITED, nullptr, ok, "");
517
if (!ok) {
518
return;
519
}
520
NBConnection prohibitorC = parseConnectionDef("prohibitor", prohibitor);
521
NBConnection prohibitedC = parseConnectionDef("prohibited", prohibited);
522
if (prohibitorC == NBConnection::InvalidConnection || prohibitedC == NBConnection::InvalidConnection) {
523
// something failed
524
return;
525
}
526
NBNode* n = prohibitorC.getFrom()->getToNode();
527
n->addSortedLinkFoes(prohibitorC, prohibitedC);
528
}
529
530
/****************************************************************************/
531
532