LCOV - code coverage report
Current view: top level - src/guisim - GUIEdge.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 91 357 25.5 %
Date: 2024-04-28 15:39:05 Functions: 11 28 39.3 %

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

Generated by: LCOV version 1.14