SUMO - Simulation of Urban MObility
Helper.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2017-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
16 // C++ TraCI client API implementation
17 /****************************************************************************/
18 
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23 
24 #include <utils/geom/GeomHelper.h>
25 #include <microsim/MSNet.h>
28 #include <microsim/MSEdgeControl.h>
30 #include <microsim/MSEdge.h>
31 #include <microsim/MSLane.h>
32 #include <microsim/MSVehicle.h>
35 #include <libsumo/TraCIDefs.h>
36 #include <libsumo/Edge.h>
37 #include <libsumo/InductionLoop.h>
38 #include <libsumo/Junction.h>
39 #include <libsumo/Lane.h>
40 #include <libsumo/LaneArea.h>
41 #include <libsumo/MultiEntryExit.h>
42 #include <libsumo/Person.h>
43 #include <libsumo/POI.h>
44 #include <libsumo/Polygon.h>
45 #include <libsumo/Route.h>
46 #include <libsumo/Simulation.h>
47 #include <libsumo/TrafficLight.h>
48 #include <libsumo/Vehicle.h>
49 #include <libsumo/VehicleType.h>
51 #include "Helper.h"
52 
53 #define FAR_AWAY 1000.0
54 
55 //#define DEBUG_MOVEXY
56 //#define DEBUG_MOVEXY_ANGLE
57 
58 
59 void
60 LaneStoringVisitor::add(const MSLane* const l) const {
61  switch (myDomain) {
63  const MSLane::VehCont& vehs = l->getVehiclesSecure();
64  for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
65  if (myShape.distance2D((*j)->getPosition()) <= myRange) {
66  myIDs.insert((*j)->getID());
67  }
68  }
69  l->releaseVehicles();
70  }
71  break;
73  l->getVehiclesSecure();
74  std::vector<MSTransportable*> persons = l->getEdge().getSortedPersons(MSNet::getInstance()->getCurrentTimeStep(), true);
75  for (auto p : persons) {
76  if (myShape.distance2D(p->getPosition()) <= myRange) {
77  myIDs.insert(p->getID());
78  }
79  }
80  l->releaseVehicles();
81  }
82  break;
83  case CMD_GET_EDGE_VARIABLE: {
84  if (myShape.size() != 1 || l->getShape().distance2D(myShape[0]) <= myRange) {
85  myIDs.insert(l->getEdge().getID());
86  }
87  }
88  break;
89  case CMD_GET_LANE_VARIABLE: {
90  if (myShape.size() != 1 || l->getShape().distance2D(myShape[0]) <= myRange) {
91  myIDs.insert(l->getID());
92  }
93  }
94  break;
95  default:
96  break;
97 
98  }
99 }
100 
101 namespace libsumo {
102 // ===========================================================================
103 // static member initializations
104 // ===========================================================================
105 std::vector<Subscription> Helper::mySubscriptions;
106 std::map<int, std::shared_ptr<VariableWrapper> > Helper::myWrapper;
107 Helper::VehicleStateListener Helper::myVehicleStateListener;
108 std::map<int, NamedRTree*> Helper::myObjects;
109 LANE_RTREE_QUAL* Helper::myLaneTree;
110 std::map<std::string, MSVehicle*> Helper::myRemoteControlledVehicles;
111 std::map<std::string, MSPerson*> Helper::myRemoteControlledPersons;
112 
113 
114 // ===========================================================================
115 // static member definitions
116 // ===========================================================================
117 void
118 Helper::subscribe(const int commandId, const std::string& id, const std::vector<int>& variables,
119  const double beginTime, const double endTime, const int contextDomain, const double range) {
120  std::vector<std::vector<unsigned char> > parameters;
121  const SUMOTime begin = beginTime == INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
122  const SUMOTime end = endTime == INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
123  libsumo::Subscription s(commandId, id, variables, parameters, begin, end, contextDomain, range);
124  mySubscriptions.push_back(s);
125  handleSingleSubscription(s);
126 }
127 
128 
129 void
130 Helper::handleSubscriptions(const SUMOTime t) {
131  for (const libsumo::Subscription& s : mySubscriptions) {
132  if (s.beginTime > t) {
133  continue;
134  }
135  handleSingleSubscription(s);
136  }
137 }
138 
139 
140 void
141 Helper::handleSingleSubscription(const Subscription& s) {
142  const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
143  std::set<std::string> objIDs;
144  if (s.contextDomain > 0) {
145  PositionVector shape;
146  findObjectShape(s.commandId, s.id, shape);
147  collectObjectsInRange(s.contextDomain, shape, s.range, objIDs);
148  } else {
149  objIDs.insert(s.id);
150  }
151  const int numVars = s.contextDomain > 0 && s.variables.size() == 1 && s.variables[0] == ID_LIST ? 0 : (int)s.variables.size();
152  if (myWrapper.empty()) {
153  myWrapper[CMD_GET_EDGE_VARIABLE] = Edge::makeWrapper();
154  myWrapper[CMD_GET_INDUCTIONLOOP_VARIABLE] = InductionLoop::makeWrapper();
155  myWrapper[CMD_GET_JUNCTION_VARIABLE] = Junction::makeWrapper();
156  myWrapper[CMD_GET_LANE_VARIABLE] = Lane::makeWrapper();
157  myWrapper[CMD_GET_LANEAREA_VARIABLE] = LaneArea::makeWrapper();
158  myWrapper[CMD_GET_MULTIENTRYEXIT_VARIABLE] = MultiEntryExit::makeWrapper();
159  myWrapper[CMD_GET_PERSON_VARIABLE] = Person::makeWrapper();
160  myWrapper[CMD_GET_POI_VARIABLE] = POI::makeWrapper();
161  myWrapper[CMD_GET_POLYGON_VARIABLE] = Polygon::makeWrapper();
162  myWrapper[CMD_GET_ROUTE_VARIABLE] = Route::makeWrapper();
163  myWrapper[CMD_GET_SIM_VARIABLE] = Simulation::makeWrapper();
164  myWrapper[CMD_GET_TL_VARIABLE] = TrafficLight::makeWrapper();
165  myWrapper[CMD_GET_VEHICLE_VARIABLE] = Vehicle::makeWrapper();
166  myWrapper[CMD_GET_VEHICLETYPE_VARIABLE] = VehicleType::makeWrapper();
167  }
168  auto wrapper = myWrapper.find(getCommandId);
169  if (wrapper == myWrapper.end()) {
170  throw TraCIException("Unsupported command specified");
171  }
172  std::shared_ptr<VariableWrapper> handler = wrapper->second;
173  for (const std::string& objID : objIDs) {
174  if (numVars > 0) {
175  for (const int variable : s.variables) {
176  handler->handle(objID, variable, handler.get());
177  }
178  } else {
179  if (!handler->handle(objID, LAST_STEP_VEHICLE_NUMBER, handler.get())) {
180  handler->handle(objID, ID_LIST, handler.get());
181  }
182  }
183  }
184 }
185 
186 
188 Helper::makeTraCIPositionVector(const PositionVector& positionVector) {
190  for (int i = 0; i < (int)positionVector.size(); ++i) {
191  tp.push_back(makeTraCIPosition(positionVector[i]));
192  }
193  return tp;
194 }
195 
196 
198 Helper::makePositionVector(const TraCIPositionVector& vector) {
199  PositionVector pv;
200  for (int i = 0; i < (int)vector.size(); i++) {
201  pv.push_back(Position(vector[i].x, vector[i].y));
202  }
203  return pv;
204 }
205 
206 
208 Helper::makeTraCIColor(const RGBColor& color) {
209  TraCIColor tc;
210  tc.a = color.alpha();
211  tc.b = color.blue();
212  tc.g = color.green();
213  tc.r = color.red();
214  return tc;
215 }
216 
217 
218 RGBColor
219 Helper::makeRGBColor(const TraCIColor& c) {
220  return RGBColor((unsigned char)c.r, (unsigned char)c.g, (unsigned char)c.b, (unsigned char)c.a);
221 }
222 
223 
225 Helper::makeTraCIPosition(const Position& position, const bool includeZ) {
226  TraCIPosition p;
227  p.x = position.x();
228  p.y = position.y();
229  p.z = includeZ ? position.z() : Position::INVALID.z();
230  return p;
231 }
232 
233 
234 Position
235 Helper::makePosition(const TraCIPosition& tpos) {
236  return Position(tpos.x, tpos.y, tpos.z);
237 }
238 
239 
240 MSEdge*
241 Helper::getEdge(const std::string& edgeID) {
242  MSEdge* edge = MSEdge::dictionary(edgeID);
243  if (edge == 0) {
244  throw TraCIException("Referenced edge '" + edgeID + "' is not known.");
245  }
246  return edge;
247 }
248 
249 
250 const MSLane*
251 Helper::getLaneChecking(const std::string& edgeID, int laneIndex, double pos) {
252  const MSEdge* edge = MSEdge::dictionary(edgeID);
253  if (edge == 0) {
254  throw TraCIException("Unknown edge " + edgeID);
255  }
256  if (laneIndex < 0 || laneIndex >= (int)edge->getLanes().size()) {
257  throw TraCIException("Invalid lane index for " + edgeID);
258  }
259  const MSLane* lane = edge->getLanes()[laneIndex];
260  if (pos < 0 || pos > lane->getLength()) {
261  throw TraCIException("Position on lane invalid");
262  }
263  return lane;
264 }
265 
266 
267 std::pair<MSLane*, double>
268 Helper::convertCartesianToRoadMap(Position pos) {
270  std::pair<MSLane*, double> result;
271  std::vector<std::string> allEdgeIds;
272  double minDistance = std::numeric_limits<double>::max();
273 
274  allEdgeIds = MSNet::getInstance()->getEdgeControl().getEdgeNames();
275  for (std::vector<std::string>::iterator itId = allEdgeIds.begin(); itId != allEdgeIds.end(); itId++) {
276  const std::vector<MSLane*>& allLanes = MSEdge::dictionary((*itId))->getLanes();
277  for (std::vector<MSLane*>::const_iterator itLane = allLanes.begin(); itLane != allLanes.end(); itLane++) {
278  const double newDistance = (*itLane)->getShape().distance2D(pos);
279  if (newDistance < minDistance) {
280  minDistance = newDistance;
281  result.first = (*itLane);
282  }
283  }
284  }
285  // @todo this may be a place where 3D is required but 2D is delivered
286  result.second = result.first->getShape().nearest_offset_to_point2D(pos, false);
287  return result;
288 }
289 
290 
291 void
292 Helper::cleanup() {
293  for (const auto i : myObjects) {
294  delete i.second;
295  }
296  myObjects.clear();
297  delete myLaneTree;
298  myLaneTree = 0;
299 }
300 
301 
302 void
303 Helper::registerVehicleStateListener() {
304  MSNet::getInstance()->addVehicleStateListener(&myVehicleStateListener);
305 }
306 
307 
308 const std::vector<std::string>&
309 Helper::getVehicleStateChanges(const MSNet::VehicleState state) {
310  return myVehicleStateListener.myVehicleStateChanges[state];
311 }
312 
313 
314 void
315 Helper::clearVehicleStates() {
316  for (auto& i : myVehicleStateListener.myVehicleStateChanges) {
317  i.second.clear();
318  }
319 }
320 
321 
322 void
323 Helper::findObjectShape(int domain, const std::string& id, PositionVector& shape) {
324  switch (domain) {
326  InductionLoop::storeShape(id, shape);
327  break;
329  Lane::storeShape(id, shape);
330  break;
332  Vehicle::storeShape(id, shape);
333  break;
335  Person::storeShape(id, shape);
336  break;
338  POI::storeShape(id, shape);
339  break;
341  Polygon::storeShape(id, shape);
342  break;
344  Junction::storeShape(id, shape);
345  break;
347  Edge::storeShape(id, shape);
348  break;
349  default:
350  break;
351  }
352 }
353 
354 
355 void
356 Helper::collectObjectsInRange(int domain, const PositionVector& shape, double range, std::set<std::string>& into) {
357  // build the look-up tree if not yet existing
358  if (myObjects.find(domain) == myObjects.end()) {
359  switch (domain) {
361  myObjects[CMD_GET_INDUCTIONLOOP_VARIABLE] = InductionLoop::getTree();
362  break;
367  myObjects[CMD_GET_EDGE_VARIABLE] = 0;
368  myObjects[CMD_GET_LANE_VARIABLE] = 0;
369  myObjects[CMD_GET_PERSON_VARIABLE] = 0;
370  myObjects[CMD_GET_VEHICLE_VARIABLE] = 0;
371  myLaneTree = new LANE_RTREE_QUAL(&MSLane::visit);
372  MSLane::fill(*myLaneTree);
373  break;
375  myObjects[CMD_GET_POI_VARIABLE] = POI::getTree();
376  break;
378  myObjects[CMD_GET_POLYGON_VARIABLE] = Polygon::getTree();
379  break;
381  myObjects[CMD_GET_JUNCTION_VARIABLE] = Junction::getTree();
382  break;
383  default:
384  break;
385  }
386  }
387  const Boundary b = shape.getBoxBoundary().grow(range);
388  const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
389  const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
390  switch (domain) {
395  Named::StoringVisitor sv(into);
396  myObjects[domain]->Search(cmin, cmax, sv);
397  }
398  break;
403  LaneStoringVisitor sv(into, shape, range, domain);
404  myLaneTree->Search(cmin, cmax, sv);
405  }
406  break;
407  default:
408  break;
409  }
410 }
411 
412 void
413 Helper::setRemoteControlled(MSVehicle* v, Position xyPos, MSLane* l, double pos, double posLat, double angle,
414  int edgeOffset, ConstMSEdgeVector route, SUMOTime t) {
415  myRemoteControlledVehicles[v->getID()] = v;
416  v->getInfluencer().setRemoteControlled(xyPos, l, pos, posLat, angle, edgeOffset, route, t);
417 }
418 
419 void
420 Helper::setRemoteControlled(MSPerson* p, Position xyPos, MSLane* l, double pos, double posLat, double angle,
421  int edgeOffset, ConstMSEdgeVector route, SUMOTime t) {
422  myRemoteControlledPersons[p->getID()] = p;
423  p->getInfluencer().setRemoteControlled(xyPos, l, pos, posLat, angle, edgeOffset, route, t);
424 }
425 
426 
427 void
428 Helper::postProcessRemoteControl() {
429  for (auto& controlled : myRemoteControlledVehicles) {
430  if (MSNet::getInstance()->getVehicleControl().getVehicle(controlled.first) != 0) {
431  controlled.second->getInfluencer().postProcessRemoteControl(controlled.second);
432  } else {
433  WRITE_WARNING("Vehicle '" + controlled.first + "' was removed though being controlled by TraCI");
434  }
435  }
436  myRemoteControlledVehicles.clear();
437  for (auto& controlled : myRemoteControlledPersons) {
438  if (MSNet::getInstance()->getPersonControl().get(controlled.first) != 0) {
439  controlled.second->getInfluencer().postProcessRemoteControl(controlled.second);
440  } else {
441  WRITE_WARNING("Person '" + controlled.first + "' was removed though being controlled by TraCI");
442  }
443  }
444  myRemoteControlledPersons.clear();
445 }
446 
447 
448 bool
449 Helper::moveToXYMap(const Position& pos, double maxRouteDistance, bool mayLeaveNetwork, const std::string& origID, const double angle,
450  double speed, const ConstMSEdgeVector& currentRoute, const int routePosition, MSLane* currentLane, double currentLanePos, bool onRoad,
451  double& bestDistance, MSLane** lane, double& lanePos, int& routeOffset, ConstMSEdgeVector& edges) {
452  // collect edges around the vehicle/person
453  const MSEdge* const currentRouteEdge = currentRoute[routePosition];
454  std::set<std::string> into;
455  PositionVector shape;
456  shape.push_back(pos);
457  collectObjectsInRange(CMD_GET_EDGE_VARIABLE, shape, maxRouteDistance, into);
458  double maxDist = 0;
459  std::map<MSLane*, LaneUtility> lane2utility;
460  // compute utility for all candidate edges
461  for (std::set<std::string>::const_iterator j = into.begin(); j != into.end(); ++j) {
462  const MSEdge* const e = MSEdge::dictionary(*j);
463  const MSEdge* prevEdge = 0;
464  const MSEdge* nextEdge = 0;
465  bool onRoute = false;
466  // the next if/the clause sets "onRoute", "prevEdge", and "nextEdge", depending on
467  // whether the currently seen edge is an internal one or a normal one
468  if (!e->isInternal()) {
469 #ifdef DEBUG_MOVEXY_ANGLE
470  std::cout << "Ego on normal" << std::endl;
471 #endif
472  // a normal edge
473  //
474  // check whether the currently seen edge is in the vehicle's route
475  // - either the one it's on or one of the next edges
476  ConstMSEdgeVector::const_iterator searchStart = currentRoute.begin() + routePosition;
477  if (onRoad && currentLane->getEdge().isInternal()) {
478  ++searchStart;
479  }
480  ConstMSEdgeVector::const_iterator edgePos = std::find(searchStart, currentRoute.end(), e);
481  onRoute = edgePos != currentRoute.end(); // no? -> onRoute is false
482  if (edgePos == currentRoute.end() - 1 && currentRouteEdge == e) {
483  // onRoute is false as well if the vehicle is beyond the edge
484  onRoute &= currentRouteEdge->getLength() > currentLanePos + SPEED2DIST(speed);
485  }
486  // save prior and next edges
487  prevEdge = e;
488  nextEdge = !onRoute || edgePos == currentRoute.end() - 1 ? 0 : *(edgePos + 1);
489 #ifdef DEBUG_MOVEXY_ANGLE
490  std::cout << "normal:" << e->getID() << " prev:" << prevEdge->getID() << " next:";
491  if (nextEdge != 0) {
492  std::cout << nextEdge->getID();
493  }
494  std::cout << std::endl;
495 #endif
496  } else {
497 #ifdef DEBUG_MOVEXY_ANGLE
498  std::cout << "Ego on internal" << std::endl;
499 #endif
500  // an internal edge
501  // get the previous edge
502  prevEdge = e;
503  while (prevEdge != 0 && prevEdge->isInternal()) {
504  MSLane* l = prevEdge->getLanes()[0];
505  l = l->getLogicalPredecessorLane();
506  prevEdge = l == 0 ? 0 : &l->getEdge();
507  }
508  // check whether the previous edge is on the route (was on the route)
509  ConstMSEdgeVector::const_iterator prevEdgePos = std::find(currentRoute.begin() + routePosition, currentRoute.end(), prevEdge);
510  nextEdge = e;
511  while (nextEdge != 0 && nextEdge->isInternal()) {
512  nextEdge = nextEdge->getSuccessors()[0]; // should be only one for an internal edge
513  }
514  if (prevEdgePos != currentRoute.end() && (prevEdgePos + 1) != currentRoute.end()) {
515  onRoute = *(prevEdgePos + 1) == nextEdge;
516  }
517 #ifdef DEBUG_MOVEXY_ANGLE
518  std::cout << "internal:" << e->getID() << " prev:" << prevEdge->getID() << " next:" << nextEdge->getID() << std::endl;
519 #endif
520  }
521 
522 
523  // weight the lanes...
524  const std::vector<MSLane*>& lanes = e->getLanes();
525  const bool perpendicular = false;
526  for (std::vector<MSLane*>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
527  MSLane* lane = *k;
528  double langle = 180.;
529  double dist = FAR_AWAY;
530  double perpendicularDist = FAR_AWAY;
531  double off = lane->getShape().nearest_offset_to_point2D(pos, true);
532  if (off != GeomHelper::INVALID_OFFSET) {
533  perpendicularDist = lane->getShape().distance2D(pos, true);
534  }
535  off = lane->getShape().nearest_offset_to_point2D(pos, perpendicular);
536  if (off != GeomHelper::INVALID_OFFSET) {
537  dist = lane->getShape().distance2D(pos, perpendicular);
538  langle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(off));
539  }
540  bool sameEdge = onRoad && &lane->getEdge() == &currentLane->getEdge() && currentRouteEdge->getLength() > currentLanePos + SPEED2DIST(speed);
541  /*
542  const MSEdge* rNextEdge = nextEdge;
543  while(rNextEdge==0&&lane->getEdge().getPurpose()==MSEdge::EDGEFUNCTION_INTERNAL) {
544  MSLane* next = lane->getLinkCont()[0]->getLane();
545  rNextEdge = next == 0 ? 0 : &next->getEdge();
546  }
547  */
548  double dist2 = dist;
549  if (mayLeaveNetwork && dist != perpendicularDist) {
550  // ambiguous mapping. Don't trust this
551  dist2 = FAR_AWAY;
552  }
553  const double angleDiff = (angle == INVALID_DOUBLE_VALUE ? 0 : GeomHelper::getMinAngleDiff(angle, langle));
554 #ifdef DEBUG_MOVEXY_ANGLE
555  std::cout << lane->getID() << " lAngle:" << langle << " lLength=" << lane->getLength()
556  << " angleDiff:" << angleDiff
557  << " off:" << off
558  << " pDist=" << perpendicularDist
559  << " dist=" << dist
560  << " dist2=" << dist2
561  << "\n";
562  std::cout << lane->getID() << " param=" << lane->getParameter(SUMO_PARAM_ORIGID, lane->getID()) << " origID='" << origID << "\n";
563 #endif
564  lane2utility[lane] = LaneUtility(
565  dist2, perpendicularDist, off, angleDiff,
566  lane->getParameter(SUMO_PARAM_ORIGID, lane->getID()) == origID,
567  onRoute, sameEdge, prevEdge, nextEdge);
568  // update scaling value
569  maxDist = MAX2(maxDist, MIN2(dist, SUMO_const_laneWidth));
570 
571  }
572  }
573 
574  // get the best lane given the previously computed values
575  double bestValue = 0;
576  MSLane* bestLane = 0;
577  for (std::map<MSLane*, LaneUtility>::iterator i = lane2utility.begin(); i != lane2utility.end(); ++i) {
578  MSLane* l = (*i).first;
579  const LaneUtility& u = (*i).second;
580  double distN = u.dist > 999 ? -10 : 1. - (u.dist / maxDist);
581  double angleDiffN = 1. - (u.angleDiff / 180.);
582  double idN = u.ID ? 1 : 0;
583  double onRouteN = u.onRoute ? 1 : 0;
584  double sameEdgeN = u.sameEdge ? MIN2(currentRouteEdge->getLength() / speed, (double)1.) : 0;
585  double value = (distN * .5 // distance is more important than angle because the vehicle might be driving in the opposite direction
586  + angleDiffN * 0.35 /*.5 */
587  + idN * 1
588  + onRouteN * 0.1
589  + sameEdgeN * 0.1);
590 #ifdef DEBUG_MOVEXY
591  std::cout << " x; l:" << l->getID() << " d:" << u.dist << " dN:" << distN << " aD:" << angleDiffN <<
592  " ID:" << idN << " oRN:" << onRouteN << " sEN:" << sameEdgeN << " value:" << value << std::endl;
593 #endif
594  if (value > bestValue || bestLane == 0) {
595  bestValue = value;
596  if (u.dist == FAR_AWAY) {
597  bestLane = 0;
598  } else {
599  bestLane = l;
600  }
601  }
602  }
603  // no best lane found, return
604  if (bestLane == 0) {
605  return false;
606  }
607  const LaneUtility& u = lane2utility.find(bestLane)->second;
608  bestDistance = u.dist;
609  *lane = bestLane;
610  lanePos = bestLane->getShape().nearest_offset_to_point2D(pos, false);
611  const MSEdge* prevEdge = u.prevEdge;
612  if (u.onRoute) {
613  ConstMSEdgeVector::const_iterator prevEdgePos = std::find(currentRoute.begin(), currentRoute.end(), prevEdge);
614  routeOffset = (int)std::distance(currentRoute.begin(), prevEdgePos);
615  //std::cout << SIMTIME << "moveToXYMap vehicle=" << veh.getID() << " currLane=" << veh.getLane()->getID() << " routeOffset=" << routeOffset << " edges=" << toString(ev) << " bestLane=" << bestLane->getID() << " prevEdge=" << prevEdge->getID() << "\n";
616  } else {
617  edges.push_back(u.prevEdge);
618  /*
619  if(bestLane->getEdge().getPurpose()!=MSEdge::EDGEFUNCTION_INTERNAL) {
620  edges.push_back(&bestLane->getEdge());
621  }
622  */
623  if (u.nextEdge != 0) {
624  edges.push_back(u.nextEdge);
625  }
626  routeOffset = 0;
627 #ifdef DEBUG_MOVEXY_ANGLE
628  std::cout << "internal2: lane=" << bestLane->getID() << " prev=" << Named::getIDSecure(u.prevEdge) << " next=" << Named::getIDSecure(u.nextEdge) << "\n";;
629 #endif
630  }
631  return true;
632 }
633 
634 
635 bool
636 Helper::findCloserLane(const MSEdge* edge, const Position& pos, double& bestDistance, MSLane** lane) {
637  if (edge == 0) {
638  return false;
639  }
640  const std::vector<MSLane*>& lanes = edge->getLanes();
641  bool newBest = false;
642  for (std::vector<MSLane*>::const_iterator k = lanes.begin(); k != lanes.end() && bestDistance > POSITION_EPS; ++k) {
643  MSLane* candidateLane = *k;
644  const double dist = candidateLane->getShape().distance2D(pos); // get distance
645 #ifdef DEBUG_MOVEXY
646  std::cout << " b at lane " << candidateLane->getID() << " dist:" << dist << " best:" << bestDistance << std::endl;
647 #endif
648  if (dist < bestDistance) {
649  // is the new distance the best one? keep then...
650  bestDistance = dist;
651  *lane = candidateLane;
652  newBest = true;
653  }
654  }
655  return newBest;
656 }
657 
658 
659 bool
660 Helper::moveToXYMap_matchingRoutePosition(const Position& pos, const std::string& origID,
661  const ConstMSEdgeVector& currentRoute, int routeIndex,
662  double& bestDistance, MSLane** lane, double& lanePos, int& routeOffset) {
663  //std::cout << "moveToXYMap_matchingRoutePosition pos=" << pos << "\n";
664  routeOffset = 0;
665  // routes may be looped which makes routeOffset ambiguous. We first try to
666  // find the closest upcoming edge on the route and then look for closer passed edges
667 
668  // look forward along the route
669  const MSEdge* prev = 0;
670  for (int i = routeIndex; i < (int)currentRoute.size(); ++i) {
671  const MSEdge* cand = currentRoute[i];
672  while (prev != 0) {
673  // check internal edge(s)
674  const MSEdge* internalCand = prev->getInternalFollowingEdge(cand);
675  findCloserLane(internalCand, pos, bestDistance, lane);
676  prev = internalCand;
677  }
678  if (findCloserLane(cand, pos, bestDistance, lane)) {
679  routeOffset = i;
680  }
681  prev = cand;
682  }
683  // look backward along the route
684  const MSEdge* next = currentRoute[routeIndex];
685  for (int i = routeIndex; i >= 0; --i) {
686  const MSEdge* cand = currentRoute[i];
687  //std::cout << " next=" << next->getID() << " cand=" << cand->getID() << " i=" << i << " routeIndex=" << routeIndex << "\n";
688  prev = cand;
689  while (prev != 0) {
690  // check internal edge(s)
691  const MSEdge* internalCand = prev->getInternalFollowingEdge(next);
692  if (findCloserLane(internalCand, pos, bestDistance, lane)) {
693  routeOffset = i;
694  }
695  prev = internalCand;
696  }
697  if (findCloserLane(cand, pos, bestDistance, lane)) {
698  routeOffset = i;
699  }
700  next = cand;
701  }
702 
703  assert(lane != 0);
704  // quit if no solution was found, reporting a failure
705  if (lane == 0) {
706 #ifdef DEBUG_MOVEXY
707  std::cout << " b failed - no best route lane" << std::endl;
708 #endif
709  return false;
710  }
711 
712 
713  // position may be inaccurate; let's checkt the given index, too
714  // @note: this is enabled for non-internal lanes only, as otherwise the position information may ambiguous
715  if (!(*lane)->getEdge().isInternal()) {
716  const std::vector<MSLane*>& lanes = (*lane)->getEdge().getLanes();
717  for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
718  if ((*i)->getParameter(SUMO_PARAM_ORIGID, (*i)->getID()) == origID) {
719  *lane = *i;
720  break;
721  }
722  }
723  }
724  // check position, stuff, we should have the best lane along the route
725  lanePos = MAX2(0., MIN2(double((*lane)->getLength() - POSITION_EPS),
726  (*lane)->interpolateGeometryPosToLanePos(
727  (*lane)->getShape().nearest_offset_to_point2D(pos, false))));
728  //std::cout << SIMTIME << " moveToXYMap_matchingRoutePosition vehicle=" << veh.getID() << " currLane=" << veh.getLane()->getID() << " routeOffset=" << routeOffset << " edges=" << toString(edges) << " lane=" << (*lane)->getID() << "\n";
729 #ifdef DEBUG_MOVEXY
730  std::cout << " b ok lane " << (*lane)->getID() << " lanePos:" << lanePos << std::endl;
731 #endif
732  return true;
733 }
734 
735 
736 Helper::SubscriptionWrapper::SubscriptionWrapper(VariableWrapper::SubscriptionHandler handler, SubscriptionResults& into, ContextSubscriptionResults& context)
737  : VariableWrapper(handler), myResults(into), myContextResults(context), myActiveResults(into) {
738 
739 }
740 
741 
742 void
743 Helper::SubscriptionWrapper::setContext(const std::string& refID) {
744  myActiveResults = refID == "" ? myResults : myContextResults[refID];
745 }
746 
747 
748 bool
749 Helper::SubscriptionWrapper::wrapDouble(const std::string& objID, const int variable, const double value) {
750  myActiveResults[objID][variable] = std::make_shared<TraCIDouble>(value);
751  return true;
752 }
753 
754 
755 bool
756 Helper::SubscriptionWrapper::wrapInt(const std::string& objID, const int variable, const int value) {
757  myActiveResults[objID][variable] = std::make_shared<TraCIInt>(value);
758  return true;
759 }
760 
761 
762 bool
763 Helper::SubscriptionWrapper::wrapString(const std::string& objID, const int variable, const std::string& value) {
764  myActiveResults[objID][variable] = std::make_shared<TraCIString>(value);
765  return true;
766 }
767 
768 
769 bool
770 Helper::SubscriptionWrapper::wrapStringList(const std::string& objID, const int variable, const std::vector<std::string>& value) {
771  auto sl = std::make_shared<TraCIStringList>();
772  sl->value = value;
773  myActiveResults[objID][variable] = sl;
774  return true;
775 }
776 
777 
778 bool
779 Helper::SubscriptionWrapper::wrapPosition(const std::string& objID, const int variable, const TraCIPosition& value) {
780  myActiveResults[objID][variable] = std::make_shared<TraCIPosition>(value);
781  return true;
782 }
783 
784 
785 bool
786 Helper::SubscriptionWrapper::wrapColor(const std::string& objID, const int variable, const TraCIColor& value) {
787  myActiveResults[objID][variable] = std::make_shared<TraCIColor>(value);
788  return true;
789 }
790 
791 
792 void
793 Helper::VehicleStateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
794  myVehicleStateChanges[to].push_back(vehicle->getID());
795 }
796 
797 
798 }
799 
800 
801 /****************************************************************************/
static double getMinAngleDiff(double angle1, double angle2)
Returns the minimum distance (clockwise/counter-clockwise) between both angles.
Definition: GeomHelper.cpp:161
unsigned char g
Definition: TraCIDefs.h:139
std::map< std::string, TraCIResults > SubscriptionResults
{object->{variable->value}}
Definition: TraCIDefs.h:199
const MSEdge * prevEdge
Definition: Helper.h:168
#define FAR_AWAY
Definition: Helper.cpp:53
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:2382
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:131
const MSEdge * nextEdge
Definition: Helper.h:169
#define CMD_SUBSCRIBE_VEHICLE_CONTEXT
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:125
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:617
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:79
Representation of a subscription.
Definition: Subscription.h:63
long long int SUMOTime
Definition: SUMOTime.h:36
double range
The range of the context.
Definition: Subscription.h:96
#define CMD_GET_TL_VARIABLE
#define CMD_SUBSCRIBE_JUNCTION_CONTEXT
#define SPEED2DIST(x)
Definition: SUMOTime.h:48
const int myDomain
Definition: Helper.h:64
double z() const
Returns the z-position.
Definition: Position.h:66
#define CMD_GET_VEHICLE_VARIABLE
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector) ...
#define LANE_RTREE_QUAL
Definition: Helper.h:74
#define CMD_GET_INDUCTIONLOOP_VARIABLE
bool wrapDouble(const std::string &objID, const int variable, const double value)
Definition: Helper.cpp:749
bool wrapString(const std::string &objID, const int variable, const std::string &value)
Definition: Helper.cpp:763
static void fill(RTREE &into)
Fills the given RTree with lane instances.
Definition: MSLane.cpp:1748
unsigned char alpha() const
Returns the alpha-amount of the color.
Definition: RGBColor.h:83
const double SUMO_const_laneWidth
Definition: StdDefs.h:51
double y() const
Returns the y-position.
Definition: Position.h:61
#define CMD_GET_LANEAREA_VARIABLE
#define CMD_GET_PERSON_VARIABLE
double x() const
Returns the x-position.
Definition: Position.h:56
void setRemoteControlled(Position xyPos, MSLane *l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector &route, SUMOTime t)
Definition: MSPerson.cpp:706
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:162
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:160
T MAX2(T a, T b)
Definition: StdDefs.h:76
void visit(const LaneStoringVisitor &cont) const
Callback for visiting the lane when traversing an RTree.
Definition: MSLane.h:1080
double getLength() const
Returns the lane&#39;s length.
Definition: MSLane.h:507
virtual const VehCont & getVehiclesSecure() const
Returns the vehicles container; locks it for microsimulation.
Definition: MSLane.h:399
const PositionVector & getShape() const
Returns this lane&#39;s shape.
Definition: MSLane.h:449
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:62
#define CMD_SUBSCRIBE_POLYGON_CONTEXT
static bool dictionary(const std::string &id, MSEdge *edge)
Inserts edge into the static dictionary Returns true if the key id isn&#39;t already in the dictionary...
Definition: MSEdge.cpp:742
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.h:76
std::map< std::string, SubscriptionResults > ContextSubscriptionResults
Definition: TraCIDefs.h:200
#define CMD_GET_POLYGON_VARIABLE
ContextSubscriptionResults myContextResults
Definition: Helper.h:185
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:72
SubscriptionResults & myActiveResults
Definition: Helper.h:186
const std::string & getID() const
Returns the id.
Definition: Named.h:69
#define TIME2STEPS(x)
Definition: SUMOTime.h:60
bool wrapPosition(const std::string &objID, const int variable, const TraCIPosition &value)
Definition: Helper.cpp:779
double getLength() const
return the length of the edge
Definition: MSEdge.h:563
std::vector< MSTransportable * > getSortedPersons(SUMOTime timestep, bool includeRiding=false) const
Returns this edge&#39;s persons sorted by pos.
Definition: MSEdge.cpp:874
void addVehicleStateListener(VehicleStateListener *listener)
Adds a vehicle states listener.
Definition: MSNet.cpp:810
#define CMD_GET_ROUTE_VARIABLE
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:42
#define CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:242
std::vector< std::string > getEdgeNames() const
Returns the list of names of all known edges.
std::string id
The id of the object that is subscribed.
Definition: Subscription.h:84
bool wrapColor(const std::string &objID, const int variable, const TraCIColor &value)
Definition: Helper.cpp:786
int commandId
commandIdArg The command id of the subscription
Definition: Subscription.h:82
#define CMD_SUBSCRIBE_LANE_CONTEXT
unsigned char b
Definition: TraCIDefs.h:139
#define CMD_GET_VEHICLETYPE_VARIABLE
A road/street connecting two junctions.
Definition: MSEdge.h:75
static double naviDegree(const double angle)
Definition: GeomHelper.cpp:180
Influencer & getInfluencer()
Returns the velocity/lane influencer.
Definition: MSPerson.cpp:681
Representation of a vehicle.
Definition: SUMOVehicle.h:60
int contextDomain
The domain ID of the context.
Definition: Subscription.h:94
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
#define CMD_GET_POI_VARIABLE
A list of positions.
bool wrapStringList(const std::string &objID, const int variable, const std::vector< std::string > &value)
Definition: Helper.cpp:770
unsigned char a
Definition: TraCIDefs.h:139
const double myRange
Definition: Helper.h:63
#define STEPS2TIME(x)
Definition: SUMOTime.h:58
#define CMD_GET_LANE_VARIABLE
void add(const MSLane *const l) const
Adds the given object to the container.
Definition: Helper.cpp:60
T MIN2(T a, T b)
Definition: StdDefs.h:70
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:119
#define POSITION_EPS
Definition: config.h:172
const std::string & getID() const
returns the id of the transportable
#define CMD_GET_SIM_VARIABLE
#define CMD_GET_EDGE_VARIABLE
SubscriptionResults myResults
Definition: Helper.h:184
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:301
unsigned char r
Definition: TraCIDefs.h:139
#define CMD_SUBSCRIBE_EDGE_CONTEXT
#define CMD_GET_JUNCTION_VARIABLE
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
Definition: GeomHelper.h:52
void setRemoteControlled(Position xyPos, MSLane *l, double pos, double posLat, double angle, int edgeOffset, const ConstMSEdgeVector &route, SUMOTime t)
Definition: MSVehicle.cpp:473
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:224
std::vector< MSVehicle * > VehCont
Container for vehicles.
Definition: MSLane.h:83
Definition: Edge.cpp:30
const MSEdge * getInternalFollowingEdge(const MSEdge *followerAfterInternal) const
Definition: MSEdge.cpp:652
#define INVALID_DOUBLE_VALUE
VehicleState
Definition of a vehicle state.
Definition: MSNet.h:487
#define LAST_STEP_VEHICLE_NUMBER
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: MSEdge.cpp:926
Allows to store the object; used as context while traveling the rtree in TraCI.
Definition: Named.h:85
std::set< std::string > & myIDs
The container.
Definition: Helper.h:61
Influencer & getInfluencer()
Returns the velocity/lane influencer.
Definition: MSVehicle.cpp:5197
#define SUMOTime_MAX
Definition: SUMOTime.h:37
void vehicleStateChanged(const SUMOVehicle *const vehicle, MSNet::VehicleState to, const std::string &info="")
Called if a vehicle changes its state.
Definition: Helper.cpp:793
const PositionVector & myShape
Definition: Helper.h:62
#define CMD_SUBSCRIBE_PERSON_CONTEXT
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.h:69
std::vector< int > variables
The subscribed variables.
Definition: Subscription.h:86
#define CMD_GET_MULTIENTRYEXIT_VARIABLE
bool wrapInt(const std::string &objID, const int variable, const int value)
Definition: Helper.cpp:756
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
const std::string SUMO_PARAM_ORIGID
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.h:62
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition: MSNet.h:352
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:137
A 3D-position.
Definition: TraCIDefs.h:107
virtual void releaseVehicles() const
Allows to use the container for microsimulation again.
Definition: MSLane.h:429
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
#define ID_LIST
const std::string & getID() const
Returns the name of the vehicle.
#define CMD_SUBSCRIBE_POI_CONTEXT
Representation of a lane in the micro simulation.
Definition: MSLane.h:71
A list of positions.
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:274
void setContext(const std::string &refID)
Definition: Helper.cpp:743