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