Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/libsumo/Helper.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2017-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file Helper.cpp
15
/// @author Laura Bieker-Walz
16
/// @author Robert Hilbrich
17
/// @author Leonhard Luecken
18
/// @date 15.09.2017
19
///
20
// C++ TraCI client API implementation
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <cstring>
25
#include <utils/geom/GeomHelper.h>
26
#include <utils/geom/GeoConvHelper.h>
27
#include <microsim/MSNet.h>
28
#include <microsim/MSVehicleControl.h>
29
#include <microsim/MSEdgeControl.h>
30
#include <microsim/MSInsertionControl.h>
31
#include <microsim/MSEdge.h>
32
#include <microsim/MSLane.h>
33
#include <microsim/MSLink.h>
34
#include <microsim/MSStoppingPlace.h>
35
#include <microsim/MSVehicle.h>
36
#include <microsim/output/MSE3Collector.h>
37
#include <microsim/transportables/MSTransportable.h>
38
#include <microsim/transportables/MSTransportableControl.h>
39
#include <microsim/transportables/MSPerson.h>
40
#include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
41
#include <libsumo/StorageHelper.h>
42
#include <libsumo/TraCIDefs.h>
43
#include <libsumo/BusStop.h>
44
#include <libsumo/Calibrator.h>
45
#include <libsumo/ChargingStation.h>
46
#include <libsumo/Edge.h>
47
#ifdef HAVE_LIBSUMOGUI
48
#include <libsumo/GUI.h>
49
#endif
50
#include <libsumo/InductionLoop.h>
51
#include <libsumo/Junction.h>
52
#include <libsumo/Lane.h>
53
#include <libsumo/LaneArea.h>
54
#include <libsumo/MeanData.h>
55
#include <libsumo/MultiEntryExit.h>
56
#include <libsumo/OverheadWire.h>
57
#include <libsumo/ParkingArea.h>
58
#include <libsumo/Person.h>
59
#include <libsumo/POI.h>
60
#include <libsumo/Polygon.h>
61
#include <libsumo/Rerouter.h>
62
#include <libsumo/Route.h>
63
#include <libsumo/RouteProbe.h>
64
#include <libsumo/Simulation.h>
65
#include <libsumo/TrafficLight.h>
66
#include <libsumo/VariableSpeedSign.h>
67
#include <libsumo/Vehicle.h>
68
#include <libsumo/VehicleType.h>
69
#include <libsumo/TraCIConstants.h>
70
#include "Helper.h"
71
72
#define FAR_AWAY 1000.0
73
74
//#define DEBUG_MOVEXY
75
//#define DEBUG_MOVEXY_ANGLE
76
//#define DEBUG_SURROUNDING
77
78
namespace libsumo {
79
// ===========================================================================
80
// static member initializations
81
// ===========================================================================
82
std::vector<Subscription> Helper::mySubscriptions;
83
Subscription* Helper::myLastContextSubscription = nullptr;
84
std::map<int, std::shared_ptr<VariableWrapper> > Helper::myWrapper;
85
Helper::VehicleStateListener Helper::myVehicleStateListener;
86
Helper::TransportableStateListener Helper::myTransportableStateListener;
87
LANE_RTREE_QUAL* Helper::myLaneTree;
88
std::map<std::string, MSVehicle*> Helper::myRemoteControlledVehicles;
89
std::map<std::string, MSPerson*> Helper::myRemoteControlledPersons;
90
91
92
// ===========================================================================
93
// static member definitions
94
// ===========================================================================
95
96
void
97
Helper::debugPrint(const SUMOTrafficObject* veh) {
98
if (veh != nullptr) {
99
if (veh->isVehicle()) {
100
std::cout << " '" << veh->getID() << "' on lane '" << ((SUMOVehicle*)veh)->getLane()->getID() << "'\n";
101
} else {
102
std::cout << " '" << veh->getID() << "' on edge '" << veh->getEdge()->getID() << "'\n";
103
}
104
}
105
}
106
107
108
void
109
Helper::subscribe(const int commandId, const std::string& id, const std::vector<int>& variables,
110
const double beginTime, const double endTime, const libsumo::TraCIResults& params,
111
const int contextDomain, const double range) {
112
myLastContextSubscription = nullptr;
113
if (variables.empty()) {
114
for (std::vector<libsumo::Subscription>::iterator j = mySubscriptions.begin(); j != mySubscriptions.end();) {
115
if (j->id == id && j->commandId == commandId && j->contextDomain == contextDomain) {
116
j = mySubscriptions.erase(j);
117
} else {
118
++j;
119
}
120
}
121
return;
122
}
123
std::vector<std::shared_ptr<tcpip::Storage> > parameters;
124
for (const int var : variables) {
125
const auto& p = params.find(var);
126
if (p == params.end()) {
127
parameters.push_back(std::make_shared<tcpip::Storage>());
128
} else {
129
parameters.push_back(libsumo::StorageHelper::toStorage(*p->second));
130
}
131
}
132
const SUMOTime begin = beginTime == INVALID_DOUBLE_VALUE ? 0 : TIME2STEPS(beginTime);
133
const SUMOTime end = endTime == INVALID_DOUBLE_VALUE || endTime > STEPS2TIME(SUMOTime_MAX) ? SUMOTime_MAX : TIME2STEPS(endTime);
134
libsumo::Subscription s(commandId, id, variables, parameters, begin, end, contextDomain, range);
135
if (commandId == libsumo::CMD_SUBSCRIBE_SIM_CONTEXT) {
136
s.range = std::numeric_limits<double>::max();
137
}
138
if (s.variables.size() == 1 && s.variables.front() == -1) {
139
if (contextDomain == 0) {
140
if (commandId == libsumo::CMD_SUBSCRIBE_VEHICLE_VARIABLE) {
141
// default for vehicles is edge id and lane position
142
s.variables = {libsumo::VAR_ROAD_ID, libsumo::VAR_LANEPOSITION};
143
s.parameters.push_back(std::make_shared<tcpip::Storage>());
144
} else if (commandId == libsumo::CMD_SUBSCRIBE_EDGE_VARIABLE ||
145
commandId == libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_VARIABLE ||
146
commandId == libsumo::CMD_SUBSCRIBE_LANE_VARIABLE ||
147
commandId == libsumo::CMD_SUBSCRIBE_LANEAREA_VARIABLE ||
148
commandId == libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_VARIABLE) {
149
// default for detectors, edges and lanes is vehicle number
150
s.variables[0] = libsumo::LAST_STEP_VEHICLE_NUMBER;
151
} else {
152
// for all others id list
153
s.variables[0] = libsumo::TRACI_ID_LIST;
154
}
155
} else {
156
s.variables.clear();
157
s.parameters.clear();
158
}
159
}
160
handleSingleSubscription(s);
161
libsumo::Subscription* modifiedSubscription = nullptr;
162
needNewSubscription(s, mySubscriptions, modifiedSubscription);
163
if (modifiedSubscription->isVehicleToVehicleContextSubscription()
164
|| modifiedSubscription->isVehicleToPersonContextSubscription()) {
165
// Set last modified vehicle context subscription active for filter modifications
166
myLastContextSubscription = modifiedSubscription;
167
}
168
}
169
170
171
void
172
Helper::handleSubscriptions(const SUMOTime t) {
173
for (auto& wrapper : myWrapper) {
174
wrapper.second->clear();
175
}
176
for (std::vector<libsumo::Subscription>::iterator i = mySubscriptions.begin(); i != mySubscriptions.end();) {
177
const libsumo::Subscription& s = *i;
178
const bool isArrivedVehicle = (s.commandId == CMD_SUBSCRIBE_VEHICLE_VARIABLE || s.commandId == CMD_SUBSCRIBE_VEHICLE_CONTEXT)
179
&& (find(getVehicleStateChanges(MSNet::VehicleState::ARRIVED).begin(), getVehicleStateChanges(MSNet::VehicleState::ARRIVED).end(), s.id) != getVehicleStateChanges(MSNet::VehicleState::ARRIVED).end());
180
const bool isArrivedPerson = (s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_VARIABLE || s.commandId == libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT)
181
&& MSNet::getInstance()->getPersonControl().get(s.id) == nullptr;
182
if (s.endTime < t || isArrivedVehicle || isArrivedPerson) {
183
i = mySubscriptions.erase(i);
184
continue;
185
}
186
++i;
187
}
188
for (const libsumo::Subscription& s : mySubscriptions) {
189
if (s.beginTime <= t) {
190
handleSingleSubscription(s);
191
}
192
}
193
}
194
195
196
bool
197
Helper::needNewSubscription(libsumo::Subscription& s, std::vector<Subscription>& subscriptions, libsumo::Subscription*& modifiedSubscription) {
198
for (libsumo::Subscription& o : subscriptions) {
199
if (s.commandId == o.commandId && s.id == o.id &&
200
s.beginTime == o.beginTime && s.endTime == o.endTime &&
201
s.contextDomain == o.contextDomain && s.range == o.range) {
202
std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
203
for (const int v : s.variables) {
204
const int offset = (int)(std::find(o.variables.begin(), o.variables.end(), v) - o.variables.begin());
205
if (offset == (int)o.variables.size() || o.parameters[offset]->size() != (*k)->size() || !std::equal((*k)->begin(), (*k)->end(), o.parameters[offset]->begin())) {
206
o.variables.push_back(v);
207
o.parameters.push_back(*k);
208
}
209
++k;
210
}
211
modifiedSubscription = &o;
212
return false;
213
}
214
}
215
subscriptions.push_back(s);
216
modifiedSubscription = &subscriptions.back();
217
return true;
218
}
219
220
221
void
222
Helper::clearSubscriptions() {
223
mySubscriptions.clear();
224
myLastContextSubscription = nullptr;
225
}
226
227
228
Subscription*
229
Helper::addSubscriptionFilter(SubscriptionFilterType filter) {
230
if (myLastContextSubscription != nullptr) {
231
myLastContextSubscription->activeFilters |= filter;
232
} else {
233
// The following code relies on the fact that the filter is 2^(filterType-1),
234
// see Subscription.h and the corresponding TraCIConstants.h.
235
// It is only for getting similar error messages with libsumo and traci.
236
int index = (int)filter;
237
int filterType = 0;
238
if (index != 0) {
239
++filterType;
240
while (index >>= 1) {
241
++filterType;
242
}
243
}
244
throw TraCIException("No previous vehicle context subscription exists to apply filter type " + toHex(filterType, 2));
245
}
246
return myLastContextSubscription;
247
}
248
249
250
void
251
Helper::handleSingleSubscription(const Subscription& s) {
252
const int getCommandId = s.contextDomain > 0 ? s.contextDomain : s.commandId - 0x30;
253
std::set<std::string> objIDs;
254
if (s.contextDomain > 0) {
255
if ((s.activeFilters & SUBS_FILTER_NO_RTREE) == 0) {
256
PositionVector shape;
257
findObjectShape(s.commandId, s.id, shape);
258
collectObjectIDsInRange(s.contextDomain, shape, s.range, objIDs);
259
}
260
applySubscriptionFilters(s, objIDs);
261
} else {
262
objIDs.insert(s.id);
263
}
264
if (myWrapper.empty()) {
265
myWrapper[libsumo::CMD_GET_BUSSTOP_VARIABLE] = BusStop::makeWrapper();
266
myWrapper[libsumo::CMD_GET_CALIBRATOR_VARIABLE] = Calibrator::makeWrapper();
267
myWrapper[libsumo::CMD_GET_CHARGINGSTATION_VARIABLE] = ChargingStation::makeWrapper();
268
myWrapper[libsumo::CMD_GET_EDGE_VARIABLE] = Edge::makeWrapper();
269
#ifdef HAVE_LIBSUMOGUI
270
myWrapper[libsumo::CMD_GET_GUI_VARIABLE] = GUI::makeWrapper();
271
#endif
272
myWrapper[libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE] = InductionLoop::makeWrapper();
273
myWrapper[libsumo::CMD_GET_JUNCTION_VARIABLE] = Junction::makeWrapper();
274
myWrapper[libsumo::CMD_GET_LANE_VARIABLE] = Lane::makeWrapper();
275
myWrapper[libsumo::CMD_GET_LANEAREA_VARIABLE] = LaneArea::makeWrapper();
276
myWrapper[libsumo::CMD_GET_MEANDATA_VARIABLE] = MeanData::makeWrapper();
277
myWrapper[libsumo::CMD_GET_MULTIENTRYEXIT_VARIABLE] = MultiEntryExit::makeWrapper();
278
myWrapper[libsumo::CMD_GET_OVERHEADWIRE_VARIABLE] = OverheadWire::makeWrapper();
279
myWrapper[libsumo::CMD_GET_PARKINGAREA_VARIABLE] = ParkingArea::makeWrapper();
280
myWrapper[libsumo::CMD_GET_PERSON_VARIABLE] = Person::makeWrapper();
281
myWrapper[libsumo::CMD_GET_POI_VARIABLE] = POI::makeWrapper();
282
myWrapper[libsumo::CMD_GET_POLYGON_VARIABLE] = Polygon::makeWrapper();
283
myWrapper[libsumo::CMD_GET_REROUTER_VARIABLE] = Rerouter::makeWrapper();
284
myWrapper[libsumo::CMD_GET_ROUTE_VARIABLE] = Route::makeWrapper();
285
myWrapper[libsumo::CMD_GET_ROUTEPROBE_VARIABLE] = RouteProbe::makeWrapper();
286
myWrapper[libsumo::CMD_GET_SIM_VARIABLE] = Simulation::makeWrapper();
287
myWrapper[libsumo::CMD_GET_TL_VARIABLE] = TrafficLight::makeWrapper();
288
myWrapper[libsumo::CMD_GET_VARIABLESPEEDSIGN_VARIABLE] = VariableSpeedSign::makeWrapper();
289
myWrapper[libsumo::CMD_GET_VEHICLE_VARIABLE] = Vehicle::makeWrapper();
290
myWrapper[libsumo::CMD_GET_VEHICLETYPE_VARIABLE] = VehicleType::makeWrapper();
291
}
292
auto wrapper = myWrapper.find(getCommandId);
293
if (wrapper == myWrapper.end()) {
294
throw TraCIException("Unsupported command " + toHex(getCommandId, 2) + " specified");
295
}
296
std::shared_ptr<VariableWrapper> handler = wrapper->second;
297
VariableWrapper* container = handler.get();
298
if (s.contextDomain > 0) {
299
auto containerWrapper = myWrapper.find(s.commandId + 0x20);
300
if (containerWrapper == myWrapper.end()) {
301
throw TraCIException("Unsupported domain " + toHex(s.commandId + 0x20, 2) + " specified");
302
}
303
container = containerWrapper->second.get();
304
container->setContext(&s.id);
305
} else {
306
container->setContext(nullptr);
307
}
308
for (const std::string& objID : objIDs) {
309
if (!s.variables.empty()) {
310
std::vector<std::shared_ptr<tcpip::Storage> >::const_iterator k = s.parameters.begin();
311
for (const int variable : s.variables) {
312
if (s.contextDomain > 0 && variable == libsumo::TRACI_ID_LIST) {
313
container->empty(objID);
314
} else {
315
(*k)->resetPos();
316
try {
317
if (!handler->handle(objID, variable, container, k->get())) {
318
throw TraCIException("Unsupported variable " + toHex(variable, 2) + " specified");
319
}
320
} catch (const std::invalid_argument&) {
321
throw TraCIException("Unsupported variable " + toHex(variable, 2) + " specified");
322
}
323
++k;
324
}
325
}
326
} else if (s.contextDomain > 0) {
327
// default for contexts is an empty map (similar to id list)
328
container->empty(objID);
329
}
330
}
331
}
332
333
334
void
335
Helper::fuseLaneCoverage(std::shared_ptr<LaneCoverageInfo> aggregatedLaneCoverage, const std::shared_ptr<LaneCoverageInfo> newLaneCoverage) {
336
for (auto& p : *newLaneCoverage) {
337
const MSLane* lane = p.first;
338
if (aggregatedLaneCoverage->find(lane) == aggregatedLaneCoverage->end()) {
339
// Lane has no coverage in aggregatedLaneCoverage, yet
340
(*aggregatedLaneCoverage)[lane] = (*newLaneCoverage)[lane];
341
} else {
342
// Lane is covered in aggregatedLaneCoverage as well
343
std::pair<double, double>& range1 = (*aggregatedLaneCoverage)[lane];
344
std::pair<double, double>& range2 = (*newLaneCoverage)[lane];
345
std::pair<double, double> hull = std::make_pair(MIN2(range1.first, range2.first), MAX2(range1.second, range2.second));
346
(*aggregatedLaneCoverage)[lane] = hull;
347
}
348
}
349
}
350
351
352
TraCIPositionVector
353
Helper::makeTraCIPositionVector(const PositionVector& positionVector) {
354
TraCIPositionVector tp;
355
for (int i = 0; i < (int)positionVector.size(); ++i) {
356
tp.value.push_back(makeTraCIPosition(positionVector[i]));
357
}
358
return tp;
359
}
360
361
362
PositionVector
363
Helper::makePositionVector(const TraCIPositionVector& vector) {
364
PositionVector pv;
365
for (const TraCIPosition& pos : vector.value) {
366
if (std::isnan(pos.x) || std::isnan(pos.y)) {
367
throw libsumo::TraCIException("NaN-Value in shape.");
368
}
369
pv.push_back(Position(pos.x, pos.y));
370
}
371
return pv;
372
}
373
374
375
TraCIColor
376
Helper::makeTraCIColor(const RGBColor& color) {
377
TraCIColor tc;
378
tc.a = color.alpha();
379
tc.b = color.blue();
380
tc.g = color.green();
381
tc.r = color.red();
382
return tc;
383
}
384
385
386
RGBColor
387
Helper::makeRGBColor(const TraCIColor& c) {
388
return RGBColor((unsigned char)c.r, (unsigned char)c.g, (unsigned char)c.b, (unsigned char)c.a);
389
}
390
391
392
TraCIPosition
393
Helper::makeTraCIPosition(const Position& position, const bool includeZ) {
394
TraCIPosition p;
395
p.x = position.x();
396
p.y = position.y();
397
p.z = includeZ ? position.z() : INVALID_DOUBLE_VALUE;
398
return p;
399
}
400
401
402
Position
403
Helper::makePosition(const TraCIPosition& tpos) {
404
return Position(tpos.x, tpos.y, tpos.z);
405
}
406
407
408
MSEdge*
409
Helper::getEdge(const std::string& edgeID) {
410
MSEdge* edge = MSEdge::dictionary(edgeID);
411
if (edge == nullptr) {
412
throw TraCIException("Referenced edge '" + edgeID + "' is not known.");
413
}
414
return edge;
415
}
416
417
418
const MSLane*
419
Helper::getLaneChecking(const std::string& edgeID, int laneIndex, double pos) {
420
const MSEdge* edge = MSEdge::dictionary(edgeID);
421
if (edge == nullptr) {
422
throw TraCIException("Unknown edge " + edgeID);
423
}
424
if (laneIndex < 0 || laneIndex >= (int)edge->getLanes().size()) {
425
throw TraCIException("Invalid lane index for " + edgeID);
426
}
427
const MSLane* lane = edge->getLanes()[laneIndex];
428
if (pos < 0 || pos > lane->getLength()) {
429
throw TraCIException("Position on lane invalid");
430
}
431
return lane;
432
}
433
434
435
std::pair<MSLane*, double>
436
Helper::convertCartesianToRoadMap(const Position& pos, const SUMOVehicleClass vClass) {
437
const PositionVector shape({ pos });
438
std::pair<MSLane*, double> result(nullptr, -1);
439
double range = 1000.;
440
const Boundary& netBounds = GeoConvHelper::getFinal().getConvBoundary();
441
const double maxRange = MAX2(1001., netBounds.getWidth() + netBounds.getHeight() + netBounds.distanceTo2D(pos));
442
while (range < maxRange) {
443
std::set<const Named*> lanes;
444
collectObjectsInRange(libsumo::CMD_GET_LANE_VARIABLE, shape, range, lanes);
445
double minDistance = std::numeric_limits<double>::max();
446
for (const Named* named : lanes) {
447
MSLane* lane = const_cast<MSLane*>(dynamic_cast<const MSLane*>(named));
448
if (lane->allowsVehicleClass(vClass)) {
449
// @todo this may be a place where 3D is required but 2D is used
450
double newDistance = lane->getShape().distance2D(pos);
451
newDistance = patchShapeDistance(lane, pos, newDistance, false);
452
if (newDistance < minDistance ||
453
(newDistance == minDistance
454
&& result.first != nullptr
455
&& lane->getID() < result.first->getID())) {
456
minDistance = newDistance;
457
result.first = lane;
458
}
459
}
460
}
461
if (minDistance < std::numeric_limits<double>::max()) {
462
result.second = result.first->interpolateGeometryPosToLanePos(result.first->getShape().nearest_offset_to_point2D(pos, false));
463
break;
464
}
465
range *= 2;
466
}
467
return result;
468
}
469
470
471
double
472
Helper::getDrivingDistance(std::pair<const MSLane*, double>& roadPos1, std::pair<const MSLane*, double>& roadPos2) {
473
if (roadPos1.first == roadPos2.first && roadPos1.second <= roadPos2.second) {
474
// same edge
475
return roadPos2.second - roadPos1.second;
476
}
477
double distance = 0.0;
478
ConstMSEdgeVector newRoute;
479
while (roadPos2.first->isInternal() && roadPos2.first != roadPos1.first) {
480
distance += roadPos2.second;
481
roadPos2.first = roadPos2.first->getLogicalPredecessorLane();
482
roadPos2.second = roadPos2.first->getLength();
483
}
484
MSNet::getInstance()->getRouterTT(0).compute(&roadPos1.first->getEdge(), &roadPos2.first->getEdge(), nullptr, SIMSTEP, newRoute, true);
485
if (newRoute.empty()) {
486
return libsumo::INVALID_DOUBLE_VALUE;
487
}
488
MSRoute route("", newRoute, false, nullptr, StopParVector());
489
return distance + route.getDistanceBetween(roadPos1.second, roadPos2.second, roadPos1.first, roadPos2.first);
490
}
491
492
493
MSBaseVehicle*
494
Helper::getVehicle(const std::string& id) {
495
SUMOVehicle* sumoVehicle = MSNet::getInstance()->getVehicleControl().getVehicle(id);
496
if (sumoVehicle == nullptr) {
497
throw TraCIException("Vehicle '" + id + "' is not known.");
498
}
499
MSBaseVehicle* v = dynamic_cast<MSBaseVehicle*>(sumoVehicle);
500
if (v == nullptr) {
501
throw TraCIException("Vehicle '" + id + "' is not a proper vehicle.");
502
}
503
return v;
504
}
505
506
507
MSPerson*
508
Helper::getPerson(const std::string& personID) {
509
MSTransportableControl& c = MSNet::getInstance()->getPersonControl();
510
MSPerson* p = dynamic_cast<MSPerson*>(c.get(personID));
511
if (p == nullptr) {
512
throw TraCIException("Person '" + personID + "' is not known");
513
}
514
return p;
515
}
516
517
SUMOTrafficObject*
518
Helper::getTrafficObject(int domain, const std::string& id) {
519
if (domain == CMD_GET_VEHICLE_VARIABLE) {
520
return getVehicle(id);
521
} else if (domain == CMD_GET_PERSON_VARIABLE) {
522
return getPerson(id);
523
} else {
524
throw TraCIException("Cannot retrieve traffic object for domain " + toString(domain));
525
}
526
}
527
528
const MSVehicleType&
529
Helper::getVehicleType(const std::string& vehicleID) {
530
return getVehicle(vehicleID)->getVehicleType();
531
}
532
533
534
MSTLLogicControl::TLSLogicVariants&
535
Helper::getTLS(const std::string& id) {
536
if (!MSNet::getInstance()->getTLSControl().knows(id)) {
537
throw TraCIException("Traffic light '" + id + "' is not known");
538
}
539
return MSNet::getInstance()->getTLSControl().get(id);
540
}
541
542
543
MSStoppingPlace*
544
Helper::getStoppingPlace(const std::string& id, const SumoXMLTag type) {
545
MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(id, type);
546
if (s == nullptr) {
547
throw TraCIException(toString(type) + " '" + id + "' is not known");
548
}
549
return s;
550
}
551
552
553
SUMOVehicleParameter::Stop
554
Helper::buildStopParameters(const std::string& edgeOrStoppingPlaceID,
555
double pos, int laneIndex, double startPos, int flags, double duration, double until) {
556
SUMOVehicleParameter::Stop newStop;
557
try {
558
checkTimeBounds(duration);
559
checkTimeBounds(until);
560
} catch (ProcessError&) {
561
throw TraCIException("Duration or until parameter exceed the time value range.");
562
}
563
newStop.duration = duration == INVALID_DOUBLE_VALUE ? SUMOTime_MAX : TIME2STEPS(duration);
564
newStop.until = until == INVALID_DOUBLE_VALUE ? -1 : TIME2STEPS(until);
565
newStop.index = STOP_INDEX_FIT;
566
if (newStop.duration >= 0) {
567
newStop.parametersSet |= STOP_DURATION_SET;
568
}
569
if (newStop.until >= 0) {
570
newStop.parametersSet |= STOP_UNTIL_SET;
571
}
572
if ((flags & 1) != 0) {
573
newStop.parking = ParkingType::OFFROAD;
574
newStop.parametersSet |= STOP_PARKING_SET;
575
}
576
if ((flags & 2) != 0) {
577
newStop.triggered = true;
578
newStop.parametersSet |= STOP_TRIGGER_SET;
579
}
580
if ((flags & 4) != 0) {
581
newStop.containerTriggered = true;
582
newStop.parametersSet |= STOP_CONTAINER_TRIGGER_SET;
583
}
584
585
SumoXMLTag stoppingPlaceType = SUMO_TAG_NOTHING;
586
if ((flags & 8) != 0) {
587
stoppingPlaceType = SUMO_TAG_BUS_STOP;
588
}
589
if ((flags & 16) != 0) {
590
stoppingPlaceType = SUMO_TAG_CONTAINER_STOP;
591
}
592
if ((flags & 32) != 0) {
593
stoppingPlaceType = SUMO_TAG_CHARGING_STATION;
594
}
595
if ((flags & 64) != 0) {
596
stoppingPlaceType = SUMO_TAG_PARKING_AREA;
597
}
598
if ((flags & 128) != 0) {
599
stoppingPlaceType = SUMO_TAG_OVERHEAD_WIRE_SEGMENT;
600
}
601
602
if (stoppingPlaceType != SUMO_TAG_NOTHING) {
603
MSStoppingPlace* bs = MSNet::getInstance()->getStoppingPlace(edgeOrStoppingPlaceID, stoppingPlaceType);
604
if (bs == nullptr) {
605
throw TraCIException("The " + toString(stoppingPlaceType) + " '" + edgeOrStoppingPlaceID + "' is not known");
606
}
607
newStop.lane = bs->getLane().getID();
608
newStop.edge = bs->getLane().getEdge().getID();
609
newStop.endPos = bs->getEndLanePosition();
610
newStop.startPos = bs->getBeginLanePosition();
611
switch (stoppingPlaceType) {
612
case SUMO_TAG_BUS_STOP:
613
newStop.busstop = edgeOrStoppingPlaceID;
614
break;
615
case SUMO_TAG_CONTAINER_STOP:
616
newStop.containerstop = edgeOrStoppingPlaceID;
617
break;
618
case SUMO_TAG_CHARGING_STATION:
619
newStop.chargingStation = edgeOrStoppingPlaceID;
620
break;
621
case SUMO_TAG_PARKING_AREA:
622
newStop.parkingarea = edgeOrStoppingPlaceID;
623
break;
624
case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
625
newStop.overheadWireSegment = edgeOrStoppingPlaceID;
626
break;
627
default:
628
throw TraCIException("Unknown stopping place type '" + toString(stoppingPlaceType) + "'.");
629
}
630
} else {
631
if (startPos == INVALID_DOUBLE_VALUE) {
632
startPos = MAX2(0.0, pos - POSITION_EPS);
633
}
634
if (startPos < 0.) {
635
throw TraCIException("Position on lane must not be negative.");
636
}
637
if (pos < startPos) {
638
throw TraCIException("End position on lane must be after start position.");
639
}
640
// get the actual lane that is referenced by laneIndex
641
MSEdge* road = MSEdge::dictionary(edgeOrStoppingPlaceID);
642
if (road == nullptr) {
643
throw TraCIException("Edge '" + edgeOrStoppingPlaceID + "' is not known.");
644
}
645
const std::vector<MSLane*>& allLanes = road->getLanes();
646
if ((laneIndex < 0) || laneIndex >= (int)(allLanes.size())) {
647
throw TraCIException("No lane with index '" + toString(laneIndex) + "' on edge '" + edgeOrStoppingPlaceID + "'.");
648
}
649
newStop.lane = allLanes[laneIndex]->getID();
650
newStop.edge = allLanes[laneIndex]->getEdge().getID();
651
newStop.endPos = pos;
652
newStop.startPos = startPos;
653
newStop.parametersSet |= STOP_START_SET | STOP_END_SET;
654
}
655
return newStop;
656
}
657
658
659
TraCINextStopData
660
Helper::buildStopData(const SUMOVehicleParameter::Stop& stopPar) {
661
std::string stoppingPlaceID = "";
662
if (stopPar.busstop != "") {
663
stoppingPlaceID = stopPar.busstop;
664
}
665
if (stopPar.containerstop != "") {
666
stoppingPlaceID = stopPar.containerstop;
667
}
668
if (stopPar.parkingarea != "") {
669
stoppingPlaceID = stopPar.parkingarea;
670
}
671
if (stopPar.chargingStation != "") {
672
stoppingPlaceID = stopPar.chargingStation;
673
}
674
if (stopPar.overheadWireSegment != "") {
675
stoppingPlaceID = stopPar.overheadWireSegment;
676
}
677
678
return TraCINextStopData(stopPar.lane,
679
stopPar.startPos,
680
stopPar.endPos,
681
stoppingPlaceID,
682
stopPar.getFlags(),
683
// negative duration is permitted to indicate that a vehicle cannot
684
// re-enter traffic after parking
685
stopPar.duration != -1 ? STEPS2TIME(stopPar.duration) : INVALID_DOUBLE_VALUE,
686
stopPar.until >= 0 ? STEPS2TIME(stopPar.until) : INVALID_DOUBLE_VALUE,
687
stopPar.arrival >= 0 ? STEPS2TIME(stopPar.arrival) : INVALID_DOUBLE_VALUE,
688
stopPar.started >= 0 ? STEPS2TIME(stopPar.started) : INVALID_DOUBLE_VALUE,
689
stopPar.ended >= 0 ? STEPS2TIME(stopPar.ended) : INVALID_DOUBLE_VALUE,
690
stopPar.split,
691
stopPar.join,
692
stopPar.actType,
693
stopPar.tripId,
694
stopPar.line,
695
stopPar.speed);
696
}
697
698
699
void
700
Helper::cleanup() {
701
// clean up NamedRTrees
702
InductionLoop::cleanup();
703
Junction::cleanup();
704
LaneArea::cleanup();
705
POI::cleanup();
706
Polygon::cleanup();
707
Helper::clearStateChanges();
708
Helper::clearSubscriptions();
709
delete myLaneTree;
710
myLaneTree = nullptr;
711
}
712
713
714
void
715
Helper::registerStateListener() {
716
if (MSNet::hasInstance()) {
717
MSNet::getInstance()->addVehicleStateListener(&myVehicleStateListener);
718
MSNet::getInstance()->addTransportableStateListener(&myTransportableStateListener);
719
}
720
}
721
722
723
const std::vector<std::string>&
724
Helper::getVehicleStateChanges(const MSNet::VehicleState state) {
725
return myVehicleStateListener.myVehicleStateChanges[state];
726
}
727
728
729
const std::vector<std::string>&
730
Helper::getTransportableStateChanges(const MSNet::TransportableState state) {
731
return myTransportableStateListener.myTransportableStateChanges[state];
732
}
733
734
735
void
736
Helper::clearStateChanges() {
737
for (auto& i : myVehicleStateListener.myVehicleStateChanges) {
738
i.second.clear();
739
}
740
for (auto& i : myTransportableStateListener.myTransportableStateChanges) {
741
i.second.clear();
742
}
743
}
744
745
746
MSCalibrator::AspiredState
747
Helper::getCalibratorState(const MSCalibrator* c) {
748
try {
749
return c->getCurrentStateInterval();
750
} catch (ProcessError& e) {
751
throw TraCIException(e.what());
752
}
753
}
754
755
756
void
757
Helper::findObjectShape(int domain, const std::string& id, PositionVector& shape) {
758
switch (domain) {
759
case libsumo::CMD_SUBSCRIBE_BUSSTOP_CONTEXT: {
760
MSStoppingPlace* const stop = getStoppingPlace(id, SUMO_TAG_BUS_STOP);
761
shape.push_back(stop->getLane().getShape().positionAtOffset(stop->getBeginLanePosition()));
762
shape.push_back(stop->getLane().getShape().positionAtOffset(stop->getEndLanePosition()));
763
break;
764
}
765
case libsumo::CMD_SUBSCRIBE_CALIBRATOR_CONTEXT: {
766
MSCalibrator* const calib = Calibrator::getCalibrator(id);
767
shape.push_back(calib->getLane()->getShape()[0]);
768
break;
769
}
770
case libsumo::CMD_SUBSCRIBE_CHARGINGSTATION_CONTEXT: {
771
MSStoppingPlace* const stop = getStoppingPlace(id, SUMO_TAG_CHARGING_STATION);
772
shape.push_back(stop->getLane().getShape().positionAtOffset(stop->getBeginLanePosition()));
773
shape.push_back(stop->getLane().getShape().positionAtOffset(stop->getEndLanePosition()));
774
break;
775
}
776
case libsumo::CMD_SUBSCRIBE_EDGE_CONTEXT:
777
Edge::storeShape(id, shape);
778
break;
779
case libsumo::CMD_SUBSCRIBE_INDUCTIONLOOP_CONTEXT:
780
InductionLoop::storeShape(id, shape);
781
break;
782
case libsumo::CMD_SUBSCRIBE_JUNCTION_CONTEXT:
783
Junction::storeShape(id, shape);
784
break;
785
case libsumo::CMD_SUBSCRIBE_LANE_CONTEXT:
786
Lane::storeShape(id, shape);
787
break;
788
case libsumo::CMD_SUBSCRIBE_LANEAREA_CONTEXT:
789
LaneArea::storeShape(id, shape);
790
break;
791
case libsumo::CMD_SUBSCRIBE_MULTIENTRYEXIT_CONTEXT: {
792
MSE3Collector* const det = MultiEntryExit::getDetector(id);
793
for (const MSCrossSection& cs : det->getEntries()) {
794
shape.push_back(cs.myLane->getShape().positionAtOffset(cs.myPosition));
795
}
796
for (const MSCrossSection& cs : det->getExits()) {
797
shape.push_back(cs.myLane->getShape().positionAtOffset(cs.myPosition));
798
}
799
break;
800
}
801
case libsumo::CMD_SUBSCRIBE_PARKINGAREA_CONTEXT: {
802
MSStoppingPlace* const stop = getStoppingPlace(id, SUMO_TAG_PARKING_AREA);
803
shape.push_back(stop->getLane().getShape().positionAtOffset(stop->getBeginLanePosition()));
804
shape.push_back(stop->getLane().getShape().positionAtOffset(stop->getEndLanePosition()));
805
break;
806
}
807
case libsumo::CMD_SUBSCRIBE_PERSON_CONTEXT:
808
Person::storeShape(id, shape);
809
break;
810
case libsumo::CMD_SUBSCRIBE_POI_CONTEXT:
811
POI::storeShape(id, shape);
812
break;
813
case libsumo::CMD_SUBSCRIBE_POLYGON_CONTEXT:
814
Polygon::storeShape(id, shape);
815
break;
816
case libsumo::CMD_SUBSCRIBE_VEHICLE_CONTEXT:
817
Vehicle::storeShape(id, shape);
818
break;
819
default:
820
Simulation::storeShape(shape);
821
break;
822
}
823
}
824
825
826
void
827
Helper::collectObjectIDsInRange(int domain, const PositionVector& shape, double range, std::set<std::string>& into) {
828
std::set<const Named*> objects;
829
collectObjectsInRange(domain, shape, range, objects);
830
for (const Named* obj : objects) {
831
into.insert(obj->getID());
832
}
833
}
834
835
836
void
837
Helper::collectObjectsInRange(int domain, const PositionVector& shape, double range, std::set<const Named*>& into) {
838
const Boundary b = shape.getBoxBoundary().grow(range);
839
const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
840
const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
841
switch (domain) {
842
case libsumo::CMD_GET_BUSSTOP_VARIABLE:
843
for (const auto& stop : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_BUS_STOP)) {
844
if (shape.distance2D(stop.second->getCenterPos()) <= range) {
845
into.insert(stop.second);
846
}
847
}
848
break;
849
case libsumo::CMD_GET_CHARGINGSTATION_VARIABLE:
850
for (const auto& stop : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_CHARGING_STATION)) {
851
if (shape.distance2D(stop.second->getCenterPos()) <= range) {
852
into.insert(stop.second);
853
}
854
}
855
break;
856
case libsumo::CMD_GET_CALIBRATOR_VARIABLE:
857
for (const auto& calib : MSCalibrator::getInstances()) {
858
if (shape.distance2D(calib.second->getLane()->getShape()[0]) <= range) {
859
into.insert(calib.second);
860
}
861
}
862
break;
863
case libsumo::CMD_GET_INDUCTIONLOOP_VARIABLE:
864
InductionLoop::getTree()->Search(cmin, cmax, Named::StoringVisitor(into));
865
break;
866
case libsumo::CMD_GET_JUNCTION_VARIABLE:
867
Junction::getTree()->Search(cmin, cmax, Named::StoringVisitor(into));
868
break;
869
case libsumo::CMD_GET_LANEAREA_VARIABLE:
870
LaneArea::getTree()->Search(cmin, cmax, Named::StoringVisitor(into));
871
break;
872
case libsumo::CMD_GET_PARKINGAREA_VARIABLE: {
873
for (const auto& stop : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_PARKING_AREA)) {
874
if (shape.distance2D(stop.second->getCenterPos()) <= range) {
875
into.insert(stop.second);
876
}
877
}
878
break;
879
}
880
case libsumo::CMD_GET_POI_VARIABLE:
881
POI::getTree()->Search(cmin, cmax, Named::StoringVisitor(into));
882
break;
883
case libsumo::CMD_GET_POLYGON_VARIABLE:
884
Polygon::getTree()->Search(cmin, cmax, Named::StoringVisitor(into));
885
break;
886
case libsumo::CMD_GET_EDGE_VARIABLE:
887
case libsumo::CMD_GET_LANE_VARIABLE:
888
case libsumo::CMD_GET_PERSON_VARIABLE:
889
case libsumo::CMD_GET_VEHICLE_VARIABLE: {
890
if (myLaneTree == nullptr) {
891
myLaneTree = new LANE_RTREE_QUAL(&MSLane::visit);
892
MSLane::fill(*myLaneTree);
893
}
894
MSLane::StoringVisitor lsv(into, shape, range, domain);
895
myLaneTree->Search(cmin, cmax, lsv);
896
}
897
break;
898
default:
899
throw TraCIException("Infeasible context domain (" + toString(domain) + ")");
900
break;
901
}
902
}
903
904
905
906
void
907
Helper::applySubscriptionFilters(const Subscription& s, std::set<std::string>& objIDs) {
908
#ifdef DEBUG_SURROUNDING
909
MSBaseVehicle* _veh = getVehicle(s.id);
910
std::cout << SIMTIME << " applySubscriptionFilters for vehicle '" << _veh->getID() << "' on lane '" << _veh->getLane()->getID() << "'"
911
<< "\n on edge '" << _veh->getLane()->getEdge().getID() << "' (" << toString(_veh->getLane()->getEdge().getLanes()) << ")\n"
912
<< "objIDs = " << toString(objIDs) << std::endl;
913
#endif
914
915
if (s.activeFilters == 0) {
916
// No filters set
917
return;
918
}
919
920
MSVehicle* v = dynamic_cast<MSVehicle*>(getVehicle(s.id));
921
922
// Whether vehicles on opposite lanes shall be taken into account
923
const bool disregardOppositeDirection = (s.activeFilters & SUBS_FILTER_NOOPPOSITE) != 0;
924
925
// Check filter specification consistency
926
if (disregardOppositeDirection && (s.activeFilters & SUBS_FILTER_NO_RTREE) == 0) {
927
WRITE_WARNINGF(TL("Ignoring veh '%' no-opposite subscription filter for geographic range object collection. Consider using the 'lanes' filter."), v->getID())
928
}
929
// TODO: Treat case, where ego vehicle is currently on opposite lane
930
931
std::set<const SUMOTrafficObject*> vehs;
932
if (s.activeFilters & SUBS_FILTER_NO_RTREE) {
933
// Set defaults for upstream/downstream/lateral distances
934
double downstreamDist = s.range, upstreamDist = s.range, lateralDist = s.range;
935
if (s.activeFilters & SUBS_FILTER_DOWNSTREAM_DIST) {
936
// Specifies maximal downstream distance for vehicles in context subscription result
937
downstreamDist = s.filterDownstreamDist;
938
}
939
if (s.activeFilters & SUBS_FILTER_UPSTREAM_DIST) {
940
// Specifies maximal downstream distance for vehicles in context subscription result
941
upstreamDist = s.filterUpstreamDist;
942
}
943
if (s.activeFilters & SUBS_FILTER_LATERAL_DIST) {
944
// Specifies maximal lateral distance for vehicles in context subscription result
945
lateralDist = s.filterLateralDist;
946
}
947
if (v == nullptr) {
948
throw TraCIException("Subscription filter not yet implemented for meso vehicle");
949
}
950
if (!v->isOnRoad()) {
951
return;
952
}
953
const MSLane* vehLane = v->getLane();
954
if (vehLane == nullptr) {
955
return;
956
}
957
MSEdge* vehEdge = &vehLane->getEdge();
958
std::vector<int> filterLanes;
959
if ((s.activeFilters & SUBS_FILTER_LANES) == 0) {
960
// No lane indices are specified (but downstream and/or upstream distance)
961
// -> use only vehicle's current lane as origin for the searches
962
filterLanes = {0};
963
// Lane indices must be specified when leader/follower information is requested.
964
assert((s.activeFilters & SUBS_FILTER_LEAD_FOLLOW) == 0);
965
} else {
966
filterLanes = s.filterLanes;
967
}
968
969
#ifdef DEBUG_SURROUNDING
970
std::cout << "Filter lanes: " << toString(filterLanes) << std::endl;
971
std::cout << "Downstream distance: " << downstreamDist << std::endl;
972
std::cout << "Upstream distance: " << upstreamDist << std::endl;
973
std::cout << "Lateral distance: " << lateralDist << std::endl;
974
#endif
975
976
if ((s.activeFilters & SUBS_FILTER_MANEUVER) != 0) {
977
// Maneuver filters disables road net search for all surrounding vehicles
978
if ((s.activeFilters & SUBS_FILTER_LEAD_FOLLOW) != 0) {
979
// Return leader and follower on the specified lanes in context subscription result.
980
for (int offset : filterLanes) {
981
MSLane* lane = v->getLane()->getParallelLane(offset, false);
982
if (lane != nullptr) {
983
// this is a non-opposite lane
984
MSVehicle* leader = lane->getLeader(v, v->getPositionOnLane(), v->getBestLanesContinuation(lane), downstreamDist).first;
985
MSVehicle* follower = lane->getFollower(v, v->getPositionOnLane(), upstreamDist,
986
MSLane::MinorLinkMode::FOLLOW_ALWAYS).first;
987
vehs.insert(vehs.end(), leader);
988
vehs.insert(vehs.end(), follower);
989
990
#ifdef DEBUG_SURROUNDING
991
std::cout << "Lane at index " << offset << ": '" << lane->getID() << std::endl;
992
std::cout << "Leader: '" << (leader != nullptr ? leader->getID() : "NULL") << "'" << std::endl;
993
std::cout << "Follower: '" << (follower != nullptr ? follower->getID() : "NULL") << "'" << std::endl;
994
#endif
995
996
} else if (!disregardOppositeDirection && offset > 0) { // TODO: offset<0 may indicate opposite query when vehicle is on opposite itself
997
// check whether ix points to an opposite lane
998
const MSEdge* opposite = vehEdge->getOppositeEdge();
999
if (opposite == nullptr) {
1000
#ifdef DEBUG_SURROUNDING
1001
std::cout << "No lane at index " << offset << std::endl;
1002
#endif
1003
// no opposite edge
1004
continue;
1005
}
1006
// Index of opposite lane at relative offset
1007
const int ix_opposite = (int)opposite->getLanes().size() - 1 - (vehLane->getIndex() + offset - (int)vehEdge->getLanes().size());
1008
if (ix_opposite < 0) {
1009
#ifdef DEBUG_SURROUNDING
1010
std::cout << "No lane on opposite at index " << ix_opposite << std::endl;
1011
#endif
1012
// no opposite edge
1013
continue;
1014
}
1015
lane = opposite->getLanes()[ix_opposite];
1016
// Search vehs along opposite lanes (swap upstream and downstream distance)
1017
// XXX transformations for curved geometries
1018
double posOnOpposite = MAX2(0., opposite->getLength() - v->getPositionOnLane());
1019
// Get leader on opposite
1020
vehs.insert(vehs.end(), lane->getFollower(v, posOnOpposite, downstreamDist, MSLane::MinorLinkMode::FOLLOW_NEVER).first);
1021
// Get follower (no search on consecutive lanes
1022
vehs.insert(vehs.end(), lane->getLeader(v, posOnOpposite - v->getLength(), std::vector<MSLane*>()).first);
1023
}
1024
}
1025
}
1026
1027
if (s.activeFilters & SUBS_FILTER_TURN) {
1028
applySubscriptionFilterTurn(s, vehs);
1029
if (s.activeFilters & SUBS_FILTER_LANES) {
1030
applySubscriptionFilterLanes(s, vehs, filterLanes, downstreamDist, upstreamDist, disregardOppositeDirection);
1031
}
1032
if (s.activeFilters & SUBS_FILTER_LATERAL_DIST) {
1033
applySubscriptionFilterLateralDistance(s, vehs, downstreamDist, upstreamDist, lateralDist);
1034
}
1035
}
1036
#ifdef DEBUG_SURROUNDING
1037
std::cout << SIMTIME << " applySubscriptionFilters() for veh '" << v->getID() << "'. Found the following vehicles:\n";
1038
for (auto veh : vehs) {
1039
debugPrint(veh);
1040
}
1041
#endif
1042
} else if (s.activeFilters & SUBS_FILTER_LATERAL_DIST) {
1043
applySubscriptionFilterLateralDistance(s, vehs, downstreamDist, upstreamDist, lateralDist);
1044
} else {
1045
// No maneuver or lateral distance filters requested, but only lanes filter (directly, or indirectly by specifying downstream or upstream distance)
1046
applySubscriptionFilterLanes(s, vehs, filterLanes, downstreamDist, upstreamDist, disregardOppositeDirection);
1047
}
1048
// Write vehs IDs in objIDs
1049
for (const SUMOTrafficObject* veh : vehs) {
1050
if (veh != nullptr) {
1051
objIDs.insert(objIDs.end(), veh->getID());
1052
}
1053
}
1054
}
1055
1056
if (s.activeFilters & SUBS_FILTER_VCLASS) {
1057
// Only return vehicles of the given vClass in context subscription result
1058
auto i = objIDs.begin();
1059
while (i != objIDs.end()) {
1060
MSBaseVehicle* veh = getVehicle(*i);
1061
if ((veh->getVehicleType().getVehicleClass() & s.filterVClasses) == 0) {
1062
i = objIDs.erase(i);
1063
} else {
1064
++i;
1065
}
1066
}
1067
}
1068
if (s.activeFilters & SUBS_FILTER_VTYPE) {
1069
// Only return vehicles of the given vType in context subscription result
1070
auto i = objIDs.begin();
1071
while (i != objIDs.end()) {
1072
MSBaseVehicle* veh = getVehicle(*i);
1073
if (s.filterVTypes.find(veh->getVehicleType().getID()) == s.filterVTypes.end()) {
1074
i = objIDs.erase(i);
1075
} else {
1076
++i;
1077
}
1078
}
1079
}
1080
if (s.activeFilters & SUBS_FILTER_FIELD_OF_VISION) {
1081
// Only return vehicles within field of vision in context subscription result
1082
applySubscriptionFilterFieldOfVision(s, objIDs);
1083
}
1084
}
1085
1086
void
1087
Helper::applySubscriptionFilterLanes(const Subscription& s, std::set<const SUMOTrafficObject*>& vehs, std::vector<int>& filterLanes, double downstreamDist,
1088
double upstreamDist, bool disregardOppositeDirection) {
1089
if (!s.isVehicleToVehicleContextSubscription()) {
1090
WRITE_WARNINGF(TL("Lanes filter is only feasible for context domain 'vehicle' (current is '%'), ignoring filter..."), toHex(s.contextDomain, 2));
1091
return;
1092
}
1093
assert(filterLanes.size() > 0);
1094
MSVehicle* v = dynamic_cast<MSVehicle*>(getVehicle(s.id));
1095
const MSLane* vehLane = v->getLane();
1096
MSEdge* vehEdge = &vehLane->getEdge();
1097
// This is to remember the lanes checked in the driving direction of the vehicle (their opposites can be added in a second pass)
1098
auto checkedLanesInDrivingDir = std::make_shared<LaneCoverageInfo>();
1099
for (int offset : filterLanes) {
1100
MSLane* lane = vehLane->getParallelLane(offset, false);
1101
if (lane != nullptr) {
1102
#ifdef DEBUG_SURROUNDING
1103
std::cout << "Checking for surrounding vehicles starting on lane '" << lane->getID() << "' at index " << offset << std::endl;
1104
#endif
1105
// Search vehs along this lane
1106
// (Coverage info is collected per origin lane since lanes reached from neighboring lanes may have different distances
1107
// and aborting at previously scanned when coming from a closer origin may prevent scanning of parts that should be included.)
1108
std::shared_ptr<LaneCoverageInfo> checkedLanes = std::make_shared<LaneCoverageInfo>();
1109
const std::set<MSVehicle*> new_vehs =
1110
lane->getSurroundingVehicles(v->getPositionOnLane(), downstreamDist, upstreamDist + v->getLength(), checkedLanes);
1111
vehs.insert(new_vehs.begin(), new_vehs.end());
1112
fuseLaneCoverage(checkedLanesInDrivingDir, checkedLanes);
1113
} else if (!disregardOppositeDirection && offset > 0) {
1114
// Check opposite edge, too
1115
assert(vehLane->getIndex() + offset >= (int)vehEdge->getLanes().size()); // index points beyond this edge
1116
const MSEdge* opposite = vehEdge->getOppositeEdge();
1117
if (opposite == nullptr) {
1118
#ifdef DEBUG_SURROUNDING
1119
std::cout << "No opposite edge, thus no lane at index " << offset << std::endl;
1120
#endif
1121
// no opposite edge
1122
continue;
1123
}
1124
// Index of opposite lane at relative offset
1125
const int ix_opposite = (int)opposite->getLanes().size() - 1 - (vehLane->getIndex() + offset - (int)vehEdge->getLanes().size());
1126
if (ix_opposite < 0) {
1127
#ifdef DEBUG_SURROUNDING
1128
std::cout << "No lane on opposite at index " << ix_opposite << std::endl;
1129
#endif
1130
// no opposite edge
1131
continue;
1132
}
1133
lane = opposite->getLanes()[ix_opposite];
1134
// Search vehs along opposite lanes (swap upstream and downstream distance)
1135
const std::set<MSVehicle*> new_vehs = lane->getSurroundingVehicles(lane->getLength() - v->getPositionOnLane(), upstreamDist + v->getLength(),
1136
downstreamDist, std::make_shared<LaneCoverageInfo>());
1137
vehs.insert(new_vehs.begin(), new_vehs.end());
1138
}
1139
#ifdef DEBUG_SURROUNDING
1140
else {
1141
std::cout << "No lane at index " << offset << std::endl;
1142
}
1143
#endif
1144
1145
if (!disregardOppositeDirection) {
1146
// If opposite should be checked, do this for each lane of the search tree in checkedLanesInDrivingDir
1147
// (For instance, some opposite lanes of these would not be obtained if the ego lane does not have an opposite.)
1148
1149
// Number of opposite lanes to be checked (assumes filterLanes.size()>0, see assertion above) determined as hypothetical offset
1150
// overlap into opposing edge from the vehicle's current lane.
1151
// TODO: offset<0 may indicate opposite query when vehicle is on opposite itself (-> use min_element(filterLanes...) instead, etc)
1152
const int nOpp = MAX2(0, (*std::max_element(filterLanes.begin(), filterLanes.end())) - ((int)vehEdge->getLanes().size() - 1 - vehLane->getIndex()));
1153
// Collect vehicles from opposite lanes
1154
if (nOpp > 0) {
1155
for (auto& laneCov : *checkedLanesInDrivingDir) {
1156
const MSLane* const l = laneCov.first;
1157
if (l == nullptr || l->getEdge().getOppositeEdge() == nullptr) {
1158
continue;
1159
}
1160
const MSEdge* opposite = l->getEdge().getOppositeEdge();
1161
const std::pair<double, double>& range = laneCov.second;
1162
auto leftMostOppositeLaneIt = opposite->getLanes().rbegin();
1163
for (auto oppositeLaneIt = leftMostOppositeLaneIt; oppositeLaneIt != opposite->getLanes().rend(); ++oppositeLaneIt) {
1164
if ((int)(oppositeLaneIt - leftMostOppositeLaneIt) == nOpp) {
1165
break;
1166
}
1167
// Add vehicles from corresponding range on opposite direction
1168
const MSLane* oppositeLane = *oppositeLaneIt;
1169
auto new_vehs = oppositeLane->getVehiclesInRange(l->getLength() - range.second, l->getLength() - range.first);
1170
vehs.insert(new_vehs.begin(), new_vehs.end());
1171
}
1172
}
1173
}
1174
}
1175
#ifdef DEBUG_SURROUNDING
1176
std::cout << SIMTIME << " applySubscriptionFilterLanes() for veh '" << v->getID() << "', lane offset '" << offset << "'. Found the following vehicles so far:\n";
1177
for (auto veh : vehs) {
1178
debugPrint(veh);
1179
}
1180
#endif
1181
}
1182
}
1183
1184
void
1185
Helper::applySubscriptionFilterTurn(const Subscription& s, std::set<const SUMOTrafficObject*>& vehs) {
1186
if (!s.isVehicleToVehicleContextSubscription()) {
1187
WRITE_WARNINGF(TL("Turn filter is only feasible for context domain 'vehicle' (current is '%'), ignoring filter..."), toHex(s.contextDomain, 2));
1188
return;
1189
}
1190
// Get upcoming junctions and vialanes within downstream distance, where foe links exist or at least the link direction is not straight
1191
MSVehicle* v = dynamic_cast<MSVehicle*>(getVehicle(s.id));
1192
const MSLane* lane = v->getLane();
1193
std::vector<const MSLink*> links = lane->getUpcomingLinks(v->getPositionOnLane(), s.filterDownstreamDist, v->getBestLanesContinuation());
1194
#ifdef DEBUG_SURROUNDING
1195
std::cout << "Applying turn filter for vehicle '" << v->getID() << "'\n Gathering foes ..." << std::endl;
1196
#endif
1197
// Iterate through junctions and find approaching foes within foeDistToJunction.
1198
for (auto& l : links) {
1199
#ifdef DEBUG_SURROUNDING
1200
std::cout << " On junction '" << l->getJunction()->getID() << "' (no. foe links = " << l->getFoeLinks().size() << "):" << std::endl;
1201
#endif
1202
for (auto& foeLane : l->getFoeLanes()) {
1203
if (foeLane->getEdge().isCrossing()) {
1204
#ifdef DEBUG_SURROUNDING
1205
std::cout << " skipping crossing foeLane '" << foeLane->getID() << "'" << std::endl;
1206
#endif
1207
continue;
1208
}
1209
#ifdef DEBUG_SURROUNDING
1210
std::cout << " foeLane '" << foeLane->getID() << "'" << std::endl;
1211
#endif
1212
// Check vehicles approaching the entry link corresponding to this lane
1213
const MSLink* foeLink = foeLane->getEntryLink();
1214
for (auto& vi : foeLink->getApproaching()) {
1215
if (vi.second.dist <= s.filterFoeDistToJunction) {
1216
#ifdef DEBUG_SURROUNDING
1217
std::cout << " Approaching foeLane entry link '" << vi.first->getID() << "'" << std::endl;
1218
#endif
1219
vehs.insert(vehs.end(), dynamic_cast<const MSVehicle*>(vi.first));
1220
}
1221
}
1222
// add vehicles currently on the junction
1223
for (const MSVehicle* foe : foeLane->getVehiclesSecure()) {
1224
#ifdef DEBUG_SURROUNDING
1225
std::cout << " On foeLane '" << foe->getID() << "'" << std::endl;
1226
#endif
1227
vehs.insert(vehs.end(), foe);
1228
}
1229
foeLane->releaseVehicles();
1230
for (auto& laneInfo : foeLane->getIncomingLanes()) {
1231
const MSLane* foeLanePred = laneInfo.lane;
1232
if (foeLanePred->isInternal()) {
1233
#ifdef DEBUG_SURROUNDING
1234
std::cout << " foeLanePred '" << foeLanePred->getID() << "'" << std::endl;
1235
#endif
1236
for (const MSVehicle* foe : foeLanePred->getVehiclesSecure()) {
1237
#ifdef DEBUG_SURROUNDING
1238
std::cout << " On foeLanePred '" << foe->getID() << "'" << std::endl;
1239
#endif
1240
vehs.insert(vehs.end(), foe);
1241
}
1242
foeLanePred->releaseVehicles();
1243
}
1244
}
1245
}
1246
}
1247
}
1248
1249
void
1250
Helper::applySubscriptionFilterFieldOfVision(const Subscription& s, std::set<std::string>& objIDs) {
1251
if (s.filterFieldOfVisionOpeningAngle <= 0. || s.filterFieldOfVisionOpeningAngle >= 360.) {
1252
WRITE_WARNINGF(TL("Field of vision opening angle ('%') should be within interval (0, 360), ignoring filter..."), s.filterFieldOfVisionOpeningAngle);
1253
return;
1254
}
1255
1256
MSBaseVehicle* egoVehicle = getVehicle(s.id);
1257
Position egoPosition = egoVehicle->getPosition();
1258
double openingAngle = DEG2RAD(s.filterFieldOfVisionOpeningAngle);
1259
1260
#ifdef DEBUG_SURROUNDING
1261
std::cout << "FOVFILTER: ego direction = " << toString(RAD2DEG(egoVehicle->getAngle())) << " (deg)" << std::endl;
1262
#endif
1263
1264
auto i = objIDs.begin();
1265
while (i != objIDs.end()) {
1266
if (s.id.compare(*i) == 0) { // skip if this is the ego vehicle
1267
++i;
1268
continue;
1269
}
1270
SUMOTrafficObject* obj = getTrafficObject(s.contextDomain, *i);
1271
double angleEgoToVeh = egoPosition.angleTo2D(obj->getPosition());
1272
double alpha = GeomHelper::angleDiff(egoVehicle->getAngle(), angleEgoToVeh);
1273
1274
#ifdef DEBUG_SURROUNDING
1275
const std::string objType = s.isVehicleToPersonContextSubscription() ? "person" : "veh";
1276
std::cout << "FOVFILTER: " << objType << " '" << *i << "' dist = " << toString(egoPosition.distanceTo2D(obj->getPosition())) << std::endl;
1277
std::cout << "FOVFILTER: " << objType << " '" << *i << "' alpha = " << toString(RAD2DEG(alpha)) << " (deg)" << std::endl;
1278
#endif
1279
1280
if (abs(alpha) > openingAngle * 0.5) {
1281
i = objIDs.erase(i);
1282
} else {
1283
++i;
1284
}
1285
}
1286
}
1287
1288
void
1289
Helper::applySubscriptionFilterLateralDistance(const Subscription& s, std::set<const SUMOTrafficObject*>& vehs, double downstreamDist, double upstreamDist,
1290
double lateralDist) {
1291
// collect all vehicles within maximum range of interest to get an upper bound
1292
PositionVector vehShape;
1293
findObjectShape(s.commandId, s.id, vehShape);
1294
double range = MAX3(downstreamDist, upstreamDist, lateralDist);
1295
std::set<std::string> objIDs;
1296
collectObjectIDsInRange(s.contextDomain, vehShape, range, objIDs);
1297
1298
#ifdef DEBUG_SURROUNDING
1299
std::cout << "FILTER_LATERAL_DIST: collected object IDs (range " << range << "):" << std::endl;
1300
for (std::string i : objIDs) {
1301
std::cout << i << std::endl;
1302
}
1303
#endif
1304
1305
MSVehicle* v = dynamic_cast<MSVehicle*>(getVehicle(s.id));
1306
#ifdef DEBUG_SURROUNDING
1307
std::cout << "FILTER_LATERAL_DIST: myLane is '" << v->getLane()->getID() << "', pos " << v->getPositionOnLane() << std::endl;
1308
std::cout << "FILTER_LATERAL_DIST: opposite lane is '" << v->getLane()->getParallelOpposite()->getID() << "'" << std::endl;
1309
#endif
1310
double frontPosOnLane = v->getPositionOnLane();
1311
if (v->getLaneChangeModel().isOpposite()) {
1312
frontPosOnLane = v->getLane()->getOppositePos(frontPosOnLane);
1313
}
1314
// 1st pass: downstream (make sure that the whole length of the vehicle is included in the match)
1315
const double backPosOnLane = MAX2(0.0, frontPosOnLane - v->getVehicleType().getLength());
1316
applySubscriptionFilterLateralDistanceSinglePass(s, objIDs, vehs, v->getUpcomingLanesUntil(downstreamDist), backPosOnLane, v->getLateralPositionOnLane(),
1317
true);
1318
// 2nd pass: upstream
1319
applySubscriptionFilterLateralDistanceSinglePass(s, objIDs, vehs, v->getPastLanesUntil(upstreamDist), frontPosOnLane, v->getLateralPositionOnLane(), false);
1320
}
1321
1322
void
1323
Helper::applySubscriptionFilterLateralDistanceSinglePass(const Subscription& s, std::set<std::string>& objIDs,
1324
std::set<const SUMOTrafficObject*>& vehs,
1325
const std::vector<const MSLane*>& lanes, double posOnLane, double posLat, bool isDownstream) {
1326
const double streamDist = isDownstream ? s.filterDownstreamDist : s.filterUpstreamDist;
1327
double distRemaining = streamDist;
1328
bool isFirstLane = true;
1329
PositionVector combinedShape;
1330
for (const MSLane* lane : lanes) {
1331
#ifdef DEBUG_SURROUNDING
1332
std::cout << "FILTER_LATERAL_DIST: current lane " << (isDownstream ? "down" : "up") << " is '" << lane->getID() << "', length " << lane->getLength()
1333
<< ", pos " << posOnLane << ", distRemaining " << distRemaining << std::endl;
1334
#endif
1335
PositionVector laneShape = lane->getShape();
1336
if (isFirstLane) {
1337
isFirstLane = false;
1338
double geometryPos = lane->interpolateLanePosToGeometryPos(posOnLane);
1339
if (geometryPos <= POSITION_EPS) {
1340
if (!isDownstream) {
1341
continue;
1342
}
1343
} else {
1344
if (geometryPos >= laneShape.length() - POSITION_EPS) {
1345
laneShape = isDownstream ? PositionVector() : laneShape;
1346
} else {
1347
auto pair = laneShape.splitAt(geometryPos, false);
1348
laneShape = isDownstream ? pair.second : pair.first;
1349
}
1350
}
1351
}
1352
double laneLength = lane->interpolateGeometryPosToLanePos(laneShape.length());
1353
if (distRemaining - laneLength < 0.) {
1354
double geometryPos = lane->interpolateLanePosToGeometryPos(isDownstream ? distRemaining : laneLength - distRemaining);
1355
if (geometryPos > POSITION_EPS && geometryPos < laneShape.length() - POSITION_EPS) {
1356
auto pair = laneShape.splitAt(geometryPos, false);
1357
laneShape = isDownstream ? pair.first : pair.second;
1358
}
1359
}
1360
distRemaining -= laneLength;
1361
try {
1362
laneShape.move2side(-posLat);
1363
} catch (ProcessError&) {
1364
WRITE_WARNINGF(TL("addSubscriptionFilterLateralDistance could not determine shape of lane '%' with a lateral shift of %."),
1365
lane->getID(), toString(posLat));
1366
}
1367
#ifdef DEBUG_SURROUNDING
1368
std::cout << " posLat=" << posLat << " laneShape=" << laneShape << "\n";
1369
#endif
1370
if (isDownstream) {
1371
combinedShape.append(laneShape);
1372
} else {
1373
combinedShape.prepend(laneShape);
1374
}
1375
if (distRemaining <= POSITION_EPS) {
1376
break;
1377
}
1378
}
1379
#ifdef DEBUG_SURROUNDING
1380
std::cout << " combinedShape=" << combinedShape << "\n";
1381
#endif
1382
// check remaining objects' distances to the combined shape
1383
auto i = objIDs.begin();
1384
while (i != objIDs.end()) {
1385
SUMOTrafficObject* obj = getTrafficObject(s.contextDomain, *i);
1386
double minPerpendicularDist = combinedShape.distance2D(obj->getPosition(), true);
1387
#ifdef DEBUG_SURROUNDING
1388
std::cout << (isDownstream ? "DOWN" : "UP") << " obj " << obj->getID() << " perpendicular dist=" << minPerpendicularDist << " filterLateralDist=" << s.filterLateralDist << "\n";
1389
#endif
1390
if ((minPerpendicularDist != GeomHelper::INVALID_OFFSET) && (minPerpendicularDist <= s.filterLateralDist)) {
1391
vehs.insert(obj);
1392
i = objIDs.erase(i);
1393
} else {
1394
++i;
1395
}
1396
}
1397
}
1398
1399
void
1400
Helper::setRemoteControlled(MSVehicle* v, Position xyPos, MSLane* l, double pos, double posLat, double angle,
1401
int edgeOffset, ConstMSEdgeVector route, SUMOTime t) {
1402
myRemoteControlledVehicles[v->getID()] = v;
1403
v->getInfluencer().setRemoteControlled(xyPos, l, pos, posLat, angle, edgeOffset, route, t);
1404
}
1405
1406
void
1407
Helper::setRemoteControlled(MSPerson* p, Position xyPos, MSLane* l, double pos, double posLat, double angle,
1408
int edgeOffset, ConstMSEdgeVector route, SUMOTime t) {
1409
myRemoteControlledPersons[p->getID()] = p;
1410
p->getInfluencer().setRemoteControlled(xyPos, l, pos, posLat, angle, edgeOffset, route, t);
1411
}
1412
1413
1414
int
1415
Helper::postProcessRemoteControl() {
1416
int numControlled = 0;
1417
for (auto& controlled : myRemoteControlledVehicles) {
1418
if (MSNet::getInstance()->getVehicleControl().getVehicle(controlled.first) != nullptr) {
1419
controlled.second->getInfluencer().postProcessRemoteControl(controlled.second);
1420
numControlled++;
1421
} else {
1422
WRITE_WARNINGF(TL("Vehicle '%' was removed though being controlled by TraCI"), controlled.first);
1423
}
1424
}
1425
myRemoteControlledVehicles.clear();
1426
for (auto& controlled : myRemoteControlledPersons) {
1427
if (MSNet::getInstance()->getPersonControl().get(controlled.first) != nullptr) {
1428
controlled.second->getInfluencer().postProcessRemoteControl(controlled.second);
1429
numControlled++;
1430
} else {
1431
WRITE_WARNINGF(TL("Person '%' was removed though being controlled by TraCI"), controlled.first);
1432
}
1433
}
1434
myRemoteControlledPersons.clear();
1435
return numControlled;
1436
}
1437
1438
1439
bool
1440
Helper::moveToXYMap(const Position& pos, double maxRouteDistance, bool mayLeaveNetwork, const std::string& origID, const double angle,
1441
double speed, const ConstMSEdgeVector& currentRoute, const int routePosition, const MSLane* currentLane, double currentLanePos, bool onRoad,
1442
SUMOVehicleClass vClass, double currentAngle, bool setLateralPos,
1443
double& bestDistance, MSLane** lane, double& lanePos, int& routeOffset, ConstMSEdgeVector& edges) {
1444
// collect edges around the vehicle/person
1445
#ifdef DEBUG_MOVEXY
1446
std::cout << SIMTIME << " moveToXYMap pos=" << pos << " angle=" << angle << " vClass=" << toString(vClass) << "\n";
1447
#endif
1448
const MSEdge* const currentRouteEdge = currentRoute[routePosition];
1449
std::set<const Named*> into;
1450
PositionVector shape;
1451
shape.push_back(pos);
1452
collectObjectsInRange(libsumo::CMD_GET_EDGE_VARIABLE, shape, maxRouteDistance, into);
1453
double maxDist = 0;
1454
std::map<MSLane*, LaneUtility, ComparatorNumericalIdLess> lane2utility;
1455
// compute utility for all candidate edges
1456
for (const Named* namedEdge : into) {
1457
const MSEdge* e = dynamic_cast<const MSEdge*>(namedEdge);
1458
if ((e->getPermissions() & vClass) != vClass) {
1459
continue;
1460
}
1461
const MSEdge* prevEdge = nullptr;
1462
const MSEdge* nextEdge = nullptr;
1463
bool onRoute = false;
1464
bool useCurrentAngle = false;
1465
// the next if/the clause sets "onRoute", "prevEdge", and "nextEdge", depending on
1466
// whether the currently seen edge is an internal one or a normal one
1467
if (e->isWalkingArea() || e->isCrossing()) {
1468
// find current intersection along the route
1469
const MSJunction* junction = e->getFromJunction();
1470
for (int i = routePosition; i < (int)currentRoute.size(); i++) {
1471
const MSEdge* cand = currentRoute[i];
1472
if (cand->getToJunction() == junction) {
1473
prevEdge = cand;
1474
if (i + 1 < (int)currentRoute.size()) {
1475
onRoute = true;
1476
nextEdge = currentRoute[i + 1];
1477
}
1478
break;
1479
}
1480
}
1481
if (!onRoute) {
1482
// search backward
1483
for (int i = routePosition - 1; i >= 0; i--) {
1484
const MSEdge* cand = currentRoute[i];
1485
if (cand->getToJunction() == junction) {
1486
onRoute = true;
1487
prevEdge = cand;
1488
nextEdge = currentRoute[i + 1];
1489
break;
1490
}
1491
}
1492
}
1493
if (prevEdge == nullptr) {
1494
// use arbitrary predecessor
1495
if (e->getPredecessors().size() > 0) {
1496
prevEdge = e->getPredecessors().front();
1497
} else if (e->getSuccessors().size() > 1) {
1498
for (MSEdge* e2 : e->getSuccessors()) {
1499
if (e2 != nextEdge) {
1500
prevEdge = e2;
1501
break;
1502
}
1503
}
1504
}
1505
}
1506
if (nextEdge == nullptr) {
1507
if (e->getSuccessors().size() > 0) {
1508
nextEdge = e->getSuccessors().front();
1509
} else if (e->getPredecessors().size() > 1) {
1510
for (MSEdge* e2 : e->getPredecessors()) {
1511
if (e2 != prevEdge) {
1512
nextEdge = e2;
1513
break;
1514
}
1515
}
1516
}
1517
}
1518
#ifdef DEBUG_MOVEXY_ANGLE
1519
std::cout << "walkingarea/crossing:" << e->getID() << " prev:" << Named::getIDSecure(prevEdge) << " next:" << Named::getIDSecure(nextEdge)
1520
<< " pred=" << toString(e->getPredecessors()) << " succ=" << toString(e->getSuccessors())
1521
<< "\n";
1522
#endif
1523
} else if (e->isNormal()) {
1524
// a normal edge
1525
//
1526
// check whether the currently seen edge is in the vehicle's route
1527
// - either the one it's on or one of the next edges
1528
ConstMSEdgeVector::const_iterator searchStart = currentRoute.begin() + routePosition;
1529
if (onRoad && currentLane->getEdge().isInternal()) {
1530
++searchStart;
1531
}
1532
ConstMSEdgeVector::const_iterator edgePos = std::find(searchStart, currentRoute.end(), e);
1533
onRoute = edgePos != currentRoute.end(); // no? -> onRoute is false
1534
if (edgePos == currentRoute.end() - 1 && currentRouteEdge == e) {
1535
// onRoute is false as well if the vehicle is beyond the edge
1536
onRoute &= currentRouteEdge->getLength() > currentLanePos + SPEED2DIST(speed);
1537
}
1538
// save prior and next edges
1539
prevEdge = e;
1540
nextEdge = !onRoute || edgePos == currentRoute.end() - 1 ? nullptr : *(edgePos + 1);
1541
#ifdef DEBUG_MOVEXY_ANGLE
1542
std::cout << "normal:" << e->getID() << " prev:" << Named::getIDSecure(prevEdge) << " next:" << Named::getIDSecure(nextEdge) << "\n";
1543
#endif
1544
} else if (e->isInternal()) {
1545
// an internal edge
1546
// get the previous edge
1547
prevEdge = e;
1548
while (prevEdge != nullptr && prevEdge->isInternal()) {
1549
MSLane* l = prevEdge->getLanes()[0];
1550
l = l->getLogicalPredecessorLane();
1551
prevEdge = l == nullptr ? nullptr : &l->getEdge();
1552
}
1553
// check whether the previous edge is on the route (was on the route)
1554
ConstMSEdgeVector::const_iterator prevEdgePos = std::find(currentRoute.begin() + routePosition, currentRoute.end(), prevEdge);
1555
nextEdge = e;
1556
while (nextEdge != nullptr && nextEdge->isInternal()) {
1557
nextEdge = nextEdge->getSuccessors()[0]; // should be only one for an internal edge
1558
}
1559
if (prevEdgePos != currentRoute.end() && (prevEdgePos + 1) != currentRoute.end()) {
1560
onRoute = *(prevEdgePos + 1) == nextEdge;
1561
} else {
1562
// we cannot make use of route information and should make
1563
// use of the current angle if the user did not supply an angle
1564
useCurrentAngle = angle == INVALID_DOUBLE_VALUE;
1565
}
1566
#ifdef DEBUG_MOVEXY_ANGLE
1567
std::cout << "internal:" << e->getID() << " prev:" << Named::getIDSecure(prevEdge) << " next:" << Named::getIDSecure(nextEdge) << "\n";
1568
#endif
1569
}
1570
1571
1572
// weight the lanes...
1573
const bool perpendicular = false;
1574
for (MSLane* const l : e->getLanes()) {
1575
if (!l->allowsVehicleClass(vClass)) {
1576
continue;
1577
}
1578
if (l->getShape().length() == 0) {
1579
// mapping to shapeless lanes is a bad idea
1580
continue;
1581
}
1582
double langle = 180.;
1583
double dist = FAR_AWAY;
1584
double perpendicularDist = FAR_AWAY;
1585
// add some slack to avoid issues from tiny gaps between consecutive lanes
1586
// except when simulating with high precision where the slack can throw of mapping
1587
const double slack = POSITION_EPS * TS;
1588
PositionVector laneShape = l->getShape();
1589
laneShape.extrapolate2D(slack);
1590
double off = laneShape.nearest_offset_to_point2D(pos, true);
1591
if (off != GeomHelper::INVALID_OFFSET) {
1592
perpendicularDist = laneShape.distance2D(pos, true);
1593
perpendicularDist = patchShapeDistance(l, pos, perpendicularDist, true);
1594
}
1595
off = l->getShape().nearest_offset_to_point2D(pos, perpendicular);
1596
if (off != GeomHelper::INVALID_OFFSET) {
1597
dist = l->getShape().distance2D(pos, perpendicular);
1598
dist = patchShapeDistance(l, pos, dist, perpendicular);
1599
langle = GeomHelper::naviDegree(l->getShape().rotationAtOffset(off));
1600
}
1601
// cannot trust lanePos on walkingArea
1602
bool sameEdge = onRoad && e == &currentLane->getEdge() && currentRouteEdge->getLength() > currentLanePos + SPEED2DIST(speed) && !e->isWalkingArea();
1603
/*
1604
const MSEdge* rNextEdge = nextEdge;
1605
while(rNextEdge==0&&lane->getEdge().getPurpose()==MSEdge::EDGEFUNCTION_INTERNAL) {
1606
MSLane* next = lane->getLinkCont()[0]->getLane();
1607
rNextEdge = next == 0 ? 0 : &next->getEdge();
1608
}
1609
*/
1610
double dist2 = dist;
1611
if (mayLeaveNetwork && fabs(dist - perpendicularDist) > slack) {
1612
// ambiguous mapping. Don't trust this
1613
dist2 = FAR_AWAY;
1614
}
1615
const double angle2 = useCurrentAngle ? currentAngle : angle;
1616
const double angleDiff = (angle2 == INVALID_DOUBLE_VALUE || l->getEdge().isWalkingArea() ? 0 : GeomHelper::getMinAngleDiff(angle2, langle));
1617
#ifdef DEBUG_MOVEXY_ANGLE
1618
std::cout << std::setprecision(gPrecision)
1619
<< " candLane=" << l->getID() << " lAngle=" << langle << " lLength=" << l->getLength()
1620
<< " angleDiff=" << angleDiff
1621
<< " off=" << off
1622
<< " pDist=" << perpendicularDist
1623
<< " dist=" << dist
1624
<< " dist2=" << dist2
1625
<< "\n";
1626
std::cout << l->getID() << " param=" << l->getParameter(SUMO_PARAM_ORIGID, "") << " origID='" << origID << "\n";
1627
#endif
1628
1629
bool origIDMatch = l->getParameter(SUMO_PARAM_ORIGID, l->getID()) == origID;
1630
if (origIDMatch && setLateralPos
1631
&& perpendicularDist > l->getWidth() / 2) {
1632
origIDMatch = false;
1633
}
1634
lane2utility.emplace(l, LaneUtility(
1635
dist2, perpendicularDist, off, angleDiff,
1636
origIDMatch,
1637
onRoute, sameEdge, prevEdge, nextEdge));
1638
// update scaling value
1639
maxDist = MAX2(maxDist, MIN2(dist, SUMO_const_laneWidth));
1640
1641
}
1642
}
1643
1644
// get the best lane given the previously computed values
1645
double bestValue = 0;
1646
MSLane* bestLane = nullptr;
1647
for (const auto& it : lane2utility) {
1648
MSLane* const l = it.first;
1649
const LaneUtility& u = it.second;
1650
double distN = u.dist > 999 ? -10 : 1. - (u.dist / maxDist);
1651
double angleDiffN = 1. - (u.angleDiff / 180.);
1652
double idN = u.ID ? 1 : 0;
1653
double onRouteN = u.onRoute ? 1 : 0;
1654
double sameEdgeN = u.sameEdge ? MIN2(currentRouteEdge->getLength() / MAX2(NUMERICAL_EPS, speed), (double)1.) : 0;
1655
// distance is more important than angle because the vehicle might be driving in the opposite direction
1656
// also, distance becomes increasingly more important with lower step lengths (because position errors from one step to the next can result in large acceleration/speed errors)
1657
double value = (distN * .5 / TS
1658
+ angleDiffN * 0.35 /*.5 */
1659
+ idN * 1
1660
+ onRouteN * 0.1
1661
+ sameEdgeN * 0.1);
1662
#ifdef DEBUG_MOVEXY
1663
std::cout << " x; l:" << l->getID() << " d:" << u.dist << " dN:" << distN << " aD:" << angleDiffN <<
1664
" ID:" << idN << " oRN:" << onRouteN << " sEN:" << sameEdgeN << " value:" << value << std::endl;
1665
#endif
1666
if (value > bestValue || bestLane == nullptr) {
1667
bestValue = value;
1668
if (u.dist == FAR_AWAY) {
1669
bestLane = nullptr;
1670
} else {
1671
bestLane = l;
1672
}
1673
}
1674
}
1675
// no best lane found, return
1676
if (bestLane == nullptr) {
1677
return false;
1678
}
1679
const LaneUtility& u = lane2utility.find(bestLane)->second;
1680
bestDistance = u.dist;
1681
*lane = bestLane;
1682
lanePos = MAX2(0., MIN2(double((*lane)->getLength() - NUMERICAL_EPS),
1683
bestLane->interpolateGeometryPosToLanePos(
1684
bestLane->getShape().nearest_offset_to_point25D(pos, false))));
1685
const MSEdge* prevEdge = u.prevEdge;
1686
if (u.onRoute) {
1687
ConstMSEdgeVector::const_iterator prevEdgePos = std::find(currentRoute.begin(), currentRoute.end(), prevEdge);
1688
routeOffset = (int)std::distance(currentRoute.begin(), prevEdgePos);
1689
//std::cout << SIMTIME << "moveToXYMap currLane=" << currentLane->getID() << " routeOffset=" << routeOffset << " edges=" << toString(edges) << " bestLane=" << bestLane->getID() << " prevEdge=" << prevEdge->getID() << "\n";
1690
} else {
1691
edges.push_back(u.prevEdge);
1692
/*
1693
if(bestLane->getEdge().getPurpose()!=MSEdge::EDGEFUNCTION_INTERNAL) {
1694
edges.push_back(&bestLane->getEdge());
1695
}
1696
*/
1697
if (u.nextEdge != nullptr) {
1698
edges.push_back(u.nextEdge);
1699
}
1700
routeOffset = 0;
1701
#ifdef DEBUG_MOVEXY_ANGLE
1702
std::cout << SIMTIME << " internal2: lane=" << bestLane->getID() << " prev=" << Named::getIDSecure(u.prevEdge) << " next=" << Named::getIDSecure(u.nextEdge) << "\n";
1703
#endif
1704
}
1705
return true;
1706
}
1707
1708
1709
bool
1710
Helper::findCloserLane(const MSEdge* edge, const Position& pos, SUMOVehicleClass vClass, double& bestDistance, MSLane** lane) {
1711
// TODO maybe there is a way to abort this early if the lane already found is good enough but simply
1712
// checking for bestDistance < POSITON_EPS gives ugly order dependencies (#7933), so think twice and profile first
1713
if (edge == nullptr) {
1714
return false;
1715
}
1716
bool newBest = false;
1717
for (MSLane* const candidateLane : edge->getLanes()) {
1718
if (!candidateLane->allowsVehicleClass(vClass)) {
1719
continue;
1720
}
1721
if (candidateLane->getShape().length() == 0) {
1722
// mapping to shapeless lanes is a bad idea
1723
continue;
1724
}
1725
double dist = candidateLane->getShape().distance2D(pos);
1726
dist = patchShapeDistance(candidateLane, pos, dist, false);
1727
#ifdef DEBUG_MOVEXY
1728
std::cout << " b at lane " << candidateLane->getID() << " dist:" << dist << " best:" << bestDistance << std::endl;
1729
#endif
1730
if (dist < bestDistance || (dist == bestDistance && candidateLane->getNumericalID() < (*lane)->getNumericalID())) {
1731
// is the new distance the best one? keep then...
1732
bestDistance = dist;
1733
*lane = candidateLane;
1734
newBest = true;
1735
}
1736
}
1737
if (edge->isInternal() && edge->getNumLanes() > 1) {
1738
// there is a parallel internal edge that isn't returned by getInternalFollowingEdge but is also usable for the same route
1739
for (const MSLane* const l : edge->getLanes()) {
1740
if (l->getIndex() == 0) {
1741
continue;
1742
}
1743
for (const MSLink* const link : l->getLinkCont()) {
1744
if (link->isInternalJunctionLink()) {
1745
if (findCloserLane(&link->getViaLane()->getEdge(), pos, vClass, bestDistance, lane)) {
1746
newBest = true;
1747
}
1748
}
1749
}
1750
}
1751
}
1752
return newBest;
1753
}
1754
1755
1756
bool
1757
Helper::moveToXYMap_matchingRoutePosition(const Position& pos, const std::string& origID,
1758
const ConstMSEdgeVector& currentRoute, int routeIndex,
1759
SUMOVehicleClass vClass, bool setLateralPos,
1760
double& bestDistance, MSLane** lane, double& lanePos, int& routeOffset) {
1761
#ifdef DEBUG_MOVEXY
1762
std::cout << SIMTIME << " moveToXYMap_matchingRoutePosition pos=" << pos << " vClass=" << toString(vClass) << "\n";
1763
#endif
1764
//std::cout << "moveToXYMap_matchingRoutePosition pos=" << pos << "\n";
1765
routeOffset = 0;
1766
// routes may be looped which makes routeOffset ambiguous. We first try to
1767
// find the closest upcoming edge on the route and then look for closer passed edges
1768
1769
// look forward along the route
1770
const MSEdge* prev = nullptr;
1771
for (int i = routeIndex; i < (int)currentRoute.size(); ++i) {
1772
const MSEdge* cand = currentRoute[i];
1773
while (prev != nullptr) {
1774
// check internal edge(s)
1775
const MSEdge* internalCand = prev->getInternalFollowingEdge(cand, vClass);
1776
#ifdef DEBUG_MOVEXY
1777
std::cout << SIMTIME << " prev=" << Named::getIDSecure(prev) << " cand=" << Named::getIDSecure(cand) << " internal=" << Named::getIDSecure(internalCand) << "\n";
1778
#endif
1779
if (findCloserLane(internalCand, pos, vClass, bestDistance, lane)) {
1780
routeOffset = i - 1;
1781
}
1782
prev = internalCand;
1783
}
1784
if (findCloserLane(cand, pos, vClass, bestDistance, lane)) {
1785
routeOffset = i;
1786
}
1787
prev = cand;
1788
}
1789
// look backward along the route
1790
const MSEdge* next = currentRoute[routeIndex];
1791
for (int i = routeIndex; i >= 0; --i) {
1792
const MSEdge* cand = currentRoute[i];
1793
//std::cout << " next=" << next->getID() << " cand=" << cand->getID() << " i=" << i << " routeIndex=" << routeIndex << "\n";
1794
prev = cand;
1795
while (prev != nullptr) {
1796
// check internal edge(s)
1797
const MSEdge* internalCand = prev->getInternalFollowingEdge(next, vClass);
1798
if (findCloserLane(internalCand, pos, vClass, bestDistance, lane)) {
1799
routeOffset = i;
1800
}
1801
prev = internalCand;
1802
}
1803
if (findCloserLane(cand, pos, vClass, bestDistance, lane)) {
1804
routeOffset = i;
1805
}
1806
next = cand;
1807
}
1808
if (vClass == SVC_PEDESTRIAN) {
1809
// consider all crossings and walkingareas along the route
1810
std::map<const MSJunction*, int> routeJunctions;
1811
for (int i = 0; i < (int)currentRoute.size() - 1; ++i) {
1812
routeJunctions[currentRoute[i]->getToJunction()] = i;
1813
}
1814
std::set<const Named*> into;
1815
PositionVector shape;
1816
shape.push_back(pos);
1817
collectObjectsInRange(libsumo::CMD_GET_LANE_VARIABLE, shape, 100, into);
1818
for (const Named* named : into) {
1819
const MSLane* cand = dynamic_cast<const MSLane*>(named);
1820
if ((cand->getEdge().isWalkingArea() || cand->getEdge().isCrossing())
1821
&& routeJunctions.count(cand->getEdge().getToJunction()) != 0) {
1822
if (findCloserLane(&cand->getEdge(), pos, vClass, bestDistance, lane)) {
1823
routeOffset = routeJunctions[cand->getEdge().getToJunction()];
1824
}
1825
}
1826
}
1827
}
1828
1829
assert(lane != nullptr);
1830
// quit if no solution was found, reporting a failure
1831
if (lane == nullptr) {
1832
#ifdef DEBUG_MOVEXY
1833
std::cout << " b failed - no best route lane" << std::endl;
1834
#endif
1835
return false;
1836
}
1837
1838
1839
// position may be inaccurate; let's check the given index, too
1840
// @note: this is enabled for non-internal lanes only, as otherwise the position information may ambiguous
1841
if (!(*lane)->getEdge().isInternal()) {
1842
const std::vector<MSLane*>& lanes = (*lane)->getEdge().getLanes();
1843
for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
1844
if ((*i)->getParameter(SUMO_PARAM_ORIGID, (*i)->getID()) == origID) {
1845
if (setLateralPos) {
1846
// vehicle might end up on top of another lane with a big
1847
// lateral offset to the lane with origID.
1848
const double dist = (*i)->getShape().distance2D(pos); // get distance
1849
if (dist < (*i)->getWidth() / 2) {
1850
*lane = *i;
1851
break;
1852
}
1853
} else {
1854
*lane = *i;
1855
break;
1856
}
1857
}
1858
}
1859
}
1860
// check position, stuff, we should have the best lane along the route
1861
lanePos = MAX2(0., MIN2(double((*lane)->getLength() - NUMERICAL_EPS),
1862
(*lane)->interpolateGeometryPosToLanePos(
1863
(*lane)->getShape().nearest_offset_to_point25D(pos, false))));
1864
//std::cout << SIMTIME << " moveToXYMap_matchingRoutePosition vehicle=" << veh.getID() << " currLane=" << veh.getLane()->getID() << " routeOffset=" << routeOffset << " edges=" << toString(edges) << " lane=" << (*lane)->getID() << "\n";
1865
#ifdef DEBUG_MOVEXY
1866
std::cout << " b ok lane " << (*lane)->getID() << " lanePos:" << lanePos << std::endl;
1867
#endif
1868
return true;
1869
}
1870
1871
1872
double
1873
Helper::patchShapeDistance(const MSLane* lane, const Position& pos, double dist, bool wasPerpendicular) {
1874
if (!lane->isWalkingArea() && (wasPerpendicular || lane->getShape().nearest_offset_to_point25D(pos, true) != GeomHelper::INVALID_OFFSET)) {
1875
dist = MAX2(0.0, dist - lane->getWidth() * 0.5);
1876
}
1877
return dist;
1878
}
1879
1880
1881
int
1882
Helper::readDistanceRequest(tcpip::Storage& data, TraCIRoadPosition& roadPos, Position& pos) {
1883
int distType = 0;
1884
StoHelp::readCompound(data, 2, "Retrieval of distance requires two parameter as compound.");
1885
const int posType = data.readUnsignedByte();
1886
switch (posType) {
1887
case libsumo::POSITION_ROADMAP: {
1888
roadPos.edgeID = data.readString();
1889
roadPos.pos = data.readDouble();
1890
roadPos.laneIndex = data.readUnsignedByte();
1891
break;
1892
}
1893
case libsumo::POSITION_2D:
1894
case libsumo::POSITION_3D: {
1895
pos.setx(data.readDouble());
1896
pos.sety(data.readDouble());
1897
if (posType == libsumo::POSITION_3D) {
1898
pos.setz(data.readDouble());
1899
}
1900
break;
1901
}
1902
default:
1903
throw TraCIException("Unknown position format used for distance request.");
1904
}
1905
distType = data.readUnsignedByte();
1906
if (distType != libsumo::REQUEST_DRIVINGDIST) {
1907
throw TraCIException("Only driving distance is supported.");
1908
}
1909
return posType;
1910
}
1911
1912
1913
Helper::SubscriptionWrapper::SubscriptionWrapper(VariableWrapper::SubscriptionHandler handler, SubscriptionResults& into, ContextSubscriptionResults& context)
1914
: VariableWrapper(handler), myResults(into), myContextResults(context), myActiveResults(&into) {
1915
1916
}
1917
1918
1919
void
1920
Helper::SubscriptionWrapper::setContext(const std::string* const refID) {
1921
myActiveResults = refID == nullptr ? &myResults : &myContextResults[*refID];
1922
}
1923
1924
1925
void
1926
Helper::SubscriptionWrapper::clear() {
1927
myActiveResults = &myResults;
1928
myResults.clear();
1929
myContextResults.clear();
1930
}
1931
1932
1933
bool
1934
Helper::SubscriptionWrapper::wrapConnectionVector(const std::string& objID, const int variable, const std::vector<TraCIConnection>& value) {
1935
auto sl = std::make_shared<TraCIConnectionVectorWrapped>();
1936
sl->value = value;
1937
(*myActiveResults)[objID][variable] = sl;
1938
return true;
1939
}
1940
1941
1942
bool
1943
Helper::SubscriptionWrapper::wrapDouble(const std::string& objID, const int variable, const double value) {
1944
(*myActiveResults)[objID][variable] = std::make_shared<TraCIDouble>(value);
1945
return true;
1946
}
1947
1948
1949
bool
1950
Helper::SubscriptionWrapper::wrapInt(const std::string& objID, const int variable, const int value) {
1951
(*myActiveResults)[objID][variable] = std::make_shared<TraCIInt>(value);
1952
return true;
1953
}
1954
1955
1956
bool
1957
Helper::SubscriptionWrapper::wrapString(const std::string& objID, const int variable, const std::string& value) {
1958
(*myActiveResults)[objID][variable] = std::make_shared<TraCIString>(value);
1959
return true;
1960
}
1961
1962
1963
bool
1964
Helper::SubscriptionWrapper::wrapStringList(const std::string& objID, const int variable, const std::vector<std::string>& value) {
1965
auto sl = std::make_shared<TraCIStringList>();
1966
sl->value = value;
1967
(*myActiveResults)[objID][variable] = sl;
1968
return true;
1969
}
1970
1971
1972
bool
1973
Helper::SubscriptionWrapper::wrapDoubleList(const std::string& objID, const int variable, const std::vector<double>& value) {
1974
auto sl = std::make_shared<TraCIDoubleList>();
1975
sl->value = value;
1976
(*myActiveResults)[objID][variable] = sl;
1977
return true;
1978
}
1979
1980
1981
bool
1982
Helper::SubscriptionWrapper::wrapPosition(const std::string& objID, const int variable, const TraCIPosition& value) {
1983
(*myActiveResults)[objID][variable] = std::make_shared<TraCIPosition>(value);
1984
return true;
1985
}
1986
1987
1988
bool
1989
Helper::SubscriptionWrapper::wrapPositionVector(const std::string& objID, const int variable, const TraCIPositionVector& value) {
1990
(*myActiveResults)[objID][variable] = std::make_shared<TraCIPositionVector>(value);
1991
return true;
1992
}
1993
1994
1995
bool
1996
Helper::SubscriptionWrapper::wrapColor(const std::string& objID, const int variable, const TraCIColor& value) {
1997
(*myActiveResults)[objID][variable] = std::make_shared<TraCIColor>(value);
1998
return true;
1999
}
2000
2001
2002
bool
2003
Helper::SubscriptionWrapper::wrapStringDoublePair(const std::string& objID, const int variable, const std::pair<std::string, double>& value) {
2004
(*myActiveResults)[objID][variable] = std::make_shared<TraCIRoadPosition>(value.first, value.second);
2005
return true;
2006
}
2007
2008
2009
bool
2010
Helper::SubscriptionWrapper::wrapStringDoublePairList(const std::string& objID, const int variable, const std::vector<std::pair<std::string, double> >& value) {
2011
auto sl = std::make_shared<TraCIStringDoublePairList>();
2012
sl->value = value;
2013
(*myActiveResults)[objID][variable] = sl;
2014
return true;
2015
}
2016
2017
2018
bool
2019
Helper::SubscriptionWrapper::wrapStringPair(const std::string& objID, const int variable, const std::pair<std::string, std::string>& value) {
2020
auto sl = std::make_shared<TraCIStringList>();
2021
sl->value.push_back(value.first);
2022
sl->value.push_back(value.second);
2023
(*myActiveResults)[objID][variable] = sl;
2024
return true;
2025
}
2026
2027
2028
bool
2029
Helper::SubscriptionWrapper::wrapIntPair(const std::string& objID, const int variable, const std::pair<int, int>& value) {
2030
auto sl = std::make_shared<TraCIIntList>();
2031
sl->value.push_back(value.first);
2032
sl->value.push_back(value.second);
2033
(*myActiveResults)[objID][variable] = sl;
2034
return true;
2035
}
2036
2037
2038
bool
2039
Helper::SubscriptionWrapper::wrapStage(const std::string& objID, const int variable, const TraCIStage& value) {
2040
(*myActiveResults)[objID][variable] = std::make_shared<TraCIStage>(value);
2041
return true;
2042
}
2043
2044
2045
bool
2046
Helper::SubscriptionWrapper::wrapReservationVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIReservation>& value) {
2047
auto sl = std::make_shared<TraCIReservationVectorWrapped>();
2048
sl->value = value;
2049
(*myActiveResults)[objID][variable] = sl;
2050
return true;
2051
}
2052
2053
2054
bool
2055
Helper::SubscriptionWrapper::wrapLogicVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCILogic>& value) {
2056
auto sl = std::make_shared<TraCILogicVectorWrapped>();
2057
sl->value = value;
2058
(*myActiveResults)[objID][variable] = sl;
2059
return true;
2060
}
2061
2062
2063
bool
2064
Helper::SubscriptionWrapper::wrapLinkVectorVector(const std::string& objID, const int variable, const std::vector<std::vector<libsumo::TraCILink> >& value) {
2065
auto sl = std::make_shared<TraCILinkVectorVectorWrapped>();
2066
sl->value = value;
2067
(*myActiveResults)[objID][variable] = sl;
2068
return true;
2069
}
2070
2071
2072
bool
2073
Helper::SubscriptionWrapper::wrapSignalConstraintVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCISignalConstraint>& value) {
2074
auto sl = std::make_shared<TraCISignalConstraintVectorWrapped>();
2075
sl->value = value;
2076
(*myActiveResults)[objID][variable] = sl;
2077
return true;
2078
}
2079
2080
2081
bool
2082
Helper::SubscriptionWrapper::wrapJunctionFoeVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIJunctionFoe>& value) {
2083
auto sl = std::make_shared<TraCIJunctionFoeVectorWrapped>();
2084
sl->value = value;
2085
(*myActiveResults)[objID][variable] = sl;
2086
return true;
2087
}
2088
2089
2090
bool
2091
Helper::SubscriptionWrapper::wrapNextStopDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCINextStopData>& value) {
2092
auto sl = std::make_shared<TraCINextStopDataVectorWrapped>();
2093
sl->value = value;
2094
(*myActiveResults)[objID][variable] = sl;
2095
return true;
2096
}
2097
2098
2099
bool
2100
Helper::SubscriptionWrapper::wrapVehicleDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIVehicleData>& value) {
2101
auto sl = std::make_shared<TraCIVehicleDataVectorWrapped>();
2102
sl->value = value;
2103
(*myActiveResults)[objID][variable] = sl;
2104
return true;
2105
}
2106
2107
2108
bool
2109
Helper::SubscriptionWrapper::wrapBestLanesDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCIBestLanesData>& value) {
2110
auto sl = std::make_shared<TraCIBestLanesDataVectorWrapped>();
2111
sl->value = value;
2112
(*myActiveResults)[objID][variable] = sl;
2113
return true;
2114
}
2115
2116
2117
bool
2118
Helper::SubscriptionWrapper::wrapNextTLSDataVector(const std::string& objID, const int variable, const std::vector<libsumo::TraCINextTLSData>& value) {
2119
auto sl = std::make_shared<TraCINextTLSDataVectorWrapped>();
2120
sl->value = value;
2121
(*myActiveResults)[objID][variable] = sl;
2122
return true;
2123
}
2124
2125
2126
void
2127
Helper::SubscriptionWrapper::empty(const std::string& objID) {
2128
(*myActiveResults)[objID]; // initiate the empty map to track the objectID for TRACI_ID_LIST context subscriptions
2129
}
2130
2131
2132
void
2133
Helper::VehicleStateListener::vehicleStateChanged(const SUMOVehicle* const vehicle, MSNet::VehicleState to, const std::string& /*info*/) {
2134
myVehicleStateChanges[to].push_back(vehicle->getID());
2135
}
2136
2137
2138
void
2139
Helper::TransportableStateListener::transportableStateChanged(const MSTransportable* const transportable, MSNet::TransportableState to, const std::string& /*info*/) {
2140
myTransportableStateChanges[to].push_back(transportable->getID());
2141
}
2142
2143
2144
}
2145
2146
2147
/****************************************************************************/
2148
2149