SUMO - Simulation of Urban MObility
MSDevice_SSM.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2013-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 /****************************************************************************/
18 // An SSM-device logs encounters / conflicts of the carrying vehicle with other surrounding vehicles
19 // XXX: Preliminary implementation. Use with care. Especially rerouting vehicles could be problematic.
20 // TODO: implement SSM time-gap (estimated conflict entry and exit times are already calculated for PET calculation)
21 /****************************************************************************/
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <iostream>
30 #include <utils/geom/GeomHelper.h>
35 #include <microsim/MSNet.h>
36 #include <microsim/MSJunction.h>
37 #include <microsim/MSLane.h>
38 #include <microsim/MSEdge.h>
39 #include <microsim/MSVehicle.h>
41 #include <utils/geom/Position.h>
43 #include "MSDevice_SSM.h"
44 
45 // ===========================================================================
46 // Debug constants
47 // ===========================================================================
48 //#define DEBUG_SSM
49 //#define DEBUG_SSM_DRAC
50 //#define DEBUG_SSM_SURROUNDING
51 //#define DEBUG_SSM_NOTIFICATIONS
52 
53 // ===========================================================================
54 // Constants
55 // ===========================================================================
56 // value indicating an invalid double parameter
57 #define INVALID std::numeric_limits<double>::max()
58 
59 // default value for the detection range of potential opponents
60 #define DEFAULT_RANGE 50.0
61 
62 // list of implemented SSMs (NOTE: To add more SSMs, identifiers are added to AVAILABLE_SSMS
63 // and a default threshold must be defined. A corresponding
64 // case should be added to the switch in buildVehicleDevices,
65 // and in computeSSMs(), the SSM-value should be computed.)
66 #define AVAILABLE_SSMS "TTC DRAC PET BR SGAP TGAP"
67 
68 #define DEFAULT_THRESHOLD_TTC 3. // in [s.], events get logged if time to collision is below threshold (1.5s. is an appropriate criticality threshold according to Van der Horst, A. R. A. (1991). Time-to-collision as a Cue for Decision-making in Braking [also see Guido et al. 2011])
69 #define DEFAULT_THRESHOLD_DRAC 3. // in [m/s^2], events get logged if "deceleration to avoid a crash" is above threshold (3.4s. is an appropriate criticality threshold according to American Association of State Highway and Transportation Officials (2004). A Policy on Geometric Design of Highways and Streets [also see Guido et al. 2011])
70 #define DEFAULT_THRESHOLD_PET 2. // in seconds, events get logged if post encroachment time is below threshold
71 
72 #define DEFAULT_THRESHOLD_BR 0.0 // in [m/s^2], events get logged if brake rate is above threshold
73 #define DEFAULT_THRESHOLD_SGAP 0.2 // in [m.], events get logged if the space headway is below threshold.
74 #define DEFAULT_THRESHOLD_TGAP 0.5 // in [m.], events get logged if the time headway is below threshold.
75 
76 #define DEFAULT_EXTRA_TIME 5. // in seconds, events get logged for extra time even if encounter is over
77 
78 // ===========================================================================
79 // method definitions
80 // ===========================================================================
81 
82 
83 
85 std::ostream& operator<<(std::ostream& out, MSDevice_SSM::EncounterType type) {
86  switch (type) {
88  out << "NOCONFLICT_AHEAD";
89  break;
91  out << "FOLLOWING";
92  break;
94  out << "FOLLOWING_FOLLOWER";
95  break;
97  out << "FOLLOWING_LEADER";
98  break;
100  out << "ON_ADJACENT_LANES";
101  break;
103  out << "MERGING";
104  break;
106  out << "MERGING_LEADER";
107  break;
109  out << "MERGING_FOLLOWER";
110  break;
112  out << "MERGING_ADJACENT";
113  break;
115  out << "CROSSING";
116  break;
118  out << "CROSSING_LEADER";
119  break;
121  out << "CROSSING_FOLLOWER";
122  break;
124  out << "EGO_ENTERED_CONFLICT_AREA";
125  break;
127  out << "FOE_ENTERED_CONFLICT_AREA";
128  break;
130  out << "BOTH_ENTERED_CONFLICT_AREA";
131  break;
133  out << "EGO_LEFT_CONFLICT_AREA";
134  break;
136  out << "FOE_LEFT_CONFLICT_AREA";
137  break;
139  out << "BOTH_LEFT_CONFLICT_AREA";
140  break;
142  out << "FOLLOWING_PASSED";
143  break;
145  out << "MERGING_PASSED";
146  break;
147  // Collision (currently unused, might be differentiated further)
149  out << "COLLISION";
150  break;
151  default:
152  out << "unknown type (" << int(type) << ")";
153  break;
154  }
155  return out;
156 }
157 
158 
159 // ---------------------------------------------------------------------------
160 // static initialisation methods
161 // ---------------------------------------------------------------------------
162 
163 std::set<MSDevice_SSM*>* MSDevice_SSM::instances = new std::set<MSDevice_SSM*>();
164 
165 std::set<std::string> MSDevice_SSM::createdOutputFiles;
166 
167 const std::set<MSDevice_SSM*>&
169  return *instances;
170 }
171 
172 void
174  // Close current encounters and flush conflicts to file for all existing devices
175  if (instances != 0) {
176  for (std::set<MSDevice_SSM*>::iterator ii = instances->begin(); ii != instances->end(); ++ii) {
177  (*ii)->resetEncounters();
178  (*ii)->flushConflicts(true);
179  (*ii)->flushGlobalMeasures();
180  }
181  instances->clear();
182  }
183  for (auto& fn : createdOutputFiles) {
185  file->closeTag();
186  }
187 }
188 
189 void
191  oc.addOptionSubTopic("SSM Device");
192  insertDefaultAssignmentOptions("ssm", "SSM Device", oc);
193 
194  // custom options
195  oc.doRegister("device.ssm.measures", new Option_String(""));
196  oc.addDescription("device.ssm.measures", "SSM Device", "Specifies which measures will be logged (as a space seperated sequence of IDs in ('TTC', 'DRAC', 'PET')).");
197  oc.doRegister("device.ssm.thresholds", new Option_String(""));
198  oc.addDescription("device.ssm.thresholds", "SSM Device", "Specifies thresholds corresponding to the specified measures (see documentation and watch the order!). Only events exceeding the thresholds will be logged.");
199  oc.doRegister("device.ssm.trajectories", new Option_Bool(false));
200  oc.addDescription("device.ssm.trajectories", "SSM Device", "Specifies whether trajectories will be logged (if false, only the extremal values and times are reported, this is the default).");
201  oc.doRegister("device.ssm.range", new Option_Float(DEFAULT_RANGE));
202  oc.addDescription("device.ssm.range", "SSM Device", "Specifies the detection range in meters (default is " + toString(DEFAULT_RANGE) + "m.). For vehicles below this distance from the equipped vehicle, SSM values are traced.");
203  oc.doRegister("device.ssm.extratime", new Option_Float(DEFAULT_EXTRA_TIME));
204  oc.addDescription("device.ssm.extratime", "SSM Device", "Specifies the time in seconds to be logged after a conflict is over (default is " + toString(DEFAULT_EXTRA_TIME) + "secs.). Required >0 if PET is to be calculated for crossing conflicts.");
205  oc.doRegister("device.ssm.geo", new Option_Bool(false));
206  oc.addDescription("device.ssm.geo", "SSM Device", "Whether to use coordinates of the original reference system in output (default is false).");
207 }
208 
209 void
210 MSDevice_SSM::buildVehicleDevices(SUMOVehicle& v, std::vector<MSDevice*>& into) {
213  WRITE_WARNING("SSM Device for vehicle '" + v.getID() + "' will not be built. (SSMs not supported in MESO)");
214  return;
215  }
216  // ID for the device
217  std::string deviceID = "ssm_" + v.getID();
218 
219  // Load parameters:
220 
221  // Measures and thresholds
222  std::map<std::string, double> thresholds;
223  bool success = getMeasuresAndThresholds(v, deviceID, thresholds);
224  if (!success) {
225  return;
226  }
227 
228  // TODO: modify trajectory option: "all", "conflictPoints", ("position" && "speed" == "vehState"), "SSMs"!
229  // Trajectories
230  bool trajectories = requestsTrajectories(v);
231 
232  // detection range
233  double range = getDetectionRange(v);
234 
235  // extra time
236  double extraTime = getExtraTime(v);
237 
238  // File
239  std::string file = getOutputFilename(v, deviceID);
240 
241  const bool useGeo = useGeoCoords(v);
242 
243  // Build the device (XXX: who deletes it?)
244  MSDevice_SSM* device = new MSDevice_SSM(v, deviceID, file, thresholds, trajectories, range, extraTime, useGeo);
245  into.push_back(device);
246  }
247 }
248 
249 
250 MSDevice_SSM::Encounter::Encounter(const MSVehicle* _ego, const MSVehicle* const _foe, double _begin, double extraTime) :
251  ego(_ego),
252  foe(_foe),
253  egoID(_ego->getID()),
254  foeID(_foe->getID()),
255  begin(_begin),
256  end(-INVALID),
257  currentType(ENCOUNTER_TYPE_NOCONFLICT_AHEAD),
258  remainingExtraTime(extraTime),
259  egoConflictEntryTime(INVALID),
260  egoConflictExitTime(INVALID),
261  foeConflictEntryTime(INVALID),
262  foeConflictExitTime(INVALID),
263  minTTC(INVALID, Position::invalidPosition(), ENCOUNTER_TYPE_NOCONFLICT_AHEAD, INVALID),
264  maxDRAC(INVALID, Position::invalidPosition(), ENCOUNTER_TYPE_NOCONFLICT_AHEAD, INVALID),
265  PET(INVALID, Position::invalidPosition(), ENCOUNTER_TYPE_NOCONFLICT_AHEAD, INVALID),
266  closingRequested(false) {
267 #ifdef DEBUG_SSM
268  std::cout << "\n" << SIMTIME << " Constructing encounter of '"
269  << ego->getID() << "' and '" << foe->getID() << "'" << std::endl;
270 #endif
271 }
272 
274 #ifdef DEBUG_SSM
275  std::cout << "\n" << SIMTIME << " Destroying encounter of '"
276  << egoID << "' and '" << foeID << "' (begin was " << begin << ")" << std::endl;
277 #endif
278 }
279 
280 
281 void
282 MSDevice_SSM::Encounter::add(double time, const EncounterType type, Position egoX, Position egoV, Position foeX, Position foeV,
283  Position conflictPoint, double egoDistToConflict, double foeDistToConflict, double ttc, double drac, std::pair<double, double> pet) {
284 #ifdef DEBUG_SSM
285  std::cout << time << " Adding data point for encounter of '" << egoID << "' and '" << foeID << "':\n"
286  << "type=" << type << ", egoDistToConflict=" << (egoDistToConflict == INVALID ? "NA" : toString(egoDistToConflict))
287  << ", foeDistToConflict=" << (foeDistToConflict == INVALID ? "NA" : toString(foeDistToConflict))
288  << ",\nttc=" << (ttc == INVALID ? "NA" : toString(ttc))
289  << ", drac=" << (drac == INVALID ? "NA" : toString(drac))
290  << ", pet=" << (pet.second == INVALID ? "NA" : toString(pet.second))
291  << std::endl;
292 #endif
293  currentType = type;
294 
295  timeSpan.push_back(time);
296  typeSpan.push_back(type);
297  egoTrajectory.x.push_back(egoX);
298  egoTrajectory.v.push_back(egoV);
299  foeTrajectory.x.push_back(foeX);
300  foeTrajectory.v.push_back(foeV);
301  conflictPointSpan.push_back(conflictPoint);
302  egoDistsToConflict.push_back(egoDistToConflict);
303  foeDistsToConflict.push_back(foeDistToConflict);
304 
305  TTCspan.push_back(ttc);
306  if (ttc != INVALID && (ttc < minTTC.value || minTTC.value == INVALID)) {
307  minTTC.value = ttc;
308  minTTC.time = time;
309  minTTC.pos = conflictPoint;
310  minTTC.type = type;
311  }
312 
313  DRACspan.push_back(drac);
314  if (drac != INVALID && (drac > maxDRAC.value || maxDRAC.value == INVALID)) {
315  maxDRAC.value = drac;
316  maxDRAC.time = time;
317  maxDRAC.pos = conflictPoint;
318  maxDRAC.type = type;
319  }
320 
321  if (pet.first != INVALID && (PET.value >= pet.second || PET.value == INVALID)) {
322  PET.value = pet.second;
323  PET.time = pet.first;
324  PET.pos = conflictPoint;
325  PET.type = type;
326  }
327 }
328 
329 
330 void
332  remainingExtraTime = value;
333 }
334 
335 
336 void
338  remainingExtraTime -= amount;
339 }
340 
341 
342 double
344  return remainingExtraTime;
345 }
346 
347 
349  encounter(e),
351  conflictPoint(Position::invalidPosition()),
352  egoConflictEntryDist(INVALID),
353  foeConflictEntryDist(INVALID),
354  egoConflictExitDist(INVALID),
355  foeConflictExitDist(INVALID),
356  egoEstimatedConflictEntryTime(INVALID),
357  foeEstimatedConflictEntryTime(INVALID),
358  egoEstimatedConflictExitTime(INVALID),
359  foeEstimatedConflictExitTime(INVALID),
360  egoConflictAreaLength(INVALID),
361  foeConflictAreaLength(INVALID),
362  egoLeftConflict(false),
363  foeLeftConflict(false),
364  ttc(INVALID),
365  drac(INVALID),
366  pet(std::make_pair(INVALID, INVALID)) {
367 }
368 
369 
370 void
372  if (myHolder.isOnRoad()) {
373  update();
374  // Write out past conflicts
375  flushConflicts();
376  } else {
377  resetEncounters();
378  // Write out past conflicts
379  flushConflicts(true);
380  }
381 }
382 
383 void
385 #ifdef DEBUG_SSM
386  std::cout << "\n" << SIMTIME << " Device '" << getID() << "' update()\n"
387  << "Size of myActiveEncounters: " << myActiveEncounters.size()
388  << "\nSize of myPastConflicts: " << myPastConflicts.size()
389  << std::endl;
390 #endif
391  // Scan surroundings for other vehicles
392  FoeInfoMap foes;
394 
395 #ifdef DEBUG_SSM
396  if (foes.size() > 0) {
397  std::cout << "Scanned surroundings: Found potential foes:\n";
398  for (FoeInfoMap::const_iterator i = foes.begin(); i != foes.end(); ++i) {
399  std::cout << i->first->getID() << " ";
400  }
401  std::cout << std::endl;
402  } else {
403  std::cout << "Scanned surroundings: No potential conflict could be identified." << std::endl;
404  }
405 #endif
406 
407  // Update encounters and conflicts -> removes all foes (and deletes corresponding FoeInfos) for which already a corresponding encounter exists
408  processEncounters(foes);
409 
410  // Make new encounters for all foes, which were not removed by processEncounters (and deletes corresponding FoeInfos)
411  createEncounters(foes);
412  foes.clear();
413 
414  // Compute "global SSMs" (only computed once per time-step)
416 
417 
418 }
419 
420 
421 void
425  if (myComputeBR) {
426  double br = MAX2(-myHolderMS->getAcceleration(), 0.0);
427  if (br > myMaxBR.second) {
428  myMaxBR = std::make_pair(std::make_pair(SIMTIME, myHolderMS->getPosition()), br);
429  }
430  myBRspan.push_back(br);
431  }
432 
433  double leaderSearchDist = 0;
434  std::pair<const MSVehicle*, double> leader(nullptr, 0.);
435  if (myComputeSGAP) {
436  leaderSearchDist = myThresholds["SGAP"];
437  }
438  if (myComputeTGAP) {
439  leaderSearchDist = MAX2(leaderSearchDist, myThresholds["TGAP"] * myHolderMS->getSpeed());
440  }
441 
442  if (leaderSearchDist > 0.) {
443  leader = myHolderMS->getLeader(leaderSearchDist);
444  }
445 
446  if (myComputeSGAP) {
447  if (leader.first == nullptr) {
448  mySGAPspan.push_back(INVALID);
449  } else {
450  double sgap = leader.second + leader.first->getVehicleType().getMinGap();
451  mySGAPspan.push_back(sgap);
452  if (sgap < myMinSGAP.first.second) {
453  myMinSGAP = std::make_pair(std::make_pair(std::make_pair(SIMTIME, myHolderMS->getPosition()), sgap), leader.first->getID());
454  }
455  }
456  }
457 
458  if (myComputeTGAP) {
459  if (leader.first == nullptr) {
460  myTGAPspan.push_back(INVALID);
461  } else {
462  double tgap = (leader.second + leader.first->getVehicleType().getMinGap()) / myHolderMS->getSpeed();
463  myTGAPspan.push_back(tgap);
464  if (tgap < myMinTGAP.first.second) {
465  myMinTGAP = std::make_pair(std::make_pair(std::make_pair(SIMTIME, myHolderMS->getPosition()), tgap), leader.first->getID());
466  }
467  }
468  }
469 
470  }
471 }
472 
473 void
475 #ifdef DEBUG_SSM
476  std::cout << "\n" << SIMTIME << " Device '" << getID() << "' createEncounters()" << std::endl;
477  std::cout << "New foes:\n";
478  for (FoeInfoMap::const_iterator vi = foes.begin(); vi != foes.end(); ++vi) {
479  std::cout << vi->first->getID() << "\n";
480  }
481  std::cout << std::endl;
482 #endif
483 
484  for (FoeInfoMap::const_iterator foe = foes.begin(); foe != foes.end(); ++foe) {
485  std::pair<MSLane*, MSLane*> conflictLanes;
486  Encounter* e = new Encounter(myHolderMS, foe->first, SIMTIME, myExtraTime);
487  updateEncounter(e, foe->second); // deletes foe->second
489  assert(myActiveEncounters.empty());
491  }
492  assert(myOldestActiveEncounterBegin <= e->begin);
493  myActiveEncounters.push_back(e);
494  }
495 }
496 
497 void
499  // Call processEncounters() with empty vehicle set
500  FoeInfoMap foes;
501  // processEncounters with empty argument closes all encounters
502  processEncounters(foes, true);
503 }
504 
505 void
507 #ifdef DEBUG_SSM
508  std::cout << "\n" << SIMTIME << " Device '" << getID() << "' processEncounters()" << std::endl;
509  std::cout << "Currently present foes:\n";
510  for (FoeInfoMap::const_iterator vi = foes.begin(); vi != foes.end(); ++vi) {
511  std::cout << vi->first->getID() << "\n";
512  }
513  std::cout << std::endl;
514 #endif
515 
516  // Run through active encounters. If corresponding foe is still present in foes update and
517  // remove foe from foes. If the foe has disappeared close the encounter (check if it qualifies
518  // as a conflict and in case transfer it to myPastConflicts).
519  // Afterwards run through remaining elements in foes and create new encounters for them.
520 
521  EncounterVector::iterator ei = myActiveEncounters.begin();
522  while (ei != myActiveEncounters.end()) {
523  Encounter* e = *ei;
524  // check whether foe is still on net
525  bool foeExists = !(MSNet::getInstance()->getVehicleControl().getVehicle(e->foeID) == 0);
526  if (!foeExists) {
527  e->foe = 0;
528  }
529  if (foes.find(e->foe) != foes.end()) {
530  FoeInfo* foeInfo = foes[e->foe];
531  // Update encounter
532  updateEncounter(e, foeInfo); // deletes foeInfo
533  // Erase foes which were already encountered
534  foes.erase(e->foe);
535  } else {
536  if (e->getRemainingExtraTime() <= 0. || forceClose || !foeExists) {
537  // Close encounter, extra time has expired (deletes e if it does not qualify as conflict)
538  e->closingRequested = true;
539  } else {
540  updateEncounter(e, 0); // counts down extra time
541  }
542  }
543 
544  if (e->closingRequested) {
545  double eBegin = e->begin;
546  closeEncounter(e);
547  ei = myActiveEncounters.erase(ei);
548  if (myActiveEncounters.empty()) {
550  } else if (eBegin == myOldestActiveEncounterBegin) {
551  // Erased the oldest encounter, update myOldestActiveEncounterBegin
552  auto i = myActiveEncounters.begin();
553  myOldestActiveEncounterBegin = (*i++)->begin;
554  while (i != myActiveEncounters.end()) {
556  }
557  }
558  } else {
559  ++ei;
560  }
561  }
562 }
563 
564 
565 bool
567  // Check if conflict measure thresholds are exceeded (to decide whether to keep the encounter for writing out)
568 #ifdef DEBUG_SSM
569  std::cout << SIMTIME << " qualifiesAsConflict() for encounter of vehicles '"
570  << e->egoID << "' and '" << e->foeID
571  << "'" << std::endl;
572 #endif
573 
574  if (myComputePET && e->PET.value != INVALID && e->PET.value <= myThresholds["PET"]) {
575  return true;
576  }
577  if (myComputeTTC && e->minTTC.value != INVALID && e->minTTC.value <= myThresholds["TTC"]) {
578  return true;
579  }
580  if (myComputeDRAC && e->maxDRAC.value != INVALID && e->maxDRAC.value >= myThresholds["DRAC"]) {
581  return true;
582  }
583  return false;
584 }
585 
586 
587 void
589  // erase pointers (encounter is stored before being destroyed and pointers could become invalid)
590  e->ego = 0;
591  e->foe = 0;
592  e->end = e->timeSpan.back();
593  bool wasConflict = qualifiesAsConflict(e);
594  if (wasConflict) {
595  myPastConflicts.push(e);
596  } else {
597  delete e;
598  }
599 #ifdef DEBUG_SSM
600  std::cout << SIMTIME << " closeEncounter() of vehicles '"
601  << e->egoID << "' and '" << e->foeID
602  << "' (was ranked as " << (wasConflict ? "conflict" : "non-conflict") << ")" << std::endl;
603 #endif
604 
605  return;
606 }
607 
608 
609 void
611 #ifdef DEBUG_SSM
612  std::cout << SIMTIME << " updateEncounter() of vehicles '"
613  << e->egoID << "' and '" << e->foeID
614  << "'" << std::endl;
615 #endif
616  assert(e->foe != 0);
617 
618  // Struct storing distances (determined in classifyEncounter()) and times to potential conflict entry / exit (in estimateConflictTimes())
619  EncounterApproachInfo eInfo(e);
620 
621  // Classify encounter type based on the present information
622  // More details on follower/lead relation are determined in a second step below, see estimateConflictTimes()
623  // If a crossing situation is ongoing (i.e. one of the vehicles entered the conflict area already in the last step,
624  // this is handled by passedEncounter by only tracing the vehicle's movements)
625  // The further developement of the encounter type is done in checkConflictEntryAndExit()
626  eInfo.type = classifyEncounter(foeInfo, eInfo);
627 
628  if (eInfo.type == ENCOUNTER_TYPE_NOCONFLICT_AHEAD) {
629  // At this state, eInfo.type == ENCOUNTER_TYPE_NOCONFLICT_AHEAD implies that the foe
630  // is either out of the device's range or its route does not interfere with the ego's route.
631 #ifdef DEBUG_SSM
632  std::cout << SIMTIME << " Encounter of vehicles '"
633  << e->egoID << "' and '" << e->foeID
634  << "' does not imply any conflict." << std::endl;
635 #endif
636  updatePassedEncounter(e, foeInfo, eInfo);
637 // return;
643  // Ongoing encounter. Treat with update passed encounter (trace covered distances)
644  // eInfo.type only holds the previous type
645  updatePassedEncounter(e, foeInfo, eInfo);
646 
647  // Estimate times until a possible conflict / collision
648  estimateConflictTimes(eInfo);
649 
650  } else {
651  // Estimate times until a possible conflict / collision
652  // Not all are used for all types of encounters:
653  // Follow/lead situation doesn't need them at all, currently (might change if more SSMs are implemented).
654  // Crossing / Merging calculates entry times to determine leader/follower and calculates the exit time for the leader.
655  estimateConflictTimes(eInfo);
656 
657  // reset the remaining extra time (foe could have re-entered the device range after beginning extra time countdown already)
659  }
660 
661  // update entry/exit times for conflict area
663 
664  // update (x,y)-coords of conflict point
665  determineConflictPoint(eInfo);
666 
667  // Compute SSMs
668  computeSSMs(eInfo);
669 
670  // Add current states to trajectories and update type
671  e->add(SIMTIME, eInfo.type, e->ego->getPosition(), e->ego->getVelocityVector(), e->foe->getPosition(), e->foe->getVelocityVector(),
672  eInfo.conflictPoint, eInfo.egoConflictEntryDist, eInfo.foeConflictEntryDist, eInfo.ttc, eInfo.drac, eInfo.pet);
673 
674  // free foeInfo
675  delete foeInfo;
676 
677 }
678 
679 
680 void
682  /* Calculates the (x,y)-coordinate for the eventually predicted conflict point and stores the result in
683  * eInfo.conflictPoint. In case of MERGING and CROSSING, this is the entry point to conflict area for follower
684  * In case of FOLLOWING it is the position of leader's back. */
685 
686 #ifdef DEBUG_SSM
687  std::cout << SIMTIME << " determineConflictPoint()" << std::endl;
688 #endif
689 
690  const EncounterType& type = eInfo.type;
691  const Encounter* e = eInfo.encounter;
696  || type == ENCOUNTER_TYPE_COLLISION) {
697  eInfo.conflictPoint = e->conflictPointSpan.back();
698  } else if (type == ENCOUNTER_TYPE_CROSSING_FOLLOWER
702  } else if (type == ENCOUNTER_TYPE_CROSSING_LEADER
706  } else if (type == ENCOUNTER_TYPE_FOLLOWING_FOLLOWER) {
707  eInfo.conflictPoint = e->foe->getPosition(-e->foe->getLength());
708  } else if (type == ENCOUNTER_TYPE_FOLLOWING_LEADER) {
709  eInfo.conflictPoint = e->ego->getPosition(-e->ego->getLength());
710  } else {
711 #ifdef DEBUG_SSM
712  std::cout << "No conflict point associated with encounter type " << type << std::endl;
713 #endif
714  return;
715  }
716 
717 #ifdef DEBUG_SSM
718  std::cout << " Conflict at " << eInfo.conflictPoint << std::endl;
719 #endif
720 }
721 
722 
723 void
725 
726  EncounterType& type = eInfo.type;
727  Encounter* e = eInfo.encounter;
728 
729  assert(type != ENCOUNTER_TYPE_NOCONFLICT_AHEAD); // arrival times not defined, if no conflict is ahead.
730 #ifdef DEBUG_SSM
731  std::cout << SIMTIME << " estimateConflictTimes() for ego '" << e->egoID << "' and foe '" << e->foeID << "'\n"
732  << " encounter type: " << eInfo.type << "\n"
733  << " egoConflictEntryDist=" << (eInfo.egoConflictEntryDist == INVALID ? "NA" : toString(eInfo.egoConflictEntryDist))
734  << ", foeConflictEntryDist=" << (eInfo.foeConflictEntryDist == INVALID ? "NA" : toString(eInfo.foeConflictEntryDist))
735  << "\n ego speed=" << e->ego->getSpeed()
736  << ", foe speed=" << e->foe->getSpeed()
737  << std::endl;
738 #endif
739 
741  // No need to know the times until ...ConflictDistEntry, currently. They would correspond to an estimated time headway or similar.
742  // TTC must take into account the movement of the leader, as would DRAC, PET doesn't need the time either, since it uses aposteriori
743  // values.
744 #ifdef DEBUG_SSM
745  std::cout << " encouter type " << type << " -> no entry/exit times to be calculated."
746  << std::endl;
747 #endif
748  return;
749  }
750 
751  assert(type == ENCOUNTER_TYPE_MERGING || type == ENCOUNTER_TYPE_CROSSING
758 
759  // Determine exit distances
760  if (type == ENCOUNTER_TYPE_MERGING) {
761  assert(type == ENCOUNTER_TYPE_MERGING);
764  } else {
767  }
768 
769  // Estimate entry times to stipulate a leader / follower relation for the encounter.
770  if (eInfo.egoConflictEntryDist > 0.) {
772  assert(eInfo.egoEstimatedConflictEntryTime > 0.);
773  } else {
774  // ego already entered conflict area
776  }
777  if (eInfo.foeConflictEntryDist > 0.) {
779  assert(eInfo.foeEstimatedConflictEntryTime > 0.);
780  } else {
781  // foe already entered conflict area
783  }
784 
785 #ifdef DEBUG_SSM
786  std::cout << " Potential conflict type: " << (type == ENCOUNTER_TYPE_CROSSING ? "CROSSING" : "MERGING") << "\n"
787  << " egoConflictEntryTime=" << (eInfo.egoEstimatedConflictEntryTime == INVALID ? "INVALID" : toString(eInfo.egoEstimatedConflictEntryTime))
788  << ", foeConflictEntryTime=" << (eInfo.foeEstimatedConflictEntryTime == INVALID ? "INVALID" : toString(eInfo.foeEstimatedConflictEntryTime))
789  << std::endl;
790 #endif
791 
792  // Estimate exit times from conflict area for leader / follower.
793  if (eInfo.egoConflictExitDist >= 0.) {
795  } else {
796  eInfo.egoEstimatedConflictExitTime = 0.;
797  }
798  if (eInfo.foeConflictExitDist >= 0.) {
800  } else {
801  eInfo.foeEstimatedConflictExitTime = 0.;
802  }
803 
804 
805  if (type != ENCOUNTER_TYPE_MERGING && type != ENCOUNTER_TYPE_CROSSING) {
806  // this call is issued in context of an ongoing conflict, therefore complete type is already known for the encounter
807  // (One of EGO_ENTERED_CONFLICT_AREA, FOE_ENTERED_CONFLICT_AREA, EGO_LEFT_CONFLICT_AREA, FOE_LEFT_CONFLICT_AREA, BOTH_ENTERED_CONFLICT_AREA)
808  // --> no need to specify incomplete encounter type
809  return;
810  }
811 
812  // For merging and crossing situation, the leader/follower relation not determined by classifyEncounter()
813  // This is done below based on the estimated conflict entry times
814  if (eInfo.egoEstimatedConflictEntryTime == 0. && eInfo.foeEstimatedConflictEntryTime == 0.) {
816  std::stringstream ss;
817  ss << "SSM device of vehicle '" << e->egoID << "' detected collision with vehicle '" << e->foeID << "'";
818  WRITE_WARNING(ss.str());
820  // ego is estimated first at conflict point
821 #ifdef DEBUG_SSM
822  std::cout << " -> ego is estimated leader at conflict entry."
823  << " egoConflictExitTime=" << (eInfo.egoEstimatedConflictExitTime == INVALID ? "NA" : toString(eInfo.egoEstimatedConflictExitTime))
824  << std::endl;
825 #endif
827  } else {
828  // ego is estimated second at conflict point
829 #ifdef DEBUG_SSM
830  std::cout << " -> foe is estimated leader at conflict entry."
831  << " foeConflictExitTime=" << (eInfo.foeEstimatedConflictExitTime == INVALID ? "NA" : toString(eInfo.foeEstimatedConflictExitTime))
832  << std::endl;
833 #endif
835  }
836 
837 }
838 
839 
840 
841 void
843 #ifdef DEBUG_SSM
844  Encounter* e = eInfo.encounter;
845  std::cout << SIMTIME << " computeSSMs() for vehicles '"
846  << e->ego->getID() << "' and '" << e->foe->getID()
847  << "'" << std::endl;
848 #endif
849 
850  const EncounterType& type = eInfo.type;
851 
856  if (myComputeTTC || myComputeDRAC) {
857  determineTTCandDRAC(eInfo);
858  }
859  determinePET(eInfo);
860  } else if (type == ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA) {
861  determinePET(eInfo);
862  } else if (type == ENCOUNTER_TYPE_COLLISION) {
863  // TODO: handle collision
866  // No conflict measures apply for these states, which correspond to intermediate times between
867  // one vehicle leaving the conflict area and the arrival time for the other (difference corresponds to the PET)
869  // No conflict measures apply for this state
870  } else if (type == ENCOUNTER_TYPE_MERGING_PASSED || type == ENCOUNTER_TYPE_FOLLOWING_PASSED) {
871  // No conflict measures apply for this state
872  } else if (type == ENCOUNTER_TYPE_NOCONFLICT_AHEAD) {
873  // No conflict measures apply for this state
874  } else {
875  std::stringstream ss;
876  ss << "'" << type << "'";
877  WRITE_WARNING("Unknown or undetermined encounter type at computeSSMs(): " + ss.str());
878  }
879 
880 #ifdef DEBUG_SSM
881  std::cout << "computeSSMs() for encounter of vehicles '" << e->egoID << "' and '" << e->foeID << "':\n"
882  << " ttc=" << (eInfo.ttc == INVALID ? "INVALID" : toString(eInfo.ttc))
883  << ", drac=" << (eInfo.drac == INVALID ? "INVALID" : toString(eInfo.drac))
884  << ", pet=" << (eInfo.pet.second == INVALID ? "INVALID" : toString(eInfo.pet.second))
885  << std::endl;
886 #endif
887 }
888 
889 
890 void
892  Encounter* e = eInfo.encounter;
893  if (e->size() == 0) {
894  return;
895  }
896  const EncounterType& type = eInfo.type;
897  std::pair<double, double>& pet = eInfo.pet;
898 
899 #ifdef DEBUG_SSM
900  std::cout << SIMTIME << " determinePET() for encounter of vehicles '" << e->egoID << "' and '" << e->foeID << "'"
901  << std::endl;
902 #endif
903 
905  // For a following situation, the corresponding PET-value is merely the time-headway.
906  // Determining these could be done by comparison of memorized gaps with memorized covered distances
907  // Implementation is postponed. Tracing the time gaps (in contrast to crossing PET) corresponds to
908  // a vector of values not a single value.
909  // pass
910  } else if (type == ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA) {
911  EncounterType prevType = static_cast<EncounterType>(e->typeSpan.back());
912  if (prevType == ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA) {
913 #ifdef DEBUG_SSM
914  std::cout << "PET for crossing encounter already calculated as " << e->PET.value
915  << std::endl;
916 #endif
917  // pet must have been calculated already
918  assert(e->PET.value != INVALID);
919  return;
920  }
921 
922  // this situation should have emerged from one of the following
923  assert(prevType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
924  || prevType == ENCOUNTER_TYPE_CROSSING_LEADER
930 
931 
932 #ifdef DEBUG_SSM
933  std::cout << "e->egoDistsToConflict.back() = " << e->egoDistsToConflict.back()
934  << "\ne->egoConflictEntryTime = " << e->egoConflictEntryTime
935  << "\ne->egoConflictExitTime = " << e->egoConflictExitTime
936  << "\ne->foeDistsToConflict.back() = " << e->foeDistsToConflict.back()
937  << "\ne->foeConflictEntryTime = " << e->foeConflictEntryTime
938  << "\ne->foeConflictExitTime = " << e->foeConflictExitTime
939  << std::endl;
940 #endif
941 
942  assert(e->foeConflictEntryTime != INVALID);
943  assert(e->egoConflictEntryTime != INVALID);
944 
945  // Both have passed the conflict area
947  // both have left the conflict region already
949  pet.first = e->egoConflictEntryTime;
950  pet.second = e->egoConflictEntryTime - e->foeConflictExitTime;
951  } else if (e->foeConflictEntryTime > e->egoConflictExitTime) {
952  pet.first = e->foeConflictEntryTime;
953  pet.second = e->foeConflictEntryTime - e->egoConflictExitTime;
954  } else {
955 
956 #ifdef DEBUG_SSM
957  std::cout << "Unexpected branch in determinePET: Both passed conflict area in the same step."
958  << std::endl;
959 #endif
960  pet.first = INVALID;
961  pet.second = INVALID;
962  assert(prevType != ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA
964  }
965 
966  // Reset entry and exit times two allow an eventual subsequent re-use
971 
972 #ifdef DEBUG_SSM
973  std::cout << "Calculated PET = " << pet.second << " (at t=" << pet.first << ")"
974  << std::endl;
975 #endif
976  } else {
977  // other cases (merging and pre-crossing situations) do not correspond to a PET calculation.
978 #ifdef DEBUG_SSM
979  std::cout << "PET unappropriate for merging and pre-crossing situations. No calculation performed."
980  << std::endl;
981 #endif
982  return;
983  }
984 }
985 
986 
987 void
989  Encounter* e = eInfo.encounter;
990  const EncounterType& type = eInfo.type;
991  double& ttc = eInfo.ttc;
992  double& drac = eInfo.drac;
993 
994 #ifdef DEBUG_SSM
995  std::cout << SIMTIME << " determineTTCandDRAC() for encounter of vehicles '" << e->egoID << "' and '" << e->foeID << "' (type = " << eInfo.type << ")"
996  << std::endl;
997 #endif
998 
999  // Dependent on the actual encounter situation (eInfo.type) calculate the TTC.
1000  // For merging and crossing, different cases occur when a collision during the merging / crossing process is predicted.
1001  if (type == ENCOUNTER_TYPE_FOLLOWING_FOLLOWER) {
1002  double gap = eInfo.egoConflictEntryDist;
1003  if (myComputeTTC) {
1004  ttc = computeTTC(gap, e->ego->getSpeed(), e->foe->getSpeed());
1005  }
1006  if (myComputeDRAC) {
1007  drac = computeDRAC(gap, e->ego->getSpeed(), e->foe->getSpeed());
1008  }
1009  } else if (type == ENCOUNTER_TYPE_FOLLOWING_LEADER) {
1010  double gap = eInfo.foeConflictEntryDist;
1011  if (myComputeTTC) {
1012  ttc = computeTTC(gap, e->foe->getSpeed(), e->ego->getSpeed());
1013  }
1014  if (myComputeDRAC) {
1015  drac = computeDRAC(gap, e->foe->getSpeed(), e->ego->getSpeed());
1016  }
1017  } else if (type == ENCOUNTER_TYPE_MERGING_FOLLOWER || type == ENCOUNTER_TYPE_MERGING_LEADER) {
1018  // TODO: calculate more specifically whether a following situation in the merge conflict area
1019  // is predicted when assuming constant speeds or whether a side collision is predicted.
1020  // Currently, we ignore any conflict area before the actual merging point of the lanes.
1021 
1022  // linearly extrapolated arrival times at the conflict
1023  // NOTE: These differ from the estimated times stored in eInfo
1024  double egoEntryTime = e->ego->getSpeed() > 0 ? eInfo.egoConflictEntryDist / e->ego->getSpeed() : INVALID;
1025  double egoExitTime = e->ego->getSpeed() > 0 ? eInfo.egoConflictExitDist / e->ego->getSpeed() : INVALID;
1026  double foeEntryTime = e->foe->getSpeed() > 0 ? eInfo.foeConflictEntryDist / e->foe->getSpeed() : INVALID;
1027  double foeExitTime = e->foe->getSpeed() > 0 ? eInfo.foeConflictExitDist / e->foe->getSpeed() : INVALID;
1028 
1029 #ifdef DEBUG_SSM
1030  std::cout << " Conflict times with constant speed extrapolation for merging situation:\n "
1031  << " egoEntryTime=" << (egoEntryTime == INVALID ? "NA" : toString(egoEntryTime))
1032  << ", egoExitTime=" << (egoExitTime == INVALID ? "NA" : toString(egoExitTime))
1033  << ", foeEntryTime=" << (foeEntryTime == INVALID ? "NA" : toString(foeEntryTime))
1034  << ", foeExitTime=" << (foeExitTime == INVALID ? "NA" : toString(foeExitTime))
1035  << std::endl;
1036 #endif
1037 
1038  // based on that, we obtain
1039  if (egoEntryTime == INVALID || foeEntryTime == INVALID) {
1040  // at least one vehicle is stopped
1041  ttc = INVALID;
1042  drac = INVALID;
1043 #ifdef DEBUG_SSM
1044  std::cout << " No TTC and DRAC computed as one vehicle is stopped." << std::endl;
1045 #endif
1046  return;
1047  }
1048  double leaderEntryTime = MIN2(egoEntryTime, foeEntryTime);
1049  double followerEntryTime = MAX2(egoEntryTime, foeEntryTime);
1050  double leaderExitTime = leaderEntryTime == egoEntryTime ? egoExitTime : foeExitTime;
1051  //double followerExitTime = leaderEntryTime==egoEntryTime?foeExitTime:egoExitTime;
1052  double leaderSpeed = leaderEntryTime == egoEntryTime ? e->ego->getSpeed() : e->foe->getSpeed();
1053  double followerSpeed = leaderEntryTime == egoEntryTime ? e->foe->getSpeed() : e->ego->getSpeed();
1054  double leaderConflictDist = leaderEntryTime == egoEntryTime ? eInfo.egoConflictEntryDist : eInfo.foeConflictEntryDist;
1055  double followerConflictDist = leaderEntryTime == egoEntryTime ? eInfo.foeConflictEntryDist : eInfo.egoConflictEntryDist;
1056  double leaderLength = leaderEntryTime == egoEntryTime ? e->ego->getLength() : e->foe->getLength();
1057  if (leaderExitTime >= followerEntryTime) {
1058  // collision would occur at merge area
1059  if (myComputeTTC) {
1060  ttc = computeTTC(followerConflictDist, followerSpeed, 0.);
1061  }
1062  // TODO: Calculate more specific drac for merging case here (complete stop is not always necessary -> see calculation for crossing case)
1063  // Rather the
1064  if (myComputeDRAC) {
1065  drac = computeDRAC(followerConflictDist, followerSpeed, 0.);
1066  }
1067 // if (myComputeDRAC) drac = computeDRAC(eInfo);
1068 
1069 #ifdef DEBUG_SSM
1070  std::cout << " Extrapolation predicts collision *at* merge point with TTC=" << ttc
1071  << ", drac=" << drac << std::endl;
1072 #endif
1073 
1074  } else {
1075  // -> No collision at the merge area
1076  if (myComputeTTC) {
1077  // Check if after merge a collision would occur if speeds are hold constant.
1078  double gapAfterMerge = followerConflictDist - leaderExitTime * followerSpeed;
1079  assert(gapAfterMerge >= 0);
1080 
1081  // ttc as for following situation (assumes no collision until leader merged)
1082  double ttcAfterMerge = computeTTC(gapAfterMerge, followerSpeed, leaderSpeed);
1083  ttc = ttcAfterMerge == INVALID ? INVALID : leaderExitTime + ttcAfterMerge;
1084  }
1085  if (myComputeDRAC) {
1086  // Intitial gap. (May be negative only if the leader speed is higher than the follower speed, i.e., dv < 0)
1087  double g0 = followerConflictDist - leaderConflictDist - leaderLength;
1088  if (g0 < 0) {
1089  // Speed difference must be positive if g0<0.
1090  assert(leaderSpeed - followerSpeed > 0);
1091  // no deceleration needed for dv>0 and gap after merge >= 0
1092  drac = INVALID;
1093  } else {
1094  // compute drac as for a following situation
1095  drac = computeDRAC(g0, followerSpeed, leaderSpeed);
1096  }
1097  }
1098 #ifdef DEBUG_SSM
1099  if (ttc == INVALID) {
1100  // assert(dv >= 0);
1101  assert(drac == INVALID);
1102  std::cout << " Extrapolation does not predict any collision." << std::endl;
1103  } else {
1104  std::cout << " Extrapolation predicts collision *after* merge point with TTC="
1105  << (ttc == INVALID ? "NA" : toString(ttc))
1106  << ", drac=" << (drac == INVALID ? "NA" : toString(drac)) << std::endl;
1107  }
1108 #endif
1109 
1110  }
1111 
1112  } else if (type == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1114  if (myComputeDRAC) {
1115  drac = computeDRAC(eInfo);
1116  }
1118  // follower's predicted arrival at the crossing area is earlier than the leader's predicted exit -> collision predicted
1119  double gap = eInfo.egoConflictEntryDist;
1120  if (myComputeTTC) {
1121  ttc = computeTTC(gap, e->ego->getSpeed(), 0.);
1122  }
1123  } else {
1124  // encounter is expected to happen without collision
1125  ttc = INVALID;
1126  }
1127  } else if (type == ENCOUNTER_TYPE_CROSSING_LEADER
1129  if (myComputeDRAC) {
1130  drac = computeDRAC(eInfo);
1131  }
1133  // follower's predicted arrival at the crossing area is earlier than the leader's predicted exit -> collision predicted
1134  double gap = eInfo.foeConflictEntryDist;
1135  if (myComputeTTC) {
1136  ttc = computeTTC(gap, e->foe->getSpeed(), 0.);
1137  }
1138  } else {
1139  // encounter is expected to happen without collision
1140  ttc = INVALID;
1141  }
1142  } else {
1143 #ifdef DEBUG_SSM
1144  std::stringstream ss;
1145  ss << "'" << type << "'";
1146  WRITE_WARNING("Underspecified or unknown encounter type in MSDevice_SSM::determineTTCandDRAC(): " + ss.str());
1147 #endif
1148  }
1149 
1150 #ifdef DEBUG_SSM
1151  std::cout << "ttc=" << (ttc == INVALID ? "INVALID" : toString(ttc)) << ", drac=" << (drac == INVALID ? "INVALID" : toString(drac))
1152  << std::endl;
1153 #endif
1154 }
1155 
1156 
1157 double
1158 MSDevice_SSM::computeTTC(double gap, double followerSpeed, double leaderSpeed) const {
1159  // TODO: in merging situations, the TTC may be lower than the one computed here for following situations
1160  // (currently only the cross section corresponding to the target lane's begin is considered)
1161  // More specifically, the minimum has to be taken from the two if a collision at merge was predicted.
1162 #ifdef DEBUG_SSM
1163  std::cout << "computeTTC() with gap=" << gap << ", followerSpeed=" << followerSpeed << ", leaderSpeed=" << leaderSpeed
1164  << std::endl;
1165 #endif
1166  if (gap <= 0.) {
1167  return 0.; // collision already happend
1168  }
1169  double dv = followerSpeed - leaderSpeed;
1170  if (dv <= 0.) {
1171  return INVALID; // no collision
1172  }
1173 
1174  return gap / dv;
1175 }
1176 
1177 
1178 double
1179 MSDevice_SSM::computeDRAC(double gap, double followerSpeed, double leaderSpeed) {
1180 #ifdef DEBUG_SSM_DRAC
1181  std::cout << "computeDRAC() with gap=" << gap << ", followerSpeed=" << followerSpeed << ", leaderSpeed=" << leaderSpeed
1182  << std::endl;
1183 #endif
1184  if (gap <= 0.) {
1185  return INVALID; // collision!
1186  }
1187  double dv = followerSpeed - leaderSpeed;
1188  if (dv <= 0.) {
1189  return 0.0; // no need to break
1190  }
1191  assert(followerSpeed > 0.);
1192  return 0.5 * dv * dv / gap; // following Guido et al. (2011)
1193 }
1194 
1195 double
1197  // Introduce concise variable names
1198  double dEntry1 = eInfo.egoConflictEntryDist;
1199  double dEntry2 = eInfo.foeConflictEntryDist;
1200  double dExit1 = eInfo.egoConflictExitDist;
1201  double dExit2 = eInfo.foeConflictExitDist;
1202  double v1 = eInfo.encounter->ego->getSpeed();
1203  double v2 = eInfo.encounter->foe->getSpeed();
1204  double tEntry1 = eInfo.egoEstimatedConflictEntryTime;
1205  double tEntry2 = eInfo.foeEstimatedConflictEntryTime;
1206  double tExit1 = eInfo.egoEstimatedConflictExitTime;
1207  double tExit2 = eInfo.foeEstimatedConflictExitTime;
1208 #ifdef DEBUG_SSM_DRAC
1209  std::cout << SIMTIME << "computeDRAC() with"
1210  << "\ndEntry1=" << dEntry1 << ", dEntry2=" << dEntry2
1211  << ", dExit1=" << dExit1 << ", dExit2=" << dExit2
1212  << ",\nv1=" << v1 << ", v2=" << v2
1213  << "\ntEntry1=" << (tEntry1 == INVALID ? "NA" : toString(tEntry1)) << ", tEntry2=" << (tEntry2 == INVALID ? "NA" : toString(tEntry2))
1214  << ", tExit1=" << (tExit1 == INVALID ? "NA" : toString(tExit1)) << ", tExit2=" << (tExit2 == INVALID ? "NA" : toString(tExit2))
1215  << std::endl;
1216 #endif
1217  if (dExit1 <= 0. || dExit2 <= 0.) {
1218  // At least one vehicle already left or is not about to enter conflict area at all => no breaking needed.
1219 #ifdef DEBUG_SSM_DRAC
1220  std::cout << "One already left conflict area -> drac == 0." << std::endl;
1221 #endif
1222  return 0.;
1223  }
1224  if (dEntry1 <= 0. && dEntry2 <= 0.) {
1225  // collision... (both already entered conflict area but none left)
1226 #ifdef DEBUG_SSM_DRAC
1227  std::cout << "Both entered conflict area but neither left. -> collision!" << std::endl;
1228 #endif
1229  return INVALID;
1230  }
1231 
1232  double drac = std::numeric_limits<double>::max();
1233  if (dEntry1 > 0.) {
1234  // vehicle 1 could break
1235 #ifdef DEBUG_SSM_DRAC
1236  std::cout << "Ego could break..." << std::endl;
1237 #endif
1238  if (tExit2 != INVALID) {
1239  // Vehicle 2 is expected to leave conflict area at t2
1240  drac = MIN2(drac, 2 * (v1 - dEntry1 / tExit2) / tExit2);
1241 #ifdef DEBUG_SSM_DRAC
1242  std::cout << " Foe expected to leave in " << tExit2 << "-> Ego needs drac=" << drac << std::endl;
1243 #endif
1244  } else {
1245  // Vehicle 2 is expected to stop on conflict area or earlier
1246  if (tEntry2 != INVALID) {
1247  // ... on conflict area => veh1 has to stop before entry
1248  drac = MIN2(drac, computeDRAC(dEntry1, v1, 0));
1249 #ifdef DEBUG_SSM_DRAC
1250  std::cout << " Foe is expected stop on conflict area -> Ego needs drac=" << drac << std::endl;
1251 #endif
1252  } else {
1253  // ... before conflict area
1254 #ifdef DEBUG_SSM_DRAC
1255  std::cout << " Foe is expected stop before conflict area -> no drac computation for ego (will be done for foe if applicable)" << std::endl;
1256 #endif
1257  }
1258  }
1259  }
1260 
1261  if (dEntry2 > 0.) {
1262  // vehicle 2 could break
1263 #ifdef DEBUG_SSM_DRAC
1264  std::cout << "Foe could break..." << std::endl;
1265 #endif
1266  if (tExit1 != INVALID) {
1267  // Vehicle 1 is expected to leave conflict area at t1
1268 #ifdef DEBUG_SSM_DRAC
1269  std::cout << " Ego expected to leave in " << tExit1 << "-> Foe needs drac=" << (2 * (v2 - dEntry2 / tExit1) / tExit1) << std::endl;
1270 #endif
1271  drac = MIN2(drac, 2 * (v2 - dEntry2 / tExit1) / tExit1);
1272  } else {
1273  // Vehicle 1 is expected to stop on conflict area or earlier
1274  if (tEntry1 != INVALID) {
1275  // ... on conflict area => veh2 has to stop before entry
1276 #ifdef DEBUG_SSM_DRAC
1277  std::cout << " Ego is expected stop on conflict area -> Foe needs drac=" << computeDRAC(dEntry2, v2, 0) << std::endl;
1278 #endif
1279  drac = MIN2(drac, computeDRAC(dEntry2, v2, 0));
1280  } else {
1281  // ... before conflict area
1282 #ifdef DEBUG_SSM_DRAC
1283  std::cout << " Ego is expected stop before conflict area -> no drac computation for foe (done for ego if applicable)" << std::endl;
1284 #endif
1285  }
1286  }
1287  }
1288 
1289  return drac > 0 ? drac : INVALID;
1290 }
1291 
1292 void
1294  // determine exact entry and exit times
1295  Encounter* e = eInfo.encounter;
1296 
1297 #ifdef DEBUG_SSM
1298  std::cout << SIMTIME << " checkConflictEntryAndExit() for encounter of vehicles '" << e->egoID << "' and '" << e->foeID << "'" << std::endl;
1299 #endif
1300 
1301  // Distances to conflict area boundaries in previous step
1302  double prevEgoConflictEntryDist = eInfo.egoConflictEntryDist + e->ego->getLastStepDist();
1303  double prevFoeConflictEntryDist = eInfo.foeConflictEntryDist + e->foe->getLastStepDist();
1304  double prevEgoConflictExitDist = prevEgoConflictEntryDist + eInfo.egoConflictAreaLength + e->ego->getLength();
1305  double prevFoeConflictExitDist = prevFoeConflictEntryDist + eInfo.foeConflictAreaLength + e->foe->getLength();
1306  EncounterType prevType = e->currentType;
1307 
1308  if (e->timeSpan.size() == 0) {
1309  // Encounter has just been created, no data points yet.
1310  // If a vehicle was already beyond conflict area boundary in last step, we set the passing time to the previous time step
1311  prevEgoConflictEntryDist = MAX2(prevEgoConflictEntryDist, 0.);
1312  prevFoeConflictEntryDist = MAX2(prevFoeConflictEntryDist, 0.);
1313  prevEgoConflictExitDist = MAX2(prevEgoConflictExitDist, 0.);
1314  prevFoeConflictExitDist = MAX2(prevFoeConflictExitDist, 0.);
1315  }
1316 
1317 
1318  // Check if ego entered in last step
1319  if (e->egoConflictEntryTime == INVALID && eInfo.egoConflictEntryDist < 0 && prevEgoConflictEntryDist >= 0) {
1320  // ego must have entered the conflict in the last step. Determine exact entry time
1321  e->egoConflictEntryTime = SIMTIME - TS + MSCFModel::passingTime(-prevEgoConflictEntryDist, 0., -eInfo.egoConflictEntryDist, e->ego->getPreviousSpeed(), e->ego->getSpeed());
1322 #ifdef DEBUG_SSM
1323  std::cout << " ego entered conflict area at t=" << e->egoConflictEntryTime << std::endl;
1324 #endif
1325  // Update encounter type (only done here for entering, the other transitions are done in updatePassedEncounter)
1326  if (prevType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1327  || prevType == ENCOUNTER_TYPE_CROSSING_LEADER) {
1329  }
1330  }
1331 
1332  // Check if foe entered in last step
1333  if (e->foeConflictEntryTime == INVALID && eInfo.foeConflictEntryDist < 0. && prevFoeConflictEntryDist >= 0) {
1334  // foe must have entered the conflict in the last step. Determine exact entry time
1335  e->foeConflictEntryTime = SIMTIME - TS + MSCFModel::passingTime(-prevFoeConflictEntryDist, 0., -eInfo.foeConflictEntryDist, e->foe->getPreviousSpeed(), e->foe->getSpeed());
1336 #ifdef DEBUG_SSM
1337  std::cout << " foe entered conflict area at t=" << e->foeConflictEntryTime << std::endl;
1338 #endif
1339  // Update encounter type (only done here for entering, the other transitions are done in updatePassedEncounter)
1340  if (prevType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1341  || prevType == ENCOUNTER_TYPE_CROSSING_LEADER) {
1343  }
1344  }
1345 
1346  // Check if ego left conflict area
1347  if (e->egoConflictExitTime == INVALID && eInfo.egoConflictExitDist < 0 && prevEgoConflictExitDist >= 0) {
1348  // ego must have left the conflict area in the last step. Determine exact exit time
1349  e->egoConflictExitTime = SIMTIME - TS + MSCFModel::passingTime(-prevEgoConflictExitDist, 0., -eInfo.egoConflictExitDist, e->ego->getPreviousSpeed(), e->ego->getSpeed());
1350  // Add cross section to calculate PET for foe
1351 // e->foePETCrossSections.push_back(std::make_pair(eInfo.foeConflictEntryCrossSection, e->egoConflictExitTime));
1352 #ifdef DEBUG_SSM
1353  std::cout << " ego left conflict area at t=" << e->egoConflictExitTime << std::endl;
1354 #endif
1355  // Update encounter type (only done here for entering, the other transitions are done in updatePassedEncounter)
1356  if (prevType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1357  || prevType == ENCOUNTER_TYPE_CROSSING_LEADER) {
1359  }
1360  }
1361 
1362  // Check if foe left conflict area
1363  if (e->foeConflictExitTime == INVALID && eInfo.foeConflictExitDist < 0 && prevFoeConflictExitDist >= 0) {
1364  // foe must have left the conflict area in the last step. Determine exact exit time
1365  e->foeConflictExitTime = SIMTIME - TS + MSCFModel::passingTime(-prevFoeConflictExitDist, 0., -eInfo.foeConflictExitDist, e->foe->getPreviousSpeed(), e->foe->getSpeed());
1366  // Add cross section to calculate PET for ego
1367 // e->egoPETCrossSections.push_back(std::make_pair(eInfo.egoConflictEntryCrossSection, e->foeConflictExitTime));
1368 #ifdef DEBUG_SSM
1369  std::cout << " foe left conflict area at t=" << e->foeConflictExitTime << std::endl;
1370 #endif
1371  // Update encounter type (only done here for entering, the other transitions are done in updatePassedEncounter)
1372  if (prevType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1373  || prevType == ENCOUNTER_TYPE_CROSSING_LEADER) {
1375  }
1376  }
1377 }
1378 
1379 
1380 void
1382 
1383 #ifdef DEBUG_SSM
1384  std::cout << SIMTIME << " updatePassedEncounter() for vehicles '"
1385  << e->egoID << "' and '" << e->foeID << "'"
1386  << std::endl;
1387 #endif
1388 
1389  if (foeInfo == 0) {
1390  // the foe is out of the device's range, proceed counting down the remaining extra time to trace
1391  e->countDownExtraTime(TS);
1392 #ifdef DEBUG_SSM
1393  std::cout << " Foe is out of range. Counting down extra time."
1394  << " Remaining seconds before closing encounter: " << e->getRemainingExtraTime()
1395  << std::endl;
1396 #endif
1397 
1398  } else {
1399  // reset the remaining extra time (foe could have re-entered the device range after beginning extra time countdown already)
1401  }
1402 
1403  // Check, whether this was really a potential conflict at some time:
1404  // Search through typeSpan for a type other than no conflict
1405  EncounterType lastPotentialConflictType = e->typeSpan.size() > 0 ? static_cast<EncounterType>(e->typeSpan.back()) : ENCOUNTER_TYPE_NOCONFLICT_AHEAD;
1406 
1407  if (lastPotentialConflictType == ENCOUNTER_TYPE_NOCONFLICT_AHEAD) {
1408  // This encounter was no conflict in the last step -> remains so
1409 #ifdef DEBUG_SSM
1410  std::cout << " This encounter wasn't classified as a potential conflict lately." << std::endl;
1411 #endif
1412  if (foeInfo == 0) {
1413  // Encounter was either never a potential conflict and foe is out of range
1414  // or the foe has left the network
1415  // -> no use in further tracing this encounter
1416  e->closingRequested = true;
1417 #ifdef DEBUG_SSM
1418  std::cout << " Closing encounter." << std::endl;
1419 #endif
1421  }
1422  } else if (lastPotentialConflictType == ENCOUNTER_TYPE_FOLLOWING_FOLLOWER
1423  || lastPotentialConflictType == ENCOUNTER_TYPE_FOLLOWING_LEADER
1424  || lastPotentialConflictType == ENCOUNTER_TYPE_FOLLOWING_PASSED) {
1425  // if a following situation leads to a no-conflict situation this encounter switches no-conflict, since no further computations (PET) are needed.
1427 #ifdef DEBUG_SSM
1428  std::cout << " Encounter was previously classified as a follow/lead situation." << std::endl;
1429 #endif
1430  } else if (lastPotentialConflictType == ENCOUNTER_TYPE_MERGING_FOLLOWER
1431  || lastPotentialConflictType == ENCOUNTER_TYPE_MERGING_LEADER
1432  || lastPotentialConflictType == ENCOUNTER_TYPE_MERGING_PASSED) {
1433  // if a merging situation leads to a no-conflict situation the leader was either removed from the net (we disregard special treatment)
1434  // or route- or lane-changes removed the conflict.
1436 #ifdef DEBUG_SSM
1437  std::cout << " Encounter was previously classified as a merging situation." << std::endl;
1438 #endif
1439  }
1440  if (lastPotentialConflictType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1441  || lastPotentialConflictType == ENCOUNTER_TYPE_CROSSING_LEADER
1442  || lastPotentialConflictType == ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA
1443  || lastPotentialConflictType == ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA
1444  || lastPotentialConflictType == ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA
1445  || lastPotentialConflictType == ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA
1446  || lastPotentialConflictType == ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA
1447  || lastPotentialConflictType == ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA
1448  || lastPotentialConflictType == ENCOUNTER_TYPE_COLLISION) {
1449  // Encounter has been a crossing situation.
1450 
1451 #ifdef DEBUG_SSM
1452  std::cout << " Encounter was previously classified as a crossing situation of type " << lastPotentialConflictType << "." << std::endl;
1453 #endif
1454  // For passed encounters, the xxxConflictAreaLength variables are not determined before -> we use the stored values.
1455 
1456  // TODO: This could also more precisely be calculated wrt the angle of the crossing *at the conflict point*
1457  if (eInfo.egoConflictAreaLength == INVALID) {
1458  eInfo.egoConflictAreaLength = e->foe->getWidth();
1459  }
1460  if (eInfo.foeConflictAreaLength == INVALID) {
1461  eInfo.foeConflictAreaLength = e->ego->getWidth();
1462  }
1463 
1464  eInfo.egoConflictEntryDist = e->egoDistsToConflict.back() - e->ego->getLastStepDist();
1466  eInfo.foeConflictEntryDist = e->foeDistsToConflict.back() - e->foe->getLastStepDist();
1468 
1469 #ifdef DEBUG_SSM
1470  std::cout << " egoConflictEntryDist = " << eInfo.egoConflictEntryDist
1471  << ", egoConflictExitDist = " << eInfo.egoConflictExitDist
1472  << "\n foeConflictEntryDist = " << eInfo.foeConflictEntryDist
1473  << ", foeConflictExitDist = " << eInfo.foeConflictExitDist
1474  << std::endl;
1475 #endif
1476 
1477  // Determine actual encounter type
1478  bool egoEnteredConflict = eInfo.egoConflictEntryDist < 0.;
1479  bool foeEnteredConflict = eInfo.foeConflictEntryDist < 0.;
1480  bool egoLeftConflict = eInfo.egoConflictExitDist < 0.;
1481  bool foeLeftConflict = eInfo.foeConflictExitDist < 0.;
1482 
1483  if ((!egoEnteredConflict) && !foeEnteredConflict) {
1484  // XXX: do we need to recompute the follow/lead order, here?
1485  assert(lastPotentialConflictType == ENCOUNTER_TYPE_CROSSING_FOLLOWER
1486  || lastPotentialConflictType == ENCOUNTER_TYPE_CROSSING_LEADER);
1487  eInfo.type = lastPotentialConflictType;
1488  } else if (egoEnteredConflict && !foeEnteredConflict) {
1490  } else if ((!egoEnteredConflict) && foeEnteredConflict) {
1492  } else { // (egoEnteredConflict && foeEnteredConflict) {
1494  }
1495 
1496  if ((!egoLeftConflict) && !foeLeftConflict) {
1499  }
1500  } else if (egoLeftConflict && !foeLeftConflict) {
1503  }
1504  } else if ((!egoLeftConflict) && foeLeftConflict) {
1507  }
1508  } else {
1510  // It should not occur that both leave the conflict at the same step
1511  assert(lastPotentialConflictType == ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA
1512  || lastPotentialConflictType == ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA
1513  || lastPotentialConflictType == ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA
1514  || lastPotentialConflictType == ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA);
1515  }
1516 
1517  // TODO: adjust the conflict distances according to lateral movement for single ENTERED-cases
1518 
1519 #ifdef DEBUG_SSM
1520  std::cout << " Updated classification: " << eInfo.type << std::endl;
1521 #endif
1522  }
1523 }
1524 
1525 
1528 #ifdef DEBUG_SSM
1529  std::cout << "classifyEncounter() called." << std::endl;
1530 #endif
1531  if (foeInfo == 0) {
1532  // foeInfo == 0 signalizes, that no corresponding foe info was returned by findSurroundingVehicles(),
1533  // i.e. the foe is actually out of range (This may also mean that it has left the network)
1535  }
1536  const Encounter* e = eInfo.encounter;
1537 
1538  // previous classification (if encounter was not just created)
1539  EncounterType prevType = e->typeSpan.size() > 0 ? static_cast<EncounterType>(e->typeSpan.back()) : ENCOUNTER_TYPE_NOCONFLICT_AHEAD;
1540  if (e->typeSpan.size() > 0
1546  // This is an ongoing crossing situation with at least one of the vehicles not
1547  // having passed the conflict area.
1548  // -> Merely trace the change of distances to the conflict entry / exit
1549  // -> Derefer this to updatePassedEncounter, where this is done anyhow.
1550 #ifdef DEBUG_SSM
1551  std::cout << " Ongoing crossing conflict will be traced by passedEncounter()." << std::endl;
1552 #endif
1553  return prevType;
1554  }
1555 
1556 
1557  // Ego's current Lane
1558  const MSLane* egoLane = e->ego->getLane();
1559  // Foe's current Lane
1560  const MSLane* foeLane = e->foe->getLane();
1561 
1562  // Ego's conflict lane is memorized in foeInfo
1563  const MSLane* egoConflictLane = foeInfo->egoConflictLane;
1564  double egoDistToConflictLane = foeInfo->egoDistToConflictLane;
1565  // Find conflicting lane and the distance to its entry link for the foe
1566  double foeDistToConflictLane;
1567  const MSLane* foeConflictLane = findFoeConflictLane(e->foe, foeInfo->egoConflictLane, foeDistToConflictLane);
1568 
1569 #ifdef DEBUG_SSM
1570  std::cout << "egoConflictLane: '" << (egoConflictLane == 0 ? "NULL" : egoConflictLane->getID()) << "'\n"
1571  << "foeConflictLane: '" << (foeConflictLane == 0 ? "NULL" : foeConflictLane->getID()) << "'"
1572  << "\nEgo's distance to conflict lane: " << egoDistToConflictLane
1573  << "\nFoe's distance to conflict lane: " << foeDistToConflictLane
1574  << std::endl;
1575 #endif
1576 
1577  // Treat different cases for foeConflictLane and egoConflictLane (internal or non-internal / equal to egoLane or to foeLane),
1578  // and thereby determine encounterType and the ego/foeEncounterDistance.
1579  // The encounter distance has a different meaning for different types of encounters:
1580  // 1) For rear-end conflicts (lead/follow situations) the follower's encounter distance is the distance to the actual back position of the leader. The leaders's distance is undefined.
1581  // 2) For merging encounters the encounter distance is the distance until the begin of the common target edge/lane.
1582  // (XXX: Perhaps this should be adjusted to include the entry point to the region where a simultaneous occupancy of
1583  // both merging lanes could imply a collision)
1584  // 3) For crossing encounters the encounter distances is the distance until the entry point to the conflicting lane.
1585 
1587 
1588  if (foeConflictLane == 0) {
1589  // foe vehicle is not on course towards the ego's route (see findFoeConflictLane)
1591 #ifdef DEBUG_SSM
1592  std::cout << "-> Encounter type: No conflict." << std::endl;
1593 #endif
1594  } else if (!egoConflictLane->isInternal()) {
1595  // The conflict lane is non-internal, therefore we either have no potential conflict or a lead/follow situation (i.e., no crossing or merging)
1596  if (egoConflictLane == egoLane) {
1597  // The conflict point is on the ego's current lane.
1598  if (foeLane == egoLane) {
1599  // Foe is on the same non-internal lane
1600  if (e->ego->getPositionOnLane() > e->foe->getPositionOnLane()) {
1603  } else {
1606  }
1607 #ifdef DEBUG_SSM
1608  std::cout << "-> Encounter type: Lead/follow-situation on non-internal lane '" << egoLane->getID() << "'" << std::endl;
1609 #endif
1610  } else if (&(foeLane->getEdge()) == &(egoLane->getEdge())) {
1611  // Foe is on the same non-internal edge but not on the same lane. Treat this as no conflict for now
1612  // XXX: this disregards conflicts for vehicles on adjacent lanes
1614 #ifdef DEBUG_SSM
1615  std::cout << "-> Encounter type: " << type << std::endl;
1616 #endif
1617  } else {
1618  assert(&(egoLane->getEdge()) == &(foeConflictLane->getEdge()));
1619  assert(egoDistToConflictLane <= 0);
1620  // Foe must be on a route leading into the ego's edge
1621  if (foeConflictLane == egoLane) {
1623  eInfo.foeConflictEntryDist = foeDistToConflictLane + e->ego->getBackPositionOnLane();
1624 
1625 #ifdef DEBUG_SSM
1626  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' leads foe '"
1627  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1628  << " (gap = " << eInfo.foeConflictEntryDist << ")"
1629  << std::endl;
1630 #endif
1631  } else {
1632  // Foe's route leads to an adjacent lane of the current lane of the ego
1634 #ifdef DEBUG_SSM
1635  std::cout << "-> Encounter type: " << type << std::endl;
1636 #endif
1637  }
1638  }
1639  } else {
1640  // The egoConflictLane is a non-internal lane which is not the ego's current lane. Thus it must lie ahead of the ego vehicle and
1641  // is located on the foe's current edge see findSurroundingVehicles()
1642  // (otherwise the foe would have had to enter the ego's route along a junction and the corresponding
1643  // conflict lane would be internal)
1644  assert(&(foeLane->getEdge()) == &(egoConflictLane->getEdge()));
1645  assert(foeDistToConflictLane <= 0);
1646  if (foeLane == egoConflictLane) {
1648  eInfo.egoConflictEntryDist = egoDistToConflictLane + e->foe->getBackPositionOnLane();
1649 #ifdef DEBUG_SSM
1650  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' follows foe '"
1651  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1652  << " (gap = " << eInfo.egoConflictEntryDist << ")"
1653  << std::endl;
1654 #endif
1655  } else {
1656  // Ego's route leads to an adjacent lane of the current lane of the foe
1658 #ifdef DEBUG_SSM
1659  std::cout << "-> Encounter type: " << type << std::endl;
1660 #endif
1661  }
1662  }
1663  } else {
1664  // egoConflictLane is internal, i.e., lies on a junction. Besides the lead/follow situation (which may stretch over different lanes of a connection),
1665  // merging or crossing of the conflict lanes is possible.
1666  assert(foeConflictLane->isInternal());
1667  MSLink* egoEntryLink = egoConflictLane->getEntryLink();
1668  MSLink* foeEntryLink = foeConflictLane->getEntryLink();
1669  if (&(egoEntryLink->getViaLane()->getEdge()) == &(foeEntryLink->getViaLane()->getEdge())) {
1670  if (egoEntryLink != foeEntryLink) {
1671  // XXX: this disregards conflicts for vehicles on adjacent internal lanes
1673 #ifdef DEBUG_SSM
1674  std::cout << "-> Encounter type: " << type << std::endl;
1675 #endif
1676  } else {
1677  // Lead / follow situation on connection
1678  if (egoLane == egoConflictLane && foeLane != foeConflictLane) {
1679  // ego on junction, foe not yet
1681  eInfo.foeConflictEntryDist = foeDistToConflictLane + e->ego->getBackPositionOnLane();
1682 #ifdef DEBUG_SSM
1683  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' leads foe '"
1684  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1685  << " (gap = " << eInfo.foeConflictEntryDist << ")"
1686  << std::endl;
1687 #endif
1688  } else if (egoLane != egoConflictLane && foeLane == foeConflictLane) {
1689  // foe on junction, ego not yet
1691  eInfo.egoConflictEntryDist = egoDistToConflictLane + e->foe->getBackPositionOnLane();
1692 #ifdef DEBUG_SSM
1693  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' follows foe '"
1694  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1695  << " (gap = " << eInfo.egoConflictEntryDist << ")"
1696  << std::endl;
1697 #endif
1698  } else {
1699  // Both must be already on the junction in a lead / follow situation on a connection
1700  // (since they approach via the same link, findSurroundingVehicles() would have determined a
1701  // different conflictLane if both are not on the junction)
1702  assert(egoLane == egoConflictLane);
1703  assert(foeLane == foeConflictLane);
1704  if (egoLane == foeLane) {
1705  // both on the same internal lane
1706  if (e->ego->getPositionOnLane() > e->foe->getPositionOnLane()) {
1708  eInfo.foeConflictEntryDist = foeDistToConflictLane + e->ego->getBackPositionOnLane();
1709 #ifdef DEBUG_SSM
1710  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' leads foe '"
1711  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1712  << " (gap = " << eInfo.foeConflictEntryDist << ")"
1713  << std::endl;
1714 #endif
1715  } else {
1717  eInfo.egoConflictEntryDist = egoDistToConflictLane + e->foe->getBackPositionOnLane();
1718 #ifdef DEBUG_SSM
1719  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' follows foe '"
1720  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1721  << " (gap = " << eInfo.egoConflictEntryDist << ")"
1722  << std::endl;
1723 #endif
1724  }
1725  } else {
1726  // ego and foe on distinct, consecutive internal lanes
1727 #ifdef DEBUG_SSM
1728  std::cout << " Lead/follow situation on consecutive internal lanes." << std::endl;
1729 #endif
1730  MSLane* lane = egoEntryLink->getViaLane();
1731 #ifdef _MSC_VER
1732 #pragma warning(push)
1733 #pragma warning(disable: 4127) // do not warn about constant conditional expression
1734 #endif
1735  while (true) {
1736 #ifdef _MSC_VER
1737 #pragma warning(pop)
1738 #endif
1739  // Find first of egoLane and foeLane while crossing the junction (this dertermines who's the follower)
1740  // Then set the conflict lane to the lane of the leader and adapt the follower's distance to conflict
1741  if (egoLane == lane) {
1742  // ego is follower
1744  // adapt conflict dist
1745  eInfo.egoConflictEntryDist = egoDistToConflictLane;
1746  while (lane != foeLane) {
1747  eInfo.egoConflictEntryDist += lane->getLength();
1748  lane = lane->getLinkCont()[0]->getViaLane();
1749  assert(lane != 0);
1750  }
1752  egoConflictLane = lane;
1753 #ifdef DEBUG_SSM
1754  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' follows foe '"
1755  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1756  << " (gap = " << eInfo.egoConflictEntryDist << ")"
1757  << std::endl;
1758 #endif
1759  break;
1760  } else if (foeLane == lane) {
1761  // ego is leader
1763  // adapt conflict dist
1764  eInfo.foeConflictEntryDist = foeDistToConflictLane;
1765  while (lane != egoLane) {
1766  eInfo.foeConflictEntryDist += lane->getLength();
1767  lane = lane->getLinkCont()[0]->getViaLane();
1768  assert(lane != 0);
1769  }
1771  foeConflictLane = lane;
1772 #ifdef DEBUG_SSM
1773  std::cout << "-> Encounter type: Ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' leads foe '"
1774  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1775  << " (gap = " << eInfo.foeConflictEntryDist << ")"
1776  << std::endl;
1777 #endif
1778  break;
1779  }
1780  lane = lane->getLinkCont()[0]->getViaLane();
1781  assert(lane != 0);
1782  }
1783  }
1784 #ifdef DEBUG_SSM
1785  std::cout << "-> Encounter type: Lead/follow-situation on connection from '" << egoEntryLink->getLaneBefore()->getID()
1786  << "' to '" << egoEntryLink->getLane()->getID() << "'" << std::endl;
1787 #endif
1788  }
1789  }
1790  } else {
1791  // Entry links to junctions lead to different internal edges.
1792  // There are three possibilities, either the edges cross, merge or have no conflict
1793  const std::vector<MSLink*>& egoFoeLinks = egoEntryLink->getFoeLinks();
1794  const std::vector<MSLink*>& foeFoeLinks = foeEntryLink->getFoeLinks();
1795  // Determine whether ego and foe links are foes
1796  bool crossOrMerge = (find(egoFoeLinks.begin(), egoFoeLinks.end(), foeEntryLink) != egoFoeLinks.end()
1797  || find(foeFoeLinks.begin(), foeFoeLinks.end(), egoEntryLink) != foeFoeLinks.end());
1798  if (!crossOrMerge) {
1799 // if (&(foeEntryLink->getLane()->getEdge()) == &(egoEntryLink->getLane()->getEdge())) {
1800 // // XXX: the situation of merging into adjacent lanes is disregarded for now <- the alleged situation appears to imply crossOrMerge!!!
1801 // type = ENCOUNTER_TYPE_MERGING_ADJACENT;
1802 //#ifdef DEBUG_SSM
1803 // std::cout << "-> Encounter type: No conflict (adjacent lanes)." << std::endl;
1804 //#endif
1805 // } else {
1807 #ifdef DEBUG_SSM
1808  std::cout << "-> Encounter type: No conflict." << std::endl;
1809 #endif
1810 // }
1811  } else if (&(foeEntryLink->getLane()->getEdge()) == &(egoEntryLink->getLane()->getEdge())) {
1812  if (foeEntryLink->getLane() == egoEntryLink->getLane()) {
1813  type = ENCOUNTER_TYPE_MERGING;
1814  eInfo.egoConflictEntryDist = egoDistToConflictLane + egoEntryLink->getInternalLengthsAfter();
1815  eInfo.foeConflictEntryDist = foeDistToConflictLane + foeEntryLink->getInternalLengthsAfter();
1816 #ifdef DEBUG_SSM
1817  std::cout << "-> Encounter type: Merging situation of ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' and foe '"
1818  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1819  << "\nDistances to merge-point: ego: " << eInfo.egoConflictEntryDist << ", foe: " << eInfo.foeConflictEntryDist
1820  << std::endl;
1821 #endif
1822  } else {
1823  // Links leading to the same edge but different lanes. XXX: Disregards conflicts on adjacent lanes
1825 #ifdef DEBUG_SSM
1826  std::cout << "-> Encounter type: No conflict: " << type << std::endl;
1827 #endif
1828  }
1829  } else {
1830  type = ENCOUNTER_TYPE_CROSSING;
1831 
1832  assert(egoConflictLane->isInternal());
1833  assert(foeConflictLane->getEdge().getToJunction() == egoConflictLane->getEdge().getToJunction());
1834 
1835  // If the conflict lanes are internal, they may not correspond to the
1836  // actually crossing parts of the corresponding connections.
1837  // Adjust the conflict lanes accordingly.
1838  // set back both to the first parts of the corresponding connections
1839  double offset = 0.;
1840  egoConflictLane = egoConflictLane->getFirstInternalInConnection(offset);
1841  egoDistToConflictLane -= offset;
1842  foeConflictLane = foeConflictLane->getFirstInternalInConnection(offset);
1843  foeDistToConflictLane -= offset;
1844  // find the distances to the conflict from the junction entry for both vehicles
1845  // Here we also determine the real crossing lanes (before the conflict lane is the first lane of the connection)
1846  // for the ego
1847  double egoDistToConflictFromJunctionEntry = INVALID;
1848  double foeInternalLaneLengthsBeforeCrossing = 0.;
1849  while (foeConflictLane != 0 && foeConflictLane->isInternal()) {
1850  egoDistToConflictFromJunctionEntry = egoEntryLink->getLengthsBeforeCrossing(foeConflictLane);
1851  if (egoDistToConflictFromJunctionEntry != INVALID) {
1852  // found correct foeConflictLane
1853  egoDistToConflictFromJunctionEntry += 0.5 * (foeConflictLane->getWidth() - e->foe->getVehicleType().getWidth());
1854  break;
1855  } else {
1856  foeInternalLaneLengthsBeforeCrossing += foeConflictLane->getLength();
1857  }
1858  foeConflictLane = foeConflictLane->getCanonicalSuccessorLane();
1859  assert(foeConflictLane != 0 && foeConflictLane->isInternal()); // this loop should be ended by the break! Otherwise the lanes do not cross, which should be the case here.
1860  }
1861  assert(egoDistToConflictFromJunctionEntry != INVALID);
1862 
1863  // for the foe
1864  double foeDistToConflictFromJunctionEntry = INVALID;
1865  double egoInternalLaneLengthsBeforeCrossing = 0.;
1866  foeDistToConflictFromJunctionEntry = INVALID;
1867  while (egoConflictLane != 0 && egoConflictLane->isInternal()) {
1868  foeDistToConflictFromJunctionEntry = foeEntryLink->getLengthsBeforeCrossing(egoConflictLane);
1869  if (foeDistToConflictFromJunctionEntry != INVALID) {
1870  // found correct egoConflictLane
1871  foeDistToConflictFromJunctionEntry += 0.5 * (egoConflictLane->getWidth() - e->ego->getVehicleType().getWidth());
1872  break;
1873  } else {
1874  egoInternalLaneLengthsBeforeCrossing += egoConflictLane->getLength();
1875  }
1876  egoConflictLane = egoConflictLane->getCanonicalSuccessorLane();
1877  assert(egoConflictLane != 0 && egoConflictLane->isInternal()); // this loop should be ended by the break! Otherwise the lanes do not cross, which should be the case here.
1878  }
1879  assert(foeDistToConflictFromJunctionEntry != INVALID);
1880 
1881  // store conflict entry information in eInfo
1882 
1883 // // TO-DO: equip these with exit times to store relevant PET sections in encounter
1884 // eInfo.egoConflictEntryCrossSection = std::make_pair(egoConflictLane, egoDistToConflictFromJunctionEntry - egoInternalLaneLengthsBeforeCrossing);
1885 // eInfo.foeConflictEntryCrossSection = std::make_pair(foeConflictLane, foeDistToConflictFromJunctionEntry - foeInternalLaneLengthsBeforeCrossing);
1886 
1887  // Take into account the lateral position for the exact determination of the conflict point
1888  // whether lateral position increases or decreases conflict distance depends on lane angles at conflict
1889  // -> conflictLaneOrientation in {-1,+1}
1890  // First, measure the angle between the two connection lines (straight lines from junction entry point to junction exit point)
1891  Position egoEntryPos = egoEntryLink->getViaLane()->getShape().front();
1892  Position egoExitPos = egoEntryLink->getCorrespondingExitLink()->getInternalLaneBefore()->getShape().back();
1893  PositionVector egoConnectionLine(egoEntryPos, egoExitPos);
1894  Position foeEntryPos = foeEntryLink->getViaLane()->getShape().front();
1895  Position foeExitPos = foeEntryLink->getCorrespondingExitLink()->getInternalLaneBefore()->getShape().back();
1896  PositionVector foeConnectionLine(foeEntryPos, foeExitPos);
1897  double angle = std::fmod(egoConnectionLine.rotationAtOffset(0.) - foeConnectionLine.rotationAtOffset(0.), (2 * M_PI));
1898  if (angle < 0) {
1899  angle += 2 * M_PI;
1900  }
1901  assert(angle >= 0);
1902  assert(angle <= 2 * M_PI);
1903  if (angle > M_PI) {
1904  angle -= 2 * M_PI;
1905  }
1906  assert(angle >= -M_PI);
1907  assert(angle <= M_PI);
1908  // Determine orientation of the connection lines. (Positive values mean that the ego vehicle approaches from the foe's left side.)
1909  double crossingOrientation = (angle < 0) - (angle > 0);
1910 
1911  // Adjust conflict dist to lateral positions
1912  // TODO: This could more precisely be calculated wrt the angle of the crossing *at the conflict point*
1913  egoDistToConflictFromJunctionEntry -= crossingOrientation * e->foe->getLateralPositionOnLane();
1914  foeDistToConflictFromJunctionEntry += crossingOrientation * e->ego->getLateralPositionOnLane();
1915 
1916  // Complete entry distances
1917  eInfo.egoConflictEntryDist = egoDistToConflictLane + egoDistToConflictFromJunctionEntry;
1918  eInfo.foeConflictEntryDist = foeDistToConflictLane + foeDistToConflictFromJunctionEntry;
1919 
1920 
1921 #ifdef DEBUG_SSM
1922  std::cout << " Determined exact conflict distances for crossing conflict."
1923  << "\n crossingOrientation=" << crossingOrientation
1924  << ", egoCrossingAngle=" << egoConnectionLine.rotationAtOffset(0.)
1925  << ", foeCrossingAngle=" << foeConnectionLine.rotationAtOffset(0.)
1926  << ", relativeAngle=" << angle
1927  << " (foe from " << (crossingOrientation > 0 ? "right)" : "left)")
1928  << "\n resulting offset for conflict entry distance:"
1929  << "\n ego=" << crossingOrientation* e->foe->getLateralPositionOnLane()
1930  << ", foe=" << crossingOrientation* e->ego->getLateralPositionOnLane()
1931  << "\n resulting entry distances:"
1932  << "\n ego=" << eInfo.egoConflictEntryDist
1933  << ", foe=" << eInfo.foeConflictEntryDist
1934  << std::endl;
1935 #endif
1936 
1937  // TODO: This could also more precisely be calculated wrt the angle of the crossing *at the conflict point*
1938  eInfo.egoConflictAreaLength = e->foe->getWidth();
1939  eInfo.foeConflictAreaLength = e->ego->getWidth();
1940 
1941  // resulting exit distances
1944 
1945 #ifdef DEBUG_SSM
1946  std::cout << "real egoConflictLane: '" << (egoConflictLane == 0 ? "NULL" : egoConflictLane->getID()) << "'\n"
1947  << "real foeConflictLane: '" << (foeConflictLane == 0 ? "NULL" : foeConflictLane->getID()) << "'\n"
1948  << "-> Encounter type: Crossing situation of ego '" << e->ego->getID() << "' on lane '" << egoLane->getID() << "' and foe '"
1949  << e->foe->getID() << "' on lane '" << foeLane->getID() << "'"
1950  << "\nDistances to crossing-point: ego: " << eInfo.egoConflictEntryDist << ", foe: " << eInfo.foeConflictEntryDist
1951  << std::endl;
1952 #endif
1953  }
1954  }
1955  }
1956  return type;
1957 }
1958 
1959 
1960 const MSLane*
1961 MSDevice_SSM::findFoeConflictLane(const MSVehicle* foe, const MSLane* egoConflictLane, double& distToConflictLane) const {
1962 
1963 #ifdef DEBUG_SSM
1964  std::cout << SIMTIME << " findFoeConflictLane() for foe '"
1965  << foe->getID() << "' on lane '" << foe->getLane()->getID()
1966  << "' (with egoConflictLane=" << (egoConflictLane == 0 ? "NULL" : egoConflictLane->getID())
1967  << ")\nfoeBestLanes: " << toString(foe->getBestLanesContinuation())
1968  << std::endl;
1969 #endif
1970  MSLane* foeLane = foe->getLane();
1971  std::vector<MSLane*>::const_iterator laneIter = foe->getBestLanesContinuation().begin();
1972  std::vector<MSLane*>::const_iterator foeBestLanesEnd = foe->getBestLanesContinuation().end();
1973  assert(foeLane->isInternal() || *laneIter == foeLane);
1974  distToConflictLane = -foe->getPositionOnLane();
1975 
1976  // Potential conflict lies on junction if egoConflictLane is internal
1977  const MSJunction* conflictJunction = egoConflictLane->isInternal() ? egoConflictLane->getEdge().getToJunction() : 0;
1978 #ifdef DEBUG_SSM
1979  if (conflictJunction != 0) {
1980  std::cout << "Potential conflict on junction '" << conflictJunction->getID()
1981  << std::endl;
1982  }
1983 #endif
1984  if (foeLane->isInternal() && foeLane->getEdge().getToJunction() == conflictJunction) {
1985  // foe is already on the conflict junction
1986  return foeLane;
1987  }
1988 
1989  // Foe is not on the conflict junction
1990 
1991  // Leading internal lanes in bestlanes are resembled as a single NULL-pointer skip them
1992  if (*laneIter == 0) {
1993  while (foeLane != 0 && foeLane->isInternal()) {
1994  distToConflictLane += foeLane->getLength();
1995  foeLane = foeLane->getLinkCont()[0]->getViaLane();
1996  }
1997  ++laneIter;
1998  assert(laneIter == foeBestLanesEnd || *laneIter != 0);
1999  }
2000 
2001  // Look for the junction downstream along foeBestLanes
2002  while (laneIter != foeBestLanesEnd && distToConflictLane <= myRange) {
2003  // Eventual internal lanes were skipped
2004  assert(*laneIter == foeLane || foeLane == 0);
2005  foeLane = *laneIter;
2006  assert(!foeLane->isInternal());
2007  if (&foeLane->getEdge() == &egoConflictLane->getEdge()) {
2008 #ifdef DEBUG_SSM
2009  std::cout << "Found conflict lane for foe: '" << foeLane->getID() << "'" << std::endl;
2010 #endif
2011  // found the potential conflict edge along foeBestLanes
2012  return foeLane;
2013  }
2014  // No conflict on foeLane
2015  distToConflictLane += foeLane->getLength();
2016 
2017  // set laneIter to next non internal lane along foeBestLanes
2018  ++laneIter;
2019  if (laneIter == foeBestLanesEnd) {
2020  return 0;
2021  }
2022  MSLane* nextNonInternalLane = *laneIter;
2023  MSLink* link = foeLane->getLinkTo(nextNonInternalLane);
2024  // Set foeLane to first internal lane on the next junction
2025  foeLane = link->getViaLane();
2026  assert(foeLane == 0 || foeLane->isInternal());
2027  if (foeLane == 0) {
2028  foeLane = nextNonInternalLane;
2029  continue;
2030  }
2031  if (foeLane->getEdge().getToJunction() == conflictJunction) {
2032  assert(foeLane != 0);
2033 #ifdef DEBUG_SSM
2034  std::cout << "Found conflict lane for foe: '" << foeLane->getID() << "'" << std::endl;
2035 #endif
2036  // found egoConflictLane, resp. the conflict junction, along foeBestLanes
2037  return foeLane;
2038  }
2039  // No conflict on junction
2040  distToConflictLane += link->getInternalLengthsAfter();
2041  foeLane = nextNonInternalLane;
2042  }
2043  // Didn't find conflicting lane on foeBestLanes within range.
2044  return 0;
2045 }
2046 
2047 void
2049 #ifdef DEBUG_SSM
2050  std::cout << "\n" << SIMTIME << " Device '" << getID() << "' flushConflicts()" << std::endl;
2051 #endif
2052  while (!myPastConflicts.empty()) {
2053  Encounter* top = myPastConflicts.top();
2054  if (flushAll || top->begin <= myOldestActiveEncounterBegin) {
2055  writeOutConflict(top);
2056  myPastConflicts.pop();
2057  delete top;
2058  } else {
2059  break;
2060  }
2061  }
2062 }
2063 
2064 void
2066  std::string egoID = myHolderMS->getID();
2067 #ifdef DEBUG_SSM
2068  std::cout << SIMTIME << " flushGlobalMeasures() of vehicle '"
2069  << egoID << "'"
2070  << "'\ntoGeo=" << myUseGeoCoords << std::endl;
2071 #endif
2073  myOutputFile->openTag("globalMeasures");
2074  myOutputFile->writeAttr("ego", egoID);
2076  if (myComputeBR) {
2077  myOutputFile->openTag("BRSpan").writeAttr("values", myBRspan).closeTag();
2078 
2079  if (myMaxBR.second != 0.0) {
2080  if (myUseGeoCoords) {
2081  toGeo(myMaxBR.first.second);
2082  }
2083  myOutputFile->openTag("maxBR").writeAttr("time", myMaxBR.first.first).writeAttr("position", toString(myMaxBR.first.second)).writeAttr("value", myMaxBR.second).closeTag();
2084  }
2085  }
2086 
2087  if (myComputeSGAP) {
2089  if (myMinSGAP.second != "") {
2090  if (myUseGeoCoords) {
2091  toGeo(myMinSGAP.first.first.second);
2092  }
2093  myOutputFile->openTag("minSGAP").writeAttr("time", myMinSGAP.first.first.first)
2094  .writeAttr("position", toString(myMinSGAP.first.first.second))
2095  .writeAttr("value", myMinSGAP.first.second)
2096  .writeAttr("leader", myMinSGAP.second).closeTag();
2097  }
2098  }
2099 
2100  if (myComputeTGAP) {
2102  if (myMinTGAP.second != "") {
2103  if (myUseGeoCoords) {
2104  toGeo(myMinTGAP.first.first.second);
2105  }
2106  myOutputFile->openTag("minTGAP").writeAttr("time", myMinTGAP.first.first.first)
2107  .writeAttr("position", toString(myMinTGAP.first.first.second))
2108  .writeAttr("value", myMinTGAP.first.second)
2109  .writeAttr("leader", myMinTGAP.second).closeTag();
2110  }
2111  }
2112  // close globalMeasures
2114  }
2115 }
2116 
2117 void
2120 }
2121 
2122 void
2124  for (Position& x : xv) {
2125  toGeo(x);
2126  }
2127 }
2128 
2129 void
2131 #ifdef DEBUG_SSM
2132  std::cout << SIMTIME << " writeOutConflict() of vehicles '"
2133  << e->egoID << "' and '" << e->foeID
2134  << "'\ntoGeo=" << myUseGeoCoords << std::endl;
2135 #endif
2136  myOutputFile->openTag("conflict");
2137  myOutputFile->writeAttr("begin", e->begin).writeAttr("end", e->end);
2138  myOutputFile->writeAttr("ego", e->egoID).writeAttr("foe", e->foeID);
2139 
2140  if (mySaveTrajectories) {
2141  myOutputFile->openTag("timeSpan").writeAttr("values", e->timeSpan).closeTag();
2142  myOutputFile->openTag("typeSpan").writeAttr("values", e->typeSpan).closeTag();
2143 
2144  // Some useful snippets for that (from MSFCDExport.cpp):
2145  if (myUseGeoCoords) {
2146  toGeo(e->egoTrajectory.x);
2147  toGeo(e->foeTrajectory.x);
2149  }
2150 
2152  myOutputFile->openTag("egoVelocity").writeAttr("values", toString(e->egoTrajectory.v)).closeTag();
2153 
2154  myOutputFile->openTag("foePosition").writeAttr("values", toString(e->foeTrajectory.x, myUseGeoCoords ? gPrecisionGeo : gPrecision)).closeTag();
2155  myOutputFile->openTag("foeVelocity").writeAttr("values", toString(e->foeTrajectory.v)).closeTag();
2156 
2157  myOutputFile->openTag("conflictPoint").writeAttr("values", toString(e->conflictPointSpan, myUseGeoCoords ? gPrecisionGeo : gPrecision)).closeTag();
2158  }
2159 
2160  if (myComputeTTC) {
2161  if (mySaveTrajectories) {
2162  myOutputFile->openTag("TTCSpan").writeAttr("values", makeStringWithNAs(e->TTCspan, INVALID)).closeTag();
2163  }
2164  if (e->minTTC.time == INVALID) {
2165  myOutputFile->openTag("minTTC").writeAttr("time", "NA").writeAttr("position", "NA").writeAttr("type", "NA").writeAttr("value", "NA").closeTag();
2166  } else {
2167  std::string time = toString(e->minTTC.time);
2168  std::string type = toString(int(e->minTTC.type));
2169  std::string value = toString(e->minTTC.value);
2170  if (myUseGeoCoords) {
2171  toGeo(e->minTTC.pos);
2172  }
2173  std::string position = toString(e->minTTC.pos, myUseGeoCoords ? gPrecisionGeo : gPrecision);
2174  myOutputFile->openTag("minTTC").writeAttr("time", time).writeAttr("position", position).writeAttr("type", type).writeAttr("value", value).closeTag();
2175  }
2176  }
2177  if (myComputeDRAC) {
2178  if (mySaveTrajectories) {
2179  myOutputFile->openTag("DRACSpan").writeAttr("values", makeStringWithNAs(e->DRACspan, {0.0, INVALID})).closeTag();
2180  }
2181  if (e->maxDRAC.time == INVALID) {
2182  myOutputFile->openTag("maxDRAC").writeAttr("time", "NA").writeAttr("position", "NA").writeAttr("type", "NA").writeAttr("value", "NA").closeTag();
2183  } else {
2184  std::string time = toString(e->maxDRAC.time);
2185  std::string type = toString(int(e->maxDRAC.type));
2186  std::string value = toString(e->maxDRAC.value);
2187  if (myUseGeoCoords) {
2188  toGeo(e->maxDRAC.pos);
2189  }
2190  std::string position = toString(e->maxDRAC.pos, myUseGeoCoords ? gPrecisionGeo : gPrecision);
2191  myOutputFile->openTag("maxDRAC").writeAttr("time", time).writeAttr("position", position).writeAttr("type", type).writeAttr("value", value).closeTag();
2192  }
2193  }
2194  if (myComputePET) {
2195  if (e->PET.time == INVALID) {
2196  myOutputFile->openTag("PET").writeAttr("time", "NA").writeAttr("position", "NA").writeAttr("type", "NA").writeAttr("value", "NA").closeTag();
2197  } else {
2198  std::string time = toString(e->PET.time);
2199  std::string type = toString(int(e->PET.type));
2200  std::string value = toString(e->PET.value);
2201  if (myUseGeoCoords) {
2202  toGeo(e->PET.pos);
2203  }
2204  std::string position = toString(e->PET.pos, myUseGeoCoords ? gPrecisionGeo : gPrecision);
2205  myOutputFile->openTag("PET").writeAttr("time", time).writeAttr("position", position).writeAttr("type", type).writeAttr("value", value).closeTag();
2206  }
2207  }
2209 }
2210 
2211 std::string
2212 MSDevice_SSM::makeStringWithNAs(std::vector<double> v, double NA, std::string sep) {
2213  std::string res = "";
2214  for (std::vector<double>::const_iterator i = v.begin(); i != v.end(); ++i) {
2215  res += (i == v.begin() ? "" : sep) + (*i == NA ? "NA" : toString(*i));
2216  }
2217  return res;
2218 }
2219 
2220 std::string
2221 MSDevice_SSM::makeStringWithNAs(std::vector<double> v, std::vector<double> NAs, std::string sep) {
2222  std::string res = "";
2223  for (std::vector<double>::const_iterator i = v.begin(); i != v.end(); ++i) {
2224  res += (i == v.begin() ? "" : sep) + (find(NAs.begin(), NAs.end(), *i) != NAs.end() ? "NA" : toString(*i));
2225  }
2226  return res;
2227 }
2228 
2229 
2230 // ---------------------------------------------------------------------------
2231 // MSDevice_SSM-methods
2232 // ---------------------------------------------------------------------------
2233 MSDevice_SSM::MSDevice_SSM(SUMOVehicle& holder, const std::string& id, std::string outputFilename, std::map<std::string, double> thresholds,
2234  bool trajectories, double range, double extraTime, bool useGeoCoords) :
2235  MSDevice(holder, id),
2236  myThresholds(thresholds),
2237  mySaveTrajectories(trajectories),
2238  myRange(range),
2239  myExtraTime(extraTime),
2240  myUseGeoCoords(useGeoCoords),
2242  myMaxBR(std::make_pair(-1, Position(0., 0.)), 0.0),
2243  myMinSGAP(std::make_pair(std::make_pair(-1, Position(0., 0.)), std::numeric_limits<double>::max()), ""),
2244  myMinTGAP(std::make_pair(std::make_pair(-1, Position(0., 0.)), std::numeric_limits<double>::max()), "") {
2245  // Take care! Holder is currently being constructed. Cast occurs before completion.
2246  myHolderMS = static_cast<MSVehicle*>(&holder);
2247 
2248  myComputeTTC = myThresholds.find("TTC") != myThresholds.end();
2249  myComputeDRAC = myThresholds.find("DRAC") != myThresholds.end();
2250  myComputePET = myThresholds.find("PET") != myThresholds.end();
2251 
2252  myComputeBR = myThresholds.find("BR") != myThresholds.end();
2253  myComputeSGAP = myThresholds.find("SGAP") != myThresholds.end();
2254  myComputeTGAP = myThresholds.find("TGAP") != myThresholds.end();
2255 
2258 
2259  // XXX: Who deletes the OutputDevice?
2260  myOutputFile = &OutputDevice::getDevice(outputFilename);
2261 // TODO: make xsd, include header
2262 // myOutputFile.writeXMLHeader("SSMLog", "SSMLog.xsd");
2263  if (createdOutputFiles.count(outputFilename) == 0) {
2264  myOutputFile->openTag("SSMLog");
2265  createdOutputFiles.insert(outputFilename);
2266  }
2267  // register at static instance container
2268  instances->insert(this);
2269 
2270 #ifdef DEBUG_SSM
2271  std::vector<std::string> measures;
2272  std::vector<double> threshVals;
2273  for (std::map<std::string, double>::const_iterator i = myThresholds.begin(); i != myThresholds.end(); ++i) {
2274  measures.push_back(i->first);
2275  threshVals.push_back(i->second);
2276  }
2277  std::cout << "Initialized ssm device '" << id << "' with "
2278  << "myMeasures=" << joinToString(measures, " ")
2279  << ", myThresholds=" << joinToString(threshVals, " ")
2280  << ", mySaveTrajectories=" << mySaveTrajectories
2281  << ", myRange=" << myRange << ", output file=" << outputFilename << ", extra time=" << myExtraTime << ", useGeo=" << myUseGeoCoords << "\n";
2282 #endif
2283 }
2284 
2287  // Deleted in ~BaseVehicle()
2288  // unregister from static instance container
2289  instances->erase(this);
2290  resetEncounters();
2291  flushConflicts(true);
2293 }
2294 
2295 
2296 bool
2298 #ifdef DEBUG_SSM_NOTIFICATIONS
2299  std::cout << "device '" << getID() << "' notifyEnter: reason=" << reason << " currentEdge=" << veh.getLane()->getEdge().getID() << "\n";
2300 #else
2301  UNUSED_PARAMETER(veh);
2302  UNUSED_PARAMETER(reason);
2303 #endif
2304  return true; // keep the device
2305 }
2306 
2307 bool
2308 MSDevice_SSM::notifyLeave(SUMOVehicle& veh, double /*lastPos*/,
2309  MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
2310 #ifdef DEBUG_SSM_NOTIFICATIONS
2311  std::cout << "device '" << getID() << "' notifyLeave: reason=" << reason << " currentEdge=" << veh.getLane()->getEdge().getID() << "\n";
2312 #else
2313  UNUSED_PARAMETER(veh);
2314  UNUSED_PARAMETER(reason);
2315 #endif
2316  return true; // keep the device
2317 }
2318 
2319 bool
2320 MSDevice_SSM::notifyMove(SUMOVehicle& /* veh */, double /* oldPos */,
2321  double /* newPos */, double newSpeed) {
2322 #ifdef DEBUG_SSM_NOTIFICATIONS
2323  std::cout << "device '" << getID() << "' notifyMove: newSpeed=" << newSpeed << "\n";
2324 #else
2325  UNUSED_PARAMETER(newSpeed);
2326 #endif
2327  return true; // keep the device
2328 }
2329 
2330 
2331 void
2332 MSDevice_SSM::findSurroundingVehicles(const MSVehicle& veh, double range, FoeInfoMap& foeCollector) {
2333 #ifdef DEBUG_SSM_SURROUNDING
2334  std::cout << SIMTIME << " Looking for surrounding vehicles for ego vehicle '" << veh.getID()
2335  << "' on edge '" << veh.getLane()->getEdge().getID()
2336  << "'."
2337  << "\nVehicle's best lanes = " << toString(veh.getBestLanesContinuation())
2338  << std::endl;
2339 #endif
2340 
2341  if (!veh.isOnRoad()) {
2342  return;
2343  }
2344 
2345  // The requesting vehicle's current route
2346  // XXX: Restriction to route scanning may have to be generalized to scanning of possible continuations when
2347  // considering situations involving sudden route changes. See also the definition of the EncounterTypes.
2348  // A second problem is that following situations on deviating routes may result in closing encounters
2349  // too early if a leading foe is not traced on its new lane. (see test 'foe_leader_deviating_routes')
2350 
2351  // If veh is on an internal edge, the edgeIter points towards the last edge before the junction
2352  ConstMSEdgeVector::const_iterator edgeIter = veh.getCurrentRouteEdge();
2353  assert(*edgeIter != 0);
2354 
2355  // Best continuation lanes for the ego vehicle
2356  const std::vector<MSLane*> egoBestLanes = veh.getBestLanesContinuation();
2357  std::vector<MSLane*>::const_iterator laneIter = egoBestLanes.begin();
2358 
2359  // current lane in loop below
2360  const MSLane* lane = veh.getLane();
2361  assert(lane->isInternal() || lane == *laneIter);
2362  assert(lane != 0);
2363  // next non-internal lane on the route
2364  const MSLane* nextNonInternalLane = 0;
2365 
2366  const MSEdge* edge; // current edge in loop below
2367 
2368  // Init pos with vehicle's current position. Below pos is set to zero to denote
2369  // the beginning position of the currently considered edge
2370  double pos = veh.getPositionOnLane();
2371  // remainingRange is the range minus the distance that is already scanned downstream along the vehicles route
2372  double remainingDownstreamRange = range;
2373  // distToConflictLane is the distance of the ego vehicle to the start of the currently considered potential conflict lane (can be negative for its current lane)
2374  double distToConflictLane = -pos;
2375  // junctions that were already scanned (break search in recurrent nets)
2376  std::set<const MSJunction*> seenJunctions;
2377 
2378  // if the current edge is internal, collect all vehicles from the junction and below range upstream (except on the vehicles own edge),
2379  // this is analogous to the code treating junctions in the loop below. Note that the distance on the junction itself is not included into
2380  // range, so vehicles farther away than range can be collected, too.
2381  if (lane->isInternal()) {
2382  edge = &(lane->getEdge());
2383 
2384 #ifdef DEBUG_SSM_SURROUNDING
2385  std::cout << SIMTIME << " Vehicle '" << veh.getID() << "' is on internal edge " << edge->getID() << "'.\n"
2386  << "Previous edge of its route: '" << (*edgeIter)->getID() << "'" << std::endl;
2387 #endif
2388 
2389  assert(edge->getToJunction() == edge->getFromJunction());
2390 
2391  const MSJunction* junction = edge->getToJunction();
2392  // Collect vehicles on the junction
2393  getVehiclesOnJunction(junction, distToConflictLane, lane, foeCollector);
2394  seenJunctions.insert(junction);
2395 
2396  // Collect vehicles on incoming edges.
2397  // Note that this includes the previous edge on the ego vehicle's route.
2398  // (The distance on the current internal edge is ignored)
2399  const ConstMSEdgeVector& incoming = junction->getIncoming();
2400  for (ConstMSEdgeVector::const_iterator ei = incoming.begin(); ei != incoming.end(); ++ei) {
2401  if ((*ei)->isInternal()) {
2402  continue;
2403  }
2404  // Upstream range is taken from the vehicle's back
2405  getUpstreamVehicles(*ei, (*ei)->getLength(), range + veh.getLength(), distToConflictLane, lane, foeCollector, seenJunctions);
2406  }
2407 
2408 // // Take into account internal distance covered on the current lane
2409 // (commented out, because upstream scanning disregards internal lanes on the last scanned junction
2410 // -- this makes the scanning symmetric between leader and follower)
2411 // remainingDownstreamRange -= lane->getLength() - pos;
2412 
2413  // Take into account non-internal lengths until next non-internal lane
2414  MSLink* link = lane->getLinkCont()[0];
2415  remainingDownstreamRange -= link->getInternalLengthsAfter();
2416  distToConflictLane += lane->getLength() + link->getInternalLengthsAfter();
2417 
2418  // The next non-internal lane
2419  pos = 0.;
2420  lane = *(++laneIter);
2421  edge = &lane->getEdge();
2422  } else {
2423  // Collect all vehicles in range behind ego vehicle
2424  edge = &(lane->getEdge());
2425  getUpstreamVehicles(edge, pos, range + veh.getLength(), distToConflictLane, lane, foeCollector, seenJunctions);
2426  }
2427 
2428  assert(lane != 0);
2429  assert(!lane->isInternal());
2430 
2431  // Advance downstream the ego vehicle's route for distance 'range'.
2432  // Collect all vehicles on the traversed Edges and on incoming edges at junctions.
2433  while (remainingDownstreamRange > 0.) {
2434 #ifdef DEBUG_SSM_SURROUNDING
2435  std::cout << SIMTIME << " Scanning downstream for vehicle '" << veh.getID() << "' on lane '" << veh.getLane()->getID() << "', position=" << pos << ".\n"
2436  << "Considering edge '" << edge->getID() << "' Remaining downstream range = " << remainingDownstreamRange
2437  << "\nbestLanes=" << toString(egoBestLanes) << "\n"
2438  << std::endl;
2439 #endif
2440  assert(!edge->isInternal());
2441  assert(!lane->isInternal());
2442  assert(pos == 0 || lane == veh.getLane());
2443  if (pos + remainingDownstreamRange < lane->getLength()) {
2444  // scan range ends on this lane
2445  getUpstreamVehicles(edge, pos + remainingDownstreamRange, remainingDownstreamRange, distToConflictLane, lane, foeCollector, seenJunctions);
2446  // scanned required downstream range
2447  break;
2448  } else {
2449  // Also need to scan area that reaches beyond the lane
2450  // Collecting vehicles on non-internal edge ahead
2451  getUpstreamVehicles(edge, edge->getLength(), edge->getLength() - pos, distToConflictLane, lane, foeCollector, seenJunctions);
2452  // account for scanned distance on lane
2453  remainingDownstreamRange -= lane->getLength() - pos;
2454  distToConflictLane += lane->getLength();
2455  pos = 0.;
2456 
2457  // proceed to next non-internal lane
2458  ++laneIter;
2459  assert(laneIter == egoBestLanes.end() || *laneIter != 0);
2460 
2461  // If the vehicle's best lanes go on, collect vehicles on the upcoming junction
2462  if (laneIter != egoBestLanes.end()) {
2463  // Upcoming junction
2464  const MSJunction* junction = lane->getEdge().getToJunction();
2465 
2466  // Find connection for ego on the junction
2467  nextNonInternalLane = *laneIter;
2468  MSLink* link = lane->getLinkTo(nextNonInternalLane);
2469  assert(link != 0 || link->getLength() == 0.);
2470 
2471  // First lane of the connection
2472  lane = link->getViaLane();
2473  if (lane == 0) {
2474  // link without internal lane
2475  lane = nextNonInternalLane;
2476  edge = &(lane->getEdge());
2477  if (seenJunctions.count(junction) == 0) {
2478  seenJunctions.insert(junction);
2479  continue;
2480  } else {
2481  break;
2482  }
2483  }
2484 
2485  if (seenJunctions.count(junction) == 0) {
2486  // Collect vehicles on the junction, if it wasn't considered already
2487  getVehiclesOnJunction(junction, distToConflictLane, lane, foeCollector);
2488  seenJunctions.insert(junction);
2489  // Collect vehicles on incoming edges (except the last edge, where we already collected). Use full range.
2490  const ConstMSEdgeVector& incoming = junction->getIncoming();
2491  for (ConstMSEdgeVector::const_iterator ei = incoming.begin(); ei != incoming.end(); ++ei) {
2492  if (*ei == edge || (*ei)->isInternal()) {
2493  continue;
2494  }
2495  getUpstreamVehicles(*ei, (*ei)->getLength(), range, distToConflictLane, lane, foeCollector, seenJunctions);
2496  }
2497  // account for scanned distance on junction
2498  double linkLength = link->getInternalLengthsAfter();
2499  remainingDownstreamRange -= linkLength;
2500  distToConflictLane += linkLength;
2501 #ifdef DEBUG_SSM_SURROUNDING
2502  std::cout << " Downstream Scan for vehicle '" << veh.getID() << "' proceeded over junction '" << junction->getID()
2503  << "',\n linkLength=" << linkLength << ", remainingDownstreamRange=" << remainingDownstreamRange
2504  << std::endl;
2505 #endif
2506 
2507  // update ego's lane to next non internal edge
2508  lane = nextNonInternalLane;
2509  edge = &(lane->getEdge());
2510  } else {
2511 #ifdef DEBUG_SSM_SURROUNDING
2512  std::cout << " Downstream Scan for vehicle '" << veh.getID() << "' stops at junction '" << junction->getID()
2513  << "', which has already been scanned."
2514  << std::endl;
2515 #endif
2516  break;
2517  }
2518  } else {
2519  // Further vehicle path unknown, break search
2520  break;
2521  }
2522  }
2523  }
2524  // remove ego vehicle
2525  foeCollector.erase(&veh);
2526 }
2527 
2528 void
2529 MSDevice_SSM::getUpstreamVehicles(const MSEdge* edge, double pos, double range, double egoDistToConflictLane, const MSLane* const egoConflictLane, FoeInfoMap& foeCollector, std::set<const MSJunction*> seenJunctions) {
2530 #ifdef DEBUG_SSM_SURROUNDING
2531  std::cout << SIMTIME << " getUpstreamVehicles() for edge '" << edge->getID() << "'"
2532  << " pos = " << pos << " range = " << range
2533  << "\nFound vehicles:"
2534  << std::endl;
2535 #endif
2536  if (range <= 0) {
2537  return;
2538  }
2539 
2540  const std::vector<MSLane*>& lanes = edge->getLanes();
2541  // Collect vehicles on the given edge with position in [pos-range,pos]
2542  for (std::vector<MSLane*>::const_iterator li = lanes.begin(); li != lanes.end(); ++li) {
2543  MSLane* lane = *li;
2544  const MSLane::VehCont& vehicles = lane->getVehiclesSecure();
2545  for (MSLane::VehCont::const_iterator vi = vehicles.begin(); vi != vehicles.end(); ++vi) {
2546  MSVehicle* veh = *vi;
2547  if (veh->getPositionOnLane() - veh->getLength() <= pos && veh->getPositionOnLane() >= pos - range) {
2548 #ifdef DEBUG_SSM
2549  std::cout << veh->getID() << "\n";
2550 #endif
2551  FoeInfo* c = new FoeInfo(); // c is deleted in updateEncounter()
2552  c->egoDistToConflictLane = egoDistToConflictLane;
2553  c->egoConflictLane = egoConflictLane;
2554  foeCollector[veh] = c;
2555  }
2556  }
2557  lane->releaseVehicles();
2558  }
2559 
2560 #ifdef DEBUG_SSM
2561  std::cout << std::endl;
2562 #endif
2563 
2564  // TODO: Gather vehicles from opposite direction. This should happen in any case, where opposite direction overtaking is possible.
2565  // If it isn't it might still be nicer to trace oncoming vehicles for the resulting trajectories in the encounters
2566  // if (edge->hasOpposite...)
2567 
2568  if (range <= pos) {
2569  return;
2570  }
2571 
2572  // Here we have: range > pos, i.e. we proceed collecting vehicles on preceding edges
2573  range -= pos;
2574 
2575  // Junction representing the origin of 'edge'
2576  const MSJunction* junction = edge->getFromJunction();
2577  if (seenJunctions.count(junction) == 0) {
2578  // Collect vehicles from incoming edges of the junction
2579  if (!edge->isInternal()) {
2580  // collect vehicles on preceding junction (for internal edges this is already done in caller,
2581  // i.e. findSurroundingVehicles() or the recursive call from getUpstreamVehicles())
2582 
2583  // Collect vehicles on the junction, if it wasn't considered already
2584  getVehiclesOnJunction(junction, egoDistToConflictLane, egoConflictLane, foeCollector);
2585  seenJunctions.insert(junction);
2586  }
2587  // Collect vehicles from incoming edges from the junction representing the origin of 'edge'
2588  const ConstMSEdgeVector& incoming = junction->getIncoming();
2589  for (ConstMSEdgeVector::const_iterator ei = incoming.begin(); ei != incoming.end(); ++ei) {
2590  if ((*ei)->isInternal()) {
2591  continue;
2592  }
2593  const MSEdge* inEdge = *ei;
2594  assert(inEdge != 0);
2595  double distOnJunction = edge->isInternal() ? 0. : inEdge->getInternalFollowingLengthTo(edge);
2596  if (distOnJunction >= range) {
2597  continue;
2598  }
2599  // account for vehicles on the predecessor edge
2600  getUpstreamVehicles(inEdge, inEdge->getLength(), range - distOnJunction, egoDistToConflictLane, egoConflictLane, foeCollector, seenJunctions);
2601  }
2602  } else {
2603 #ifdef DEBUG_SSM_SURROUNDING
2604  std::cout << " Downstream Scan for stops at junction '" << junction->getID()
2605  << "', which has already been scanned."
2606  << std::endl;
2607 #endif
2608  }
2609 }
2610 
2611 void
2612 MSDevice_SSM::getVehiclesOnJunction(const MSJunction* junction, double egoDistToConflictLane, const MSLane* const egoConflictLane, FoeInfoMap& foeCollector) {
2613 #ifdef DEBUG_SSM_SURROUNDING
2614  std::cout << SIMTIME << " getVehiclesOnJunction() for junction '" << junction->getID() << "'"
2615  << "\nFound vehicles:"
2616  << std::endl;
2617 #endif
2618  // Collect vehicles on internal lanes
2619  const std::vector<MSLane*> lanes = junction->getInternalLanes();
2620  for (std::vector<MSLane*>::const_iterator li = lanes.begin(); li != lanes.end(); ++li) {
2621  MSLane* lane = *li;
2622  const MSLane::VehCont& vehicles = lane->getVehiclesSecure();
2623 
2624  // Add FoeInfos (XXX: for some situations, a vehicle may be collected twice. Then the later finding overwrites the earlier in foeCollector.
2625  // This could lead to neglecting a conflict when determining foeConflictLane later.) -> TODO: test with twice intersecting routes
2626  for (MSLane::VehCont::const_iterator vi = vehicles.begin(); vi != vehicles.end(); ++vi) {
2627  FoeInfo* c = new FoeInfo();
2628  c->egoConflictLane = egoConflictLane;
2629  c->egoDistToConflictLane = egoDistToConflictLane;
2630  foeCollector[*vi] = c;
2631 #ifdef DEBUG_SSM_SURROUNDING
2632  for (MSLane::VehCont::const_iterator vi = vehicles.begin(); vi != vehicles.end(); ++vi) {
2633  std::cout << (*vi)->getID() << "\n";
2634  }
2635 #endif
2636  }
2637  lane->releaseVehicles();
2638 
2639  // If there is an internal continuation lane, also collect vehicles on that lane
2640  if (lane->getLinkCont().size() > 1 && lane->getLinkCont()[0]->getViaLane() != 0) {
2641  // There's a second internal lane of the connection
2642  lane = lane->getLinkCont()[0]->getViaLane();
2643  // This code must be modified, if more than two-piece internal lanes are allowed. Thus, assert:
2644  assert(lane->getLinkCont().size() == 0 || lane->getLinkCont()[0]->getViaLane() == 0);
2645 
2646  // collect vehicles
2647  const MSLane::VehCont& vehicles2 = lane->getVehiclesSecure();
2648  // Add FoeInfos. This duplicates the loop for the first internal lane
2649  for (MSLane::VehCont::const_iterator vi = vehicles2.begin(); vi != vehicles2.end(); ++vi) {
2650  FoeInfo* c = new FoeInfo();
2651  c->egoConflictLane = egoConflictLane;
2652  c->egoDistToConflictLane = egoDistToConflictLane;
2653  foeCollector[*vi] = c;
2654 #ifdef DEBUG_SSM_SURROUNDING
2655  for (MSLane::VehCont::const_iterator vi = vehicles2.begin(); vi != vehicles2.end(); ++vi) {
2656  std::cout << (*vi)->getID() << "\n";
2657  }
2658 #endif
2659  }
2660  lane->releaseVehicles();
2661  }
2662  }
2663 
2664 #ifdef DEBUG_SSM_SURROUNDING
2665  std::cout << std::endl;
2666 #endif
2667 }
2668 
2669 
2670 
2671 void
2673  // This is called once at vehicle removal.
2674  // Also: flush myOutputFile? Or is this done automatically?
2675  // myOutputFile->closeTag();
2676 }
2677 
2678 // ---------------------------------------------------------------------------
2679 // Static parameter load helpers
2680 // ---------------------------------------------------------------------------
2681 std::string
2682 MSDevice_SSM::getOutputFilename(const SUMOVehicle& v, std::string deviceID) {
2683  std::string file = deviceID + ".xml";
2684  if (v.getParameter().knowsParameter("device.ssm.file")) {
2685  try {
2686  file = v.getParameter().getParameter("device.ssm.file", file);
2687  } catch (...) {
2688  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.file", file) + "'for vehicle parameter 'ssm.measures'");
2689  }
2690  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.file")) {
2691  try {
2692  file = v.getVehicleType().getParameter().getParameter("device.ssm.file", file);
2693  } catch (...) {
2694  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.file", file) + "'for vType parameter 'ssm.measures'");
2695  }
2696  } else {
2697  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.file'. Using default of '" << file << "'\n";
2698  }
2699  return file;
2700 }
2701 
2702 bool
2705  bool useGeo = false;
2706  if (v.getParameter().knowsParameter("device.ssm.geo")) {
2707  try {
2708  useGeo = TplConvert::_2bool(v.getParameter().getParameter("device.ssm.geo", "no").c_str());
2709  } catch (...) {
2710  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.geo", "no") + "'for vehicle parameter 'ssm.geo'");
2711  }
2712  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.geo")) {
2713  try {
2714  useGeo = TplConvert::_2bool(v.getVehicleType().getParameter().getParameter("device.ssm.geo", "no").c_str());
2715  } catch (...) {
2716  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.geo", "no") + "'for vType parameter 'ssm.geo'");
2717  }
2718  } else {
2719  useGeo = oc.getBool("device.ssm.geo");
2720 #ifdef DEBUG_SSM
2721  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.geo'. Using default of '" << useGeo << "'\n";
2722 #endif
2723  }
2724  return useGeo;
2725 }
2726 
2727 
2728 double
2731  double range = -INVALID;
2732  if (v.getParameter().knowsParameter("device.ssm.range")) {
2733  try {
2734  range = TplConvert::_2double(v.getParameter().getParameter("device.ssm.range", "").c_str());
2735  } catch (...) {
2736  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.range", "") + "'for vehicle parameter 'ssm.range'");
2737  }
2738  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.range")) {
2739  try {
2740  range = TplConvert::_2double(v.getVehicleType().getParameter().getParameter("device.ssm.range", "").c_str());
2741  } catch (...) {
2742  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.range", "") + "'for vType parameter 'ssm.range'");
2743  }
2744  } else {
2745  range = oc.getFloat("device.ssm.range");
2746 #ifdef DEBUG_SSM
2747  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.range'. Using default of '" << range << "'\n";
2748 #endif
2749  }
2750  return range;
2751 }
2752 
2753 
2754 double
2757  double extraTime = INVALID;
2758  if (v.getParameter().knowsParameter("device.ssm.extratime")) {
2759  try {
2760  extraTime = TplConvert::_2double(v.getParameter().getParameter("device.ssm.extratime", "").c_str());
2761  } catch (...) {
2762  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.extratime", "") + "'for vehicle parameter 'ssm.extratime'");
2763  }
2764  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.extratime")) {
2765  try {
2766  extraTime = TplConvert::_2double(v.getVehicleType().getParameter().getParameter("device.ssm.extratime", "").c_str());
2767  } catch (...) {
2768  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.extratime", "") + "'for vType parameter 'ssm.extratime'");
2769  }
2770  } else {
2771  extraTime = oc.getFloat("device.ssm.extratime");
2772 #ifdef DEBUG_SSM
2773  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.extratime'. Using default of '" << extraTime << "'\n";
2774 #endif
2775  }
2776  if (extraTime < 0.) {
2777  extraTime = DEFAULT_EXTRA_TIME;
2778  WRITE_WARNING("Negative (or no) value encountered for vehicle parameter 'device.ssm.extratime' in vehicle '" + v.getID() + "' using default value " + toString(extraTime) + " instead");
2779  }
2780  return extraTime;
2781 }
2782 
2783 
2784 bool
2787  bool trajectories = false;
2788  if (v.getParameter().knowsParameter("device.ssm.trajectories")) {
2789  try {
2790  trajectories = TplConvert::_2bool(v.getParameter().getParameter("device.ssm.trajectories", "no").c_str());
2791  } catch (...) {
2792  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.trajectories", "no") + "'for vehicle parameter 'ssm.trajectories'");
2793  }
2794  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.trajectories")) {
2795  try {
2796  trajectories = TplConvert::_2bool(v.getVehicleType().getParameter().getParameter("device.ssm.trajectories", "no").c_str());
2797  } catch (...) {
2798  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.trajectories", "no") + "'for vType parameter 'ssm.trajectories'");
2799  }
2800  } else {
2801  trajectories = oc.getBool("device.ssm.trajectories");
2802 #ifdef DEBUG_SSM
2803  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.trajectories'. Using default of '" << trajectories << "'\n";
2804 #endif
2805  }
2806  return trajectories;
2807 }
2808 
2809 
2810 bool
2811 MSDevice_SSM::getMeasuresAndThresholds(const SUMOVehicle& v, std::string deviceID, std::map<std::string, double>& thresholds) {
2813 
2814  // Measures
2815  std::string measures_str = "";
2816  if (v.getParameter().knowsParameter("device.ssm.measures")) {
2817  try {
2818  measures_str = v.getParameter().getParameter("device.ssm.measures", "");
2819  } catch (...) {
2820  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.measures", "") + "'for vehicle parameter 'ssm.measures'");
2821  }
2822  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.measures")) {
2823  try {
2824  measures_str = v.getVehicleType().getParameter().getParameter("device.ssm.measures", "");
2825  } catch (...) {
2826  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.measures", "") + "'for vType parameter 'ssm.measures'");
2827  }
2828  } else {
2829  measures_str = oc.getString("device.ssm.measures");
2830  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.measures'. Using default of '" << measures_str << "'\n";
2831  }
2832 
2833  // Check retrieved measures
2834  if (measures_str == "") {
2835  WRITE_WARNING("No measures specified for ssm device of vehicle '" + v.getID() + "'. Registering all available SSMs.");
2836  measures_str = AVAILABLE_SSMS;
2837  }
2839  std::vector<std::string> available = st.getVector();
2840  st = StringTokenizer(measures_str);
2841  std::vector<std::string> measures = st.getVector();
2842  for (std::vector<std::string>::const_iterator i = measures.begin(); i != measures.end(); ++i) {
2843  if (std::find(available.begin(), available.end(), *i) == available.end()) {
2844  // Given identifier is unknown
2845  WRITE_ERROR("SSM identifier '" + *i + "' is not supported. Aborting construction of SSM device '" + deviceID + "'.");
2846  return false;
2847  }
2848  }
2849 
2850  // Thresholds
2851  std::string thresholds_str = "";
2852  if (v.getParameter().knowsParameter("device.ssm.thresholds")) {
2853  try {
2854  thresholds_str = v.getParameter().getParameter("device.ssm.thresholds", "");
2855  } catch (...) {
2856  WRITE_WARNING("Invalid value '" + v.getParameter().getParameter("device.ssm.thresholds", "") + "'for vehicle parameter 'ssm.thresholds'");
2857  }
2858  } else if (v.getVehicleType().getParameter().knowsParameter("device.ssm.thresholds")) {
2859  try {
2860  thresholds_str = v.getVehicleType().getParameter().getParameter("device.ssm.thresholds", "");
2861  } catch (...) {
2862  WRITE_WARNING("Invalid value '" + v.getVehicleType().getParameter().getParameter("device.ssm.thresholds", "") + "'for vType parameter 'ssm.thresholds'");
2863  }
2864  } else {
2865  thresholds_str = oc.getString("device.ssm.thresholds");
2866 #ifdef DEBUG_SSM
2867  std::cout << "vehicle '" << v.getID() << "' does not supply vehicle parameter 'device.ssm.thresholds'. Using default of '" << thresholds_str << "'\n";
2868 #endif
2869  }
2870 
2871  // Parse vector of doubles from threshold_str
2872  int count = 0;
2873  if (thresholds_str != "") {
2874  st = StringTokenizer(thresholds_str);
2875  while (count < (int)measures.size() && st.hasNext()) {
2876  double thresh = TplConvert::_2double(st.next().c_str());
2877  thresholds.insert(std::make_pair(measures[count], thresh));
2878  ++count;
2879  }
2880  if (thresholds.size() < measures.size() || st.hasNext()) {
2881  WRITE_ERROR("Given list of thresholds ('" + thresholds_str + "') is not of the same size as the list of measures ('" + measures_str + "').\nPlease specify exactly one threshold for each measure.");
2882  return false;
2883  }
2884  } else {
2885  // assume default thresholds if none are given
2886  for (std::vector<std::string>::const_iterator i = measures.begin(); i != measures.end(); ++i) {
2887  if (*i == "TTC") {
2888  thresholds.insert(std::make_pair(*i, DEFAULT_THRESHOLD_TTC));
2889  } else if (*i == "DRAC") {
2890  thresholds.insert(std::make_pair(*i, DEFAULT_THRESHOLD_DRAC));
2891  } else if (*i == "PET") {
2892  thresholds.insert(std::make_pair(*i, DEFAULT_THRESHOLD_PET));
2893  } else if (*i == "BR") {
2894  thresholds.insert(std::make_pair(*i, DEFAULT_THRESHOLD_BR));
2895  } else if (*i == "SGAP") {
2896  thresholds.insert(std::make_pair(*i, DEFAULT_THRESHOLD_SGAP));
2897  } else if (*i == "TGAP") {
2898  thresholds.insert(std::make_pair(*i, DEFAULT_THRESHOLD_TGAP));
2899  } else {
2900  WRITE_ERROR("Unknown SSM identifier '" + (*i) + "'. Aborting construction of ssm device."); // should never occur
2901  return false;
2902  }
2903  }
2904  }
2905  return true;
2906 }
2907 
2908 
2909 
2910 /****************************************************************************/
2911 
#define DEFAULT_THRESHOLD_BR
bool myUseGeoCoords
Whether to use the original coordinate system for output.
Definition: MSDevice_SSM.h:631
void doRegister(const std::string &name, Option *v)
Adds an option under the given name.
Definition: OptionsCont.cpp:75
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
static void determineConflictPoint(EncounterApproachInfo &eInfo)
Calculates the (x,y)-coordinate for the eventually predicted conflict point and stores the result in ...
#define AVAILABLE_SSMS
std::vector< double > myBRspan
All values for brake rate.
Definition: MSDevice_SSM.h:654
ENCOUNTER_TYPE_MERGING_ADJACENT.
Definition: MSDevice_SSM.h:87
const std::string egoID
Definition: MSDevice_SSM.h:184
double getLength() const
Returns the vehicle&#39;s length.
MSEdge & getEdge() const
Returns the lane&#39;s edge.
Definition: MSLane.h:617
static void getVehiclesOnJunction(const MSJunction *, double egoDistToConflictLane, const MSLane *const egoConflictLane, FoeInfoMap &foeCollector)
Collects all vehicles on the junction into foeCollector.
Representation of a vehicle in the micro simulation.
Definition: MSVehicle.h:79
double getPreviousSpeed() const
Returns the vehicle&#39;s speed before the previous time step.
Definition: MSVehicle.h:487
#define DEFAULT_RANGE
void createEncounters(FoeInfoMap &foes)
Makes new encounters for all given vehicles (these should be the ones entering the device&#39;s range in ...
static std::set< MSDevice_SSM * > * instances
All currently existing SSM devices.
Definition: MSDevice_SSM.h:60
std::string next()
bool notifyLeave(SUMOVehicle &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Called whenever the holder leaves a lane.
ConflictPointInfo minTTC
Definition: MSDevice_SSM.h:226
Position getVelocityVector() const
Returns the vehicle&#39;s direction in radians.
Definition: MSVehicle.h:689
ConflictPointInfo maxDRAC
Definition: MSDevice_SSM.h:227
static void cleanup()
Clean up remaining devices instances.
EncounterType
Different types of encounters corresponding to relative positions of the vehicles. The name describes the type from the ego perspective.
Definition: MSDevice_SSM.h:65
MSLane * getLane() const
Returns the lane the vehicle is on.
Definition: MSVehicle.h:561
PositionVector conflictPointSpan
Predicted location of the conflict: In case of MERGING and CROSSING: entry point to conflict area for...
Definition: MSDevice_SSM.h:213
static bool _2bool(const E *const data)
converts a 0-terminated char-type array into the boolean value described by it
Definition: TplConvert.h:382
void updatePassedEncounter(Encounter *e, FoeInfo *foeInfo, EncounterApproachInfo &eInfo)
Updates an encounter, which was classified as ENCOUNTER_TYPE_NOCONFLICT_AHEAD this may be the case be...
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_SSM-options.
MSVehicle * myHolderMS
Definition: MSDevice_SSM.h:634
SUMOVehicle & myHolder
The vehicle that stores the device.
Definition: MSDevice.h:195
int gPrecision
the precision for floating point outputs
Definition: StdDefs.cpp:27
double egoConflictEntryTime
Times when the ego vehicle entered/left the conflict area. Currently only applies for crossing situat...
Definition: MSDevice_SSM.h:193
void determinePET(EncounterApproachInfo &eInfo) const
Discriminates between different encounter types and correspondingly determines the PET for those case...
std::pair< const MSVehicle *const, double > getLeader(double dist=0) const
Returns the leader of the vehicle looking for a fixed distance.
Definition: MSVehicle.cpp:4451
A device which collects info on the vehicle trip (mainly on departure and arrival) ...
Definition: MSDevice_SSM.h:56
void determineTTCandDRAC(EncounterApproachInfo &eInfo) const
Discriminates between different encounter types and correspondingly determines TTC and DRAC for those...
std::pair< std::pair< double, Position >, double > myMaxBR
Extremal values for the global measures (as <<<time, Position>, value>, [leaderID]>-pairs) ...
Definition: MSDevice_SSM.h:661
The base class for an intersection.
Definition: MSJunction.h:60
const MSVehicle * foe
Definition: MSDevice_SSM.h:183
double getPositionOnLane() const
Get the vehicle&#39;s position along the lane.
Definition: MSVehicle.h:399
EncounterVector myActiveEncounters
Definition: MSDevice_SSM.h:641
#define INVALID
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
Notification
Definition of a vehicle state.
ENCOUNTER_TYPE_FOLLOWING_PASSED.
Definition: MSDevice_SSM.h:111
virtual MSLane * getLane() const =0
Returns the lane the vehicle is on.
double computeTTC(double gap, double followerSpeed, double leaderSpeed) const
Computes the time to collision (in seconds) for two vehicles with a given initial gap under the assum...
EncounterType classifyEncounter(const FoeInfo *foeInfo, EncounterApproachInfo &eInfo) const
Classifies the current type of the encounter provided some information on the opponents.
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:162
std::vector< double > myGlobalMeasuresTimeSpan
Definition: MSDevice_SSM.h:652
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:68
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
void closeEncounter(Encounter *e)
Finalizes the encounter and calculates SSM values.
MSLink * getLinkTo(const MSLane *) const
returns the link to the given lane or 0, if it is not connected
Definition: MSLane.cpp:1947
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
Definition: MSVehicle.cpp:932
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
static double getDetectionRange(const SUMOVehicle &v)
ENCOUNTER_TYPE_COLLISION.
Definition: MSDevice_SSM.h:115
static void toGeo(Position &x)
convert SUMO-positions to geo coordinates (in place)
std::vector< double > TTCspan
All values for TTC.
Definition: MSDevice_SSM.h:216
ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA.
Definition: MSDevice_SSM.h:98
Position pos
Predicted location of the conflict: In case of MERGING and CROSSING: entry point to conflict area for...
Definition: MSDevice_SSM.h:139
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:72
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const std::string & getID() const
Returns the id.
Definition: Named.h:69
ENCOUNTER_TYPE_CROSSING.
Definition: MSDevice_SSM.h:90
const std::string foeID
Definition: MSDevice_SSM.h:185
#define TS
Definition: SUMOTime.h:45
#define DEFAULT_THRESHOLD_PET
double getLength() const
return the length of the edge
Definition: MSEdge.h:563
double time
time point of the conflict
Definition: MSDevice_SSM.h:135
const MSJunction * getToJunction() const
Definition: MSEdge.h:346
void updateEncounter(Encounter *e, FoeInfo *foeInfo)
Updates the encounter (adds a new trajectory point) and deletes the foeInfo.
void generateOutput() const
Finalizes output. Called on vehicle removal.
void resetExtraTime(double value)
resets remainingExtraTime to the given value
MSDevice_SSM(SUMOVehicle &holder, const std::string &id, std::string outputFilename, std::map< std::string, double > thresholds, bool trajectories, double range, double extraTime, bool useGeoCoords)
Constructor.
ENCOUNTER_TYPE_CROSSING_FOLLOWER.
Definition: MSDevice_SSM.h:96
double getWidth() const
Returns the lane&#39;s width.
Definition: MSLane.h:523
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:33
ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA.
Definition: MSDevice_SSM.h:106
Position getPositionAlongBestLanes(double offset) const
Return the (x,y)-position, which the vehicle would reach if it continued along its best continuation ...
Definition: MSVehicle.cpp:965
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:242
MSLane * getCanonicalSuccessorLane() const
Definition: MSLane.cpp:2429
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
std::vector< double > mySGAPspan
All values for space gap.
Definition: MSDevice_SSM.h:656
#define SIMTIME
Definition: SUMOTime.h:65
static bool requestsTrajectories(const SUMOVehicle &v)
Encounter(const MSVehicle *_ego, const MSVehicle *const _foe, double _begin, double extraTime)
Constructor.
ENCOUNTER_TYPE_CROSSING_LEADER.
Definition: MSDevice_SSM.h:93
double getMaxSpeedOnLane() const
Returns the maximal speed for the vehicle on its current lane (including speed factor and deviation...
Definition: MSVehicle.h:571
EncounterType currentType
Definition: MSDevice_SSM.h:187
std::vector< double > DRACspan
All values for DRAC.
Definition: MSDevice_SSM.h:218
ENCOUNTER_TYPE_FOLLOWING_LEADER.
Definition: MSDevice_SSM.h:74
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
bool myComputeSGAP
Definition: MSDevice_SSM.h:633
bool isInternal() const
Definition: MSLane.cpp:1840
A road/street connecting two junctions.
Definition: MSEdge.h:75
bool isOnRoad() const
Returns the information whether the vehicle is on a road (is simulated)
Definition: MSVehicle.h:583
ENCOUNTER_TYPE_MERGING_FOLLOWER.
Definition: MSDevice_SSM.h:85
const MSCFModel & getCarFollowModel() const
Returns the vehicle&#39;s car following model definition.
Definition: MSVehicle.h:887
ENCOUNTER_TYPE_MERGING.
Definition: MSDevice_SSM.h:79
std::size_t size() const
Returns the number of trajectory points stored.
Definition: MSDevice_SSM.h:160
static bool getMeasuresAndThresholds(const SUMOVehicle &v, std::string deviceID, std::map< std::string, double > &thresholds)
ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA.
Definition: MSDevice_SSM.h:108
MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else 0.
Definition: MSLane.cpp:1968
bool knowsParameter(const std::string &key) const
Returns whether the parameter is known.
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
std::vector< double > myTGAPspan
All values for time gap.
Definition: MSDevice_SSM.h:658
#define DEFAULT_THRESHOLD_TGAP
Representation of a vehicle.
Definition: SUMOVehicle.h:60
static double computeDRAC(double gap, double followerSpeed, double leaderSpeed)
Computes the DRAC (deceleration to avoid a collision) for a lead/follow situation as defined...
void processEncounters(FoeInfoMap &foes, bool forceClose=false)
Finds encounters for which the foe vehicle has disappeared from range. remainingExtraTime is decrease...
#define DEFAULT_THRESHOLD_DRAC
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
bool myComputeTTC
Flags for switching on / off comutation of different SSMs, derived from myMeasures.
Definition: MSDevice_SSM.h:633
int gPrecisionGeo
Definition: StdDefs.cpp:28
A list of positions.
OutputDevice * myOutputFile
Output device.
Definition: MSDevice_SSM.h:668
ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA.
Definition: MSDevice_SSM.h:104
void resetEncounters()
Closes all current Encounters and moves conflicts to myPastConflicts,.
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
Definition: MSVehicle.cpp:4379
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:309
double getRemainingExtraTime() const
returns the remaining extra time
double myRange
Detection range. For vehicles closer than this distance from the ego vehicle, SSMs are traced...
Definition: MSDevice_SSM.h:627
std::vector< double > egoDistsToConflict
Evolution of the ego vehicle&#39;s distance to the conflict point.
Definition: MSDevice_SSM.h:206
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
ENCOUNTER_TYPE_FOLLOWING_FOLLOWER.
Definition: MSDevice_SSM.h:72
ENCOUNTER_TYPE_NOCONFLICT_AHEAD.
Definition: MSDevice_SSM.h:67
#define DEFAULT_EXTRA_TIME
static void getUpstreamVehicles(const MSEdge *edge, double pos, double range, double egoDistToConflictLane, const MSLane *const egoConflictLane, FoeInfoMap &foeCollector, std::set< const MSJunction *> seenJunctions)
Collects all vehicles within range &#39;range&#39; upstream of the position &#39;pos&#39; on the edge &#39;edge&#39; into foe...
bool notifyEnter(SUMOVehicle &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Called whenever the holder enteres a lane.
void computeSSMs(EncounterApproachInfo &e) const
Compute current values of the logged SSMs (myMeasures) for the given encounter &#39;e&#39; and update &#39;e&#39; acc...
const ConstMSEdgeVector & getIncoming() const
Definition: MSJunction.h:101
bool qualifiesAsConflict(Encounter *e)
Tests if the SSM values exceed the threshold for qualification as conflict.
T MIN2(T a, T b)
Definition: StdDefs.h:62
static void checkConflictEntryAndExit(EncounterApproachInfo &eInfo)
Checks whether ego or foe have entered or left the conflict area in the last step and eventually writ...
ENCOUNTER_TYPE_MERGING_LEADER.
Definition: MSDevice_SSM.h:82
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc)
Adds common command options that allow to assign devices to vehicles.
Definition: MSDevice.cpp:112
std::ostream & operator<<(std::ostream &out, MSDevice_SSM::EncounterType type)
Nicer output for EncounterType enum.
std::pair< std::pair< std::pair< double, Position >, double >, std::string > myMinTGAP
Definition: MSDevice_SSM.h:663
ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA.
Definition: MSDevice_SSM.h:100
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
virtual bool isOnRoad() const =0
Returns the information whether the vehicle is on a road (is simulated)
void updateAndWriteOutput()
This is called once per time step in MSNet::writeOutput() and collects the surrounding vehicles...
ConflictPointInfo PET
Definition: MSDevice_SSM.h:228
void flushGlobalMeasures()
Write out all non-encounter specific measures as headways and braking rates.
static const std::set< MSDevice_SSM * > & getInstances()
returns all currently existing SSM devices
const MSLane * findFoeConflictLane(const MSVehicle *foe, const MSLane *egoConflictLane, double &distToConflictLane) const
Computes the conflict lane for the foe.
EncounterType type
Type of the conflict.
Definition: MSDevice_SSM.h:141
double myOldestActiveEncounterBegin
begin time of the oldest active encounter
Definition: MSDevice_SSM.h:643
bool isInternal() const
return whether this edge is an internal edge
Definition: MSEdge.h:224
virtual const std::vector< MSLane * > getInternalLanes() const
Returns all internal lanes on the junction.
Definition: MSJunction.h:113
ENCOUNTER_TYPE_FOLLOWING.
Definition: MSDevice_SSM.h:70
bool mySaveTrajectories
This determines whether the whole trajectories of the vehicles (position, speed, ssms) shall be saved...
Definition: MSDevice_SSM.h:625
const SUMOVTypeParameter & getParameter() const
static std::string getOutputFilename(const SUMOVehicle &v, std::string deviceID)
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::vector< MSVehicle * > VehCont
Container for vehicles.
Definition: MSLane.h:83
const MSVehicle * ego
Definition: MSDevice_SSM.h:182
static double getExtraTime(const SUMOVehicle &v)
void flushConflicts(bool all=false)
Writes out all past conflicts that have begun earlier than the oldest active encounter.
static std::string makeStringWithNAs(std::vector< double > v, double NA, std::string sep=" ")
make a string of a double vector and treat a special value as invalid ("NA")
double getLateralPositionOnLane() const
Get the vehicle&#39;s lateral position on the lane.
Definition: MSVehicle.h:436
std::vector< double > foeDistsToConflict
Evolution of the foe vehicle&#39;s distance to the conflict point.
Definition: MSDevice_SSM.h:208
bool closingRequested
this flag is set by updateEncounter() or directly in processEncounters(), where encounters are closed...
Definition: MSDevice_SSM.h:232
std::vector< std::string > getVector()
#define DEFAULT_THRESHOLD_SGAP
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:248
Abstract in-vehicle device.
Definition: MSDevice.h:65
bool myComputeDRAC
Definition: MSDevice_SSM.h:633
ENCOUNTER_TYPE_FOLLOWING_PASSED.
Definition: MSDevice_SSM.h:113
static double passingTime(const double lastPos, const double passedPos, const double currentPos, const double lastSpeed, const double currentSpeed)
Calculates the time at which the position passedPosition has been passed In case of a ballistic updat...
Definition: MSCFModel.cpp:591
std::vector< Encounter * > EncounterVector
Definition: MSDevice_SSM.h:285
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
static bool useGeoCoords(const SUMOVehicle &v)
void countDownExtraTime(double amount)
decreases myRemaingExtraTime by given amount in seconds
bool myComputeTGAP
Definition: MSDevice_SSM.h:633
double foeConflictEntryTime
Times when the foe vehicle entered/left the conflict area. Currently only applies for crossing situat...
Definition: MSDevice_SSM.h:195
const MSVehicleType & getVehicleType() const
Returns the vehicle&#39;s type definition.
#define M_PI
Definition: odrSpiral.cpp:40
std::map< const MSVehicle *, FoeInfo * > FoeInfoMap
Definition: MSDevice_SSM.h:286
const MSLane * egoConflictLane
Definition: MSDevice_SSM.h:273
Trajectory egoTrajectory
Trajectory of the ego vehicle.
Definition: MSDevice_SSM.h:202
const MSLane * getFirstInternalInConnection(double &offset) const
Returns 0 if the lane is not internal. Otherwise the first part of the connection (sequence of intern...
Definition: MSLane.cpp:1678
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle&#39;s parameter (including departure definition)
~MSDevice_SSM()
Destructor.
const MSJunction * getFromJunction() const
Definition: MSEdge.h:342
static double estimateArrivalTime(double dist, double speed, double maxSpeed, double accel)
Computes the time needed to travel a distance dist given an initial speed and constant acceleration...
Definition: MSCFModel.cpp:383
void computeGlobalMeasures()
Stores measures, that are not associated to a specific encounter as headways and brake rates...
double getAcceleration() const
Returns the vehicle&#39;s acceleration in m/s (this is computed as the last step&#39;s mean acceleration in c...
Definition: MSVehicle.h:496
Structure to collect some info on the encounter needed during ssm calculation by various functions...
Definition: MSDevice_SSM.h:244
std::vector< double > timeSpan
time points corresponding to the trajectories
Definition: MSDevice_SSM.h:198
A storage for options typed value containers)
Definition: OptionsCont.h:92
static double _2double(const E *const data)
converts a char-type array into the double value described by it
Definition: TplConvert.h:305
const std::string getParameter(const std::string &key, const std::string &defaultValue="") const
Returns the value for a given key.
double getInternalFollowingLengthTo(const MSEdge *followerAfterInternal) const
returns the length of all internal edges on the junction until reaching the non-internal edge followe...
Definition: MSEdge.cpp:672
ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA.
Definition: MSDevice_SSM.h:102
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
std::pair< double, double > pet
Definition: MSDevice_SSM.h:263
double getLength() const
Get vehicle&#39;s length [m].
std::map< std::string, double > myThresholds
Definition: MSDevice_SSM.h:622
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, SUMOVehicle &v, bool outputOptionSet)
Determines whether a vehicle should get a certain device.
Definition: MSDevice.cpp:126
std::pair< std::pair< std::pair< double, Position >, double >, std::string > myMinSGAP
Definition: MSDevice_SSM.h:662
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle&#39;s position relative to the given lane.
Definition: MSVehicle.cpp:3445
double getLastStepDist() const
Get the distance the vehicle covered in the previous timestep.
Definition: MSVehicle.h:406
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
An encounter is an episode involving two vehicles, which are closer to each other than some specified...
Definition: MSDevice_SSM.h:121
#define DEFAULT_THRESHOLD_TTC
double myExtraTime
Extra time in seconds to be logged after a conflict is over.
Definition: MSDevice_SSM.h:629
std::vector< int > typeSpan
Evolution of the encounter classification (.
Definition: MSDevice_SSM.h:200
double remainingExtraTime
Remaining extra time (decreases after an encounter ended)
Definition: MSDevice_SSM.h:190
ENCOUNTER_TYPE_ON_ADJACENT_LANES.
Definition: MSDevice_SSM.h:76
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
const MSLinkCont & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.cpp:1940
static void estimateConflictTimes(EncounterApproachInfo &eInfo)
Estimates the time until conflict for the vehicles based on the distance to the conflict entry points...
double getSpeed() const
Returns the vehicle&#39;s current speed.
Definition: MSVehicle.h:479
void writeOutConflict(Encounter *e)
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
virtual void releaseVehicles() const
Allows to use the container for microsimulation again.
Definition: MSLane.h:429
bool notifyMove(SUMOVehicle &veh, double oldPos, double newPos, double newSpeed)
Checks for waiting steps when the vehicle moves.
const std::string & getID() const
Returns the name of the vehicle.
static std::set< std::string > createdOutputFiles
remember which files were created already (don&#39;t duplicate xml root-elements)
Definition: MSDevice_SSM.h:671
static double fn[10]
Definition: odrSpiral.cpp:82
static bool gUseMesoSim
Definition: MSGlobals.h:91
Representation of a lane in the micro simulation.
Definition: MSLane.h:71
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:230
EncounterQueue myPastConflicts
Past encounters that where qualified as conflicts and are not yet flushed to the output file...
Definition: MSDevice_SSM.h:645
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
double value
value of the corresponding SSM
Definition: MSDevice_SSM.h:143
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSDevice *> &into)
Build devices for the given vehicle, if needed.
double getWidth() const
Returns the vehicle&#39;s width.
Trajectory foeTrajectory
Trajectory of the foe vehicle.
Definition: MSDevice_SSM.h:204
static void findSurroundingVehicles(const MSVehicle &veh, double range, FoeInfoMap &foeCollector)
Returns all vehicles, which are within the given range of the given vehicle.
virtual const MSVehicleType & getVehicleType() const =0
Returns the vehicle&#39;s type.
std::priority_queue< Encounter *, std::vector< Encounter * >, Encounter::compare > EncounterQueue
Definition: MSDevice_SSM.h:284
void add(double time, EncounterType type, Position egoX, Position egoV, Position foeX, Position foeV, Position conflictPoint, double egoDistToConflict, double foeDistToConflict, double ttc, double drac, std::pair< double, double > pet)
add a new data point and update encounter type