SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NIXMLConnectionsHandler.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // Importer for edge connections stored in XML
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
13 // Copyright (C) 2001-2013 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include <string>
35 #include <iostream>
36 #include <xercesc/sax/HandlerBase.hpp>
37 #include <xercesc/sax/AttributeList.hpp>
38 #include <xercesc/sax/SAXParseException.hpp>
39 #include <xercesc/sax/SAXException.hpp>
41 #include <netbuild/NBEdge.h>
42 #include <netbuild/NBEdgeCont.h>
43 #include <netbuild/NBNode.h>
47 #include <utils/common/ToString.h>
52 
53 #ifdef CHECK_MEMORY_LEAKS
54 #include <foreign/nvwa/debug_new.h>
55 #endif // CHECK_MEMORY_LEAKS
56 
57 
58 // ===========================================================================
59 // method definitions
60 // ===========================================================================
62  SUMOSAXHandler("xml-connection-description"),
63  myEdgeCont(ec),
64  myHaveWarnedAboutDeprecatedLanes(false),
65  myErrorMsgHandler(OptionsCont::getOptions().getBool("ignore-errors.connections") ?
66  MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()) {}
67 
68 
70 
71 
72 void
74  const SUMOSAXAttributes& attrs) {
75  if (element == SUMO_TAG_DELETE) {
76  bool ok = true;
77  std::string from = attrs.get<std::string>(SUMO_ATTR_FROM, 0, ok);
78  std::string to = attrs.get<std::string>(SUMO_ATTR_TO, 0, ok);
79  if (!ok) {
80  return;
81  }
82  // these connections were removed when the edge was deleted
83  if (myEdgeCont.wasRemoved(from) || myEdgeCont.wasRemoved(to)) {
84  return;
85  }
86  NBEdge* fromEdge = myEdgeCont.retrieve(from);
87  NBEdge* toEdge = myEdgeCont.retrieve(to);
88  if (fromEdge == 0) {
89  myErrorMsgHandler->inform("The connection-source edge '" + from + "' to reset is not known.");
90  return;
91  }
92  if (toEdge == 0) {
93  myErrorMsgHandler->inform("The connection-destination edge '" + to + "' to reset is not known.");
94  return;
95  }
96  if (!fromEdge->isConnectedTo(toEdge) && fromEdge->getStep() >= NBEdge::EDGE2EDGES) {
97  WRITE_WARNING("Target edge '" + toEdge->getID() + "' is not connected with '" + fromEdge->getID() + "'; the connection cannot be reset.");
98  return;
99  }
100  int fromLane = -1; // Assume all lanes are to be reset.
101  int toLane = -1;
102  if (attrs.hasAttribute(SUMO_ATTR_LANE)
104  || attrs.hasAttribute(SUMO_ATTR_TO_LANE)) {
105  if (!parseLaneInfo(attrs, fromEdge, toEdge, &fromLane, &toLane)) {
106  return;
107  }
108  // we could be trying to reset a connection loaded from a sumo net and which has become obsolete.
109  // In this case it's ok to encounter invalid lance indices
110  if (!fromEdge->hasConnectionTo(toEdge, toLane) && fromEdge->getStep() >= NBEdge::LANES2EDGES) {
111  WRITE_WARNING("Edge '" + fromEdge->getID() + "' has no connection to lane " + toString(toLane) + " of edge '" + toEdge->getID() + "'; the connection cannot be reset.");
112  }
113  }
114  fromEdge->removeFromConnections(toEdge, fromLane, toLane, true);
115  }
116 
117  if (element == SUMO_TAG_CONNECTION) {
118  bool ok = true;
119  std::string from = attrs.get<std::string>(SUMO_ATTR_FROM, "connection", ok);
120  std::string to = attrs.getOpt<std::string>(SUMO_ATTR_TO, "connection", ok, "");
121  if (!ok || myEdgeCont.wasIgnored(from) || myEdgeCont.wasIgnored(to)) {
122  return;
123  }
124  // extract edges
125  NBEdge* fromEdge = myEdgeCont.retrieve(from);
126  NBEdge* toEdge = to.length() != 0 ? myEdgeCont.retrieve(to) : 0;
127  // check whether they are valid
128  if (fromEdge == 0) {
129  myErrorMsgHandler->inform("The connection-source edge '" + from + "' is not known.");
130  return;
131  }
132  if (toEdge == 0 && to.length() != 0) {
133  myErrorMsgHandler->inform("The connection-destination edge '" + to + "' is not known.");
134  return;
135  }
136  // parse optional lane information
138  parseLaneBound(attrs, fromEdge, toEdge);
139  } else {
140  fromEdge->addEdge2EdgeConnection(toEdge);
141  }
142  }
143  if (element == SUMO_TAG_PROHIBITION) {
144  bool ok = true;
145  std::string prohibitor = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITOR, 0, ok, "");
146  std::string prohibited = attrs.getOpt<std::string>(SUMO_ATTR_PROHIBITED, 0, ok, "");
147  if (!ok) {
148  return;
149  }
150  NBConnection prohibitorC = parseConnection("prohibitor", prohibitor);
151  NBConnection prohibitedC = parseConnection("prohibited", prohibited);
152  if (prohibitorC.getFrom() == 0 || prohibitedC.getFrom() == 0) {
153  // something failed
154  return;
155  }
156  NBNode* n = prohibitorC.getFrom()->getToNode();
157  n->addSortedLinkFoes(prohibitorC, prohibitedC);
158  }
159 }
160 
161 
163 NIXMLConnectionsHandler::parseConnection(const std::string& defRole, const std::string& def) {
164  // split from/to
165  size_t div = def.find("->");
166  if (div == std::string::npos) {
167  myErrorMsgHandler->inform("Missing connection divider in " + defRole + " '" + def + "'");
168  return NBConnection(0, 0);
169  }
170  std::string fromDef = def.substr(0, div);
171  std::string toDef = def.substr(div + 2);
172 
173  // retrieve the edges
174  // check whether the definition includes a lane information (do not process it)
175  if (fromDef.find('_') != std::string::npos) {
176  fromDef = fromDef.substr(0, fromDef.find('_'));
177  }
178  if (toDef.find('_') != std::string::npos) {
179  toDef = toDef.substr(0, toDef.find('_'));
180  }
181  // retrieve them now
182  NBEdge* fromE = myEdgeCont.retrieve(fromDef);
183  NBEdge* toE = myEdgeCont.retrieve(toDef);
184  // check
185  if (fromE == 0) {
186  myErrorMsgHandler->inform("Could not find edge '" + fromDef + "' in " + defRole + " '" + def + "'");
187  return NBConnection(0, 0);
188  }
189  if (toE == 0) {
190  myErrorMsgHandler->inform("Could not find edge '" + toDef + "' in " + defRole + " '" + def + "'");
191  return NBConnection(0, 0);
192  }
193  return NBConnection(fromE, toE);
194 }
195 
196 
197 void
199  if (to == 0) {
200  // do nothing if it's a dead end
201  return;
202  }
203  bool ok = true;
204  const bool mayDefinitelyPass = attrs.getOpt<bool>(SUMO_ATTR_PASS, 0, ok, false);
205  if (!ok) {
206  return;
207  }
208  // get the begin and the end lane
209  int fromLane;
210  int toLane;
211  try {
212  if (!parseLaneInfo(attrs, from, to, &fromLane, &toLane)) {
213  return;
214  }
215  if (!validateLaneInfo(false /* canLanesBeNegative */, from, to, fromLane, toLane)) {
216  return;
217  }
218  if (from->hasConnectionTo(to, toLane)) {
219  WRITE_WARNING("Target lane '" + to->getLaneID(toLane) + "' is already connected from '" + from->getID() + "'.");
220  }
221  if (!from->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER, true, mayDefinitelyPass)) {
222  NBEdge* nFrom = from;
223  bool toNext = true;
224  do {
225  if (nFrom->getToNode()->getOutgoingEdges().size() != 1) {
226  toNext = false;
227  break;
228  }
229  NBEdge* t = nFrom->getToNode()->getOutgoingEdges()[0];
230  if (t->getID().substr(0, t->getID().find('/')) != nFrom->getID().substr(0, nFrom->getID().find('/'))) {
231  toNext = false;
232  break;
233  }
234  if (toNext) {
235  nFrom = t;
236  }
237  } while (toNext);
238  if (nFrom == 0 || !nFrom->addLane2LaneConnection(fromLane, to, toLane, NBEdge::L2L_USER, false, mayDefinitelyPass)) {
239  if (OptionsCont::getOptions().getBool("show-errors.connections-first-try")) {
240  WRITE_WARNING("Could not set loaded connection from '" + from->getLaneID(fromLane) + "' to '" + to->getLaneID(toLane) + "'.");
241  }
242  // set as to be re-applied after network processing
243  myEdgeCont.addPostProcessConnection(nFrom->getID(), fromLane, to->getID(), toLane, mayDefinitelyPass);
244  } else {
245  from = nFrom;
246  }
247  }
248  } catch (NumberFormatException&) {
249  myErrorMsgHandler->inform("At least one of the defined lanes was not numeric");
250  }
251  //
252  bool keepUncontrolled = attrs.getOpt<bool>(SUMO_ATTR_UNCONTROLLED, 0, ok, false);
253  if (keepUncontrolled) {
254  from->disableConnection4TLS(fromLane, to, toLane);
255  }
256 }
257 
258 bool
260  int* fromLane, int* toLane) {
261  if (attributes.hasAttribute(SUMO_ATTR_LANE)) {
262  return parseDeprecatedLaneDefinition(attributes, fromEdge, toEdge, fromLane, toLane);
263  } else {
264  return parseLaneDefinition(attributes, fromLane, toLane);
265  }
266 }
267 
268 
269 inline bool
271  NBEdge* from, NBEdge* to,
272  int* fromLane, int* toLane) {
273  bool ok = true;
276  WRITE_WARNING("'" + toString(SUMO_ATTR_LANE) + "' is deprecated, please use '" +
278  "' instead.");
279  }
280 
281  std::string laneConn = attributes.get<std::string>(SUMO_ATTR_LANE, 0, ok);
282  StringTokenizer st(laneConn, ':');
283  if (!ok || st.size() != 2) {
284  myErrorMsgHandler->inform("Invalid lane to lane connection from '" +
285  from->getID() + "' to '" + to->getID() + "'.");
286  return false; // There was an error.
287  }
288 
289  *fromLane = TplConvert::_2intSec(st.next().c_str(), -1);
290  *toLane = TplConvert::_2intSec(st.next().c_str(), -1);
291 
292  return true; // We succeeded.
293 }
294 
295 
296 inline bool
298  int* fromLane,
299  int* toLane) {
300  bool ok = true;
301  *fromLane = attributes.get<int>(SUMO_ATTR_FROM_LANE, 0, ok);
302  *toLane = attributes.get<int>(SUMO_ATTR_TO_LANE, 0, ok);
303  return ok;
304 }
305 
306 
307 bool
308 NIXMLConnectionsHandler::validateLaneInfo(bool canLanesBeNegative, NBEdge* fromEdge, NBEdge* toEdge, int fromLane, int toLane) {
309  if ((!canLanesBeNegative && fromLane < 0) ||
310  static_cast<unsigned int>(fromLane) >= fromEdge->getNumLanes()) {
311  myErrorMsgHandler->inform("Invalid value '" + toString(fromLane) +
312  "' for " + toString(SUMO_ATTR_FROM_LANE) + " in connection from '" +
313  fromEdge->getID() + "' to '" + toEdge->getID() + "'.");
314  return false;
315  }
316  if ((!canLanesBeNegative && toLane < 0) ||
317  static_cast<unsigned int>(toLane) >= toEdge->getNumLanes()) {
318  myErrorMsgHandler->inform("Invalid value '" + toString(toLane) +
319  "' for " + toString(SUMO_ATTR_TO_LANE) + " in connection from '" +
320  fromEdge->getID() + "' to '" + toEdge->getID() + "'.");
321  return false;
322  }
323  return true;
324 }
325 
326 /****************************************************************************/
327