SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NIXMLEdgesHandler.cpp
Go to the documentation of this file.
1 /****************************************************************************/
11 // Importer for network edges stored in XML
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
14 // Copyright (C) 2001-2014 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 
25 
26 // ===========================================================================
27 // included modules
28 // ===========================================================================
29 #ifdef _MSC_VER
30 #include <windows_config.h>
31 #else
32 #include <config.h>
33 #endif
34 
35 #include <string>
36 #include <iostream>
37 #include <map>
38 #include <cmath>
39 #include <xercesc/sax/HandlerBase.hpp>
40 #include <xercesc/sax/AttributeList.hpp>
41 #include <xercesc/sax/SAXParseException.hpp>
42 #include <xercesc/sax/SAXException.hpp>
44 #include <netbuild/NBNodeCont.h>
45 #include <netbuild/NBTypeCont.h>
46 #include <netbuild/NBNetBuilder.h>
52 #include <utils/common/ToString.h>
55 #include "NIXMLEdgesHandler.h"
56 
57 #ifdef CHECK_MEMORY_LEAKS
58 #include <foreign/nvwa/debug_new.h>
59 #endif // CHECK_MEMORY_LEAKS
60 
61 
62 // ===========================================================================
63 // used constants
64 // ===========================================================================
66 
67 // ===========================================================================
68 // method definitions
69 // ===========================================================================
71  NBEdgeCont& ec,
72  NBTypeCont& tc,
73  NBDistrictCont& dc,
75  OptionsCont& options)
76  : SUMOSAXHandler("xml-edges - file"),
77  myOptions(options),
78  myNodeCont(nc),
79  myEdgeCont(ec),
80  myTypeCont(tc),
81  myDistrictCont(dc),
82  myTLLogicCont(tlc),
83  myCurrentEdge(0), myHaveReportedAboutOverwriting(false),
84  myHaveWarnedAboutDeprecatedLaneId(false),
85  myKeepEdgeShape(!options.getBool("plain.extend-edge-shape"))
86 {}
87 
88 
90 
91 
92 void
94  const SUMOSAXAttributes& attrs) {
95  switch (element) {
96  case SUMO_TAG_EDGE:
97  addEdge(attrs);
98  break;
99  case SUMO_TAG_LANE:
100  addLane(attrs);
101  break;
102  case SUMO_TAG_SPLIT:
103  addSplit(attrs);
104  break;
105  case SUMO_TAG_DELETE:
106  deleteEdge(attrs);
107  break;
108  default:
109  break;
110  }
111 }
112 
113 
114 void
116  myIsUpdate = false;
117  bool ok = true;
118  // initialise the edge
119  myCurrentEdge = 0;
120  mySplits.clear();
121  // get the id, report an error if not given or empty...
122  myCurrentID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
123  if (!ok) {
124  return;
125  }
127  // check deprecated (unused) attributes
128  // use default values, first
135  myCurrentType = "";
139  myCurrentStreetName = "";
140  myReinitKeepEdgeShape = false;
141  // check whether a type's values shall be used
142  if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
143  myCurrentType = attrs.get<std::string>(SUMO_ATTR_TYPE, myCurrentID.c_str(), ok);
144  if (!ok) {
145  return;
146  }
147  if (!myTypeCont.knows(myCurrentType) && !myOptions.getBool("ignore-errors.edge-type")) {
148  WRITE_ERROR("Type '" + myCurrentType + "' used by edge '" + myCurrentID + "' was not defined (ignore with option --ignore-errors.edge-type).");
149  return;
150  }
156  }
157  // use values from the edge to overwrite if existing, then
158  if (myCurrentEdge != 0) {
159  myIsUpdate = true;
161  WRITE_MESSAGE("Duplicate edge id occured ('" + myCurrentID + "'); assuming overwriting is wished.");
163  }
164  if (attrs.getOpt<bool>(SUMO_ATTR_REMOVE, myCurrentID.c_str(), ok, false)) {
166  myCurrentEdge = 0;
167  return;
168  }
176  myReinitKeepEdgeShape = true;
177  }
183  }
185  }
186  // speed, priority and the number of lanes have now default values;
187  // try to read the real values from the file
188  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
189  myCurrentSpeed = attrs.get<SUMOReal>(SUMO_ATTR_SPEED, myCurrentID.c_str(), ok);
190  }
191  if (myOptions.getBool("speed-in-kmh")) {
193  }
194  // try to get the number of lanes
195  if (attrs.hasAttribute(SUMO_ATTR_NUMLANES)) {
196  myCurrentLaneNo = attrs.get<int>(SUMO_ATTR_NUMLANES, myCurrentID.c_str(), ok);
197  }
198  // try to get the priority
199  if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
200  myCurrentPriority = attrs.get<int>(SUMO_ATTR_PRIORITY, myCurrentID.c_str(), ok);
201  }
202  // try to get the width
203  if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
204  myCurrentWidth = attrs.get<SUMOReal>(SUMO_ATTR_WIDTH, myCurrentID.c_str(), ok);
205  }
206  // try to get the width
207  if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
209  }
210  // try to get the street name
211  if (attrs.hasAttribute(SUMO_ATTR_NAME)) {
212  myCurrentStreetName = attrs.get<std::string>(SUMO_ATTR_NAME, myCurrentID.c_str(), ok);
213  if (myCurrentStreetName != "" && myOptions.isDefault("output.street-names")) {
214  myOptions.set("output.street-names", "true");
215  }
216  }
217 
218  // try to get the allowed/disallowed classes
220  std::string allowS = attrs.hasAttribute(SUMO_ATTR_ALLOW) ? attrs.getStringSecure(SUMO_ATTR_ALLOW, "") : "";
221  std::string disallowS = attrs.hasAttribute(SUMO_ATTR_DISALLOW) ? attrs.getStringSecure(SUMO_ATTR_DISALLOW, "") : "";
222  // XXX matter of interpretation: should updated permissions replace or extend previously set permissions?
223  myPermissions = parseVehicleClasses(allowS, disallowS);
224  }
225  // try to set the nodes
226  if (!setNodes(attrs)) {
227  // return if this failed
228  return;
229  }
230  // try to get the shape
231  myShape = tryGetShape(attrs);
232  // try to get the spread type
234  // try to get the length
236  // insert the parsed edge into the edges map
237  if (!ok) {
238  return;
239  }
240  // check whether a previously defined edge shall be overwritten
241  if (myCurrentEdge != 0) {
247  } else {
248  // the edge must be allocated in dependence to whether a shape is given
249  if (myShape.size() == 0) {
253  } else {
258  }
259  }
263  // lane specifications may override this
265  }
266 }
267 
268 
269 void
271  if (myCurrentEdge == 0) {
272  if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
273  WRITE_ERROR("Additional lane information could not be set - the edge with id '" + myCurrentID + "' is not known.");
274  }
275  return;
276  }
277  bool ok = true;
278  int lane;
279  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
280  lane = attrs.get<int>(SUMO_ATTR_ID, myCurrentID.c_str(), ok);
283  WRITE_WARNING("'" + toString(SUMO_ATTR_ID) + "' is deprecated, please use '" + toString(SUMO_ATTR_INDEX) + "' instead.");
284  }
285  } else {
286  lane = attrs.get<int>(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok);
287  }
288  std::string allowed, disallowed, preferred;
289  allowed = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, 0, ok, "");
290  disallowed = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, 0, ok, "");
291  preferred = attrs.getOpt<std::string>(SUMO_ATTR_PREFER, 0, ok, "");
292  if (!ok) {
293  return;
294  }
295  // check whether this lane exists
296  if (lane >= (int) myCurrentEdge->getNumLanes()) {
297  WRITE_ERROR("Lane index is larger than number of lanes (edge '" + myCurrentID + "').");
298  return;
299  }
300  // set information about allowed / disallowed vehicle classes
301  myCurrentEdge->setPermissions(parseVehicleClasses(allowed, disallowed), lane);
303  // try to get the width
304  if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
305  myCurrentEdge->setLaneWidth(lane, attrs.get<SUMOReal>(SUMO_ATTR_WIDTH, myCurrentID.c_str(), ok));
306  }
307  // try to get the end-offset (lane shortened due to pedestrian crossing etc..)
308  if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
310  }
311  // try to get lane specific speed (should not occur for german networks)
312  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
313  myCurrentEdge->setSpeed(lane, attrs.get<SUMOReal>(SUMO_ATTR_SPEED, myCurrentID.c_str(), ok));
314  }
315 }
316 
317 
319  if (myCurrentEdge == 0) {
320  WRITE_WARNING("Ignoring 'split' because it cannot be assigned to an edge");
321  return;
322  }
323  bool ok = true;
324  Split e;
325  e.pos = attrs.get<SUMOReal>(SUMO_ATTR_POSITION, 0, ok);
326  if (ok) {
327  if (fabs(e.pos) > myCurrentEdge->getGeometry().length()) {
328  WRITE_ERROR("Edge '" + myCurrentID + "' has a split at invalid position " + toString(e.pos) + ".");
329  return;
330  }
331  std::vector<Split>::iterator i = find_if(mySplits.begin(), mySplits.end(), split_by_pos_finder(e.pos));
332  if (i != mySplits.end()) {
333  WRITE_ERROR("Edge '" + myCurrentID + "' has already a split at position " + toString(e.pos) + ".");
334  return;
335  }
336  e.nameid = (int)e.pos;
337  if (myCurrentEdge == 0) {
338  if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
339  WRITE_ERROR("Additional lane information could not be set - the edge with id '" + myCurrentID + "' is not known.");
340  }
341  return;
342  }
343  if (e.pos < 0) {
345  }
346  std::vector<std::string> lanes;
347  SUMOSAXAttributes::parseStringVector(attrs.getOpt<std::string>(SUMO_ATTR_LANES, 0, ok, ""), lanes);
348  for (std::vector<std::string>::iterator i = lanes.begin(); i != lanes.end(); ++i) {
349  try {
350  int lane = TplConvert::_2int((*i).c_str());
351  e.lanes.push_back(lane);
352  } catch (NumberFormatException&) {
353  WRITE_ERROR("Error on parsing a split (edge '" + myCurrentID + "').");
354  } catch (EmptyData&) {
355  WRITE_ERROR("Error on parsing a split (edge '" + myCurrentID + "').");
356  }
357  }
358  if (e.lanes.empty()) {
359  for (size_t l = 0; l < myCurrentEdge->getNumLanes(); ++l) {
360  e.lanes.push_back((int) l);
361  }
362  }
363  mySplits.push_back(e);
364  }
365 }
366 
367 
368 bool
370  // the names and the coordinates of the beginning and the end node
371  // may be found, try
372  bool ok = true;
373  std::string begNodeID = myIsUpdate ? myCurrentEdge->getFromNode()->getID() : "";
374  std::string endNodeID = myIsUpdate ? myCurrentEdge->getToNode()->getID() : "";
375  std::string oldBegID = begNodeID;
376  std::string oldEndID = endNodeID;
377  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
378  begNodeID = attrs.get<std::string>(SUMO_ATTR_FROM, 0, ok);
379  } else if (!myIsUpdate) {
380  WRITE_ERROR("The from-node is not given for edge '" + myCurrentID + "'.");
381  ok = false;
382  }
383  if (attrs.hasAttribute(SUMO_ATTR_TO)) {
384  endNodeID = attrs.get<std::string>(SUMO_ATTR_TO, 0, ok);
385  } else if (!myIsUpdate) {
386  WRITE_ERROR("The to-node is not given for edge '" + myCurrentID + "'.");
387  ok = false;
388  }
389  if (!ok) {
390  return false;
391  }
392  myFromNode = myNodeCont.retrieve(begNodeID);
393  myToNode = myNodeCont.retrieve(endNodeID);
394  if (myFromNode == 0) {
395  WRITE_ERROR("Edge's '" + myCurrentID + "' from-node '" + begNodeID + "' is not known.");
396  }
397  if (myToNode == 0) {
398  WRITE_ERROR("Edge's '" + myCurrentID + "' to-node '" + endNodeID + "' is not known.");
399  }
400  if (myFromNode != 0 && myToNode != 0) {
401  if (myIsUpdate && (myFromNode->getID() != oldBegID || myToNode->getID() != oldEndID)) {
403  }
404  }
405  return myFromNode != 0 && myToNode != 0;
406 }
407 
408 
411  if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
412  return myShape;
413  }
414  // try to build shape
415  bool ok = true;
416  if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
417  myReinitKeepEdgeShape = false;
418  return PositionVector();
419  }
422  WRITE_ERROR("Unable to project coordinates for edge '" + myCurrentID + "'.");
423  }
425  return shape;
426 }
427 
428 
431  bool ok = true;
433  std::string lsfS = toString(result);
434  lsfS = attrs.getOpt<std::string>(SUMO_ATTR_SPREADTYPE, myCurrentID.c_str(), ok, lsfS);
435  if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
437  } else {
438  WRITE_WARNING("Ignoring unknown spreadType '" + lsfS + "' for edge '" + myCurrentID + "'.");
439  }
440  return result;
441 }
442 
443 
444 void
446  bool ok = true;
447  myCurrentID = attrs.get<std::string>(SUMO_ATTR_ID, 0, ok);
448  if (!ok) {
449  return;
450  }
452  if (edge == 0) {
453  WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DELETE) + "' for unknown edge '" +
454  myCurrentID + "'");
455  return;
456  }
457  myEdgeCont.extract(myDistrictCont, edge, true);
458 }
459 
460 
461 void
463  if (element == SUMO_TAG_EDGE && myCurrentEdge != 0) {
464  if (!myIsUpdate) {
465  try {
467  WRITE_ERROR("Duplicate edge occured. ID='" + myCurrentID + "'");
468  delete myCurrentEdge;
469  }
470  } catch (InvalidArgument& e) {
471  WRITE_ERROR(e.what());
472  throw;
473  } catch (...) {
474  WRITE_ERROR("An important information is missing in edge '" + myCurrentID + "'.");
475  }
476  }
477  if (mySplits.size() != 0) {
478  std::vector<Split>::iterator i;
479  NBEdge* e = myCurrentEdge;
480  sort(mySplits.begin(), mySplits.end(), split_sorter());
481  unsigned int noLanesMax = e->getNumLanes();
482  // compute the node positions and sort the lanes
483  for (i = mySplits.begin(); i != mySplits.end(); ++i) {
484  (*i).gpos = e->getGeometry().positionAtOffset((*i).pos);
485  sort((*i).lanes.begin(), (*i).lanes.end());
486  noLanesMax = MAX2(noLanesMax, (unsigned int)(*i).lanes.size());
487  }
488  // invalidate traffic light definitions loaded from a SUMO network
489  // XXX it would be preferable to reconstruct the phase definitions heuristically
491  e->invalidateConnections(true);
492 
493  // split the edge
494  std::vector<int> currLanes;
495  for (unsigned int l = 0; l < e->getNumLanes(); ++l) {
496  currLanes.push_back(l);
497  }
498  std::string edgeid = e->getID();
499  SUMOReal seen = 0;
500  for (i = mySplits.begin(); i != mySplits.end(); ++i) {
501  const Split& exp = *i;
502  assert(exp.lanes.size() != 0);
503  if (exp.pos > 0 && e->getGeometry().length() + seen > exp.pos && exp.pos > seen) {
504  std::string nid = edgeid + "." + toString(exp.nameid);
505  NBNode* rn = new NBNode(nid, exp.gpos);
506  if (myNodeCont.insert(rn)) {
507  // split the edge
508  std::string nid = myCurrentID + "." + toString(exp.nameid);
509  std::string pid = e->getID();
510  myEdgeCont.splitAt(myDistrictCont, e, exp.pos - seen, rn,
511  pid, nid, e->getNumLanes(), (unsigned int) exp.lanes.size());
512  seen = exp.pos;
513  std::vector<int> newLanes = exp.lanes;
514  NBEdge* pe = myEdgeCont.retrieve(pid);
515  NBEdge* ne = myEdgeCont.retrieve(nid);
516  // reconnect lanes
517  pe->invalidateConnections(true);
518  // new on right
519  unsigned int rightMostP = currLanes[0];
520  unsigned int rightMostN = newLanes[0];
521  for (int l = 0; l < (int) rightMostP - (int) rightMostN; ++l) {
522  pe->addLane2LaneConnection(0, ne, l, NBEdge::L2L_VALIDATED, true);
523  }
524  // new on left
525  unsigned int leftMostP = currLanes.back();
526  unsigned int leftMostN = newLanes.back();
527  for (int l = 0; l < (int) leftMostN - (int) leftMostP; ++l) {
528  pe->addLane2LaneConnection(pe->getNumLanes() - 1, ne, leftMostN - l - rightMostN, NBEdge::L2L_VALIDATED, true);
529  }
530  // all other connected
531  for (unsigned int l = 0; l < noLanesMax; ++l) {
532  if (find(currLanes.begin(), currLanes.end(), l) == currLanes.end()) {
533  continue;
534  }
535  if (find(newLanes.begin(), newLanes.end(), l) == newLanes.end()) {
536  continue;
537  }
538  pe->addLane2LaneConnection(l - rightMostP, ne, l - rightMostN, NBEdge::L2L_VALIDATED, true);
539  }
540  // move to next
541  e = ne;
542  currLanes = newLanes;
543  } else {
544  WRITE_WARNING("Error on parsing a split (edge '" + myCurrentID + "').");
545  }
546  } else if (exp.pos == 0) {
547  if (e->getNumLanes() < exp.lanes.size()) {
548  e->incLaneNo((int) exp.lanes.size() - e->getNumLanes());
549  } else {
550  e->decLaneNo(e->getNumLanes() - (int) exp.lanes.size());
551  }
552  currLanes = exp.lanes;
553  // invalidate traffic light definition loaded from a SUMO network
554  // XXX it would be preferable to reconstruct the phase definitions heuristically
556  } else {
557  WRITE_WARNING("Split at '" + toString(exp.pos) + "' lies beyond the edge's length (edge '" + myCurrentID + "').");
558  }
559  }
560  // patch lane offsets
561  e = myEdgeCont.retrieve(edgeid);
562  i = mySplits.begin();
563  if ((*i).pos != 0) {
564  e = e->getToNode()->getOutgoingEdges()[0];
565  }
566  for (; i != mySplits.end(); ++i) {
567  unsigned int maxLeft = (*i).lanes.back();
568  SUMOReal offset = 0;
569  if (maxLeft < noLanesMax) {
571  offset = SUMO_const_laneWidthAndOffset * (noLanesMax - 1 - maxLeft);
572  } else {
573  offset = SUMO_const_halfLaneAndOffset * (noLanesMax - 1 - maxLeft);
574  }
575  }
576  unsigned int maxRight = (*i).lanes.front();
577  if (maxRight > 0 && e->getLaneSpreadFunction() == LANESPREAD_CENTER) {
578  offset -= SUMO_const_halfLaneAndOffset * maxRight;
579  }
580  if (offset != 0) {
581  PositionVector g = e->getGeometry();
582  g.move2side(offset);
583  e->setGeometry(g);
584  }
585  if (e->getToNode()->getOutgoingEdges().size() != 0) {
586  e = e->getToNode()->getOutgoingEdges()[0];
587  }
588  }
589  }
590  }
591 }
592 
593 /****************************************************************************/
594