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.sourceforge.net/
14 // Copyright (C) 2001-2012 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>
51 #include <utils/common/ToString.h>
54 #include "NILoader.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,
74  OptionsCont& options)
75  : SUMOSAXHandler("xml-edges - file"),
76  myOptions(options),
77  myNodeCont(nc), myEdgeCont(ec), myTypeCont(tc), myDistrictCont(dc),
78  myCurrentEdge(0), myHaveReportedAboutOverwriting(false),
79  myHaveWarnedAboutDeprecatedLaneId(false),
80  myKeepEdgeShape(!options.getBool("plain.extend-edge-shape"))
81 {}
82 
83 
85 
86 
87 void
89  const SUMOSAXAttributes& attrs) {
90  switch (element) {
91  case SUMO_TAG_EDGE:
92  addEdge(attrs);
93  break;
94  case SUMO_TAG_LANE:
95  addLane(attrs);
96  break;
97  case SUMO_TAG_SPLIT:
98  addSplit(attrs);
99  break;
100  case SUMO_TAG_DELETE:
101  deleteEdge(attrs);
102  break;
103  default:
104  break;
105  }
106 }
107 
108 
109 void
111  myIsUpdate = false;
112  bool ok = true;
113  // initialise the edge
114  myCurrentEdge = 0;
115  mySplits.clear();
116  // get the id, report an error if not given or empty...
118  if (!ok) {
119  return;
120  }
122  // check deprecated (unused) attributes
123  // use default values, first
130  myCurrentType = "";
134  myCurrentStreetName = "";
135  myReinitKeepEdgeShape = false;
136  // check whether a type's values shall be used
137  if (attrs.hasAttribute(SUMO_ATTR_TYPE)) {
139  if (!ok) {
140  return;
141  }
143  WRITE_ERROR("Type '" + myCurrentType + "' used by edge '" + myCurrentID + "' was not defined.");
144  return;
145  }
151  }
152  // use values from the edge to overwrite if existing, then
153  if (myCurrentEdge != 0) {
154  myIsUpdate = true;
156  WRITE_MESSAGE("Duplicate edge id occured ('" + myCurrentID + "'); assuming overwriting is wished.");
158  }
159  if (attrs.getOptBoolReporting(SUMO_ATTR_REMOVE, myCurrentID.c_str(), ok, false)) {
161  myCurrentEdge = 0;
162  return;
163  }
171  myReinitKeepEdgeShape = true;
172  }
178  }
180  }
181  // speed, priority and the number of lanes have now default values;
182  // try to read the real values from the file
183  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
185  }
186  if (myOptions.getBool("speed-in-kmh")) {
188  }
189  // try to get the number of lanes
190  if (attrs.hasAttribute(SUMO_ATTR_NUMLANES)) {
192  }
193  // try to get the priority
194  if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
196  }
197  // try to get the width
198  if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
200  }
201  // try to get the width
202  if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
204  }
205  // try to get the street name
207 
208  // try to get the allowed/disallowed classes
210  std::string allowS = attrs.hasAttribute(SUMO_ATTR_ALLOW) ? attrs.getStringSecure(SUMO_ATTR_ALLOW, "") : "";
211  std::string disallowS = attrs.hasAttribute(SUMO_ATTR_DISALLOW) ? attrs.getStringSecure(SUMO_ATTR_DISALLOW, "") : "";
212  // XXX matter of interpretation: should updated permissions replace or extend previously set permissions?
213  myPermissions = parseVehicleClasses(allowS, disallowS);
214  }
215  // try to set the nodes
216  if (!setNodes(attrs)) {
217  // return if this failed
218  return;
219  }
220  // try to get the shape
221  myShape = tryGetShape(attrs);
222  // try to get the spread type
224  // try to get the length
226  // insert the parsed edge into the edges map
227  if (!ok) {
228  return;
229  }
230  // check whether a previously defined edge shall be overwritten
231  if (myCurrentEdge != 0) {
237  } else {
238  // the edge must be allocated in dependence to whether a shape is given
239  if (myShape.size() == 0) {
243  } else {
248  }
249  }
252 }
253 
254 
255 void
257  if (myCurrentEdge == 0) {
258  if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
259  WRITE_ERROR("Additional lane information could not be set - the edge with id '" + myCurrentID + "' is not known.");
260  }
261  return;
262  }
263  bool ok = true;
264  int lane;
265  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
266  lane = attrs.getIntReporting(SUMO_ATTR_ID, myCurrentID.c_str(), ok);
269  WRITE_WARNING("'" + toString(SUMO_ATTR_ID) + "' is deprecated, please use '" + toString(SUMO_ATTR_INDEX) + "' instead.");
270  }
271  } else {
272  lane = attrs.getIntReporting(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok);
273  }
274  std::string allowed, disallowed, preferred;
275  allowed = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, 0, ok, "");
276  disallowed = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, 0, ok, "");
277  preferred = attrs.getOptStringReporting(SUMO_ATTR_PREFER, 0, ok, "");
278  if (!ok) {
279  return;
280  }
281  // check whether this lane exists
282  if (lane >= (int) myCurrentEdge->getNumLanes()) {
283  WRITE_ERROR("Lane index is larger than number of lanes (edge '" + myCurrentID + "').");
284  return;
285  }
286  // set information about allowed / disallowed vehicle classes
287  myCurrentEdge->setPermissions(parseVehicleClasses(allowed, disallowed), lane);
289  // try to get the width
290  if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
292  }
293  // try to get the end-offset (lane shortened due to pedestrian crossing etc..)
294  if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
296  }
297  // try to get lane specific speed (should not occur for german networks)
298  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
300  }
301 }
302 
303 
305  if (myCurrentEdge == 0) {
306  WRITE_WARNING("Ignoring 'split' because it cannot be assigned to an edge");
307  return;
308  }
309  bool ok = true;
310  Split e;
311  e.pos = attrs.getSUMORealReporting(SUMO_ATTR_POSITION, 0, ok);
312  if (ok) {
313  if (fabs(e.pos) > myCurrentEdge->getGeometry().length()) {
314  WRITE_ERROR("Edge '" + myCurrentID + "' has a split at invalid position " + toString(e.pos) + ".");
315  return;
316  }
317  std::vector<Split>::iterator i = find_if(mySplits.begin(), mySplits.end(), split_by_pos_finder(e.pos));
318  if (i != mySplits.end()) {
319  WRITE_ERROR("Edge '" + myCurrentID + "' has already a split at position " + toString(e.pos) + ".");
320  return;
321  }
322  e.nameid = (int)e.pos;
323  if (myCurrentEdge == 0) {
324  if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
325  WRITE_ERROR("Additional lane information could not be set - the edge with id '" + myCurrentID + "' is not known.");
326  }
327  return;
328  }
329  if (e.pos < 0) {
331  }
332  std::vector<std::string> lanes;
334  for (std::vector<std::string>::iterator i = lanes.begin(); i != lanes.end(); ++i) {
335  try {
336  int lane = TplConvert::_2int((*i).c_str());
337  e.lanes.push_back(lane);
338  } catch (NumberFormatException&) {
339  WRITE_ERROR("Error on parsing a split (edge '" + myCurrentID + "').");
340  } catch (EmptyData&) {
341  WRITE_ERROR("Error on parsing a split (edge '" + myCurrentID + "').");
342  }
343  }
344  if (e.lanes.empty()) {
345  for (size_t l = 0; l < myCurrentEdge->getNumLanes(); ++l) {
346  e.lanes.push_back((int) l);
347  }
348  }
349  mySplits.push_back(e);
350  }
351 }
352 
353 
354 bool
356  // the names and the coordinates of the beginning and the end node
357  // may be found, try
358  bool ok = true;
359  std::string begNodeID = myIsUpdate ? myCurrentEdge->getFromNode()->getID() : "";
360  std::string endNodeID = myIsUpdate ? myCurrentEdge->getToNode()->getID() : "";
361  std::string oldBegID = begNodeID;
362  std::string oldEndID = endNodeID;
363  if (attrs.hasAttribute(SUMO_ATTR_FROM)) {
364  begNodeID = attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok);
365  } else if (!myIsUpdate) {
366  WRITE_ERROR("The from-node is not given for edge '" + myCurrentID + "'.");
367  ok = false;
368  }
369  if (attrs.hasAttribute(SUMO_ATTR_TO)) {
370  endNodeID = attrs.getStringReporting(SUMO_ATTR_TO, 0, ok);
371  } else if (!myIsUpdate) {
372  WRITE_ERROR("The to-node is not given for edge '" + myCurrentID + "'.");
373  ok = false;
374  }
375  if (!ok) {
376  return false;
377  }
378  myFromNode = myNodeCont.retrieve(begNodeID);
379  myToNode = myNodeCont.retrieve(endNodeID);
380  if (myFromNode == 0) {
381  WRITE_ERROR("Edge's '" + myCurrentID + "' from-node '" + begNodeID + "' is not known.");
382  }
383  if (myToNode == 0) {
384  WRITE_ERROR("Edge's '" + myCurrentID + "' to-node '" + endNodeID + "' is not known.");
385  }
386  if (myFromNode != 0 && myToNode != 0) {
387  if (myIsUpdate && (myFromNode->getID() != oldBegID || myToNode->getID() != oldEndID)) {
389  }
390  }
391  return myFromNode != 0 && myToNode != 0;
392 }
393 
394 
397  if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
398  return myShape;
399  }
400  // try to build shape
401  bool ok = true;
402  if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
403  myReinitKeepEdgeShape = false;
404  return PositionVector();
405  }
406  PositionVector shape = attrs.getShapeReporting(SUMO_ATTR_SHAPE, 0, ok, true);
407  if (!NILoader::transformCoordinates(shape)) {
408  WRITE_ERROR("Unable to project coordinates for edge '" + myCurrentID + "'.");
409  }
411  return shape;
412 }
413 
414 
417  bool ok = true;
419  std::string lsfS = toString(result);
420  lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, myCurrentID.c_str(), ok, lsfS);
421  if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
423  } else {
424  WRITE_WARNING("Ignoring unknown spreadType '" + lsfS + "' for edge '" + myCurrentID + "'.");
425  }
426  return result;
427 }
428 
429 
430 void
432  bool ok = true;
434  if (!ok) {
435  return;
436  }
438  if (edge == 0) {
439  WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DELETE) + "' for unknown edge '" +
440  myCurrentID + "'");
441  return;
442  }
443  myEdgeCont.extract(myDistrictCont, edge, true);
444 }
445 
446 
447 void
449  if (element == SUMO_TAG_EDGE && myCurrentEdge != 0) {
450  if (!myIsUpdate) {
451  try {
453  WRITE_ERROR("Duplicate edge occured. ID='" + myCurrentID + "'");
454  delete myCurrentEdge;
455  }
456  } catch (InvalidArgument& e) {
457  WRITE_ERROR(e.what());
458  throw;
459  } catch (...) {
460  WRITE_ERROR("An important information is missing in edge '" + myCurrentID + "'.");
461  }
462  }
463  if (mySplits.size() != 0) {
464  std::vector<Split>::iterator i;
465  NBEdge* e = myCurrentEdge;
466  sort(mySplits.begin(), mySplits.end(), split_sorter());
467  unsigned int noLanesMax = e->getNumLanes();
468  // compute the node positions and sort the lanes
469  for (i = mySplits.begin(); i != mySplits.end(); ++i) {
470  (*i).gpos = e->getGeometry().positionAtLengthPosition((*i).pos);
471  sort((*i).lanes.begin(), (*i).lanes.end());
472  noLanesMax = MAX2(noLanesMax, (unsigned int)(*i).lanes.size());
473  }
474  // split the edge
475  std::vector<int> currLanes;
476  for (unsigned int l = 0; l < e->getNumLanes(); ++l) {
477  currLanes.push_back(l);
478  }
479  std::string edgeid = e->getID();
480  SUMOReal seen = 0;
481  for (i = mySplits.begin(); i != mySplits.end(); ++i) {
482  const Split& exp = *i;
483  assert(exp.lanes.size() != 0);
484  if (exp.pos > 0 && e->getGeometry().length() + seen > exp.pos && exp.pos > seen) {
485  std::string nid = edgeid + "." + toString(exp.nameid);
486  NBNode* rn = new NBNode(nid, exp.gpos);
487  if (myNodeCont.insert(rn)) {
488  // split the edge
489  std::string nid = myCurrentID + "." + toString(exp.nameid);
490  std::string pid = e->getID();
491  myEdgeCont.splitAt(myDistrictCont, e, exp.pos - seen, rn,
492  pid, nid, e->getNumLanes(), (unsigned int) exp.lanes.size());
493  seen = exp.pos;
494  std::vector<int> newLanes = exp.lanes;
495  NBEdge* pe = myEdgeCont.retrieve(pid);
496  NBEdge* ne = myEdgeCont.retrieve(nid);
497  // reconnect lanes
498  pe->invalidateConnections(true);
499  // new on right
500  unsigned int rightMostP = currLanes[0];
501  unsigned int rightMostN = newLanes[0];
502  for (int l = 0; l < (int) rightMostP - (int) rightMostN; ++l) {
503  pe->addLane2LaneConnection(0, ne, l, NBEdge::L2L_VALIDATED, true);
504  }
505  // new on left
506  unsigned int leftMostP = currLanes.back();
507  unsigned int leftMostN = newLanes.back();
508  for (int l = 0; l < (int) leftMostN - (int) leftMostP; ++l) {
509  pe->addLane2LaneConnection(pe->getNumLanes() - 1, ne, leftMostN - l - rightMostN, NBEdge::L2L_VALIDATED, true);
510  }
511  // all other connected
512  for (unsigned int l = 0; l < noLanesMax; ++l) {
513  if (find(currLanes.begin(), currLanes.end(), l) == currLanes.end()) {
514  continue;
515  }
516  if (find(newLanes.begin(), newLanes.end(), l) == newLanes.end()) {
517  continue;
518  }
519  pe->addLane2LaneConnection(l - rightMostP, ne, l - rightMostN, NBEdge::L2L_VALIDATED, true);
520  }
521  // move to next
522  e = ne;
523  currLanes = newLanes;
524  } else {
525  WRITE_WARNING("Error on parsing a split (edge '" + myCurrentID + "').");
526  }
527  } else if (exp.pos == 0) {
528  if (e->getNumLanes() < exp.lanes.size()) {
529  e->incLaneNo((int) exp.lanes.size() - e->getNumLanes());
530  } else {
531  e->decLaneNo(e->getNumLanes() - (int) exp.lanes.size());
532  }
533  currLanes = exp.lanes;
534  } else {
535  WRITE_WARNING("Split at '" + toString(exp.pos) + "' lies beyond the edge's length (edge '" + myCurrentID + "').");
536  }
537  }
538  // patch lane offsets
539  e = myEdgeCont.retrieve(edgeid);
540  i = mySplits.begin();
541  if ((*i).pos != 0) {
542  e = e->getToNode()->getOutgoingEdges()[0];
543  }
544  for (; i != mySplits.end(); ++i) {
545  unsigned int maxLeft = (*i).lanes.back();
546  SUMOReal offset = 0;
547  if (maxLeft < noLanesMax) {
549  offset = SUMO_const_laneWidthAndOffset * (noLanesMax - 1 - maxLeft);
550  } else {
551  offset = SUMO_const_halfLaneAndOffset * (noLanesMax - 1 - maxLeft);
552  }
553  }
554  unsigned int maxRight = (*i).lanes.front();
555  if (maxRight > 0 && e->getLaneSpreadFunction() == LANESPREAD_CENTER) {
556  offset -= SUMO_const_halfLaneAndOffset * maxRight;
557  }
558  if (offset != 0) {
559  PositionVector g = e->getGeometry();
560  g.move2side(offset);
561  e->setGeometry(g);
562  }
563  if (e->getToNode()->getOutgoingEdges().size() != 0) {
564  e = e->getToNode()->getOutgoingEdges()[0];
565  }
566  }
567  }
568  }
569 }
570 
571 /****************************************************************************/
572