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 228 : Lane::getIDList() {
52 228 : MSNet::getInstance(); // just to check that we actually have a network
53 : std::vector<std::string> ids;
54 226 : MSLane::insertIDs(ids);
55 226 : return ids;
56 0 : }
57 :
58 :
59 : int
60 12 : Lane::getIDCount() {
61 12 : return (int)getIDList().size();
62 : }
63 :
64 :
65 : std::string
66 16 : Lane::getEdgeID(const std::string& laneID) {
67 16 : return getLane(laneID)->getEdge().getID();
68 : }
69 :
70 :
71 : double
72 7162 : Lane::getLength(const std::string& laneID) {
73 7162 : return getLane(laneID)->getLength();
74 : }
75 :
76 :
77 : double
78 355 : Lane::getMaxSpeed(const std::string& laneID) {
79 355 : 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 19 : Lane::getLinkNumber(const std::string& laneID) {
89 19 : return (int)getLane(laneID)->getLinkCont().size();
90 : }
91 :
92 :
93 : std::vector<TraCIConnection>
94 39 : Lane::getLinks(const std::string& laneID) {
95 : std::vector<TraCIConnection> v;
96 39 : const MSLane* const lane = getLane(laneID);
97 39 : const SUMOTime currTime = MSNet::getInstance()->getCurrentTimeStep();
98 123 : for (const MSLink* const link : lane->getLinkCont()) {
99 168 : 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 168 : const bool isOpen = link->opened(currTime, speed, speed, SUMOVTypeParameter::getDefault().length,
103 84 : SUMOVTypeParameter::getDefault().impatience, SUMOVTypeParameter::getDefaultDecel(), 0);
104 84 : const bool hasFoe = link->hasApproachingFoe(currTime, currTime, 0, SUMOVTypeParameter::getDefaultDecel());
105 96 : const std::string approachedInternal = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
106 84 : const std::string state = SUMOXMLDefinitions::LinkStates.getString(link->getState());
107 84 : const std::string direction = SUMOXMLDefinitions::LinkDirections.getString(link->getDirection());
108 : const double length = link->getLength();
109 252 : v.push_back(TraCIConnection(approachedLane, hasPrio, isOpen, hasFoe, approachedInternal, state, direction, length));
110 : }
111 39 : return v;
112 0 : }
113 :
114 :
115 : std::vector<std::string>
116 74 : Lane::getAllowed(const std::string& laneID) {
117 74 : SVCPermissions permissions = getLane(laneID)->getPermissions();
118 74 : if (permissions == SVCAll) { // special case: write nothing
119 : permissions = 0;
120 : }
121 74 : return getVehicleClassNamesList(permissions);
122 : }
123 :
124 :
125 : std::vector<std::string>
126 59 : Lane::getDisallowed(const std::string& laneID) {
127 59 : return getVehicleClassNamesList(invertPermissions((getLane(laneID)->getPermissions()))); // negation yields disallowed
128 : }
129 :
130 :
131 : std::vector<std::string>
132 36 : Lane::getChangePermissions(const std::string& laneID, const int direction) {
133 36 : if (direction == libsumo::LANECHANGE_LEFT) {
134 18 : return getVehicleClassNamesList(getLane(laneID)->getChangeLeft());
135 18 : } else if (direction == libsumo::LANECHANGE_RIGHT) {
136 18 : 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 16032 : Lane::getShape(const std::string& laneID) {
145 : TraCIPositionVector pv;
146 16032 : const PositionVector& shp = getLane(laneID)->getShape();
147 48096 : for (PositionVector::const_iterator pi = shp.begin(); pi != shp.end(); ++pi) {
148 32064 : TraCIPosition p;
149 32064 : p.x = pi->x();
150 32064 : p.y = pi->y();
151 32064 : p.z = pi->z();
152 32064 : pv.value.push_back(p);
153 : }
154 16032 : return pv;
155 : }
156 :
157 :
158 : double
159 16 : Lane::getWidth(const std::string& laneID) {
160 16 : return getLane(laneID)->getWidth();
161 : }
162 :
163 :
164 : double
165 18 : Lane::getCO2Emission(const std::string& laneID) {
166 18 : return getLane(laneID)->getEmissions<PollutantsInterface::CO2>();
167 : }
168 :
169 :
170 : double
171 18 : Lane::getCOEmission(const std::string& laneID) {
172 18 : return getLane(laneID)->getEmissions<PollutantsInterface::CO>();
173 : }
174 :
175 :
176 : double
177 18 : Lane::getHCEmission(const std::string& laneID) {
178 18 : return getLane(laneID)->getEmissions<PollutantsInterface::HC>();
179 : }
180 :
181 :
182 : double
183 18 : Lane::getPMxEmission(const std::string& laneID) {
184 18 : return getLane(laneID)->getEmissions<PollutantsInterface::PM_X>();
185 : }
186 :
187 :
188 : double
189 18 : Lane::getNOxEmission(const std::string& laneID) {
190 18 : return getLane(laneID)->getEmissions<PollutantsInterface::NO_X>();
191 : }
192 :
193 : double
194 18 : Lane::getFuelConsumption(const std::string& laneID) {
195 18 : return getLane(laneID)->getEmissions<PollutantsInterface::FUEL>();
196 : }
197 :
198 :
199 : double
200 18 : Lane::getNoiseEmission(const std::string& laneID) {
201 18 : return getLane(laneID)->getHarmonoise_NoiseEmissions();
202 : }
203 :
204 :
205 : double
206 14 : Lane::getElectricityConsumption(const std::string& laneID) {
207 14 : return getLane(laneID)->getEmissions<PollutantsInterface::ELEC>();
208 : }
209 :
210 :
211 : double
212 18 : Lane::getLastStepMeanSpeed(const std::string& laneID) {
213 18 : return getLane(laneID)->getMeanSpeed();
214 : }
215 :
216 :
217 : double
218 18 : Lane::getLastStepOccupancy(const std::string& laneID) {
219 18 : return getLane(laneID)->getNettoOccupancy();
220 : }
221 :
222 :
223 : double
224 18 : Lane::getLastStepLength(const std::string& laneID) {
225 18 : const MSLane* lane = getLane(laneID);
226 : double length = 0;
227 18 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
228 28 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
229 10 : length += (*j)->getVehicleType().getLength();
230 : }
231 18 : if (vehs.size() > 0) {
232 10 : length = length / (double)vehs.size();
233 : }
234 18 : lane->releaseVehicles();
235 18 : return length;
236 : }
237 :
238 :
239 : double
240 15 : Lane::getWaitingTime(const std::string& laneID) {
241 15 : return getLane(laneID)->getWaitingSeconds();
242 : }
243 :
244 :
245 : double
246 18 : Lane::getTraveltime(const std::string& laneID) {
247 18 : const MSLane* lane = getLane(laneID);
248 18 : double meanSpeed = lane->getMeanSpeed();
249 18 : if (meanSpeed != 0) {
250 18 : return lane->getLength() / meanSpeed;
251 : } else {
252 : return 1000000.;
253 : }
254 : }
255 :
256 :
257 : int
258 1742 : Lane::getLastStepVehicleNumber(const std::string& laneID) {
259 1742 : return (int)getLane(laneID)->getVehicleNumber();
260 : }
261 :
262 :
263 : int
264 18 : Lane::getLastStepHaltingNumber(const std::string& laneID) {
265 18 : const MSLane* lane = getLane(laneID);
266 : int halting = 0;
267 18 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
268 28 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
269 10 : if ((*j)->getSpeed() < SUMO_const_haltingSpeed) {
270 0 : ++halting;
271 : }
272 : }
273 18 : lane->releaseVehicles();
274 18 : return halting;
275 : }
276 :
277 :
278 : std::vector<std::string>
279 636 : Lane::getLastStepVehicleIDs(const std::string& laneID) {
280 636 : const MSLane* lane = getLane(laneID);
281 : std::vector<std::string> vehIDs;
282 636 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
283 1030 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
284 394 : vehIDs.push_back((*j)->getID());
285 : }
286 636 : lane->releaseVehicles();
287 636 : return vehIDs;
288 0 : }
289 :
290 :
291 : std::vector<std::string>
292 15 : Lane::getFoes(const std::string& laneID, const std::string& toLaneID) {
293 : std::vector<std::string> foeIDs;
294 15 : const MSLink* const link = getLane(laneID)->getLinkTo(getLane(toLaneID));
295 15 : if (link == nullptr) {
296 2 : throw TraCIException("No connection from lane '" + laneID + "' to lane '" + toLaneID + "'");
297 : }
298 84 : for (const MSLink* foe : link->getFoeLinks()) {
299 70 : foeIDs.push_back(foe->getLaneBefore()->getID());
300 : }
301 14 : return foeIDs;
302 1 : }
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 : std::vector<std::string> foeIDs;
311 :
312 8 : if ((lane->isInternal() || lane->isCrossing()) && lane->getLinkCont().size() > 0) {
313 7 : MSLink* link = lane->getLinkCont().front();
314 : foeLanes = &link->getFoeLanes();
315 :
316 102 : for (it = foeLanes->begin(); foeLanes->end() != it; ++it) {
317 95 : foeIDs.push_back((*it)->getID());
318 : }
319 : }
320 8 : return foeIDs;
321 0 : }
322 :
323 :
324 : const std::vector<std::string>
325 42 : Lane::getPendingVehicles(const std::string& laneID) {
326 42 : MSLane* const l = getLane(laneID); // validate laneID
327 : std::vector<std::string> vehIDs;
328 50 : for (const SUMOVehicle* veh : MSNet::getInstance()->getInsertionControl().getPendingVehicles()) {
329 8 : if (veh->getLane() == l) {
330 8 : vehIDs.push_back(veh->getID());
331 : }
332 : }
333 42 : return vehIDs;
334 0 : }
335 :
336 :
337 : double
338 29 : Lane::getAngle(const std::string& laneID, double relativePosition) {
339 : double angle;
340 29 : MSLane* lane = getLane(laneID);
341 29 : 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 15 : angle = lane->getShape().rotationAtOffset(lane->interpolateLanePosToGeometryPos(relativePosition));
347 : }
348 :
349 29 : return GeomHelper::naviDegree(angle);
350 : }
351 :
352 :
353 : std::string
354 90 : Lane::getBidiLane(const std::string& laneID) {
355 90 : const MSLane* bidi = getLane(laneID)->getBidiLane();
356 90 : return bidi == nullptr ? "" : bidi->getID();
357 : }
358 :
359 : void
360 8 : Lane::setAllowed(const std::string& laneID, std::string allowedClass) {
361 16 : setAllowed(laneID, std::vector<std::string>({allowedClass}));
362 8 : }
363 :
364 :
365 : void
366 35 : Lane::setAllowed(const std::string& laneID, std::vector<std::string> allowedClasses) {
367 35 : MSLane* const l = getLane(laneID);
368 35 : l->setPermissions(parseVehicleClasses(allowedClasses), MSLane::CHANGE_PERMISSIONS_PERMANENT);
369 35 : l->getEdge().rebuildAllowedLanes();
370 35 : }
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();
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 32 : Lane::setMaxSpeed(const std::string& laneID, double speed) {
402 32 : getLane(laneID)->setMaxSpeed(speed, false, true);
403 32 : }
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 89 : Lane::getParameter(const std::string& laneID, const std::string& param) {
420 178 : return getLane(laneID)->getParameter(param, "");
421 : }
422 :
423 :
424 46 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Lane)
425 :
426 :
427 : void
428 54 : Lane::setParameter(const std::string& laneID, const std::string& key, const std::string& value) {
429 54 : getLane(laneID)->setParameter(key, value);
430 54 : }
431 :
432 :
433 8318 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Lane, LANE)
434 :
435 :
436 : MSLane*
437 43256 : Lane::getLane(const std::string& id) {
438 43256 : MSLane* const lane = MSLane::dictionary(id);
439 43256 : if (lane == nullptr) {
440 8 : throw TraCIException("Lane '" + id + "' is not known");
441 : }
442 43252 : return lane;
443 : }
444 :
445 :
446 : void
447 16361 : Lane::storeShape(const std::string& id, PositionVector& shape) {
448 16361 : shape = getLane(id)->getShape();
449 16361 : }
450 :
451 :
452 : std::shared_ptr<VariableWrapper>
453 266 : Lane::makeWrapper() {
454 266 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
455 : }
456 :
457 :
458 : bool
459 16064 : Lane::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
460 16064 : switch (variable) {
461 110 : case TRACI_ID_LIST:
462 110 : return wrapper->wrapStringList(objID, variable, getIDList());
463 8 : case ID_COUNT:
464 8 : return wrapper->wrapInt(objID, variable, getIDCount());
465 13 : case LANE_LINK_NUMBER:
466 13 : return wrapper->wrapInt(objID, variable, getLinkNumber(objID));
467 10 : case LANE_EDGE_ID:
468 20 : return wrapper->wrapString(objID, variable, getEdgeID(objID));
469 4726 : case VAR_LENGTH:
470 4726 : return wrapper->wrapDouble(objID, variable, getLength(objID));
471 341 : case VAR_MAXSPEED:
472 341 : return wrapper->wrapDouble(objID, variable, getMaxSpeed(objID));
473 0 : case VAR_FRICTION:
474 0 : return wrapper->wrapDouble(objID, variable, getFriction(objID));
475 46 : case LANE_ALLOWED:
476 46 : return wrapper->wrapStringList(objID, variable, getAllowed(objID));
477 37 : case LANE_DISALLOWED:
478 37 : return wrapper->wrapStringList(objID, variable, getDisallowed(objID));
479 20 : case LANE_CHANGES:
480 20 : paramData->readUnsignedByte();
481 20 : return wrapper->wrapStringList(objID, variable, getChangePermissions(objID, paramData->readByte()));
482 12 : case VAR_CO2EMISSION:
483 12 : return wrapper->wrapDouble(objID, variable, getCO2Emission(objID));
484 12 : case VAR_COEMISSION:
485 12 : return wrapper->wrapDouble(objID, variable, getCOEmission(objID));
486 12 : case VAR_HCEMISSION:
487 12 : return wrapper->wrapDouble(objID, variable, getHCEmission(objID));
488 12 : case VAR_PMXEMISSION:
489 12 : return wrapper->wrapDouble(objID, variable, getPMxEmission(objID));
490 12 : case VAR_NOXEMISSION:
491 12 : return wrapper->wrapDouble(objID, variable, getNOxEmission(objID));
492 12 : case VAR_FUELCONSUMPTION:
493 12 : return wrapper->wrapDouble(objID, variable, getFuelConsumption(objID));
494 12 : case VAR_NOISEEMISSION:
495 12 : return wrapper->wrapDouble(objID, variable, getNoiseEmission(objID));
496 8 : case VAR_ELECTRICITYCONSUMPTION:
497 8 : return wrapper->wrapDouble(objID, variable, getElectricityConsumption(objID));
498 1736 : case LAST_STEP_VEHICLE_NUMBER:
499 1736 : return wrapper->wrapInt(objID, variable, getLastStepVehicleNumber(objID));
500 12 : case LAST_STEP_MEAN_SPEED:
501 12 : return wrapper->wrapDouble(objID, variable, getLastStepMeanSpeed(objID));
502 630 : case LAST_STEP_VEHICLE_ID_LIST:
503 630 : return wrapper->wrapStringList(objID, variable, getLastStepVehicleIDs(objID));
504 12 : case LAST_STEP_OCCUPANCY:
505 12 : return wrapper->wrapDouble(objID, variable, getLastStepOccupancy(objID));
506 12 : case LAST_STEP_VEHICLE_HALTING_NUMBER:
507 12 : return wrapper->wrapInt(objID, variable, getLastStepHaltingNumber(objID));
508 12 : case LAST_STEP_LENGTH:
509 12 : return wrapper->wrapDouble(objID, variable, getLastStepLength(objID));
510 9 : case VAR_WAITING_TIME:
511 9 : return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
512 12 : case VAR_CURRENT_TRAVELTIME:
513 12 : return wrapper->wrapDouble(objID, variable, getTraveltime(objID));
514 10 : case VAR_WIDTH:
515 10 : return wrapper->wrapDouble(objID, variable, getWidth(objID));
516 8018 : case VAR_SHAPE:
517 16036 : return wrapper->wrapPositionVector(objID, variable, getShape(objID));
518 24 : case VAR_PENDING_VEHICLES:
519 24 : return wrapper->wrapStringList(objID, variable, getPendingVehicles(objID));
520 11 : case VAR_ANGLE:
521 11 : paramData->readUnsignedByte();
522 11 : return wrapper->wrapDouble(objID, variable, getAngle(objID, paramData->readDouble()));
523 54 : case VAR_BIDI:
524 108 : return wrapper->wrapString(objID, variable, getBidiLane(objID));
525 46 : case libsumo::VAR_PARAMETER:
526 46 : paramData->readUnsignedByte();
527 92 : return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
528 19 : case libsumo::VAR_PARAMETER_WITH_KEY:
529 19 : paramData->readUnsignedByte();
530 38 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
531 : default:
532 : return false;
533 : }
534 : }
535 : }
536 :
537 :
538 : /****************************************************************************/
|