Eclipse SUMO - Simulation of Urban MObility
NBAlgorithms_Ramps.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2012-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
20 // Algorithms for highway on-/off-ramps computation
21 /****************************************************************************/
22 #include <config.h>
23 
24 #include <cassert>
27 #include <utils/common/ToString.h>
28 #include "NBNetBuilder.h"
29 #include "NBNodeCont.h"
30 #include "NBNode.h"
31 #include "NBEdge.h"
32 #include "NBAlgorithms_Ramps.h"
33 
34 #define OFFRAMP_LOOKBACK 500
35 
36 //#define DEBUG_RAMPS
37 #define DEBUGNODEID "260479469"
38 #define DEBUGCOND(obj) ((obj != 0 && (obj)->getID() == DEBUGNODEID))
39 
40 // ===========================================================================
41 // static members
42 // ===========================================================================
43 const std::string NBRampsComputer::ADDED_ON_RAMP_EDGE("-AddedOnRampEdge");
44 
45 // ===========================================================================
46 // method definitions
47 // ===========================================================================
48 // ---------------------------------------------------------------------------
49 // NBRampsComputer
50 // ---------------------------------------------------------------------------
51 void
52 NBRampsComputer::computeRamps(NBNetBuilder& nb, OptionsCont& oc, bool mayAddOrRemove) {
53  const bool guessAndAdd = oc.getBool("ramps.guess") && mayAddOrRemove;
54  const double minHighwaySpeed = oc.getFloat("ramps.min-highway-speed");
55  const double maxRampSpeed = oc.getFloat("ramps.max-ramp-speed");
56  const double rampLength = oc.getFloat("ramps.ramp-length");
57  const double minWeaveLength = oc.getFloat("ramps.min-weave-length");
58  const bool dontSplit = oc.getBool("ramps.no-split");
59  NBEdgeCont& ec = nb.getEdgeCont();
60  std::set<NBEdge*> incremented;
61  // collect join exclusions
62  std::set<std::string> noramps;
63  if (oc.isSet("ramps.unset")) {
64  std::vector<std::string> edges = oc.getStringVector("ramps.unset");
65  noramps.insert(edges.begin(), edges.end());
66  }
67  // exclude roundabouts
68  const std::set<EdgeSet>& roundabouts = ec.getRoundabouts();
69  for (std::set<EdgeSet>::const_iterator it_round = roundabouts.begin();
70  it_round != roundabouts.end(); ++it_round) {
71  for (EdgeSet::const_iterator it_edge = it_round->begin(); it_edge != it_round->end(); ++it_edge) {
72  noramps.insert((*it_edge)->getID());
73  }
74  }
75  // exclude public transport edges
76  nb.getPTStopCont().addEdges2Keep(oc, noramps);
77  nb.getPTLineCont().addEdges2Keep(oc, noramps);
78  nb.getParkingCont().addEdges2Keep(oc, noramps);
79 
80  // check whether on-off ramps shall be guessed
81  if (guessAndAdd || oc.getBool("ramps.guess-acceleration-lanes")) {
82  NBNodeCont& nc = nb.getNodeCont();
83  NBEdgeCont& ec = nb.getEdgeCont();
85  for (auto it = ec.begin(); it != ec.end(); ++it) {
86  it->second->markOffRamp(false);
87  }
88 
89  // if an edge is part of two ramps, ordering is important
90  std::set<NBNode*, ComparatorIdLess> potOnRamps;
91  std::set<NBNode*, ComparatorIdLess> potOffRamps;
92  for (std::map<std::string, NBNode*>::const_iterator i = nc.begin(); i != nc.end(); ++i) {
93  NBNode* cur = (*i).second;
94  if (mayNeedOnRamp(cur, minHighwaySpeed, maxRampSpeed, noramps, minWeaveLength)) {
95  potOnRamps.insert(cur);
96  }
97  if (mayNeedOffRamp(cur, minHighwaySpeed, maxRampSpeed, noramps)) {
98  potOffRamps.insert(cur);
99  }
100  }
101  for (std::set<NBNode*, ComparatorIdLess>::const_iterator i = potOnRamps.begin(); i != potOnRamps.end(); ++i) {
102  buildOnRamp(*i, nc, ec, dc, rampLength, dontSplit || !guessAndAdd, guessAndAdd);
103  }
104  for (std::set<NBNode*, ComparatorIdLess>::const_iterator i = potOffRamps.begin(); i != potOffRamps.end(); ++i) {
105  buildOffRamp(*i, nc, ec, dc, rampLength, dontSplit || !guessAndAdd, guessAndAdd, potOnRamps);
106  }
107  }
108  // check whether on-off ramps are specified
109  if (oc.isSet("ramps.set") && mayAddOrRemove) {
110  std::vector<std::string> edges = oc.getStringVector("ramps.set");
111  NBNodeCont& nc = nb.getNodeCont();
112  NBEdgeCont& ec = nb.getEdgeCont();
113  NBDistrictCont& dc = nb.getDistrictCont();
114  std::set<NBNode*, ComparatorIdLess> potOnRamps;
115  for (std::vector<std::string>::iterator i = edges.begin(); i != edges.end(); ++i) {
116  NBEdge* e = ec.retrieve(*i);
117  if (noramps.count(*i) != 0) {
118  WRITE_WARNING("Can not build ramp on edge '" + *i + "' - the edge is unsuitable.");
119  continue;
120  }
121  if (e == nullptr) {
122  WRITE_WARNING("Can not build on ramp on edge '" + *i + "' - the edge is not known.");
123  continue;
124  }
125  NBNode* from = e->getFromNode();
126  if (from->getIncomingEdges().size() == 2 && from->getOutgoingEdges().size() == 1) {
127  buildOnRamp(from, nc, ec, dc, rampLength, dontSplit, true);
128  potOnRamps.insert(from);
129  }
130  // load edge again to check offramps
131  e = ec.retrieve(*i);
132  if (e == nullptr) {
133  WRITE_WARNING("Can not build off ramp on edge '" + *i + "' - the edge is not known.");
134  continue;
135  }
136  NBNode* to = e->getToNode();
137  if (to->getIncomingEdges().size() == 1 && to->getOutgoingEdges().size() == 2) {
138  buildOffRamp(to, nc, ec, dc, rampLength, dontSplit, true, potOnRamps);
139  }
140  }
141  }
142 }
143 
144 
145 bool
146 NBRampsComputer::mayNeedOnRamp(NBNode* cur, double minHighwaySpeed, double maxRampSpeed, const std::set<std::string>& noramps, double minWeaveLength) {
147  if (cur->getOutgoingEdges().size() != 1 || cur->getIncomingEdges().size() != 2) {
148  return false;
149  }
150  NBEdge* potHighway, *potRamp, *cont;
151  getOnRampEdges(cur, &potHighway, &potRamp, &cont);
152  // may be an on-ramp
153  if (fulfillsRampConstraints(potHighway, potRamp, cont, minHighwaySpeed, maxRampSpeed, noramps)) {
154  // prevent short weaving section
155  double seen = cont->getLength();
156  while (seen < minWeaveLength) {
157  if (cont->getToNode()->getOutgoingEdges().size() > 1) {
158  return false;
159  } else if (cont->getToNode()->getOutgoingEdges().size() == 0) {
160  return true;
161  }
162  cont = cont->getToNode()->getOutgoingEdges().front();
163  seen += cont->getLength();
164  }
165  return true;
166  } else {
167  return false;
168  }
169 }
170 
171 
172 bool
173 NBRampsComputer::mayNeedOffRamp(NBNode* cur, double minHighwaySpeed, double maxRampSpeed, const std::set<std::string>& noramps) {
174  if (cur->getIncomingEdges().size() != 1 || cur->getOutgoingEdges().size() != 2) {
175  return false;
176  }
177  // may be an off-ramp
178  NBEdge* potHighway, *potRamp, *prev;
179  getOffRampEdges(cur, &potHighway, &potRamp, &prev);
180  return fulfillsRampConstraints(potHighway, potRamp, prev, minHighwaySpeed, maxRampSpeed, noramps);
181 }
182 
183 
184 void
185 NBRampsComputer::buildOnRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, double rampLength, bool dontSplit, bool addLanes) {
186  NBEdge* potHighway, *potRamp, *cont;
187  getOnRampEdges(cur, &potHighway, &potRamp, &cont);
188 #ifdef DEBUG_RAMPS
189  if (DEBUGCOND(cur)) {
190  std::cout << "buildOnRamp cur=" << cur->getID() << " hw=" << potHighway->getID() << " ramp=" << potRamp->getID() << " cont=" << cont->getID() << "\n";
191  }
192 #endif
193  // compute the number of lanes to append
194  const int firstLaneNumber = cont->getNumLanes();
195  int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber;
196  NBEdge* first = cont;
197  NBEdge* last = cont;
198  NBEdge* curr = cont;
199  std::set<NBEdge*> incremented;
200  if (addLanes && toAdd > 0 && std::find(incremented.begin(), incremented.end(), cont) == incremented.end()) {
201  double currLength = 0;
202  while (curr != nullptr && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) {
203  if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
204  curr->incLaneNo(toAdd);
206  curr->invalidateConnections(true);
207  }
208  incremented.insert(curr);
209  moveRampRight(curr, toAdd);
210  currLength += curr->getGeometry().length(); // !!! loaded length?
211  last = curr;
212  // mark acceleration lanes
213  for (int i = 0; i < curr->getNumLanes() - potHighway->getNumLanes(); ++i) {
214  curr->setAcceleration(i, true);
215  }
216  }
217  NBNode* nextN = curr->getToNode();
218  if (nextN->getOutgoingEdges().size() == 1 && nextN->getIncomingEdges().size() == 1) {
219  curr = nextN->getOutgoingEdges()[0];
220  if (curr->getNumLanes() != firstLaneNumber) {
221  // the number of lanes changes along the computation; we'll stop...
222  curr = nullptr;
223  } else if (curr->isTurningDirectionAt(last)) {
224  // turnarounds certainly should not be included in a ramp
225  curr = nullptr;
226  } else if (curr == potHighway || curr == potRamp) {
227  // circular connectivity. do not split!
228  curr = nullptr;
229  }
230  } else {
231  // ambiguous; and, in fact, what should it be? ...stop
232  curr = nullptr;
233  }
234  }
235  // check whether a further split is necessary
236  if (curr != nullptr && !dontSplit && currLength - POSITION_EPS < rampLength && curr->getNumLanes() == firstLaneNumber && std::find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
237  // there is enough place to build a ramp; do it
238  bool wasFirst = first == curr;
239  NBNode* rn = new NBNode(curr->getID() + "-AddedOnRampNode", curr->getGeometry().positionAtOffset(rampLength - currLength));
240  if (!nc.insert(rn)) {
241  throw ProcessError("Ups - could not build on-ramp for edge '" + curr->getID() + "' (node could not be build)!");
242  }
243  std::string name = curr->getID();
244  bool ok = ec.splitAt(dc, curr, rn, curr->getID() + ADDED_ON_RAMP_EDGE, curr->getID(), curr->getNumLanes() + toAdd, curr->getNumLanes());
245  if (!ok) {
246  WRITE_ERROR("Ups - could not build on-ramp for edge '" + curr->getID() + "'!");
247  return;
248  }
249  //ec.retrieve(name)->invalidateConnections();
250  curr = ec.retrieve(name + ADDED_ON_RAMP_EDGE);
251  incremented.insert(curr);
252  last = curr;
253  moveRampRight(curr, toAdd);
254  if (wasFirst) {
255  first = curr;
256  }
257  // mark acceleration lanes
258  for (int i = 0; i < curr->getNumLanes() - potHighway->getNumLanes(); ++i) {
259  curr->setAcceleration(i, true);
260  }
261  }
262  if (curr == cont && dontSplit && addLanes) {
263  WRITE_WARNING("Could not build on-ramp for edge '" + curr->getID() + "' due to option '--ramps.no-split'");
264  return;
265  }
266  } else {
267  // mark acceleration lanes
268  for (int i = 0; i < firstLaneNumber - potHighway->getNumLanes(); ++i) {
269  cont->setAcceleration(i, true);
270  }
271  }
272  // set connections from ramp/highway to added ramp
273  if (addLanes) {
275  if (!potHighway->addLane2LaneConnections(0, first, potRamp->getNumLanes(), MIN2(first->getNumLanes() - potRamp->getNumLanes(), potHighway->getNumLanes()), NBEdge::Lane2LaneInfoType::VALIDATED, true)) {
276  throw ProcessError("Could not set connection!");
277  }
278  }
280  if (!potRamp->addLane2LaneConnections(0, first, 0, potRamp->getNumLanes(), NBEdge::Lane2LaneInfoType::VALIDATED, true)) {
281  throw ProcessError("Could not set connection!");
282  }
283  }
284  patchRampGeometry(potRamp, first, potHighway, false);
285  }
286 }
287 
288 
289 void
290 NBRampsComputer::buildOffRamp(NBNode* cur, NBNodeCont& nc, NBEdgeCont& ec, NBDistrictCont& dc, double rampLength, bool dontSplit, bool addLanes,
291  const std::set<NBNode*, ComparatorIdLess>& potOnRamps) {
292  NBEdge* potHighway, *potRamp, *prev;
293  getOffRampEdges(cur, &potHighway, &potRamp, &prev);
294 #ifdef DEBUG_RAMPS
295  if (DEBUGCOND(cur)) {
296  std::cout << "buildOffRamp cur=" << cur->getID() << " hw=" << potHighway->getID() << " ramp=" << potRamp->getID() << " prev=" << prev->getID() << "\n";
297  }
298 #endif
299  // compute the number of lanes to append
300  const int firstLaneNumber = prev->getNumLanes();
301  int toAdd = (potRamp->getNumLanes() + potHighway->getNumLanes()) - firstLaneNumber;
302  NBEdge* first = prev;
303  NBEdge* last = prev;
304  NBEdge* curr = prev;
305  std::set<NBEdge*> incremented;
306  if (addLanes && toAdd > 0 && std::find(incremented.begin(), incremented.end(), prev) == incremented.end()) {
307  double currLength = 0;
308  while (curr != nullptr && currLength + curr->getGeometry().length() - POSITION_EPS < rampLength) {
309  if (find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
310  curr->incLaneNo(toAdd);
312  curr->invalidateConnections(true);
313  }
314  incremented.insert(curr);
315  moveRampRight(curr, toAdd);
316  currLength += curr->getGeometry().length(); // !!! loaded length?
317  last = curr;
318  }
319  NBNode* prevN = curr->getFromNode();
320  if (prevN->getIncomingEdges().size() == 1 && prevN->getOutgoingEdges().size() == 1) {
321  curr = prevN->getIncomingEdges()[0];
322  if (curr->getStep() < NBEdge::EdgeBuildingStep::LANES2LANES_USER && toAdd != 0) {
323  // curr might be an onRamp. In this case connections need to be rebuilt
324  curr->invalidateConnections();
325  }
326  if (curr->getNumLanes() != firstLaneNumber) {
327  // the number of lanes changes along the computation; we'll stop...
328  curr = nullptr;
329  } else if (last->isTurningDirectionAt(curr)) {
330  // turnarounds certainly should not be included in a ramp
331  curr = nullptr;
332  } else if (curr == potHighway || curr == potRamp) {
333  // circular connectivity. do not split!
334  curr = nullptr;
335  }
336  } else {
337  // ambiguous; and, in fact, what should it be? ...stop
338  curr = nullptr;
339  }
340  }
341  // check whether a further split is necessary
342  if (curr != nullptr && !dontSplit && currLength - POSITION_EPS < rampLength && curr->getNumLanes() == firstLaneNumber && std::find(incremented.begin(), incremented.end(), curr) == incremented.end()) {
343  // there is enough place to build a ramp; do it
344  bool wasFirst = first == curr;
345  Position pos = curr->getGeometry().positionAtOffset(curr->getGeometry().length() - (rampLength - currLength));
346  NBNode* rn = new NBNode(curr->getID() + "-AddedOffRampNode", pos);
347  if (!nc.insert(rn)) {
348  throw ProcessError("Ups - could not build off-ramp for edge '" + curr->getID() + "' (node could not be build)!");
349  }
350  std::string name = curr->getID();
351  bool ok = ec.splitAt(dc, curr, rn, curr->getID(), curr->getID() + "-AddedOffRampEdge", curr->getNumLanes(), curr->getNumLanes() + toAdd);
352  if (!ok) {
353  WRITE_ERROR("Ups - could not build off-ramp for edge '" + curr->getID() + "'!");
354  return;
355  }
356  curr = ec.retrieve(name + "-AddedOffRampEdge");
357  incremented.insert(curr);
358  last = curr;
359  moveRampRight(curr, toAdd);
360  if (wasFirst) {
361  first = curr;
362  }
363  }
364  if (curr == prev && dontSplit && addLanes) {
365  WRITE_WARNING("Could not build off-ramp for edge '" + curr->getID() + "' due to option '--ramps.no-split'");
366  return;
367  }
368  }
369  NBEdge* toMark = first;
370  toMark->markOffRamp(true);
371  double markedLength = toMark->getLoadedLength();
372  while (markedLength < OFFRAMP_LOOKBACK) {
373  if (toMark != first && toMark->getToNode()->getOutgoingEdges().size() != 1) {
374  break;
375  }
376  NBNode* from = toMark->getFromNode();
377  if (from->getIncomingEdges().size() == 1) {
378  toMark = from->getIncomingEdges()[0];
379  } else if (potOnRamps.count(from) == 1) {
380  NBEdge* potOnRamp, *cont;
381  getOnRampEdges(from, &toMark, &potOnRamp, &cont);
382  } else {
383  break;
384  }
385  toMark->markOffRamp(true);
386  markedLength += toMark->getLoadedLength();
387  }
388  // set connections from added ramp to ramp/highway
389  if (addLanes) {
391  if (!first->addLane2LaneConnections(potRamp->getNumLanes(), potHighway, 0, MIN2(first->getNumLanes() - 1, potHighway->getNumLanes()), NBEdge::Lane2LaneInfoType::VALIDATED, true)) {
392  throw ProcessError("Could not set connection!");
393  }
394  if (!first->addLane2LaneConnections(0, potRamp, 0, potRamp->getNumLanes(), NBEdge::Lane2LaneInfoType::VALIDATED, false)) {
395  throw ProcessError("Could not set connection!");
396  }
397  }
398  patchRampGeometry(potRamp, first, potHighway, true);
399  }
400 }
401 
402 
403 void
404 NBRampsComputer::moveRampRight(NBEdge* ramp, int addedLanes) {
406  return;
407  }
408  try {
409  PositionVector g = ramp->getGeometry();
410  const double offset = (0.5 * addedLanes *
412  g.move2side(offset);
413  ramp->setGeometry(g);
414  } catch (InvalidArgument&) {
415  WRITE_WARNING("For edge '" + ramp->getID() + "': could not compute shape.");
416  }
417 }
418 
419 
420 bool
422  if (fabs((*potHighway)->getSpeed() - (*potRamp)->getSpeed()) < .1) {
423  return false;
424  }
425  if ((*potHighway)->getSpeed() < (*potRamp)->getSpeed()) {
426  std::swap(*potHighway, *potRamp);
427  }
428  return true;
429 }
430 
431 
432 bool
434  if ((*potHighway)->getNumLanes() == (*potRamp)->getNumLanes()) {
435  return false;
436  }
437  if ((*potHighway)->getNumLanes() < (*potRamp)->getNumLanes()) {
438  std::swap(*potHighway, *potRamp);
439  }
440  return true;
441 }
442 
443 
444 void
445 NBRampsComputer::getOnRampEdges(NBNode* n, NBEdge** potHighway, NBEdge** potRamp, NBEdge** other) {
446  *other = n->getOutgoingEdges()[0];
447  const std::vector<NBEdge*>& edges = n->getIncomingEdges();
448  assert(edges.size() == 2);
449  *potHighway = edges[0];
450  *potRamp = edges[1];
451  /*
452  // heuristic: highway is faster than ramp
453  if(determinedBySpeed(potHighway, potRamp)) {
454  return;
455  }
456  // heuristic: highway has more lanes than ramp
457  if(determinedByLaneNumber(potHighway, potRamp)) {
458  return;
459  }
460  */
461  // heuristic: ramp comes from right
462  if (NBContHelper::relative_incoming_edge_sorter(*other)(*potRamp, *potHighway)) {
463  std::swap(*potHighway, *potRamp);
464  }
465 }
466 
467 
468 void
469 NBRampsComputer::getOffRampEdges(NBNode* n, NBEdge** potHighway, NBEdge** potRamp, NBEdge** other) {
470  *other = n->getIncomingEdges()[0];
471  const std::vector<NBEdge*>& edges = n->getOutgoingEdges();
472  *potHighway = edges[0];
473  *potRamp = edges[1];
474  assert(edges.size() == 2);
475  /*
476  // heuristic: highway is faster than ramp
477  if(determinedBySpeed(potHighway, potRamp)) {
478  return;
479  }
480  // heuristic: highway has more lanes than ramp
481  if(determinedByLaneNumber(potHighway, potRamp)) {
482  return;
483  }
484  */
485  // heuristic: ramp goes to right
486  const std::vector<NBEdge*>& edges2 = n->getEdges();
487 #ifdef DEBUG_RAMPS
488  if (DEBUGCOND(n)) {
489  std::cout << " edges=" << toString(edges) << " edges2=" << toString(edges2) << "\n";
490  }
491 #endif
492  std::vector<NBEdge*>::const_iterator i = std::find(edges2.begin(), edges2.end(), *other);
493  NBContHelper::nextCW(edges2, i);
494  if ((*i) == *potRamp) {
495  std::swap(*potHighway, *potRamp);
496  }
497  // the following would be better but runs afoul of misleading angles when both edges
498  // have the same geometry start point but different references lanes are
499  // chosen for NBEdge::computeAngle()
500  //if (NBContHelper::relative_outgoing_edge_sorter(*other)(*potHighway, *potRamp)) {
501  // std::swap(*potHighway, *potRamp);
502  //}
503 }
504 
505 
506 bool
508  NBEdge* potHighway, NBEdge* potRamp, NBEdge* other, double minHighwaySpeed, double maxRampSpeed,
509  const std::set<std::string>& noramps) {
510  // check modes that are not appropriate for rampsdo not build ramps on rail edges
511  if (hasWrongMode(potHighway) || hasWrongMode(potRamp) || hasWrongMode(other)) {
512  return false;
513  }
514  // do not build ramps at traffic lights
515  if (NBNode::isTrafficLight(potRamp->getToNode()->getType())) {
516  return false;
517  }
518  // do not build ramps on connectors
519  if (potHighway->isMacroscopicConnector() || potRamp->isMacroscopicConnector() || other->isMacroscopicConnector()) {
520  return false;
521  }
522  // check whether a lane is missing
523  if (potHighway->getNumLanes() + potRamp->getNumLanes() < other->getNumLanes()) {
524  return false;
525  }
526  // is it really a highway?
527  double maxSpeed = MAX3(potHighway->getSpeed(), other->getSpeed(), potRamp->getSpeed());
528  if (maxSpeed < minHighwaySpeed) {
529  return false;
530  }
531  // is any of the connections a turnaround?
532  if (other->getToNode() == potHighway->getFromNode()) {
533  // off ramp
534  if (other->isTurningDirectionAt(potHighway) ||
535  other->isTurningDirectionAt(potRamp)) {
536  return false;
537  }
538  } else {
539  // on ramp
540  if (other->isTurningDirectionAt(potHighway) ||
541  other->isTurningDirectionAt(potRamp)) {
542  return false;
543  }
544  }
545  // are the angles between highway and other / ramp and other more or less straight?
546  const NBNode* node = ((potHighway->getToNode() == potRamp->getToNode() && potHighway->getToNode() == other->getFromNode())
547  ? potHighway->getToNode() : potHighway->getFromNode());
548  double angle = fabs(NBHelpers::relAngle(potHighway->getAngleAtNode(node), other->getAngleAtNode(node)));
549  if (angle >= 60) {
550  return false;
551  }
552  angle = fabs(NBHelpers::relAngle(potRamp->getAngleAtNode(node), other->getAngleAtNode(node)));
553  if (angle >= 60) {
554  return false;
555  }
556  /*
557  if (potHighway->getSpeed() < minHighwaySpeed || other->getSpeed() < minHighwaySpeed) {
558  return false;
559  }
560  */
561  // is it really a ramp?
562  if (maxRampSpeed > 0 && maxRampSpeed < potRamp->getSpeed()) {
563  return false;
564  }
565  if (noramps.find(other->getID()) != noramps.end()) {
566  return false;
567  }
568  return true;
569 }
570 
571 
572 bool
574  // must allow passenger vehicles
575  if ((edge->getPermissions() & SVC_PASSENGER) == 0) {
576  return true;
577  }
578  // must not have a green verge or a lane that is only for soft modes
579  for (int i = 0; i < (int)edge->getNumLanes(); ++i) {
580  if ((edge->getPermissions(i) & ~(SVC_PEDESTRIAN | SVC_BICYCLE)) == 0) {
581  return true;
582  }
583  }
584  return false;
585 }
586 
587 void
588 NBRampsComputer::patchRampGeometry(NBEdge* potRamp, NBEdge* first, NBEdge* potHighway, bool onRamp) {
589  // geometry of first and highway should allign on the left side
591  const NBNode* n = onRamp ? potHighway->getToNode() : potHighway->getFromNode();
592  if (potHighway->hasDefaultGeometryEndpointAtNode(n)) {
593  PositionVector p2 = first->getGeometry();
594  try {
595  p2.move2side((first->getNumLanes() - potHighway->getNumLanes()) * first->getLaneWidth(0) * 0.5);
596  first->setGeometry(p2);
597  } catch (InvalidArgument&) {}
598  }
599  }
600 
601  // ramp should merge smoothly with first
602  PositionVector p = potRamp->getGeometry();
603  double offset = 0;
604  int firstIndex = MAX2(0, MIN2(potRamp->getNumLanes(), first->getNumLanes()) - 1);
606  offset = -first->getLaneWidth(firstIndex) / 2;
607  } else {
608  if (firstIndex % 2 == 1) {
609  // even number of lanes
610  offset = -first->getLaneWidth(firstIndex / 2) / 2;
611  }
612  firstIndex /= 2; // integer division
613  }
614  // reset lane shape (might be affected by earlier junctions.join step. see #947)
615  first->resetLaneShapes();
616  PositionVector l = first->getLaneShape(firstIndex);
617  try {
618  l.move2side(offset);
619  } catch (InvalidArgument&) {}
620  //std::cout << " ramp=" << potRamp->getID() << " firstIndex=" << firstIndex << " offset=" << offset << " l=" << l << "\n";
621 
622  if (onRamp) {
623  p[0] = l[-1];
624  } else {
625  p.pop_back();
626  p.push_back(l[0]);
627  }
628  potRamp->setGeometry(p);
629 
630 }
631 
632 
633 /****************************************************************************/
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
#define DEBUGCOND(obj)
#define OFFRAMP_LOOKBACK
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_PEDESTRIAN
pedestrian
const double SUMO_const_laneWidth
Definition: StdDefs.h:47
T MIN2(T a, T b)
Definition: StdDefs.h:73
T MAX2(T a, T b)
Definition: StdDefs.h:79
T MAX3(T a, T b, T c)
Definition: StdDefs.h:93
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
static void nextCW(const EdgeVector &edges, EdgeVector::const_iterator &from)
A container for districts.
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:59
std::map< std::string, NBEdge * >::const_iterator begin() const
Returns the pointer to the begin of the stored edges.
Definition: NBEdgeCont.h:183
const std::set< EdgeSet > getRoundabouts() const
Returns the determined roundabouts.
std::map< std::string, NBEdge * >::const_iterator end() const
Returns the pointer to the end of the stored edges.
Definition: NBEdgeCont.h:191
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
Definition: NBEdgeCont.cpp:275
bool splitAt(NBDistrictCont &dc, NBEdge *edge, NBNode *node)
Splits the edge at the position nearest to the given node.
Definition: NBEdgeCont.cpp:586
The representation of a single edge during network building.
Definition: NBEdge.h:91
double getLength() const
Returns the computed length of the edge.
Definition: NBEdge.h:563
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:3655
double getLoadedLength() const
Returns the length was set explicitly or the computed length if it wasn't set.
Definition: NBEdge.h:572
double getLaneWidth() const
Returns the default width of lanes of this edge.
Definition: NBEdge.h:605
void incLaneNo(int by)
increment lane
Definition: NBEdge.cpp:3402
void markOffRamp(bool isOffRamp)
marks this edge has being an offRamp or leading to one (used for connection computation)
Definition: NBEdge.h:1300
LaneSpreadFunction getLaneSpreadFunction() const
Returns how this edge's lanes' lateral offset is computed.
Definition: NBEdge.h:803
bool hasDefaultGeometryEndpoints() const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:581
EdgeBuildingStep getStep() const
The building step of this edge.
Definition: NBEdge.h:598
const std::string & getID() const
Definition: NBEdge.h:1423
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:516
@ LANES2LANES_USER
Lanes to lanes - relationships are loaded; no recheck is necessary/wished.
double getSpeed() const
Returns the speed allowed on this edge.
Definition: NBEdge.h:589
void resetLaneShapes()
reset lane shapes to what they would be before cutting with the junction shapes
Definition: NBEdge.cpp:1987
void setAcceleration(int lane, bool accelRamp)
marks one lane as acceleration lane
Definition: NBEdge.cpp:3612
bool isTurningDirectionAt(const NBEdge *const edge) const
Returns whether the given edge is the opposite direction to this edge.
Definition: NBEdge.cpp:3006
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:490
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:716
void invalidateConnections(bool reallowSetting=false)
invalidate current connections of edge
Definition: NBEdge.cpp:1399
@ VALIDATED
The connection was computed and validated.
double getAngleAtNode(const NBNode *const node) const
Returns the angle of the edge's geometry at the given node.
Definition: NBEdge.cpp:1946
bool hasDefaultGeometryEndpointAtNode(const NBNode *node) const
Returns whether the geometry is terminated by the node positions This default may be violated by init...
Definition: NBEdge.cpp:588
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:324
bool addLane2LaneConnections(int fromLane, NBEdge *dest, int toLane, int no, Lane2LaneInfoType type, bool invalidatePrevious=false, bool mayDefinitelyPass=false)
Builds no connections starting at the given lanes.
Definition: NBEdge.cpp:1049
bool isMacroscopicConnector() const
Returns whether this edge was marked as a macroscopic connector.
Definition: NBEdge.h:1059
const PositionVector & getLaneShape(int i) const
Returns the shape of the nth lane.
Definition: NBEdge.cpp:901
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:604
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:509
static double relAngle(double angle1, double angle2)
computes the relative angle between the two angles
Definition: NBHelpers.cpp:45
Instance responsible for building networks.
Definition: NBNetBuilder.h:107
NBDistrictCont & getDistrictCont()
Returns a reference the districts container.
Definition: NBNetBuilder.h:168
NBParkingCont & getParkingCont()
Definition: NBNetBuilder.h:184
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:179
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:148
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:174
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:153
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:58
std::map< std::string, NBNode * >::const_iterator begin() const
Returns the pointer to the begin of the stored nodes.
Definition: NBNodeCont.h:113
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:90
std::map< std::string, NBNode * >::const_iterator end() const
Returns the pointer to the end of the stored nodes.
Definition: NBNodeCont.h:118
Represents a single node (junction) during network building.
Definition: NBNode.h:66
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:271
static bool isTrafficLight(SumoXMLNodeType type)
return whether the given type is a traffic light
Definition: NBNode.cpp:3424
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:259
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:264
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:254
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
Definition: NBParking.cpp:78
static void computeRamps(NBNetBuilder &nb, OptionsCont &oc, bool mayAddOrRemove)
Computes highway on-/off-ramps (if wished)
static void getOffRampEdges(NBNode *n, NBEdge **potHighway, NBEdge **potRamp, NBEdge **other)
static bool mayNeedOffRamp(NBNode *cur, double minHighwaySpeed, double maxRampSpeed, const std::set< std::string > &noramps)
Determines whether the given node may be an off-ramp end.
static bool mayNeedOnRamp(NBNode *cur, double minHighwaySpeed, double maxRampSpeed, const std::set< std::string > &noramps, double minWeaveLength)
Determines whether the given node may be an on-ramp begin.
static bool determinedBySpeed(NBEdge **potHighway, NBEdge **potRamp)
static void moveRampRight(NBEdge *ramp, int addedLanes)
Moves the ramp to the right, as new lanes were added.
static void getOnRampEdges(NBNode *n, NBEdge **potHighway, NBEdge **potRamp, NBEdge **other)
static const std::string ADDED_ON_RAMP_EDGE
suffix for newly generated on-ramp edges
static void patchRampGeometry(NBEdge *potRamp, NBEdge *first, NBEdge *potHighway, bool onRamp)
shift ramp geometry to merge smoothly with the motorway
static void buildOffRamp(NBNode *cur, NBNodeCont &nc, NBEdgeCont &ec, NBDistrictCont &dc, double rampLength, bool dontSplit, bool addLanes, const std::set< NBNode *, ComparatorIdLess > &potOnRamps)
Builds an off-ramp ending at the given node.
static bool determinedByLaneNumber(NBEdge **potHighway, NBEdge **potRamp)
static bool hasWrongMode(NBEdge *edge)
whether the edge has a mode that does not indicate a ramp edge
static void buildOnRamp(NBNode *cur, NBNodeCont &nc, NBEdgeCont &ec, NBDistrictCont &dc, double rampLength, bool dontSplit, bool addLanes)
Builds an on-ramp starting at the given node.
static bool fulfillsRampConstraints(NBEdge *potHighway, NBEdge *potRamp, NBEdge *other, double minHighwaySpeed, double maxRampSpeed, const std::set< std::string > &noramps)
Checks whether an on-/off-ramp can be bult here.
const std::string & getID() const
Returns the id.
Definition: Named.h:73
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:36
A list of positions.
double length() const
Returns the length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain ammount