LCOV - code coverage report
Current view: top level - src/guisim - GUIEdge.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 25.3 % 360 91
Test Date: 2025-11-13 15:38:19 Functions: 39.3 % 28 11

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    GUIEdge.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Laura Bieker
      19              : /// @date    Sept 2002
      20              : ///
      21              : // A road/street connecting two junctions (gui-version)
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <vector>
      26              : #include <cmath>
      27              : #include <string>
      28              : #include <algorithm>
      29              : #include <utils/common/MsgHandler.h>
      30              : #include <utils/foxtools/fxheader.h>
      31              : #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
      32              : #include <utils/gui/windows/GUIMainWindow.h>
      33              : #include <utils/gui/windows/GUISUMOAbstractView.h>
      34              : #include <utils/geom/GeomHelper.h>
      35              : #include <utils/gui/div/GUIParameterTableWindow.h>
      36              : #include <utils/gui/div/GLHelper.h>
      37              : #include <utils/gui/div/GUIGlobalSelection.h>
      38              : #include <utils/gui/globjects/GLIncludes.h>
      39              : #include <gui/GUIGlobals.h>
      40              : #include <microsim/MSBaseVehicle.h>
      41              : #include <microsim/MSEdge.h>
      42              : #include <microsim/MSJunction.h>
      43              : #include <microsim/MSLaneChanger.h>
      44              : #include <microsim/MSInsertionControl.h>
      45              : #include <microsim/MSGlobals.h>
      46              : #include <microsim/logging/CastingFunctionBinding.h>
      47              : #include <microsim/logging/FunctionBinding.h>
      48              : #include <utils/gui/div/GUIDesigns.h>
      49              : #include <mesogui/GUIMEVehicleControl.h>
      50              : #include <mesogui/GUIMEVehicle.h>
      51              : #include <mesosim/MESegment.h>
      52              : #include <mesosim/MELoop.h>
      53              : #include <mesosim/MEVehicle.h>
      54              : 
      55              : #include "GUITriggeredRerouter.h"
      56              : #include "GUIEdge.h"
      57              : #include "GUIVehicle.h"
      58              : #include "GUINet.h"
      59              : #include "GUILane.h"
      60              : #include "GUIPerson.h"
      61              : #include "GUIContainer.h"
      62              : 
      63              : 
      64       334618 : GUIEdge::GUIEdge(const std::string& id, int numericalID,
      65              :                  const SumoXMLEdgeFunc function,
      66              :                  const std::string& streetName, const std::string& edgeType,
      67              :                  const std::string& routingType, int priority,
      68       334618 :                  double distance) :
      69              :     MSEdge(id, numericalID, function, streetName, edgeType, routingType, priority, distance),
      70              :     GUIGlObject(GLO_EDGE, id, GUIIconSubSys::getIcon(GUIIcon::EDGE)),
      71       334618 :     myLock(true)
      72       334618 : {}
      73              : 
      74              : 
      75       668506 : GUIEdge::~GUIEdge() {
      76              :     // just to quit cleanly on a failure
      77       334253 :     if (myLock.locked()) {
      78            0 :         myLock.unlock();
      79              :     }
      80       668506 : }
      81              : 
      82              : void
      83       330516 : GUIEdge::closeBuilding() {
      84       330516 :     MSEdge::closeBuilding();
      85              :     bool hasNormalSuccessors = false;
      86       330516 :     for (const MSEdge* out : getSuccessors()) {
      87       255580 :         if (!out->isTazConnector()) {
      88              :             hasNormalSuccessors = true;
      89              :             break;
      90              :         }
      91              :     }
      92       330516 :     myShowDeadEnd = (!isTazConnector() && !hasNormalSuccessors && getToJunction()->getOutgoing().size() > 0
      93        69850 :                      && (getPermissions() & ~SVC_PEDESTRIAN) != 0
      94       399225 :                      && (getToJunction()->getOutgoing().size() > 1 ||
      95         2432 :                          getToJunction()->getOutgoing().front()->getToJunction() != getFromJunction()));
      96       330516 : }
      97              : 
      98              : MSLane&
      99            0 : GUIEdge::getLane(int laneNo) {
     100              :     assert(laneNo < (int)myLanes->size());
     101            0 :     return *((*myLanes)[laneNo]);
     102              : }
     103              : 
     104              : 
     105              : std::vector<GUIGlID>
     106            0 : GUIEdge::getIDs(bool includeInternal) {
     107              :     std::vector<GUIGlID> ret;
     108            0 :     ret.reserve(MSEdge::myDict.size());
     109            0 :     for (MSEdge::DictType::const_iterator i = MSEdge::myDict.begin(); i != MSEdge::myDict.end(); ++i) {
     110            0 :         const GUIEdge* edge = dynamic_cast<const GUIEdge*>(i->second);
     111              :         assert(edge);
     112            0 :         if (includeInternal || edge->isNormal()) {
     113            0 :             ret.push_back(edge->getGlID());
     114              :         }
     115              :     }
     116            0 :     return ret;
     117            0 : }
     118              : 
     119              : 
     120              : double
     121            0 : GUIEdge::getTotalLength(bool includeInternal, bool eachLane) {
     122              :     double result = 0;
     123            0 :     for (MSEdge::DictType::const_iterator i = MSEdge::myDict.begin(); i != MSEdge::myDict.end(); ++i) {
     124            0 :         const MSEdge* edge = i->second;
     125            0 :         if (includeInternal || !edge->isInternal()) {
     126              :             // @note needs to be change once lanes may have different length
     127            0 :             result += edge->getLength() * (eachLane ? (double)edge->getLanes().size() : 1.);
     128              :         }
     129              :     }
     130            0 :     return result;
     131              : }
     132              : 
     133              : 
     134              : Boundary
     135            0 : GUIEdge::getBoundary() const {
     136            0 :     Boundary ret;
     137            0 :     const bool s2 = GUIGlobals::gSecondaryShape;
     138            0 :     if (!isTazConnector()) {
     139            0 :         for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     140            0 :             ret.add((*i)->getShape(s2).getBoxBoundary());
     141              :         }
     142              :     } else {
     143              :         // take the starting coordinates of all follower edges and the endpoints
     144              :         // of all successor edges
     145            0 :         for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
     146            0 :             const std::vector<MSLane*>& lanes = (*it)->getLanes();
     147            0 :             for (std::vector<MSLane*>::const_iterator it_lane = lanes.begin(); it_lane != lanes.end(); ++it_lane) {
     148            0 :                 ret.add((*it_lane)->getShape(s2).front());
     149              :             }
     150              :         }
     151            0 :         for (MSEdgeVector::const_iterator it = myPredecessors.begin(); it != myPredecessors.end(); ++it) {
     152            0 :             const std::vector<MSLane*>& lanes = (*it)->getLanes();
     153            0 :             for (std::vector<MSLane*>::const_iterator it_lane = lanes.begin(); it_lane != lanes.end(); ++it_lane) {
     154            0 :                 ret.add((*it_lane)->getShape(s2).back());
     155              :             }
     156              :         }
     157              :     }
     158            0 :     ret.grow(10);
     159            0 :     return ret;
     160              : }
     161              : 
     162              : 
     163              : GUIGLObjectPopupMenu*
     164            0 : GUIEdge::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
     165            0 :     GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
     166            0 :     buildPopupHeader(ret, app);
     167            0 :     buildCenterPopupEntry(ret);
     168            0 :     buildNameCopyPopupEntry(ret);
     169            0 :     buildSelectionPopupEntry(ret);
     170            0 :     if (MSGlobals::gUseMesoSim) {
     171            0 :         buildShowParamsPopupEntry(ret);
     172            0 :         buildShowTypeParamsPopupEntry(ret);
     173              :     }
     174            0 :     MESegment* segment = getSegmentAtPosition(parent.getPositionInformation());
     175            0 :     GUIDesigns::buildFXMenuCommand(ret, "segment: " + toString(segment->getIndex()), nullptr, nullptr, 0);
     176            0 :     buildPositionCopyEntry(ret, app);
     177            0 :     return ret;
     178              : }
     179              : 
     180              : 
     181              : GUIParameterTableWindow*
     182            0 : GUIEdge::getParameterWindow(GUIMainWindow& app,
     183              :                             GUISUMOAbstractView& parent) {
     184              :     GUIParameterTableWindow* ret = nullptr;
     185            0 :     ret = new GUIParameterTableWindow(app, *this);
     186              :     // add edge items
     187            0 :     ret->mkItem(TL("max speed [m/s]"), false, getAllowedSpeed());
     188            0 :     ret->mkItem(TL("length [m]"), false, (*myLanes)[0]->getLength());
     189            0 :     ret->mkItem(TL("street name"), false, getStreetName());
     190            0 :     ret->mkItem(TL("pending insertions [#]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getPendingEmits));
     191            0 :     ret->mkItem(TL("mean friction [%]"), true, new FunctionBinding<GUIEdge, double>(this, &MSEdge::getMeanFriction, 100.));
     192            0 :     ret->mkItem(TL("mean vehicle speed [m/s]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getMeanSpeed));
     193            0 :     ret->mkItem(TL("routing speed [m/s]"), true, new FunctionBinding<MSEdge, double>(this, &MSEdge::getRoutingSpeed));
     194            0 :     ret->mkItem(TL("time penalty [s]"), true, new FunctionBinding<MSEdge, double>(this, &MSEdge::getTimePenalty));
     195            0 :     ret->mkItem(TL("brutto occupancy [%]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getBruttoOccupancy, 100.));
     196            0 :     ret->mkItem(TL("edge flow [veh/h/m]"), true, new FunctionBinding<GUIEdge, double>(this, &GUIEdge::getFlow));
     197            0 :     ret->mkItem(TL("vehicles [#]"), true, new CastingFunctionBinding<GUIEdge, int, int>(this, &MSEdge::getVehicleNumber));
     198              :     // add segment items
     199            0 :     MESegment* segment = getSegmentAtPosition(parent.getPositionInformation());
     200            0 :     ret->mkItem(TL("segment index"), false, segment->getIndex());
     201            0 :     ret->mkItem(TL("segment queues"), false, segment->numQueues());
     202            0 :     ret->mkItem(TL("segment length [m]"), false, segment->getLength());
     203            0 :     ret->mkItem(TL("segment allowed speed [m/s]"), false, segment->getEdge().getSpeedLimit());
     204            0 :     ret->mkItem(TL("segment jam threshold [%]"), false, segment->getRelativeJamThreshold() * 100);
     205            0 :     ret->mkItem(TL("segment brutto occupancy [%]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getRelativeOccupancy, 100));
     206            0 :     ret->mkItem(TL("segment mean vehicle speed [m/s]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getMeanSpeed));
     207            0 :     ret->mkItem(TL("segment flow [veh/h/m]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getFlow));
     208            0 :     ret->mkItem(TL("segment vehicles [#]"), true, new CastingFunctionBinding<MESegment, int, int>(segment, &MESegment::getCarNumber));
     209            0 :     ret->mkItem(TL("segment leader leave time"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getEventTimeSeconds));
     210            0 :     ret->mkItem(TL("segment headway [s]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getLastHeadwaySeconds));
     211            0 :     ret->mkItem(TL("segment entry block time [s]"), true, new FunctionBinding<MESegment, double>(segment, &MESegment::getEntryBlockTimeSeconds));
     212              :     // lane params
     213            0 :     for (MSLane* lane : *myLanes) {
     214            0 :         for (const auto& kv : lane->getParametersMap()) {
     215            0 :             ret->mkItem(("laneParam " + toString(lane->getIndex()) + ":" + kv.first).c_str(), false, kv.second);
     216              :         }
     217              :     }
     218              :     // close building
     219            0 :     ret->closeBuilding();
     220            0 :     return ret;
     221              : }
     222              : 
     223              : GUIParameterTableWindow*
     224            0 : GUIEdge::getTypeParameterWindow(GUIMainWindow& app,
     225              :                                 GUISUMOAbstractView&) {
     226            0 :     GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
     227            0 :     const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
     228              :     // add items
     229            0 :     ret->mkItem(TL("Type Information:"), false, "");
     230            0 :     ret->mkItem(TL("type [id]"), false, getEdgeType());
     231            0 :     ret->mkItem(TL("routing type [id]"), false, getRoutingType());
     232            0 :     ret->mkItem(TL("tauff"), false, STEPS2TIME(edgeType.tauff));
     233            0 :     ret->mkItem(TL("taufj"), false, STEPS2TIME(edgeType.taufj));
     234            0 :     ret->mkItem(TL("taujf"), false, STEPS2TIME(edgeType.taujf));
     235            0 :     ret->mkItem(TL("taujj"), false, STEPS2TIME(edgeType.taujj));
     236            0 :     ret->mkItem(TL("jam threshold"), false, edgeType.jamThreshold);
     237            0 :     ret->mkItem(TL("junction control"), false, edgeType.junctionControl);
     238            0 :     ret->mkItem(TL("tls penalty"), false, edgeType.tlsPenalty);
     239            0 :     ret->mkItem(TL("tls flow penalty"), false, edgeType.tlsFlowPenalty);
     240            0 :     ret->mkItem(TL("minor penalty"), false, STEPS2TIME(edgeType.minorPenalty));
     241            0 :     ret->mkItem(TL("overtaking"), false, edgeType.overtaking);
     242              :     // close building
     243            0 :     ret->closeBuilding();
     244            0 :     return ret;
     245              : }
     246              : 
     247              : 
     248              : Boundary
     249            0 : GUIEdge::getCenteringBoundary() const {
     250            0 :     Boundary b = getBoundary();
     251              :     // ensure that vehicles and persons on the side are drawn even if the edge
     252              :     // is outside the view
     253            0 :     b.grow(10);
     254            0 :     return b;
     255              : }
     256              : 
     257              : const std::string
     258            0 : GUIEdge::getOptionalName() const {
     259            0 :     return myStreetName;
     260              : }
     261              : 
     262              : void
     263     29842892 : GUIEdge::drawGL(const GUIVisualizationSettings& s) const {
     264     29842892 :     if (s.hideConnectors && myFunction == SumoXMLEdgeFunc::CONNECTOR) {
     265              :         return;
     266              :     }
     267     29842892 :     GLHelper::pushName(getGlID());
     268              :     // draw the lanes
     269     29842892 :     if (MSGlobals::gUseMesoSim) {
     270      2471273 :         setColor(s);
     271              :     }
     272     66098885 :     for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
     273     36255993 :         static_cast<GUILane*>(*i)->drawGL(s);
     274              :     }
     275     29842892 :     if (MSGlobals::gUseMesoSim) {
     276      2471273 :         if (s.scale * s.vehicleSize.getExaggeration(s, nullptr) > s.vehicleSize.minSize) {
     277       424097 :             drawMesoVehicles(s);
     278              :         }
     279              :     }
     280     29842892 :     GLHelper::popName();
     281              :     // (optionally) draw the name and/or the street name
     282     29842892 :     GUILane* lane2 = dynamic_cast<GUILane*>((*myLanes).back());
     283     29842892 :     const GUIGlObject* selCheck = gSelected.isSelected(this) ? (GUIGlObject*)this : (GUIGlObject*)lane2;
     284     29842892 :     const bool drawEdgeName = s.edgeName.show(selCheck) && myFunction == SumoXMLEdgeFunc::NORMAL;
     285     29842892 :     const bool drawInternalEdgeName = s.internalEdgeName.show(selCheck) && myFunction == SumoXMLEdgeFunc::INTERNAL;
     286     29842892 :     const bool drawCwaEdgeName = s.cwaEdgeName.show(selCheck) && (myFunction == SumoXMLEdgeFunc::CROSSING || myFunction == SumoXMLEdgeFunc::WALKINGAREA);
     287     29842892 :     const bool drawStreetName = s.streetName.show(selCheck) && myStreetName != "";
     288     29842892 :     const bool drawEdgeValue = s.edgeValue.show(selCheck) && (myFunction == SumoXMLEdgeFunc::NORMAL
     289            0 :                                || (myFunction == SumoXMLEdgeFunc::INTERNAL && !s.drawJunctionShape)
     290            0 :                                || ((myFunction == SumoXMLEdgeFunc::CROSSING || myFunction == SumoXMLEdgeFunc::WALKINGAREA) && s.drawCrossingsAndWalkingareas));
     291     29842892 :     const bool drawEdgeScaleValue = s.edgeScaleValue.show(selCheck) && (myFunction == SumoXMLEdgeFunc::NORMAL
     292            0 :                                     || (myFunction == SumoXMLEdgeFunc::INTERNAL && !s.drawJunctionShape)
     293            0 :                                     || ((myFunction == SumoXMLEdgeFunc::CROSSING || myFunction == SumoXMLEdgeFunc::WALKINGAREA) && s.drawCrossingsAndWalkingareas));
     294     29842892 :     if (drawEdgeName || drawInternalEdgeName || drawCwaEdgeName || drawStreetName || drawEdgeValue || drawEdgeScaleValue) {
     295            0 :         GUILane* lane1 = dynamic_cast<GUILane*>((*myLanes)[0]);
     296            0 :         if (lane1 != nullptr && lane2 != nullptr) {
     297            0 :             const bool s2 = s.secondaryShape;
     298            0 :             const bool spreadSuperposed = s.spreadSuperposed && getBidiEdge() != nullptr;
     299            0 :             Position p = lane1->getShape(s2).positionAtOffset(lane1->getShape(s2).length() / (double) 2.);
     300            0 :             p.add(lane2->getShape(s2).positionAtOffset(lane2->getShape(s2).length() / (double) 2.));
     301              :             p.mul(.5);
     302            0 :             if (spreadSuperposed) {
     303              :                 // move name to the right of the edge and towards its beginning
     304            0 :                 const double dist = 0.6 * s.edgeName.scaledSize(s.scale);
     305            0 :                 const double shiftA = lane1->getShape(s2).rotationAtOffset(lane1->getShape(s2).length() / (double) 2.) - DEG2RAD(135);
     306            0 :                 Position shift(dist * cos(shiftA), dist * sin(shiftA));
     307              :                 p.add(shift);
     308              :             }
     309            0 :             double angle = s.getTextAngle(lane1->getShape(s2).rotationDegreeAtOffset(lane1->getShape(s2).length() / (double) 2.) + 90);
     310            0 :             if (drawEdgeName) {
     311            0 :                 drawName(p, s.scale, s.edgeName, angle, true);
     312            0 :             } else if (drawInternalEdgeName) {
     313            0 :                 drawName(p, s.scale, s.internalEdgeName, angle, true);
     314            0 :             } else if (drawCwaEdgeName) {
     315            0 :                 drawName(p, s.scale, s.cwaEdgeName, angle, true);
     316              :             }
     317            0 :             if (drawStreetName) {
     318            0 :                 GLHelper::drawTextSettings(s.streetName, getStreetName(), p, s.scale, angle);
     319              :             }
     320            0 :             if (drawEdgeValue) {
     321            0 :                 const int activeScheme = s.getLaneEdgeMode();
     322            0 :                 std::string value = "";
     323            0 :                 if (activeScheme == 31) {
     324              :                     // edge param, could be non-numerical
     325            0 :                     value = getParameter(s.edgeParam, "");
     326            0 :                 } else if (activeScheme == 32) {
     327              :                     // lane param, could be non-numerical
     328            0 :                     value = lane2->getParameter(s.laneParam, "");
     329              :                 } else {
     330              :                     // use numerical value value of leftmost lane to hopefully avoid sidewalks, bikelanes etc
     331              :                     const double doubleValue = (MSGlobals::gUseMesoSim
     332            0 :                                                 ? getColorValue(s, activeScheme)
     333            0 :                                                 : lane2->getColorValueWithFunctional(s, activeScheme));
     334            0 :                     const RGBColor color = (MSGlobals::gUseMesoSim ? s.edgeColorer : s.laneColorer).getScheme().getColor(doubleValue);
     335            0 :                     if (doubleValue != s.MISSING_DATA
     336            0 :                             && color.alpha() != 0
     337            0 :                             && (!s.edgeValueRainBow.hideMin || doubleValue > s.edgeValueRainBow.minThreshold)
     338            0 :                             && (!s.edgeValueRainBow.hideMax || doubleValue < s.edgeValueRainBow.maxThreshold)
     339              :                        ) {
     340            0 :                         value = toString(doubleValue);
     341              :                     }
     342              :                 }
     343            0 :                 if (value != "") {
     344            0 :                     if (drawEdgeName || drawInternalEdgeName || drawCwaEdgeName) {
     345            0 :                         const double dist = 0.4 * (s.edgeName.scaledSize(s.scale) + s.edgeValue.scaledSize(s.scale));
     346            0 :                         const double shiftA = lane1->getShape(s2).rotationAtOffset(lane1->getShape(s2).length() / (double) 2.) - DEG2RAD(90);
     347            0 :                         Position shift(dist * cos(shiftA), dist * sin(shiftA));
     348              :                         p.add(shift);
     349              :                     }
     350            0 :                     GLHelper::drawTextSettings(s.edgeValue, value, p, s.scale, angle);
     351              :                 }
     352              :             }
     353            0 :             if (drawEdgeScaleValue) {
     354            0 :                 const int activeScheme = s.getLaneEdgeScaleMode();
     355            0 :                 std::string value = "";
     356              :                 // use numerical value value of leftmost lane to hopefully avoid sidewalks, bikelanes etc
     357              :                 const double doubleValue = (MSGlobals::gUseMesoSim
     358            0 :                                             ? getScaleValue(s, activeScheme)
     359            0 :                                             : lane2->getScaleValue(s, activeScheme, s2));
     360            0 :                 if (doubleValue != s.MISSING_DATA) {
     361            0 :                     value = toString(doubleValue);
     362              :                 }
     363            0 :                 if (value != "") {
     364            0 :                     if (drawEdgeName || drawInternalEdgeName || drawCwaEdgeName || drawEdgeValue) {
     365            0 :                         const double dist = 0.4 * (s.edgeName.scaledSize(s.scale) + s.edgeScaleValue.scaledSize(s.scale));
     366            0 :                         const double shiftA = lane1->getShape(s2).rotationAtOffset(lane1->getShape(s2).length() / (double) 2.) - DEG2RAD(90);
     367            0 :                         Position shift(dist * cos(shiftA), dist * sin(shiftA));
     368              :                         p.add(shift);
     369              :                     }
     370            0 :                     GLHelper::drawTextSettings(s.edgeScaleValue, value, p, s.scale, angle);
     371              :                 }
     372              :             }
     373              :         }
     374              :     }
     375     29842892 :     if (s.scale * s.personSize.getExaggeration(s, nullptr) > s.personSize.minSize) {
     376      5928669 :         FXMutexLock locker(myLock);
     377      6912781 :         for (MSTransportable* t : myPersons) {
     378       984112 :             GUIPerson* person = dynamic_cast<GUIPerson*>(t);
     379              :             assert(person != 0);
     380       984112 :             person->drawGL(s);
     381              :         }
     382              :     }
     383     29842892 :     if (s.scale * s.containerSize.getExaggeration(s, nullptr) > s.containerSize.minSize) {
     384      5928669 :         FXMutexLock locker(myLock);
     385      5945066 :         for (MSTransportable* t : myContainers) {
     386        16397 :             GUIContainer* container = dynamic_cast<GUIContainer*>(t);
     387              :             assert(container != 0);
     388        16397 :             container->drawGL(s);
     389              :         }
     390              :     }
     391              : }
     392              : 
     393              : 
     394              : void
     395       424097 : GUIEdge::drawMesoVehicles(const GUIVisualizationSettings& s) const {
     396       424097 :     GUIMEVehicleControl* vehicleControl = GUINet::getGUIInstance()->getGUIMEVehicleControl();
     397       424097 :     const double now = SIMTIME;
     398       424097 :     if (vehicleControl != nullptr) {
     399              :         // draw the meso vehicles
     400       424097 :         vehicleControl->secureVehicles();
     401       424097 :         FXMutexLock locker(myLock);
     402              :         int laneIndex = 0;
     403      1085536 :         for (std::vector<MSLane*>::const_iterator msl = myLanes->begin(); msl != myLanes->end(); ++msl, ++laneIndex) {
     404       661439 :             GUILane* l = static_cast<GUILane*>(*msl);
     405              :             // go through the vehicles
     406              :             double segmentOffset = 0; // offset at start of current segment
     407       661439 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     408      1503643 :                     segment != nullptr; segment = segment->getNextSegment()) {
     409              :                 const double length = segment->getLength();
     410       842204 :                 if (laneIndex < segment->numQueues()) {
     411              :                     // make a copy so we don't have to worry about synchronization
     412       562960 :                     std::vector<MEVehicle*> queue = segment->getQueue(laneIndex);
     413       562960 :                     const int queueSize = (int)queue.size();
     414       562960 :                     double vehiclePosition = segmentOffset + length;
     415              :                     // draw vehicles beginning with the leader at the end of the segment
     416              :                     double latOff = 0.;
     417      1689335 :                     for (int i = 0; i < queueSize; ++i) {
     418      1126375 :                         const GUIMEVehicle* const veh = static_cast<GUIMEVehicle*>(queue[queueSize - i - 1]);
     419              :                         const double intendedLeave = MIN2(veh->getEventTimeSeconds(), veh->getBlockTimeSeconds());
     420              :                         const double entry = veh->getLastEntryTimeSeconds();
     421      1126375 :                         const double relPos = segmentOffset + length * (now - entry) / (intendedLeave - entry);
     422      1126375 :                         if (relPos < vehiclePosition) {
     423              :                             vehiclePosition = relPos;
     424              :                         }
     425      1168058 :                         while (vehiclePosition < segmentOffset) {
     426              :                             // if there is only a single queue for a
     427              :                             // multi-lane edge shift vehicles and start
     428              :                             // drawing again from the end of the segment
     429        41683 :                             vehiclePosition += length;
     430        41683 :                             latOff += 0.2;
     431              :                         }
     432              :                         /// @fixme use correct shape for geometryPositionAtOffset
     433              :                         const Position p = l->geometryPositionAtOffset(vehiclePosition, latOff);
     434      1126375 :                         const double angle = l->getShape(s.secondaryShape).rotationAtOffset(l->interpolateLanePosToGeometryPos(vehiclePosition));
     435      1126375 :                         veh->drawOnPos(s, p, angle);
     436      1126375 :                         vehiclePosition -= veh->getVehicleType().getLengthWithGap();
     437              :                     }
     438       562960 :                 }
     439       842204 :                 segmentOffset += length;
     440              :             }
     441       661439 :             GLHelper::popMatrix();
     442              :         }
     443       424097 :         vehicleControl->releaseVehicles();
     444              :     }
     445       424097 : }
     446              : 
     447              : 
     448              : 
     449              : double
     450            0 : GUIEdge::getAllowedSpeed() const {
     451            0 :     return (*myLanes)[0]->getSpeedLimit();
     452              : }
     453              : 
     454              : 
     455              : double
     456            0 : GUIEdge::getRelativeSpeed() const {
     457            0 :     return getMeanSpeed() / getAllowedSpeed();
     458              : }
     459              : 
     460              : 
     461              : void
     462      2471273 : GUIEdge::setColor(const GUIVisualizationSettings& s) const {
     463      2471273 :     myMesoColor = RGBColor(0, 0, 0); // default background color when using multiColor
     464      2471273 :     const GUIColorer& c = s.edgeColorer;
     465      2471273 :     if (!setFunctionalColor(c) && !setMultiColor(c)) {
     466      2471273 :         myMesoColor = c.getScheme().getColor(getColorValue(s, c.getActive()));
     467              :     }
     468      2471273 : }
     469              : 
     470              : 
     471              : bool
     472      2471273 : GUIEdge::setFunctionalColor(const GUIColorer& c) const {
     473              :     const int activeScheme = c.getActive();
     474              :     int activeMicroScheme = -1;
     475      2471273 :     switch (activeScheme) {
     476              :         case 0:
     477              :             activeMicroScheme = 0; // color uniform
     478              :             break;
     479            0 :         case 9:
     480              :             activeMicroScheme = 18; // color by angle
     481            0 :             break;
     482            0 :         case 17:
     483              :             activeMicroScheme = 30; // color by TAZ
     484            0 :             break;
     485              :         default:
     486              :             return false;
     487              :     }
     488      2471273 :     GUILane* guiLane = static_cast<GUILane*>(getLanes()[0]);
     489      2471273 :     return guiLane->setFunctionalColor(c, myMesoColor, activeMicroScheme);
     490              : }
     491              : 
     492              : 
     493              : bool
     494      2471273 : GUIEdge::setMultiColor(const GUIColorer& c) const {
     495              :     const int activeScheme = c.getActive();
     496              :     mySegmentColors.clear();
     497      2471273 :     switch (activeScheme) {
     498            0 :         case 10: // alternating segments
     499            0 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     500            0 :                     segment != nullptr; segment = segment->getNextSegment()) {
     501            0 :                 mySegmentColors.push_back(c.getScheme().getColor(segment->getIndex() % 2));
     502              :             }
     503              :             //std::cout << getID() << " scheme=" << c.getScheme().getName() << " schemeCols=" << c.getScheme().getColors().size() << " thresh=" << toString(c.getScheme().getThresholds()) << " segmentColors=" << mySegmentColors.size() << " [0]=" << mySegmentColors[0] << " [1]=" << mySegmentColors[1] <<  "\n";
     504              :             return true;
     505            0 :         case 11: // by segment jammed state
     506            0 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     507            0 :                     segment != nullptr; segment = segment->getNextSegment()) {
     508            0 :                 mySegmentColors.push_back(
     509            0 :                     c.getScheme().getColor(segment->getRelativeOccupancy() > segment->getRelativeJamThreshold() ? 2 :
     510            0 :                                            (segment->getRelativeOccupancy() * 2 < segment->getRelativeJamThreshold() ? 0 : 1)));
     511              :             }
     512              :             return true;
     513            0 :         case 12: // by segment occupancy
     514            0 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     515            0 :                     segment != nullptr; segment = segment->getNextSegment()) {
     516            0 :                 mySegmentColors.push_back(c.getScheme().getColor(segment->getRelativeOccupancy()));
     517              :             }
     518              :             return true;
     519            0 :         case 13: // by segment speed
     520            0 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     521            0 :                     segment != nullptr; segment = segment->getNextSegment()) {
     522            0 :                 mySegmentColors.push_back(c.getScheme().getColor(segment->getMeanSpeed()));
     523              :             }
     524              :             return true;
     525            0 :         case 14: // by segment flow
     526            0 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     527            0 :                     segment != nullptr; segment = segment->getNextSegment()) {
     528            0 :                 mySegmentColors.push_back(c.getScheme().getColor(3600 * segment->getCarNumber() * segment->getMeanSpeed() / segment->getLength()));
     529              :             }
     530              :             return true;
     531            0 :         case 15: // by segment relative speed
     532            0 :             for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
     533            0 :                     segment != nullptr; segment = segment->getNextSegment()) {
     534            0 :                 mySegmentColors.push_back(c.getScheme().getColor(segment->getMeanSpeed() / getAllowedSpeed()));
     535              :             }
     536              :             return true;
     537              :         default:
     538              :             return false;
     539              :     }
     540              : }
     541              : 
     542              : 
     543              : double
     544      2471273 : GUIEdge::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
     545      2471273 :     switch (activeScheme) {
     546            0 :         case 1:
     547            0 :             return gSelected.isSelected(getType(), getGlID());
     548            0 :         case 2:
     549            0 :             return (double)getFunction();
     550            0 :         case 3:
     551            0 :             return getAllowedSpeed();
     552            0 :         case 4:
     553            0 :             return getBruttoOccupancy();
     554            0 :         case 5:
     555            0 :             return getMeanSpeed();
     556            0 :         case 6:
     557            0 :             return getFlow();
     558            0 :         case 7:
     559            0 :             return getRelativeSpeed();
     560            0 :         case 8:
     561            0 :             return getRoutingSpeed();
     562            0 :         case 16:
     563            0 :             return getPendingEmits();
     564            0 :         case 18:
     565              :             // by numerical edge param value
     566              :             try {
     567            0 :                 return StringUtils::toDouble(getParameter(s.edgeParam, "0"));
     568            0 :             } catch (NumberFormatException&) {
     569              :                 try {
     570            0 :                     return StringUtils::toBool(getParameter(s.edgeParam, "0"));
     571            0 :                 } catch (BoolFormatException&) {
     572              :                     return -1;
     573            0 :                 }
     574            0 :             }
     575            0 :         case 19:
     576              :             // by edge data value
     577            0 :             return GUINet::getGUIInstance()->getEdgeData(this, s.edgeData);
     578              :     }
     579              :     return 0;
     580              : }
     581              : 
     582              : 
     583              : double
     584      3249512 : GUIEdge::getScaleValue(const GUIVisualizationSettings& s, int activeScheme) const {
     585      3249512 :     switch (activeScheme) {
     586            0 :         case 1:
     587            0 :             return gSelected.isSelected(getType(), getGlID());
     588            0 :         case 2:
     589            0 :             return getAllowedSpeed();
     590            0 :         case 3:
     591            0 :             return getBruttoOccupancy();
     592            0 :         case 4:
     593            0 :             return getMeanSpeed();
     594            0 :         case 5:
     595            0 :             return getFlow();
     596            0 :         case 6:
     597            0 :             return getRelativeSpeed();
     598            0 :         case 7:
     599            0 :             return getPendingEmits();
     600            0 :         case 8:
     601              :             // by edge data value
     602            0 :             return GUINet::getGUIInstance()->getEdgeData(this, s.edgeDataScaling);
     603              :     }
     604              :     return 0;
     605              : }
     606              : 
     607              : 
     608              : MESegment*
     609            0 : GUIEdge::getSegmentAtPosition(const Position& pos) {
     610            0 :     const PositionVector& shape = getLanes()[0]->getShape();
     611            0 :     const double lanePos = shape.nearest_offset_to_point2D(pos);
     612            0 :     return MSGlobals::gMesoNet->getSegmentForEdge(*this, lanePos);
     613              : }
     614              : 
     615              : 
     616              : 
     617              : void
     618            0 : GUIEdge::closeTraffic(const GUILane* lane) {
     619              :     const std::vector<MSLane*>& lanes = getLanes();
     620              :     const bool isClosed = lane->isClosed();
     621            0 :     for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
     622            0 :         GUILane* l = dynamic_cast<GUILane*>(*i);
     623            0 :         if (l->isClosed() == isClosed) {
     624            0 :             l->closeTraffic(false);
     625              :         }
     626              :     }
     627            0 :     rebuildAllowedLanes();
     628            0 : }
     629              : 
     630              : 
     631              : void
     632            0 : GUIEdge::addRerouter() {
     633              :     MSEdgeVector edges;
     634            0 :     edges.push_back(this);
     635            0 :     GUITriggeredRerouter* rr = new GUITriggeredRerouter(getID() + "_dynamic_rerouter", edges, 1, false, false, 0, "", Position::INVALID,
     636            0 :             std::numeric_limits<double>::max(), GUINet::getGUIInstance()->getVisualisationSpeedUp());
     637              : 
     638            0 :     MSTriggeredRerouter::RerouteInterval ri;
     639            0 :     ri.begin = MSNet::getInstance()->getCurrentTimeStep();
     640            0 :     ri.end = SUMOTime_MAX;
     641            0 :     ri.edgeProbs.add(&MSTriggeredRerouter::mySpecialDest_keepDestination, 1.);
     642            0 :     rr->myIntervals.push_back(ri);
     643              : 
     644              :     // trigger rerouting for vehicles already on this edge
     645              :     const std::vector<MSLane*>& lanes = getLanes();
     646            0 :     for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
     647            0 :         const MSLane::VehCont& vehicles = (*i)->getVehiclesSecure();
     648            0 :         for (MSLane::VehCont::const_iterator v = vehicles.begin(); v != vehicles.end(); ++v) {
     649            0 :             if ((*v)->getLane() == (*i)) {
     650            0 :                 rr->notifyEnter(**v, MSMoveReminder::NOTIFICATION_JUNCTION);
     651              :             } // else: this is the shadow during a continuous lane change
     652              :         }
     653            0 :         (*i)->releaseVehicles();
     654              :     }
     655            0 : }
     656              : 
     657              : 
     658              : bool
     659            0 : GUIEdge::isSelected() const {
     660            0 :     return gSelected.isSelected(GLO_EDGE, getGlID());
     661              : }
     662              : 
     663              : double
     664            0 : GUIEdge::getPendingEmits() const {
     665            0 :     return MSNet::getInstance()->getInsertionControl().getPendingEmits(getLanes()[0]);
     666              : }
     667              : 
     668              : double
     669            0 : GUIEdge::getClickPriority() const {
     670            0 :     if (!MSGlobals::gUseMesoSim) {
     671              :         // do not select edgse in meso mode
     672            0 :         return INVALID_PRIORITY;
     673              :     }
     674              :     return GLO_EDGE;
     675              : }
     676              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1