Line data Source code
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 Lane.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Mario Krumnow
17 : /// @author Jakob Erdmann
18 : /// @author Michael Behrisch
19 : /// @author Robert Hilbrich
20 : /// @author Leonhard Luecken
21 : /// @date 30.05.2012
22 : ///
23 : // C++ TraCI client API implementation
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <microsim/MSNet.h>
28 : #include <microsim/MSLane.h>
29 : #include <microsim/MSEdge.h>
30 : #include <microsim/MSVehicle.h>
31 : #include <microsim/MSLink.h>
32 : #include <microsim/MSInsertionControl.h>
33 : #include <utils/geom/GeomHelper.h>
34 : #include <libsumo/Helper.h>
35 : #include <libsumo/StorageHelper.h>
36 : #include <libsumo/TraCIConstants.h>
37 : #include "Lane.h"
38 :
39 :
40 : namespace libsumo {
41 : // ===========================================================================
42 : // static member initializations
43 : // ===========================================================================
44 : SubscriptionResults Lane::mySubscriptionResults;
45 : ContextSubscriptionResults Lane::myContextSubscriptionResults;
46 :
47 :
48 : // ===========================================================================
49 : // static member definitions
50 : // ===========================================================================
51 : std::vector<std::string>
52 268 : Lane::getIDList() {
53 268 : MSNet::getInstance(); // just to check that we actually have a network
54 : std::vector<std::string> ids;
55 266 : MSLane::insertIDs(ids);
56 266 : return ids;
57 0 : }
58 :
59 :
60 : int
61 20 : Lane::getIDCount() {
62 20 : return (int)getIDList().size();
63 : }
64 :
65 :
66 : std::string
67 24 : Lane::getEdgeID(const std::string& laneID) {
68 24 : return getLane(laneID)->getEdge().getID();
69 : }
70 :
71 :
72 : double
73 6942 : Lane::getLength(const std::string& laneID) {
74 6942 : return getLane(laneID)->getLength();
75 : }
76 :
77 :
78 : double
79 363 : Lane::getMaxSpeed(const std::string& laneID) {
80 363 : return getLane(laneID)->getSpeedLimit();
81 : }
82 :
83 : double
84 8 : Lane::getFriction(const std::string& laneID) {
85 8 : return getLane(laneID)->getFrictionCoefficient();
86 : }
87 :
88 : int
89 27 : Lane::getLinkNumber(const std::string& laneID) {
90 27 : return (int)getLane(laneID)->getLinkCont().size();
91 : }
92 :
93 :
94 : std::vector<TraCIConnection>
95 47 : Lane::getLinks(const std::string& laneID) {
96 : std::vector<TraCIConnection> v;
97 47 : const MSLane* const lane = getLane(laneID);
98 47 : const SUMOTime currTime = MSNet::getInstance()->getCurrentTimeStep();
99 139 : for (const MSLink* const link : lane->getLinkCont()) {
100 184 : const std::string approachedLane = link->getLane() != nullptr ? link->getLane()->getID() : "";
101 : const bool hasPrio = link->havePriority();
102 : const double speed = MIN2(lane->getSpeedLimit(), link->getLane()->getSpeedLimit());
103 184 : const bool isOpen = link->opened(currTime, speed, speed, SUMOVTypeParameter::getDefault().length,
104 92 : SUMOVTypeParameter::getDefault().impatience, SUMOVTypeParameter::getDefaultDecel(), 0);
105 92 : const bool hasFoe = link->hasApproachingFoe(currTime, currTime, 0, SUMOVTypeParameter::getDefaultDecel());
106 104 : const std::string approachedInternal = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
107 92 : const std::string state = SUMOXMLDefinitions::LinkStates.getString(link->getState());
108 92 : const std::string direction = SUMOXMLDefinitions::LinkDirections.getString(link->getDirection());
109 : const double length = link->getLength();
110 276 : v.push_back(TraCIConnection(approachedLane, hasPrio, isOpen, hasFoe, approachedInternal, state, direction, length));
111 : }
112 47 : return v;
113 0 : }
114 :
115 :
116 : std::vector<std::string>
117 82 : Lane::getAllowed(const std::string& laneID) {
118 82 : SVCPermissions permissions = getLane(laneID)->getPermissions();
119 82 : if (permissions == SVCAll) { // special case: write nothing
120 : permissions = 0;
121 : }
122 82 : return getVehicleClassNamesList(permissions);
123 : }
124 :
125 :
126 : std::vector<std::string>
127 67 : Lane::getDisallowed(const std::string& laneID) {
128 67 : return getVehicleClassNamesList(invertPermissions((getLane(laneID)->getPermissions()))); // negation yields disallowed
129 : }
130 :
131 :
132 : std::vector<std::string>
133 44 : Lane::getChangePermissions(const std::string& laneID, const int direction) {
134 44 : if (direction == libsumo::LANECHANGE_LEFT) {
135 26 : return getVehicleClassNamesList(getLane(laneID)->getChangeLeft());
136 18 : } else if (direction == libsumo::LANECHANGE_RIGHT) {
137 18 : return getVehicleClassNamesList(getLane(laneID)->getChangeRight());
138 : } else {
139 0 : throw TraCIException("Invalid direction for change permission (must be " + toString(libsumo::LANECHANGE_LEFT) + " or " + toString(libsumo::LANECHANGE_RIGHT));
140 : }
141 : }
142 :
143 :
144 : TraCIPositionVector
145 16040 : Lane::getShape(const std::string& laneID) {
146 : TraCIPositionVector pv;
147 16040 : const PositionVector& shp = getLane(laneID)->getShape();
148 48120 : for (PositionVector::const_iterator pi = shp.begin(); pi != shp.end(); ++pi) {
149 32080 : TraCIPosition p;
150 32080 : p.x = pi->x();
151 32080 : p.y = pi->y();
152 32080 : p.z = pi->z();
153 32080 : pv.value.push_back(p);
154 : }
155 16040 : return pv;
156 : }
157 :
158 :
159 : double
160 24 : Lane::getWidth(const std::string& laneID) {
161 24 : return getLane(laneID)->getWidth();
162 : }
163 :
164 :
165 : double
166 26 : Lane::getCO2Emission(const std::string& laneID) {
167 26 : return getLane(laneID)->getEmissions<PollutantsInterface::CO2>();
168 : }
169 :
170 :
171 : double
172 26 : Lane::getCOEmission(const std::string& laneID) {
173 26 : return getLane(laneID)->getEmissions<PollutantsInterface::CO>();
174 : }
175 :
176 :
177 : double
178 26 : Lane::getHCEmission(const std::string& laneID) {
179 26 : return getLane(laneID)->getEmissions<PollutantsInterface::HC>();
180 : }
181 :
182 :
183 : double
184 26 : Lane::getPMxEmission(const std::string& laneID) {
185 26 : return getLane(laneID)->getEmissions<PollutantsInterface::PM_X>();
186 : }
187 :
188 :
189 : double
190 26 : Lane::getNOxEmission(const std::string& laneID) {
191 26 : return getLane(laneID)->getEmissions<PollutantsInterface::NO_X>();
192 : }
193 :
194 : double
195 26 : Lane::getFuelConsumption(const std::string& laneID) {
196 26 : return getLane(laneID)->getEmissions<PollutantsInterface::FUEL>();
197 : }
198 :
199 :
200 : double
201 26 : Lane::getNoiseEmission(const std::string& laneID) {
202 26 : return getLane(laneID)->getHarmonoise_NoiseEmissions();
203 : }
204 :
205 :
206 : double
207 22 : Lane::getElectricityConsumption(const std::string& laneID) {
208 22 : return getLane(laneID)->getEmissions<PollutantsInterface::ELEC>();
209 : }
210 :
211 :
212 : double
213 26 : Lane::getLastStepMeanSpeed(const std::string& laneID) {
214 26 : return getLane(laneID)->getMeanSpeed();
215 : }
216 :
217 :
218 : double
219 26 : Lane::getLastStepOccupancy(const std::string& laneID) {
220 26 : return getLane(laneID)->getNettoOccupancy();
221 : }
222 :
223 :
224 : double
225 26 : Lane::getLastStepLength(const std::string& laneID) {
226 26 : const MSLane* lane = getLane(laneID);
227 : double length = 0;
228 26 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
229 44 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
230 18 : length += (*j)->getVehicleType().getLength();
231 : }
232 26 : if (vehs.size() > 0) {
233 18 : length = length / (double)vehs.size();
234 : }
235 26 : lane->releaseVehicles();
236 26 : return length;
237 : }
238 :
239 :
240 : double
241 23 : Lane::getWaitingTime(const std::string& laneID) {
242 23 : return getLane(laneID)->getWaitingSeconds();
243 : }
244 :
245 :
246 : double
247 26 : Lane::getTraveltime(const std::string& laneID) {
248 26 : const MSLane* lane = getLane(laneID);
249 26 : double meanSpeed = lane->getMeanSpeed();
250 26 : if (meanSpeed != 0) {
251 22 : return lane->getLength() / meanSpeed;
252 : } else {
253 : return 1000000.;
254 : }
255 : }
256 :
257 :
258 : int
259 1750 : Lane::getLastStepVehicleNumber(const std::string& laneID) {
260 1750 : return (int)getLane(laneID)->getVehicleNumber();
261 : }
262 :
263 :
264 : int
265 26 : Lane::getLastStepHaltingNumber(const std::string& laneID) {
266 26 : const MSLane* lane = getLane(laneID);
267 : int halting = 0;
268 26 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
269 44 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
270 18 : if ((*j)->getSpeed() < SUMO_const_haltingSpeed) {
271 4 : ++halting;
272 : }
273 : }
274 26 : lane->releaseVehicles();
275 26 : return halting;
276 : }
277 :
278 :
279 : std::vector<std::string>
280 644 : Lane::getLastStepVehicleIDs(const std::string& laneID) {
281 644 : const MSLane* lane = getLane(laneID);
282 : std::vector<std::string> vehIDs;
283 644 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
284 1046 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
285 402 : vehIDs.push_back((*j)->getID());
286 : }
287 644 : lane->releaseVehicles();
288 644 : return vehIDs;
289 0 : }
290 :
291 :
292 : std::vector<std::string>
293 31 : Lane::getFoes(const std::string& laneID, const std::string& toLaneID) {
294 31 : if (toLaneID == "") {
295 8 : return getInternalFoes(laneID);
296 : }
297 : std::vector<std::string> foeIDs;
298 23 : const MSLink* const link = getLane(laneID)->getLinkTo(getLane(toLaneID));
299 23 : if (link == nullptr) {
300 2 : throw TraCIException("No connection from lane '" + laneID + "' to lane '" + toLaneID + "'");
301 : }
302 100 : for (const MSLink* foe : link->getFoeLinks()) {
303 78 : foeIDs.push_back(foe->getLaneBefore()->getID());
304 : }
305 : return foeIDs;
306 23 : }
307 :
308 :
309 : std::vector<std::string>
310 10 : Lane::getInternalFoes(const std::string& laneID) {
311 10 : const MSLane* lane = getLane(laneID);
312 : const std::vector<const MSLane*>* foeLanes;
313 : std::vector<const MSLane*>::const_iterator it;
314 : std::vector<std::string> foeIDs;
315 :
316 8 : if ((lane->isInternal() || lane->isCrossing()) && lane->getLinkCont().size() > 0) {
317 7 : MSLink* link = lane->getLinkCont().front();
318 : foeLanes = &link->getFoeLanes();
319 :
320 102 : for (it = foeLanes->begin(); foeLanes->end() != it; ++it) {
321 95 : foeIDs.push_back((*it)->getID());
322 : }
323 : }
324 8 : return foeIDs;
325 0 : }
326 :
327 :
328 : const std::vector<std::string>
329 50 : Lane::getPendingVehicles(const std::string& laneID) {
330 50 : MSLane* const l = getLane(laneID); // validate laneID
331 : std::vector<std::string> vehIDs;
332 58 : for (const SUMOVehicle* veh : MSNet::getInstance()->getInsertionControl().getPendingVehicles()) {
333 8 : if (veh->getLane() == l) {
334 8 : vehIDs.push_back(veh->getID());
335 : }
336 : }
337 50 : return vehIDs;
338 0 : }
339 :
340 :
341 : double
342 81 : Lane::getAngle(const std::string& laneID, double relativePosition) {
343 : double angle;
344 81 : MSLane* lane = getLane(laneID);
345 81 : if (relativePosition == libsumo::INVALID_DOUBLE_VALUE) {
346 14 : Position start = lane->getShape().front();
347 14 : Position end = lane->getShape().back();
348 : angle = start.angleTo2D(end);
349 : } else {
350 67 : angle = lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(relativePosition));
351 : }
352 :
353 81 : return GeomHelper::naviDegree(angle);
354 : }
355 :
356 :
357 : std::string
358 98 : Lane::getBidiLane(const std::string& laneID) {
359 98 : const MSLane* bidi = getLane(laneID)->getBidiLane();
360 98 : return bidi == nullptr ? "" : bidi->getID();
361 : }
362 :
363 : void
364 8 : Lane::setAllowed(const std::string& laneID, std::string allowedClass) {
365 16 : setAllowed(laneID, std::vector<std::string>({allowedClass}));
366 8 : }
367 :
368 :
369 : void
370 35 : Lane::setAllowed(const std::string& laneID, std::vector<std::string> allowedClasses) {
371 35 : MSLane* const l = getLane(laneID);
372 35 : l->setPermissions(parseVehicleClasses(allowedClasses), MSLane::CHANGE_PERMISSIONS_PERMANENT);
373 35 : l->getEdge().rebuildAllowedLanes();
374 35 : }
375 :
376 :
377 : void
378 0 : Lane::setDisallowed(const std::string& laneID, std::string disallowedClasses) {
379 0 : setDisallowed(laneID, std::vector<std::string>({disallowedClasses}));
380 0 : }
381 :
382 :
383 : void
384 20 : Lane::setDisallowed(const std::string& laneID, std::vector<std::string> disallowedClasses) {
385 20 : MSLane* const l = getLane(laneID);
386 20 : l->setPermissions(invertPermissions(parseVehicleClasses(disallowedClasses)), MSLane::CHANGE_PERMISSIONS_PERMANENT); // negation yields allowed
387 20 : l->getEdge().rebuildAllowedLanes();
388 20 : }
389 :
390 :
391 : void
392 18 : Lane::setChangePermissions(const std::string& laneID, std::vector<std::string> allowedClasses, const int direction) {
393 18 : MSLane* const l = getLane(laneID);
394 18 : if (direction == libsumo::LANECHANGE_LEFT) {
395 9 : l->setChangeLeft(parseVehicleClasses(allowedClasses));
396 9 : } else if (direction == libsumo::LANECHANGE_RIGHT) {
397 9 : l->setChangeRight(parseVehicleClasses(allowedClasses));
398 : } else {
399 0 : throw TraCIException("Invalid direction for change permission (must be " + toString(libsumo::LANECHANGE_LEFT) + " or " + toString(libsumo::LANECHANGE_RIGHT));
400 : }
401 18 : }
402 :
403 :
404 : void
405 34 : Lane::setMaxSpeed(const std::string& laneID, double speed) {
406 34 : getLane(laneID)->setMaxSpeed(speed, false, true);
407 34 : }
408 :
409 :
410 : void
411 15 : Lane::setLength(const std::string& laneID, double length) {
412 15 : getLane(laneID)->setLength(length);
413 15 : }
414 :
415 :
416 : void
417 0 : Lane::setFriction(const std::string& laneID, double friction) {
418 0 : getLane(laneID)->setFrictionCoefficient(friction);
419 0 : }
420 :
421 :
422 : std::string
423 135 : Lane::getParameter(const std::string& laneID, const std::string& param) {
424 270 : return getLane(laneID)->getParameter(param, "");
425 : }
426 :
427 :
428 102 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Lane)
429 :
430 :
431 : void
432 99 : Lane::setParameter(const std::string& laneID, const std::string& key, const std::string& value) {
433 99 : getLane(laneID)->setParameter(key, value);
434 99 : }
435 :
436 :
437 8377 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Lane, LANE)
438 :
439 :
440 : MSLane*
441 43458 : Lane::getLane(const std::string& id) {
442 43458 : MSLane* const lane = MSLane::dictionary(id);
443 43458 : if (lane == nullptr) {
444 8 : throw TraCIException("Lane '" + id + "' is not known");
445 : }
446 43454 : return lane;
447 : }
448 :
449 :
450 : void
451 16398 : Lane::storeShape(const std::string& id, PositionVector& shape) {
452 16398 : shape = getLane(id)->getShape();
453 16398 : }
454 :
455 :
456 : std::shared_ptr<VariableWrapper>
457 269 : Lane::makeWrapper() {
458 269 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
459 : }
460 :
461 :
462 : bool
463 16434 : Lane::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
464 16434 : switch (variable) {
465 142 : case TRACI_ID_LIST:
466 142 : return wrapper->wrapStringList(objID, variable, getIDList());
467 16 : case ID_COUNT:
468 16 : return wrapper->wrapInt(objID, variable, getIDCount());
469 21 : case LANE_LINK_NUMBER:
470 21 : return wrapper->wrapInt(objID, variable, getLinkNumber(objID));
471 18 : case LANE_EDGE_ID:
472 36 : return wrapper->wrapString(objID, variable, getEdgeID(objID));
473 4734 : case VAR_LENGTH:
474 4734 : return wrapper->wrapDouble(objID, variable, getLength(objID));
475 349 : case VAR_MAXSPEED:
476 349 : return wrapper->wrapDouble(objID, variable, getMaxSpeed(objID));
477 8 : case VAR_FRICTION:
478 8 : return wrapper->wrapDouble(objID, variable, getFriction(objID));
479 54 : case LANE_ALLOWED:
480 54 : return wrapper->wrapStringList(objID, variable, getAllowed(objID));
481 45 : case LANE_DISALLOWED:
482 45 : return wrapper->wrapStringList(objID, variable, getDisallowed(objID));
483 28 : case LANE_CHANGES:
484 56 : return wrapper->wrapStringList(objID, variable, getChangePermissions(objID, StoHelp::readTypedByte(*paramData)));
485 20 : case VAR_CO2EMISSION:
486 20 : return wrapper->wrapDouble(objID, variable, getCO2Emission(objID));
487 20 : case VAR_COEMISSION:
488 20 : return wrapper->wrapDouble(objID, variable, getCOEmission(objID));
489 20 : case VAR_HCEMISSION:
490 20 : return wrapper->wrapDouble(objID, variable, getHCEmission(objID));
491 20 : case VAR_PMXEMISSION:
492 20 : return wrapper->wrapDouble(objID, variable, getPMxEmission(objID));
493 20 : case VAR_NOXEMISSION:
494 20 : return wrapper->wrapDouble(objID, variable, getNOxEmission(objID));
495 20 : case VAR_FUELCONSUMPTION:
496 20 : return wrapper->wrapDouble(objID, variable, getFuelConsumption(objID));
497 20 : case VAR_NOISEEMISSION:
498 20 : return wrapper->wrapDouble(objID, variable, getNoiseEmission(objID));
499 16 : case VAR_ELECTRICITYCONSUMPTION:
500 16 : return wrapper->wrapDouble(objID, variable, getElectricityConsumption(objID));
501 1744 : case LAST_STEP_VEHICLE_NUMBER:
502 1744 : return wrapper->wrapInt(objID, variable, getLastStepVehicleNumber(objID));
503 20 : case LAST_STEP_MEAN_SPEED:
504 20 : return wrapper->wrapDouble(objID, variable, getLastStepMeanSpeed(objID));
505 638 : case LAST_STEP_VEHICLE_ID_LIST:
506 638 : return wrapper->wrapStringList(objID, variable, getLastStepVehicleIDs(objID));
507 20 : case LAST_STEP_OCCUPANCY:
508 20 : return wrapper->wrapDouble(objID, variable, getLastStepOccupancy(objID));
509 20 : case LAST_STEP_VEHICLE_HALTING_NUMBER:
510 20 : return wrapper->wrapInt(objID, variable, getLastStepHaltingNumber(objID));
511 20 : case LAST_STEP_LENGTH:
512 20 : return wrapper->wrapDouble(objID, variable, getLastStepLength(objID));
513 17 : case VAR_WAITING_TIME:
514 17 : return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
515 20 : case VAR_CURRENT_TRAVELTIME:
516 20 : return wrapper->wrapDouble(objID, variable, getTraveltime(objID));
517 18 : case VAR_WIDTH:
518 18 : return wrapper->wrapDouble(objID, variable, getWidth(objID));
519 8026 : case VAR_SHAPE:
520 16052 : return wrapper->wrapPositionVector(objID, variable, getShape(objID));
521 32 : case VAR_PENDING_VEHICLES:
522 32 : return wrapper->wrapStringList(objID, variable, getPendingVehicles(objID));
523 55 : case VAR_ANGLE:
524 110 : return wrapper->wrapDouble(objID, variable, getAngle(objID, StoHelp::readTypedDouble(*paramData)));
525 62 : case VAR_BIDI:
526 124 : return wrapper->wrapString(objID, variable, getBidiLane(objID));
527 26 : case VAR_FOES:
528 49 : return wrapper->wrapStringList(objID, variable, getFoes(objID, StoHelp::readTypedString(*paramData)));
529 32 : case LANE_LINKS:
530 32 : return wrapper->wrapConnectionVector(objID, variable, getLinks(objID));
531 60 : case VAR_PARAMETER:
532 120 : return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
533 47 : case VAR_PARAMETER_WITH_KEY:
534 94 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
535 : default:
536 : return false;
537 : }
538 : }
539 : }
540 :
541 :
542 : /****************************************************************************/
|