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