SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NBAlgorithms_Ramps.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // Algorithms for highway on-/off-ramps computation
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo-sim.org/
12 // Copyright (C) 2012-2014 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <cassert>
36 #include "NBNetBuilder.h"
37 #include "NBNodeCont.h"
38 #include "NBNode.h"
39 #include "NBEdge.h"
40 #include "NBAlgorithms_Ramps.h"
41 
42 #ifdef CHECK_MEMORY_LEAKS
43 #include <foreign/nvwa/debug_new.h>
44 #endif // CHECK_MEMORY_LEAKS
45 
46 
47 // ===========================================================================
48 // static members
49 // ===========================================================================
50 const std::string NBRampsComputer::ADDED_ON_RAMP_EDGE("-AddedOnRampEdge");
51 
52 // ===========================================================================
53 // method definitions
54 // ===========================================================================
55 // ---------------------------------------------------------------------------
56 // NBRampsComputer
57 // ---------------------------------------------------------------------------
58 void
60  SUMOReal minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
61  SUMOReal maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
62  SUMOReal rampLength = oc.getFloat("ramps.ramp-length");
63  bool dontSplit = oc.getBool("ramps.no-split");
64  std::set<NBEdge*> incremented;
65  // check whether on-off ramps shall be guessed
66  if (oc.getBool("ramps.guess")) {
67  NBNodeCont& nc = nb.getNodeCont();
68  NBEdgeCont& ec = nb.getEdgeCont();
70  std::set<NBNode*> potOnRamps;
71  std::set<NBNode*> potOffRamps;
72  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
73  NBNode* cur = (*i).second;
74  if (mayNeedOnRamp(cur, minHighwaySpeed, maxRampSpeed)) {
75  potOnRamps.insert(cur);
76  }
77  if (mayNeedOffRamp(cur, minHighwaySpeed, maxRampSpeed)) {
78  potOffRamps.insert(cur);
79  }
80  }
81  for (std::set<NBNode*>::const_iterator i = potOnRamps.begin(); i != potOnRamps.end(); ++i) {
82  buildOnRamp(*i, nc, ec, dc, rampLength, dontSplit, incremented);
83  }
84  for (std::set<NBNode*>::const_iterator i = potOffRamps.begin(); i != potOffRamps.end(); ++i) {
85  buildOffRamp(*i, nc, ec, dc, rampLength, dontSplit, incremented);
86  }
87  }
88  // check whether on-off ramps shall be guessed
89  if (oc.isSet("ramps.set")) {
90  std::vector<std::string> edges = oc.getStringVector("ramps.set");
91  NBNodeCont& nc = nb.getNodeCont();
92  NBEdgeCont& ec = nb.getEdgeCont();
94  for (std::vector<std::string>::iterator i = edges.begin(); i != edges.end(); ++i) {
95  NBEdge* e = ec.retrieve(*i);
96  if (e == 0) {
97  WRITE_WARNING("Can not build on ramp on edge '" + *i + "' - the edge is not known.");
98  continue;
99  }
100  NBNode* from = e->getFromNode();
101  if (from->getIncomingEdges().size() == 2 && from->getOutgoingEdges().size() == 1) {
102  buildOnRamp(from, nc, ec, dc, rampLength, dontSplit, incremented);
103  }
104  // load edge again to check offramps
105  e = ec.retrieve(*i);
106  if (e == 0) {
107  WRITE_WARNING("Can not build off ramp on edge '" + *i + "' - the edge is not known.");
108  continue;
109  }
110  NBNode* to = e->getToNode();
111  if (to->getIncomingEdges().size() == 1 && to->getOutgoingEdges().size() == 2) {
112  buildOffRamp(to, nc, ec, dc, rampLength, dontSplit, incremented);
113  }
114  }
115  }
116 }
117 
118 
119 bool
120 NBRampsComputer::mayNeedOnRamp(NBNode* cur, SUMOReal minHighwaySpeed, SUMOReal maxRampSpeed) {
121  if (cur->getOutgoingEdges().size() != 1 || cur->getIncomingEdges().size() != 2) {
122  return false;
123  }
124  NBEdge* potHighway, *potRamp, *cont;
125  getOnRampEdges(cur, &potHighway, &potRamp, &cont);
126  // may be an on-ramp
127  return fulfillsRampConstraints(potHighway, potRamp, cont, minHighwaySpeed, maxRampSpeed);
128 }
129 
130 
131 bool
132 NBRampsComputer::mayNeedOffRamp(NBNode* cur, SUMOReal minHighwaySpeed, SUMOReal maxRampSpeed) {
133  if (cur->getIncomingEdges().size() != 1 || cur->getOutgoingEdges().size() != 2) {
134  return false;
135  }
136  // may be an off-ramp
137  NBEdge* potHighway, *potRamp, *prev;
138  getOffRampEdges(cur, &potHighway, &potRamp, &prev);
139  return fulfillsRampConstraints(potHighway, potRamp, prev, minHighwaySpeed, maxRampSpeed);
140 }
141 
142 
143 void
144 NBRampsComputer::buildOnRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, SUMOReal rampLength, bool dontSplit, std::set<NBEdge*>& incremented) {
145  NBEdge* potHighway, *potRamp, *cont;
146  getOnRampEdges(cur, &potHighway, &potRamp, &cont);
147  // compute the number of lanes to append
148  const unsigned int firstLaneNumber = cont->getNumLanes();
149  int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber;
150  NBEdge* first = cont;
151  NBEdge* last = cont;
152  NBEdge* curr = cont;
153  if (toAdd > 0 && find(incremented.begin(), incremented.end(), cont) == incremented.end()) {
154  SUMOReal currLength = 0;
155  while (curr != 0 && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) {
156  if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
157  curr->incLaneNo(toAdd);
158  curr->invalidateConnections(true);
159  incremented.insert(curr);
160  moveRampRight(curr, toAdd);
161  currLength += curr->getLength(); // !!! loaded length?
162  last = curr;
163  }
164  NBNode* nextN = curr->getToNode();
165  if (nextN->getOutgoingEdges().size() == 1) {
166  curr = nextN->getOutgoingEdges()[0];
167  if (curr->getNumLanes() != firstLaneNumber) {
168  // the number of lanes changes along the computation; we'll stop...
169  curr = 0;
170  } else if (curr->isTurningDirectionAt(nextN, last)) {
171  // turnarounds certainly should not be included in a ramp
172  curr = 0;
173  } else if (curr == potHighway || curr == potRamp) {
174  // circular connectivity. do not split!
175  curr = 0;
176  }
177  } else {
178  // ambigous; and, in fact, what should it be? ...stop
179  curr = 0;
180  }
181  }
182  // check whether a further split is necessary
183  if (curr != 0 && !dontSplit && currLength - POSITION_EPS < rampLength && curr->getNumLanes() == firstLaneNumber && find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
184  // there is enough place to build a ramp; do it
185  bool wasFirst = first == curr;
186  NBNode* rn = new NBNode(curr->getID() + "-AddedOnRampNode", curr->getGeometry().positionAtOffset(rampLength - currLength));
187  if (!nc.insert(rn)) {
188  throw ProcessError("Ups - could not build on-ramp for edge '" + curr->getID() + "' (node could not be build)!");
189  }
190  std::string name = curr->getID();
191  bool ok = ec.splitAt(dc, curr, rn, curr->getID() + ADDED_ON_RAMP_EDGE, curr->getID(), curr->getNumLanes() + toAdd, curr->getNumLanes());
192  if (!ok) {
193  WRITE_ERROR("Ups - could not build on-ramp for edge '" + curr->getID() + "'!");
194  return;
195  }
196  //ec.retrieve(name)->invalidateConnections();
197  curr = ec.retrieve(name + ADDED_ON_RAMP_EDGE);
198  curr->invalidateConnections(true);
199  incremented.insert(curr);
200  last = curr;
201  moveRampRight(curr, toAdd);
202  if (wasFirst) {
203  first = curr;
204  }
205  }
206  if (curr == cont && dontSplit) {
207  WRITE_WARNING("Could not build on-ramp for edge '" + curr->getID() + "' due to option '--ramps.no-split'");
208  return;
209  }
210  }
211  // set connections from ramp/highway to added ramp
212  if (!potHighway->addLane2LaneConnections(0, first, potRamp->getNumLanes(), MIN2(first->getNumLanes() - potRamp->getNumLanes(), potHighway->getNumLanes()), NBEdge::L2L_VALIDATED, true, true)) {
213  throw ProcessError("Could not set connection!");
214  }
215  if (!potRamp->addLane2LaneConnections(0, first, 0, potRamp->getNumLanes(), NBEdge::L2L_VALIDATED, true, true)) {
216  throw ProcessError("Could not set connection!");
217  }
218  // patch ramp geometry
219  PositionVector p = potRamp->getGeometry();
220  p.pop_back();
221  p.push_back(first->getLaneShape(0)[0]);
222  potRamp->setGeometry(p);
223  // set connections from added ramp to following highway
224  NBNode* nextN = last->getToNode();
225  if (nextN->getOutgoingEdges().size() == 1) {
226  NBEdge* next = nextN->getOutgoingEdges()[0];//const EdgeVector& o1 = cont->getToNode()->getOutgoingEdges();
227  if (next->getNumLanes() < last->getNumLanes()) {
228  last->addLane2LaneConnections(last->getNumLanes() - next->getNumLanes(), next, 0, next->getNumLanes(), NBEdge::L2L_VALIDATED);
229  }
230  }
231 }
232 
233 
234 void
235 NBRampsComputer::buildOffRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, SUMOReal rampLength, bool dontSplit, std::set<NBEdge*>& incremented) {
236  NBEdge* potHighway, *potRamp, *prev;
237  getOffRampEdges(cur, &potHighway, &potRamp, &prev);
238  // compute the number of lanes to append
239  const unsigned int firstLaneNumber = prev->getNumLanes();
240  int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber;
241  NBEdge* first = prev;
242  NBEdge* last = prev;
243  NBEdge* curr = prev;
244  if (toAdd > 0 && find(incremented.begin(), incremented.end(), prev) == incremented.end()) {
245  SUMOReal currLength = 0;
246  while (curr != 0 && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) {
247  if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
248  curr->incLaneNo(toAdd);
249  curr->invalidateConnections(true);
250  incremented.insert(curr);
251  moveRampRight(curr, toAdd);
252  currLength += curr->getLength(); // !!! loaded length?
253  last = curr;
254  }
255  NBNode* prevN = curr->getFromNode();
256  if (prevN->getIncomingEdges().size() == 1) {
257  curr = prevN->getIncomingEdges()[0];
258  if (curr->getNumLanes() != firstLaneNumber) {
259  // the number of lanes changes along the computation; we'll stop...
260  curr = 0;
261  } else if (last->isTurningDirectionAt(prevN, curr)) {
262  // turnarounds certainly should not be included in a ramp
263  curr = 0;
264  } else if (curr == potHighway || curr == potRamp) {
265  // circular connectivity. do not split!
266  curr = 0;
267  }
268  } else {
269  // ambigous; and, in fact, what should it be? ...stop
270  curr = 0;
271  }
272  }
273  // check whether a further split is necessary
274  if (curr != 0 && !dontSplit && currLength - POSITION_EPS < rampLength && curr->getNumLanes() == firstLaneNumber && find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
275  // there is enough place to build a ramp; do it
276  bool wasFirst = first == curr;
277  Position pos = curr->getGeometry().positionAtOffset(curr->getGeometry().length() - (rampLength - currLength));
278  NBNode* rn = new NBNode(curr->getID() + "-AddedOffRampNode", pos);
279  if (!nc.insert(rn)) {
280  throw ProcessError("Ups - could not build on-ramp for edge '" + curr->getID() + "' (node could not be build)!");
281  }
282  std::string name = curr->getID();
283  bool ok = ec.splitAt(dc, curr, rn, curr->getID(), curr->getID() + "-AddedOffRampEdge", curr->getNumLanes(), curr->getNumLanes() + toAdd);
284  if (!ok) {
285  WRITE_ERROR("Ups - could not build on-ramp for edge '" + curr->getID() + "'!");
286  return;
287  }
288  curr = ec.retrieve(name + "-AddedOffRampEdge");
289  curr->invalidateConnections(true);
290  incremented.insert(curr);
291  last = curr;
292  moveRampRight(curr, toAdd);
293  if (wasFirst) {
294  first = curr;
295  }
296  }
297  if (curr == prev && dontSplit) {
298  WRITE_WARNING("Could not build off-ramp for edge '" + curr->getID() + "' due to option '--ramps.no-split'");
299  return;
300  }
301  }
302  // set connections from added ramp to ramp/highway
303  if (!first->addLane2LaneConnections(potRamp->getNumLanes(), potHighway, 0, MIN2(first->getNumLanes() - 1, potHighway->getNumLanes()), NBEdge::L2L_VALIDATED, true)) {
304  throw ProcessError("Could not set connection!");
305  }
306  if (!first->addLane2LaneConnections(0, potRamp, 0, potRamp->getNumLanes(), NBEdge::L2L_VALIDATED, false)) {
307  throw ProcessError("Could not set connection!");
308  }
309  // patch ramp geometry
310  PositionVector p = potRamp->getGeometry();
311  p.pop_front();
312  p.push_front(first->getLaneShape(0)[-1]);
313  potRamp->setGeometry(p);
314  // set connections from previous highway to added ramp
315  NBNode* prevN = last->getFromNode();
316  if (prevN->getIncomingEdges().size() == 1) {
317  NBEdge* prev = prevN->getIncomingEdges()[0];//const EdgeVector& o1 = cont->getToNode()->getOutgoingEdges();
318  if (prev->getNumLanes() < last->getNumLanes()) {
319  last->addLane2LaneConnections(last->getNumLanes() - prev->getNumLanes(), last, 0, prev->getNumLanes(), NBEdge::L2L_VALIDATED);
320  }
321  }
322 }
323 
324 
325 void
326 NBRampsComputer::moveRampRight(NBEdge* ramp, int addedLanes) {
327  if (ramp->getLaneSpreadFunction() != LANESPREAD_CENTER) {
328  return;
329  }
330  try {
331  PositionVector g = ramp->getGeometry();
332  SUMOReal factor = SUMO_const_laneWidthAndOffset * (SUMOReal)(addedLanes - 1) + SUMO_const_halfLaneAndOffset * (SUMOReal)(addedLanes % 2);
333  g.move2side(factor);
334  ramp->setGeometry(g);
335  } catch (InvalidArgument&) {
336  WRITE_WARNING("For edge '" + ramp->getID() + "': could not compute shape.");
337  }
338 }
339 
340 
341 bool
343  if (fabs((*potHighway)->getSpeed() - (*potRamp)->getSpeed()) < .1) {
344  return false;
345  }
346  if ((*potHighway)->getSpeed() < (*potRamp)->getSpeed()) {
347  std::swap(*potHighway, *potRamp);
348  }
349  return true;
350 }
351 
352 
353 bool
355  if ((*potHighway)->getNumLanes() == (*potRamp)->getNumLanes()) {
356  return false;
357  }
358  if ((*potHighway)->getNumLanes() < (*potRamp)->getNumLanes()) {
359  std::swap(*potHighway, *potRamp);
360  }
361  return true;
362 }
363 
364 
365 void
366 NBRampsComputer::getOnRampEdges(NBNode* n, NBEdge** potHighway, NBEdge** potRamp, NBEdge** other) {
367  *other = n->getOutgoingEdges()[0];
368  const std::vector<NBEdge*>& edges = n->getIncomingEdges();
369  assert(edges.size() == 2);
370  *potHighway = edges[0];
371  *potRamp = edges[1];
372  /*
373  // heuristic: highway is faster than ramp
374  if(determinedBySpeed(potHighway, potRamp)) {
375  return;
376  }
377  // heuristic: highway has more lanes than ramp
378  if(determinedByLaneNumber(potHighway, potRamp)) {
379  return;
380  }
381  */
382  // heuristic: ramp comes from right
383  const std::vector<NBEdge*>& edges2 = n->getEdges();
384  std::vector<NBEdge*>::const_iterator i = std::find(edges2.begin(), edges2.end(), *other);
385  NBContHelper::nextCW(edges2, i);
386  if ((*i) == *potHighway) {
387  std::swap(*potHighway, *potRamp);
388  }
389 }
390 
391 
392 void
393 NBRampsComputer::getOffRampEdges(NBNode* n, NBEdge** potHighway, NBEdge** potRamp, NBEdge** other) {
394  *other = n->getIncomingEdges()[0];
395  const std::vector<NBEdge*>& edges = n->getOutgoingEdges();
396  *potHighway = edges[0];
397  *potRamp = edges[1];
398  assert(edges.size() == 2);
399  /*
400  // heuristic: highway is faster than ramp
401  if(determinedBySpeed(potHighway, potRamp)) {
402  return;
403  }
404  // heuristic: highway has more lanes than ramp
405  if(determinedByLaneNumber(potHighway, potRamp)) {
406  return;
407  }
408  */
409  // heuristic: ramp goes to right
410  const std::vector<NBEdge*>& edges2 = n->getEdges();
411  std::vector<NBEdge*>::const_iterator i = std::find(edges2.begin(), edges2.end(), *other);
412  NBContHelper::nextCW(edges2, i);
413  if ((*i) == *potRamp) {
414  std::swap(*potHighway, *potRamp);
415  }
416 }
417 
418 
419 bool
421  NBEdge* potHighway, NBEdge* potRamp, NBEdge* other, SUMOReal minHighwaySpeed, SUMOReal maxRampSpeed) {
422  // do not build ramps on rail edges
423  if (isRailway(potHighway->getPermissions()) || isRailway(potRamp->getPermissions())) {
424  return false;
425  }
426  // do not build ramps on connectors
427  if (potHighway->isMacroscopicConnector() || potRamp->isMacroscopicConnector() || other->isMacroscopicConnector()) {
428  return false;
429  }
430  // check whether a lane is missing
431  if (potHighway->getNumLanes() + potRamp->getNumLanes() <= other->getNumLanes()) {
432  return false;
433  }
434  // is it really a highway?
435  SUMOReal maxSpeed = MAX3(potHighway->getSpeed(), other->getSpeed(), potRamp->getSpeed());
436  if (maxSpeed < minHighwaySpeed) {
437  return false;
438  }
439  // is any of the connections a turnaround?
440  if (other->getToNode() == potHighway->getFromNode()) {
441  // off ramp
442  if (other->isTurningDirectionAt(other->getToNode(), potHighway) ||
443  other->isTurningDirectionAt(other->getToNode(), potRamp)) {
444  return false;
445  }
446  } else {
447  // on ramp
448  if (other->isTurningDirectionAt(other->getFromNode(), potHighway) ||
449  other->isTurningDirectionAt(other->getFromNode(), potRamp)) {
450  return false;
451  }
452  }
453  /*
454  if (potHighway->getSpeed() < minHighwaySpeed || other->getSpeed() < minHighwaySpeed) {
455  return false;
456  }
457  */
458  // is it really a ramp?
459  if (maxRampSpeed > 0 && maxRampSpeed < potRamp->getSpeed()) {
460  return false;
461  }
462  return true;
463 }
464 
465 
466 /****************************************************************************/
467