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  myHaveWarnedAboutDeprecatedSpreadType(false),
80  myHaveWarnedAboutDeprecatedFromTo(false),
81  myHaveWarnedAboutDeprecatedNoLanes(false),
82  myHaveWarnedAboutDeprecatedLaneId(false) {}
83 
84 
86 
87 
88 void
90  const SUMOSAXAttributes& attrs) {
91  switch (element) {
92  case SUMO_TAG_EDGE:
93  addEdge(attrs);
94  break;
95  case SUMO_TAG_LANE:
96  addLane(attrs);
97  break;
98  case SUMO_TAG_SPLIT:
99  addSplit(attrs);
100  break;
101  case SUMO_TAG_DELETE:
102  deleteEdge(attrs);
103  break;
104  default:
105  break;
106  }
107 }
108 
109 
110 void
112  myIsUpdate = false;
113  bool ok = true;
114  // initialise the edge
115  myCurrentEdge = 0;
116  mySplits.clear();
117  // get the id, report an error if not given or empty...
119  if (!ok) {
120  return;
121  }
123  // check deprecated (unused) attributes
124  // use default values, first
131  myCurrentType = "";
135  myCurrentStreetName = "";
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  }
177  }
179  }
180  // speed, priority and the number of lanes have now default values;
181  // try to read the real values from the file
182  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
184  }
185  if (myOptions.getBool("speed-in-kmh")) {
187  }
188  // try to get the number of lanes
193  WRITE_WARNING("'" + toString(SUMO_ATTR_NOLANES__DEPRECATED) + "' is deprecated, please use '" + toString(SUMO_ATTR_NUMLANES) + "' instead.");
194  }
195  }
196  if (attrs.hasAttribute(SUMO_ATTR_NUMLANES)) {
198  }
199  // try to get the priority
200  if (attrs.hasAttribute(SUMO_ATTR_PRIORITY)) {
202  }
203  // try to get the width
204  if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
206  }
207  // try to get the width
208  if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
210  }
211  // try to get the street name
213 
214  // try to get the allowed/disallowed classes
216  std::string allowS = attrs.hasAttribute(SUMO_ATTR_ALLOW) ? attrs.getStringSecure(SUMO_ATTR_ALLOW, "") : "";
217  std::string disallowS = attrs.hasAttribute(SUMO_ATTR_DISALLOW) ? attrs.getStringSecure(SUMO_ATTR_DISALLOW, "") : "";
218  // XXX matter of interpretation: should updated permissions replace or extend previously set permissions?
219  myPermissions = parseVehicleClasses(allowS, disallowS);
220  }
221  // try to set the nodes
222  if (!setNodes(attrs)) {
223  // return if this failed
224  return;
225  }
226  // try to get the shape
227  myShape = tryGetShape(attrs);
228  // try to get the spread type
230  // try to get the length
232  // insert the parsed edge into the edges map
233  if (!ok) {
234  return;
235  }
236  // check whether a previously defined edge shall be overwritten
237  if (myCurrentEdge != 0) {
242  OptionsCont::getOptions().getBool("plain.keep-edge-shape"));
243  } else {
244  // the edge must be allocated in dependence to whether a shape is given
245  if (myShape.size() == 0) {
249  } else {
253  OptionsCont::getOptions().getBool("plain.keep-edge-shape"));
254  }
255  }
258 }
259 
260 
261 void
263  if (myCurrentEdge == 0) {
264  if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
265  WRITE_ERROR("Additional lane information could not been set - the edge with id '" + myCurrentID + "' is not known.");
266  }
267  return;
268  }
269  bool ok = true;
270  int lane;
271  if (attrs.hasAttribute(SUMO_ATTR_ID)) {
272  lane = attrs.getIntReporting(SUMO_ATTR_ID, myCurrentID.c_str(), ok);
275  WRITE_WARNING("'" + toString(SUMO_ATTR_ID) + "' is deprecated, please use '" + toString(SUMO_ATTR_INDEX) + "' instead.");
276  }
277  } else {
278  lane = attrs.getIntReporting(SUMO_ATTR_INDEX, myCurrentID.c_str(), ok);
279  }
280  std::string allowed, disallowed, preferred;
281  allowed = attrs.getOptStringReporting(SUMO_ATTR_ALLOW, 0, ok, "");
282  disallowed = attrs.getOptStringReporting(SUMO_ATTR_DISALLOW, 0, ok, "");
283  preferred = attrs.getOptStringReporting(SUMO_ATTR_PREFER, 0, ok, "");
284  if (!ok) {
285  return;
286  }
287  // check whether this lane exists
288  if (lane >= (int) myCurrentEdge->getNumLanes()) {
289  WRITE_ERROR("Lane index is larger than number of lanes (edge '" + myCurrentID + "').");
290  return;
291  }
292  // set information about allowed / disallowed vehicle classes
293  myCurrentEdge->setPermissions(parseVehicleClasses(allowed, disallowed), lane);
295  // try to get the width
296  if (attrs.hasAttribute(SUMO_ATTR_WIDTH)) {
298  }
299  // try to get the end-offset (lane shortened due to pedestrian crossing etc..)
300  if (attrs.hasAttribute(SUMO_ATTR_ENDOFFSET)) {
302  }
303  // try to get lane specific speed (should not occur for german networks)
304  if (attrs.hasAttribute(SUMO_ATTR_SPEED)) {
306  }
307 }
308 
309 
311  if (myCurrentEdge == 0) {
312  WRITE_WARNING("Ignoring 'split' because it cannot be assigned to an edge");
313  return;
314  }
315  bool ok = true;
316  Split e;
317  e.pos = attrs.getSUMORealReporting(SUMO_ATTR_POSITION, 0, ok);
318  if (ok) {
319  if (fabs(e.pos) > myCurrentEdge->getGeometry().length()) {
320  WRITE_ERROR("Edge '" + myCurrentID + "' has a split at invalid position " + toString(e.pos) + ".");
321  return;
322  }
323  std::vector<Split>::iterator i = find_if(mySplits.begin(), mySplits.end(), split_by_pos_finder(e.pos));
324  if (i != mySplits.end()) {
325  WRITE_ERROR("Edge '" + myCurrentID + "' has already a split at position " + toString(e.pos) + ".");
326  return;
327  }
328  e.nameid = (int)e.pos;
329  if (myCurrentEdge == 0) {
330  if (!OptionsCont::getOptions().isInStringVector("remove-edges.explicit", myCurrentID)) {
331  WRITE_ERROR("Additional lane information could not been set - the edge with id '" + myCurrentID + "' is not known.");
332  }
333  return;
334  }
335  if (e.pos < 0) {
337  }
338  std::vector<std::string> lanes;
340  for (std::vector<std::string>::iterator i = lanes.begin(); i != lanes.end(); ++i) {
341  try {
342  int lane = TplConvert<char>::_2int((*i).c_str());
343  e.lanes.push_back(lane);
344  } catch (NumberFormatException&) {
345  WRITE_ERROR("Error on parsing a split (edge '" + myCurrentID + "').");
346  } catch (EmptyData&) {
347  WRITE_ERROR("Error on parsing a split (edge '" + myCurrentID + "').");
348  }
349  }
350  if (e.lanes.empty()) {
351  for (size_t l = 0; l < myCurrentEdge->getNumLanes(); ++l) {
352  e.lanes.push_back((int) l);
353  }
354  }
355  mySplits.push_back(e);
356  }
357 }
358 
359 
360 bool
362  // the names and the coordinates of the beginning and the end node
363  // may be found, try
364  bool ok = true;
365  std::string begNodeID = myIsUpdate ? myCurrentEdge->getFromNode()->getID() : "";
366  std::string endNodeID = myIsUpdate ? myCurrentEdge->getToNode()->getID() : "";
367  std::string oldBegID = begNodeID;
368  std::string oldEndID = endNodeID;
369  if (attrs.hasAttribute(SUMO_ATTR_FROMNODE)) {
370  begNodeID = attrs.getStringReporting(SUMO_ATTR_FROMNODE, 0, ok);
372  WRITE_WARNING("'" + toString(SUMO_ATTR_FROMNODE) + "' is deprecated; please use '" + toString(SUMO_ATTR_FROM) + "'.");
374  }
375  }
376  if (attrs.hasAttribute(SUMO_ATTR_TONODE)) {
377  endNodeID = attrs.getStringReporting(SUMO_ATTR_TONODE, 0, ok);
379  WRITE_WARNING("'" + toString(SUMO_ATTR_TONODE) + "' is deprecated; please use '" + toString(SUMO_ATTR_TO) + "'.");
381  }
382  }
383  begNodeID = attrs.hasAttribute(SUMO_ATTR_FROM) ? attrs.getStringReporting(SUMO_ATTR_FROM, 0, ok) : begNodeID;
384  endNodeID = attrs.hasAttribute(SUMO_ATTR_TO) ? attrs.getStringReporting(SUMO_ATTR_TO, 0, ok) : endNodeID;
385  if (!ok) {
386  return false;
387  }
388  // or their positions !!! deprecated
389  SUMOReal begNodeXPos = tryGetPosition(attrs, SUMO_ATTR_XFROM, "XFrom");
390  SUMOReal begNodeYPos = tryGetPosition(attrs, SUMO_ATTR_YFROM, "YFrom");
391  SUMOReal endNodeXPos = tryGetPosition(attrs, SUMO_ATTR_XTO, "XTo");
392  SUMOReal endNodeYPos = tryGetPosition(attrs, SUMO_ATTR_YTO, "YTo");
393  if (begNodeXPos != SUMOXML_INVALID_POSITION && begNodeYPos != SUMOXML_INVALID_POSITION) {
394  Position pos(begNodeXPos, begNodeYPos);
396  begNodeXPos = pos.x();
397  begNodeYPos = pos.y();
399  WRITE_WARNING("'" + toString(SUMO_ATTR_XFROM) + "' and '" + toString(SUMO_ATTR_YFROM) + "' are deprecated; please define nodes separately.");
401  }
402  }
403  if (endNodeXPos != SUMOXML_INVALID_POSITION && endNodeYPos != SUMOXML_INVALID_POSITION) {
404  Position pos(endNodeXPos, endNodeYPos);
406  endNodeXPos = pos.x();
407  endNodeYPos = pos.y();
409  WRITE_WARNING("'" + toString(SUMO_ATTR_XTO) + "' and '" + toString(SUMO_ATTR_YTO) + "' are deprecated; please define nodes separately.");
411  }
412  }
413  // check the obtained values for nodes
414  myFromNode = insertNodeChecking(Position(begNodeXPos, begNodeYPos), begNodeID, "from");
415  myToNode = insertNodeChecking(Position(endNodeXPos, endNodeYPos), endNodeID, "to");
416  if (myFromNode != 0 && myToNode != 0) {
417  if (myIsUpdate && (myFromNode->getID() != oldBegID || myToNode->getID() != oldEndID)) {
419  }
420  }
421  return myFromNode != 0 && myToNode != 0;
422 }
423 
424 
425 SUMOReal
427  const std::string& attrName) {
428  UNUSED_PARAMETER(attrName);
429  bool ok = true;
430  return attrs.getOptSUMORealReporting(attrID, myCurrentID.c_str(), ok, SUMOXML_INVALID_POSITION);
431 }
432 
433 
434 NBNode*
436  const std::string& name, const std::string& dir) {
437  NBNode* ret = 0;
438  if (name == "" && (pos.x() == SUMOXML_INVALID_POSITION || pos.y() == SUMOXML_INVALID_POSITION)) {
439  WRITE_ERROR("Neither the name nor the position of the " + dir + "-node is given for edge '" + myCurrentID + "'.");
440  return ret;
441  }
442  if (name != "") {
443  if (pos.x() != SUMOXML_INVALID_POSITION && pos.y() != SUMOXML_INVALID_POSITION) {
444  // the node is named and it has a position given
445  if (!myNodeCont.insert(name, pos)) {
446  WRITE_ERROR("Position of " + dir + "-node '" + name + "' mismatches previous positions.");
447  return 0;
448  }
449  }
450  // the node is given by its name
451  ret = myNodeCont.retrieve(name);
452  if (ret == 0) {
453  WRITE_ERROR("Edge's '" + myCurrentID + "' " + dir + "-node '" + name + "' is not known.");
454  }
455  } else {
456  ret = myNodeCont.retrieve(pos);
457  if (ret == 0) {
458  ret = new NBNode(myNodeCont.getFreeID(), pos);
459  if (!myNodeCont.insert(ret)) {
460  WRITE_ERROR("Could not insert " + dir + "-node at position " + toString(pos) + ".");
461  delete ret;
462  return 0;
463  }
464  }
465  }
466  return ret;
467 }
468 
469 
472  if (!attrs.hasAttribute(SUMO_ATTR_SHAPE)) {
473  return myShape;
474  }
475  // try to build shape
476  bool ok = true;
477  std::string shpdef = attrs.getOptStringReporting(SUMO_ATTR_SHAPE, 0, ok, "");
478  if (shpdef == "") {
479  return PositionVector();
480  }
481  PositionVector shape = GeomConvHelper::parseShapeReporting(shpdef, attrs.getObjectType(), 0, ok, true);
482  if (!NILoader::transformCoordinates(shape)) {
483  WRITE_ERROR("Unable to project coordinates for edge '" + myCurrentID + "'.");
484  }
485  return shape;
486 }
487 
488 
491  bool ok = true;
493  std::string lsfS = toString(result);
497  WRITE_WARNING("'" + toString(SUMO_ATTR_SPREADFUNC__DEPRECATED) + " is deprecated; please use '" + toString(SUMO_ATTR_SPREADTYPE) + "'.");
499  }
500  } else {
501  lsfS = attrs.getOptStringReporting(SUMO_ATTR_SPREADTYPE, myCurrentID.c_str(), ok, lsfS);
502  }
503  if (SUMOXMLDefinitions::LaneSpreadFunctions.hasString(lsfS)) {
505  } else {
506  WRITE_WARNING("Ignoring unknown spreadType '" + lsfS + "' for edge '" + myCurrentID + "'.");
507  }
508  return result;
509 }
510 
511 
512 void
514  bool ok = true;
516  if (!ok) {
517  return;
518  }
520  if (edge == 0) {
521  WRITE_WARNING("Ignoring tag '" + toString(SUMO_TAG_DELETE) + "' for unknown edge '" +
522  myCurrentID + "'");
523  return;
524  }
525  myEdgeCont.extract(myDistrictCont, edge, true);
526 }
527 
528 
529 void
531  if (element == SUMO_TAG_EDGE && myCurrentEdge != 0) {
532  if (!myIsUpdate) {
533  try {
535  WRITE_ERROR("Duplicate edge occured. ID='" + myCurrentID + "'");
536  delete myCurrentEdge;
537  }
538  } catch (InvalidArgument& e) {
539  WRITE_ERROR(e.what());
540  throw;
541  } catch (...) {
542  WRITE_ERROR("An important information is missing in edge '" + myCurrentID + "'.");
543  }
544  }
545  if (mySplits.size() != 0) {
546  std::vector<Split>::iterator i;
547  NBEdge* e = myCurrentEdge;
548  SUMOReal length = e->getLength();
549  sort(mySplits.begin(), mySplits.end(), split_sorter());
550  unsigned int noLanesMax = e->getNumLanes();
551  // compute the node positions and sort the lanes
552  for (i = mySplits.begin(); i != mySplits.end(); ++i) {
553  (*i).gpos = e->getGeometry().positionAtLengthPosition((*i).pos);
554  sort((*i).lanes.begin(), (*i).lanes.end());
555  noLanesMax = MAX2(noLanesMax, (unsigned int)(*i).lanes.size());
556  }
557  // split the edge
558  std::vector<int> currLanes;
559  for (unsigned int l = 0; l < e->getNumLanes(); ++l) {
560  currLanes.push_back(l);
561  }
562  std::string edgeid = e->getID();
563  SUMOReal seen = 0;
564  for (i = mySplits.begin(); i != mySplits.end(); ++i) {
565  const Split& exp = *i;
566  assert(exp.lanes.size() != 0);
567  if (exp.pos > 0 && e->getGeometry().length() + seen > exp.pos && exp.pos > seen) {
568  std::string nid = edgeid + "." + toString(exp.nameid);
569  NBNode* rn = new NBNode(nid, exp.gpos);
570  if (myNodeCont.insert(rn)) {
571  // split the edge
572  std::string nid = myCurrentID + "." + toString(exp.nameid);
573  std::string pid = e->getID();
574  myEdgeCont.splitAt(myDistrictCont, e, exp.pos - seen, rn,
575  pid, nid, e->getNumLanes(), (unsigned int) exp.lanes.size());
576  seen = exp.pos;
577  std::vector<int> newLanes = exp.lanes;
578  NBEdge* pe = myEdgeCont.retrieve(pid);
579  NBEdge* ne = myEdgeCont.retrieve(nid);
580  // reconnect lanes
581  pe->invalidateConnections(true);
582  // new on right
583  unsigned int rightMostP = currLanes[0];
584  unsigned int rightMostN = newLanes[0];
585  for (int l = 0; l < (int) rightMostP - (int) rightMostN; ++l) {
586  pe->addLane2LaneConnection(0, ne, l, NBEdge::L2L_VALIDATED, true);
587  }
588  // new on left
589  unsigned int leftMostP = currLanes.back();
590  unsigned int leftMostN = newLanes.back();
591  for (int l = 0; l < (int) leftMostN - (int) leftMostP; ++l) {
592  pe->addLane2LaneConnection(pe->getNumLanes() - 1, ne, leftMostN - l - rightMostN, NBEdge::L2L_VALIDATED, true);
593  }
594  // all other connected
595  for (unsigned int l = 0; l < noLanesMax; ++l) {
596  if (find(currLanes.begin(), currLanes.end(), l) == currLanes.end()) {
597  continue;
598  }
599  if (find(newLanes.begin(), newLanes.end(), l) == newLanes.end()) {
600  continue;
601  }
602  pe->addLane2LaneConnection(l - rightMostP, ne, l - rightMostN, NBEdge::L2L_VALIDATED, true);
603  }
604  // move to next
605  e = ne;
606  currLanes = newLanes;
607  } else {
608  WRITE_WARNING("Error on parsing a split (edge '" + myCurrentID + "').");
609  }
610  } else if (exp.pos == 0) {
611  if (e->getNumLanes() < exp.lanes.size()) {
612  e->incLaneNo((int) exp.lanes.size() - e->getNumLanes());
613  } else {
614  e->decLaneNo(e->getNumLanes() - (int) exp.lanes.size());
615  }
616  currLanes = exp.lanes;
617  } else {
618  WRITE_WARNING("Split at '" + toString(exp.pos) + "' lies beyond the edge's length (edge '" + myCurrentID + "').");
619  }
620  }
621  // patch lane offsets
622  e = myEdgeCont.retrieve(edgeid);
623  i = mySplits.begin();
624  if ((*i).pos != 0) {
625  e = e->getToNode()->getOutgoingEdges()[0];
626  }
627  for (; i != mySplits.end(); ++i) {
628  unsigned int maxLeft = (*i).lanes.back();
629  if (maxLeft < noLanesMax) {
630  PositionVector g = e->getGeometry();
631  g.move2side(SUMO_const_laneWidthAndOffset * (noLanesMax - 1 - maxLeft));
632  e->setGeometry(g);
633  }
634  if (e->getToNode()->getOutgoingEdges().size() != 0) {
635  e = e->getToNode()->getOutgoingEdges()[0];
636  }
637  }
638  }
639  }
640 }
641 
642 /****************************************************************************/
643