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