Eclipse SUMO - Simulation of Urban MObility
NBPTStopCont.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2022 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 /****************************************************************************/
18 // Container for pt stops during the netbuilding process
19 /****************************************************************************/
20 
21 
23 #include <utils/geom/Boundary.h>
25 #include <microsim/MSLane.h>
26 #include "NBPTStopCont.h"
27 #include "NBEdgeCont.h"
28 #include "NBEdge.h"
29 #include "NBNode.h"
30 #include <utils/geom/Position.h>
31 
32 
34  for (auto& myPTStop : myPTStops) {
35  delete myPTStop.second;
36  }
37  myPTStops.clear();
38 }
39 
40 
41 bool
43  std::string id = ptStop->getID();
44  auto i = myPTStops.find(id);
45  if (i != myPTStops.end()) {
46  return false;
47  }
48  myPTStops[id] = ptStop;
49  return true;
50 }
51 
52 
53 NBPTStop*
54 NBPTStopCont::get(std::string id) const {
55  if (myPTStops.find(id) != myPTStops.end()) {
56  return myPTStops.find(id)->second;
57  }
58  return nullptr;
59 }
60 
61 
62 void
64  std::vector<NBPTStop*> reverseStops;
65  //first pass localize pt stop at correct side of the street; create stop for opposite side if needed
66  for (auto& myPTStop : myPTStops) {
67 
68  NBPTStop* stop = myPTStop.second;
69 
70  bool multipleStopPositions = stop->getIsMultipleStopPositions();
71  bool platformsDefined = !stop->getPlatformCands().empty();
72  if (!platformsDefined) {
73  //create pt stop for reverse edge if edge exists
74  NBPTStop* reverseStop = getReverseStop(stop, cont);
75  if (reverseStop != nullptr) {
76  reverseStops.push_back(reverseStop);
77  }
78  } else if (multipleStopPositions) {
79  //create pt stop for closest platform at corresponding edge
81 
82  } else {
83  //create pt stop for each side of the street where a platform is defined (create additional pt stop as needed)
84  NBPTStop* additionalStop = assignAndCreatNewPTStopAsNeeded(stop, cont);
85  if (additionalStop != nullptr) {
86  reverseStops.push_back(additionalStop);
87  }
88  }
89  }
90 
91  //insrt new stops if any
92  for (auto& reverseStop : reverseStops) {
93  insert(reverseStop);
94  }
95 }
96 
97 
99  //scnd pass set correct lane
100  for (auto i = myPTStops.begin(); i != myPTStops.end();) {
101  NBPTStop* stop = i->second;
102 
103  if (!stop->findLaneAndComputeBusStopExtent(cont)) {
104  WRITE_WARNINGF("Could not find corresponding edge or compatible lane for pt stop '%' (%). Thus, it will be removed!",
105  i->first, i->second->getName());
106  EdgeVector edgeVector = cont.getGeneratedFrom((*i).second->getOrigEdgeId());
107  //std::cout << edgeVector.size() << std::endl;
108  myPTStops.erase(i++);
109  } else {
110  i++;
111  }
112  }
113 }
114 
115 
116 int
118  //scnd pass set correct lane
119  std::vector<NBPTStop*> toAdd;
120  for (auto i = myPTStops.begin(); i != myPTStops.end(); i++) {
121  NBPTStop* stop = i->second;
122  NBEdge* edge = ec.getByID(stop->getEdgeId());
123  if (edge != nullptr && edge->isBidiRail()) {
124  NBEdge* bidiEdge = edge->getTurnDestination(true);
125  assert(bidiEdge != 0);
126  const std::string id = getReverseID(stop->getID());
127  if (myPTStops.count(id) > 0) {
128  if (myPTStops[id]->getEdgeId() != bidiEdge->getID()) {
129  WRITE_WARNINGF("Could not create reverse-direction stop for superposed edge '%' (origStop '%'). Stop id '%' already in use by stop on edge '%'.",
130  bidiEdge->getID(), i->first, id, myPTStops[id]->getEdgeId());
131  }
132  continue;
133  }
134  NBPTStop* bidiStop = new NBPTStop(id,
135  stop->getPosition(),
136  bidiEdge->getID(),
137  stop->getOrigEdgeId(),
138  stop->getLength(),
139  stop->getName(),
140  stop->getPermissions());
141  if (bidiStop->findLaneAndComputeBusStopExtent(ec)) {
142  toAdd.push_back(bidiStop);
143  stop->setBidiStop(bidiStop);
144  bidiStop->setBidiStop(stop);
145  } else {
146  // should not happen
147  assert(false);
148  }
149  }
150  }
151  for (NBPTStop* newStop : toAdd) {
152  myPTStops[newStop->getID()] = newStop;
153  }
154  if (toAdd.size() > 0) {
155  WRITE_MESSAGE("Added " + toString(toAdd.size()) + " stops for superposed rail edges.");
156  }
157  return (int)toAdd.size();
158 }
159 
160 
161 NBPTStop*
163  std::string edgeId = pStop->getEdgeId();
164  NBEdge* edge = ec.getByID(edgeId);
165  NBEdge* reverse = NBPTStopCont::getReverseEdge(edge);
166  if (reverse != nullptr) {
167  const std::string reverseID = getReverseID(pStop->getID());
168  if (myPTStops.count(reverseID) == 0) {
169  return new NBPTStop(reverseID, pStop->getPosition(), reverse->getID(), reverse->getID(),
170  pStop->getLength(), pStop->getName(), pStop->getPermissions());
171  } else {
172  return myPTStops[reverseID];
173  }
174  }
175  return nullptr;
176 }
177 
178 
179 NBPTStop*
181  std::string edgeId = pStop->getEdgeId();
182  NBEdge* edge = cont.getByID(edgeId);
183  bool rightOfEdge = false;
184  bool leftOfEdge = false;
185  const NBPTPlatform* left = nullptr;
186  for (const NBPTPlatform& platform : pStop->getPlatformCands()) {
187  double crossProd = computeCrossProductEdgePosition(edge, platform.getPos());
188  //TODO consider driving on the left!!! [GL May '17]
189  if (crossProd > 0) {
190  leftOfEdge = true;
191  left = &platform;
192  } else {
193  rightOfEdge = true;
194  pStop->setPTStopLength(platform.getLength());
195  }
196  }
197 
198  if (leftOfEdge && rightOfEdge) {
199  NBPTStop* leftStop = getReverseStop(pStop, cont);
200  leftStop->setPTStopLength(left->getLength());
201  return leftStop;
202  } else if (leftOfEdge) {
203  NBEdge* reverse = getReverseEdge(edge);
204  if (reverse != nullptr) {
205  pStop->setEdgeId(reverse->getID(), cont);
206  pStop->setPTStopLength(left->getLength());
207  }
208  }
209 
210  return nullptr;
211 }
212 
213 
214 void
216  std::string edgeId = pStop->getEdgeId();
217  NBEdge* edge = cont.getByID(edgeId);
218  NBEdge* reverse = NBPTStopCont::getReverseEdge(edge);
219  const NBPTPlatform* closestPlatform = getClosestPlatformToPTStopPosition(pStop);
220  pStop->setPTStopLength(closestPlatform->getLength());
221  if (reverse != nullptr) {
222 
223  //TODO make isLeft in PositionVector static [GL May '17]
224 // if (PositionVector::isLeft(edge->getFromNode()->getPosition(),edge->getToNode()->getPosition(),closestPlatform)){
225 //
226 // }
227  double crossProd = computeCrossProductEdgePosition(edge, closestPlatform->getPos());
228 
229  //TODO consider driving on the left!!! [GL May '17]
230  if (crossProd > 0) { //pt stop is on the left of the orig edge
231  pStop->setEdgeId(reverse->getID(), cont);
232  }
233  }
234 }
235 
236 
237 double
238 NBPTStopCont::computeCrossProductEdgePosition(const NBEdge* edge, const Position& closestPlatform) const {
239  PositionVector geom = edge->getGeometry();
240  int idxTmp = geom.indexOfClosest(closestPlatform);
241  double offset = geom.nearest_offset_to_point2D(closestPlatform, true);
242  double offset2 = geom.offsetAtIndex2D(idxTmp);
243  int idx1, idx2;
244  if (offset2 < offset) {
245  idx1 = idxTmp;
246  idx2 = idx1 + 1;
247  } else {
248  idx2 = idxTmp;
249  idx1 = idxTmp - 1;
250  }
251  if (idx1 < 0 || idx1 >= (int) geom.size() || idx2 < 0 || idx2 >= (int) geom.size()) {
252  WRITE_WARNINGF("Could not determine cross product for edge '%'.", edge->getID());
253  return 0;
254  }
255  Position p1 = geom[idx1];
256  Position p2 = geom[idx2];
257 
258  double x0 = p1.x();
259  double y0 = p1.y();
260  double x1 = p2.x();
261  double y1 = p2.y();
262  double x2 = closestPlatform.x();
263  double y2 = closestPlatform.y();
264  double crossProd = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0);
265  return crossProd;
266 }
267 
268 
269 const NBPTPlatform*
271  Position stopPosition = pStop->getPosition();
272  const NBPTPlatform* closest = nullptr;
273  double minSqrDist = std::numeric_limits<double>::max();
274  for (const NBPTPlatform& platform : pStop->getPlatformCands()) {
275  double sqrDist = stopPosition.distanceSquaredTo2D(platform.getPos());
276  if (sqrDist < minSqrDist) {
277  minSqrDist = sqrDist;
278  closest = &platform;
279  }
280  }
281  return closest;
282 }
283 
284 //static functions
285 
286 NBEdge*
288  if (edge != nullptr) {
289  for (auto it = edge->getToNode()->getOutgoingEdges().begin();
290  it != edge->getToNode()->getOutgoingEdges().end();
291  it++) {
292  if ((*it)->getToNode() == edge->getFromNode()) {
293  return (*it);
294  }
295  }
296  }
297  return nullptr;
298 }
299 
300 
301 int
303  int numDeleted = 0;
304  for (auto i = myPTStops.begin(); i != myPTStops.end();) {
305  if (cont.getByID(i->second->getEdgeId()) == nullptr) {
306  WRITE_WARNINGF("Removing pt stop '%' on non existing edge '%'.", i->first, i->second->getEdgeId());
307  i = myPTStops.erase(i);
308  numDeleted++;
309  } else {
310  i++;
311  }
312  }
313  return numDeleted;
314 }
315 
316 
317 void
318 NBPTStopCont::addEdges2Keep(const OptionsCont& oc, std::set<std::string>& into) {
319  if (oc.isSet("ptstop-output")) {
320  for (auto stop : myPTStops) {
321  into.insert(stop.second->getEdgeId());
322  }
323  }
324 }
325 
326 
327 void
328 NBPTStopCont::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
329  if (myPTStops.size() > 0 && myPTStopLookup.size() == 0) {
330  // init lookup once
331  for (auto& item : myPTStops) {
332  myPTStopLookup[item.second->getEdgeId()].push_back(item.second);
333  }
334  }
335  // make a copy because the vector gets modified
336  const std::vector<NBPTStop*> stops = myPTStopLookup[edgeID];
337  for (NBPTStop* stop : stops) {
338  if (!stop->replaceEdge(edgeID, replacement)) {
339  WRITE_WARNINGF("Could not re-assign pt stop '%' after replacing edge '%'.", stop->getID(), edgeID);
340  } else {
341  myPTStopLookup[stop->getEdgeId()].push_back(stop);
342  }
343  }
344  myPTStopLookup.erase(edgeID);
345 }
346 
347 
348 void
349 NBPTStopCont::postprocess(std::set<std::string>& usedStops) {
350  for (auto i = myPTStops.begin(); i != myPTStops.end();) {
351  if (usedStops.find(i->second->getID()) == usedStops.end()) {
352  myPTStops.erase(i++);
353  } else {
354  i++;
355  }
356  }
357 }
358 
359 std::string
360 NBPTStopCont::getReverseID(const std::string& id) {
361  return id.size() > 0 && id[0] == '-' ? id.substr(1) : "-" + id;
362 }
363 
364 void
366  PTStopsCont stops = myPTStops;
367  for (auto& i : stops) {
368  NBPTStop* s = i.second;
369  const std::string& stopId = s->getID();
370  if (s->getEdgeId() == "") {
371  continue;
372  }
373  const char edgeSign = s->getEdgeId().at(0);
374  const char stopSign = stopId.at(0);
375  if (edgeSign != stopSign && (edgeSign == '-' || stopSign == '-')) {
376  const std::string reverseID = getReverseID(stopId);
377  NBPTStop* rs = get(reverseID);
378  s->setPTStopId(reverseID);
379  myPTStops.erase(stopId);
380  myPTStops[reverseID] = s;
381  if (rs != nullptr) {
382  rs->setPTStopId(stopId);
383  myPTStops[stopId] = rs;
384  }
385  }
386  }
387 }
388 
389 
390 void
391 NBPTStopCont::findAccessEdgesForRailStops(NBEdgeCont& cont, double maxRadius, int maxCount, double accessFactor) {
392  NamedRTree r;
393  for (auto edge : cont) {
394  const Boundary& bound = edge.second->getGeometry().getBoxBoundary();
395  float min[2] = { static_cast<float>(bound.xmin()), static_cast<float>(bound.ymin()) };
396  float max[2] = { static_cast<float>(bound.xmax()), static_cast<float>(bound.ymax()) };
397  r.Insert(min, max, edge.second);
398  }
399  for (auto& ptStop : myPTStops) {
400  const std::string& stopEdgeID = ptStop.second->getEdgeId();
401  NBEdge* stopEdge = cont.getByID(stopEdgeID);
402  //std::cout << "findAccessEdgesForRailStops edge=" << stopEdgeID << " exists=" << (stopEdge != 0) << "\n";
403  if (stopEdge != nullptr && (stopEdge->getPermissions() & SVC_PEDESTRIAN) == 0) {
404  //if (stopEdge != 0 && isRailway(stopEdge->getPermissions())) {
405  std::set<const Named*> edges;
406  Named::StoringVisitor visitor(edges);
407  const Position& pos = ptStop.second->getPosition();
408  float min[2] = {static_cast<float>(pos.x() - maxRadius), static_cast<float>(pos.y() - maxRadius)};
409  float max[2] = {static_cast<float>(pos.x() + maxRadius), static_cast<float>(pos.y() + maxRadius)};
410  r.Search(min, max, visitor);
411  std::vector<NBEdge*> edgCants;
412  for (const Named* namedEdge : edges) {
413  NBEdge* e = const_cast<NBEdge*>(dynamic_cast<const NBEdge*>(namedEdge));
414  edgCants.push_back(e);
415  }
416  std::sort(edgCants.begin(), edgCants.end(), [pos](NBEdge * a, NBEdge * b) {
417  return a->getLaneShape(0).distance2D(pos, false) < b->getLaneShape(0).distance2D(pos, false);
418  });
419  int cnt = 0;
420  for (auto edge : edgCants) {
421  int laneIdx = 0;
422  for (auto lane : edge->getLanes()) {
423  if ((lane.permissions & SVC_PEDESTRIAN) != 0) {
424  double offset = lane.shape.nearest_offset_to_point2D(pos, false);
425  double finalLength = edge->getFinalLength();
426  double laneLength = lane.shape.length();
427  double accessLength = pos.distanceTo2D(lane.shape.positionAtOffset2D(offset)) * accessFactor;
428  ptStop.second->addAccess(edge->getLaneID(laneIdx), offset * finalLength / laneLength, accessLength);
429  cnt++;
430  break;
431  }
432  laneIdx++;
433  }
434  if (cnt == maxCount) {
435  break;
436  }
437  }
438  }
439  }
440 }
441 
442 
443 NBPTStop*
444 NBPTStopCont::findStop(const std::string& origEdgeID, Position pos, double threshold) const {
445  for (auto& item : myPTStops) {
446  if (item.second->getOrigEdgeId() == origEdgeID &&
447  item.second->getPosition().distanceTo2D(pos) < threshold) {
448  return item.second;
449  }
450  }
451  return nullptr;
452 }
453 
454 
455 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:282
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:35
@ SVC_PEDESTRIAN
pedestrian
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:129
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:117
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:135
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:123
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:59
NBEdge * getByID(const std::string &edgeID) const
Returns the edge with id if it exists.
EdgeVector getGeneratedFrom(const std::string &id) const
Returns the edges which have been built by splitting the edge of the given id.
The representation of a single edge during network building.
Definition: NBEdge.h:91
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4022
bool isBidiRail(bool ignoreSpread=false) const
whether this edge is part of a bidirectional railway
Definition: NBEdge.cpp:742
const std::string & getID() const
Definition: NBEdge.h:1465
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:541
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:752
NBEdge * getTurnDestination(bool possibleDestination=false) const
Definition: NBEdge.cpp:3684
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:534
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:261
double getLength() const
const Position & getPos() const
bool insert(NBPTStop *ptStop)
Inserts a node into the map.
static std::string getReverseID(const std::string &id)
int cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
static NBEdge * getReverseEdge(NBEdge *edge)
double computeCrossProductEdgePosition(const NBEdge *edge, const Position &closestPlatform) const
void postprocess(std::set< std::string > &usedStops)
std::map< std::string, std::vector< NBPTStop * > > myPTStopLookup
The map of edge ids to stops.
Definition: NBPTStopCont.h:106
NBPTStop * findStop(const std::string &origEdgeID, Position pos, double threshold=1) const
void replaceEdge(const std::string &edgeID, const EdgeVector &replacement)
replace the edge with the closes edge on the given edge list in all stops
void addEdges2Keep(const OptionsCont &oc, std::set< std::string > &into)
add edges that must be kept
std::map< std::string, NBPTStop * > PTStopsCont
Definition of the map of names to pt stops.
Definition: NBPTStopCont.h:100
NBPTStop * get(std::string id) const
Retrieve a previously inserted pt stop.
PTStopsCont myPTStops
The map of names to pt stops.
Definition: NBPTStopCont.h:103
NBPTStop * getReverseStop(NBPTStop *pStop, const NBEdgeCont &ec)
const NBPTPlatform * getClosestPlatformToPTStopPosition(NBPTStop *pStop)
void localizePTStops(NBEdgeCont &cont)
void alignIdSigns()
void findAccessEdgesForRailStops(NBEdgeCont &cont, double maxRadius, int maxCount, double accessFactor)
int generateBidiStops(NBEdgeCont &cont)
duplicate stops for superposed rail edges and return the number of generated stops
void assignLanes(NBEdgeCont &cont)
void assignPTStopToEdgeOfClosestPlatform(NBPTStop *pStop, NBEdgeCont &cont)
NBPTStop * assignAndCreatNewPTStopAsNeeded(NBPTStop *pStop, NBEdgeCont &cont)
The representation of a single pt stop.
Definition: NBPTStop.h:46
bool findLaneAndComputeBusStopExtent(const NBEdgeCont &ec)
Definition: NBPTStop.cpp:201
void setPTStopLength(double ptStopLength)
Definition: NBPTStop.h:151
bool setEdgeId(std::string edgeId, const NBEdgeCont &ec)
Definition: NBPTStop.cpp:188
const std::string getEdgeId() const
Definition: NBPTStop.cpp:66
std::string getID() const
Definition: NBPTStop.cpp:54
bool getIsMultipleStopPositions() const
Definition: NBPTStop.cpp:169
const std::vector< NBPTPlatform > & getPlatformCands()
Definition: NBPTStop.cpp:163
void setPTStopId(std::string id)
Definition: NBPTStop.h:100
double getLength() const
Definition: NBPTStop.cpp:182
void setBidiStop(NBPTStop *bidiStop)
Definition: NBPTStop.h:119
SVCPermissions getPermissions() const
Definition: NBPTStop.cpp:151
const Position & getPosition() const
Definition: NBPTStop.cpp:78
const std::string getOrigEdgeId() const
Definition: NBPTStop.cpp:60
const std::string getName() const
Definition: NBPTStop.cpp:72
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:90
Base class for objects which have an id.
Definition: Named.h:54
A RT-tree for efficient storing of SUMO's Named objects.
Definition: NamedRTree.h:61
void Insert(const float a_min[2], const float a_max[2], Named *const &a_data)
Insert entry.
Definition: NamedRTree.h:79
int Search(const float a_min[2], const float a_max[2], const Named::StoringVisitor &c) const
Find all within search rectangle.
Definition: NamedRTree.h:112
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.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
double distanceSquaredTo2D(const Position &p2) const
returns the square of the distance to another position (Only using x and y positions)
Definition: Position.h:257
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition: Position.h:252
double x() const
Returns the x-position.
Definition: Position.h:55
double y() const
Returns the y-position.
Definition: Position.h:60
A list of positions.
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
int indexOfClosest(const Position &p, bool twoD=false) const
double offsetAtIndex2D(int index) const
return the offset at the given index