LCOV - code coverage report
Current view: top level - src/guisim - GUIBusStop.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 65.6 % 154 101
Test Date: 2025-11-13 15:38:19 Functions: 69.2 % 13 9

            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    GUIBusStop.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Johannes Rummel
      19              : /// @date    Wed, 07.12.2005
      20              : ///
      21              : // A lane area vehicles can halt at (gui-version)
      22              : /****************************************************************************/
      23              : #include <config.h>
      24              : 
      25              : #include <string>
      26              : #include <utils/common/MsgHandler.h>
      27              : #include <utils/common/RGBColor.h>
      28              : #include <utils/geom/PositionVector.h>
      29              : #include <utils/geom/Boundary.h>
      30              : #include <utils/gui/div/GLHelper.h>
      31              : #include <utils/common/ToString.h>
      32              : #include <microsim/MSNet.h>
      33              : #include <microsim/MSLane.h>
      34              : #include <microsim/MSEdge.h>
      35              : #include <microsim/transportables/MSTransportable.h>
      36              : #include <microsim/transportables/MSStageDriving.h>
      37              : #include "GUINet.h"
      38              : #include "GUIEdge.h"
      39              : #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
      40              : #include <utils/gui/windows/GUIAppEnum.h>
      41              : #include <gui/GUIGlobals.h>
      42              : #include <utils/gui/div/GUIParameterTableWindow.h>
      43              : #include <gui/GUIApplicationWindow.h>
      44              : #include <microsim/logging/FunctionBinding.h>
      45              : #include <utils/gui/div/GUIGlobalSelection.h>
      46              : #include <foreign/fontstash/fontstash.h>
      47              : #include <utils/geom/GeomHelper.h>
      48              : #include <guisim/GUIBusStop.h>
      49              : #include <utils/common/MsgHandler.h>
      50              : #include <utils/gui/globjects/GLIncludes.h>
      51              : 
      52              : 
      53              : 
      54              : // ===========================================================================
      55              : // method definitions
      56              : // ===========================================================================
      57         1813 : GUIBusStop::GUIBusStop(const std::string& id, SumoXMLTag element, const std::vector<std::string>& lines, MSLane& lane,
      58              :                        double frompos, double topos, const std::string name, int personCapacity,
      59         1813 :                        double parkingLength, const RGBColor& color, double angle) :
      60              :     MSStoppingPlace(id, element, lines, lane, frompos, topos, name, personCapacity, parkingLength, color, angle),
      61              :     GUIGlObject_AbstractAdd(GLO_BUS_STOP, id, GUIIconSubSys::getIcon(GUIIcon::BUSSTOP)),
      62         3626 :     myEmptyColor(RGBColor::INVISIBLE) {
      63              :     // see MSVehicleControl defContainerType
      64         1813 :     myWidth = MAX2(1.0, ceil((double)myTransportableCapacity / getTransportablesAbreast()) * myTransportableDepth);
      65         1813 :     initShape(myFGShape, myFGShapeRotations, myFGShapeLengths, myFGSignPos, myFGSignRot);
      66         1813 :     if (myLane.getShape(true).size() > 0) {
      67         1813 :         initShape(myFGShape2, myFGShapeRotations2, myFGShapeLengths2, myFGSignPos2, myFGSignRot2, true);
      68              :     }
      69         1813 : }
      70              : 
      71              : 
      72         3624 : GUIBusStop::~GUIBusStop() {}
      73              : 
      74              : 
      75              : void
      76         3626 : GUIBusStop::initShape(PositionVector& fgShape,
      77              :                       std::vector<double>& fgShapeRotations, std::vector<double>& fgShapeLengths,
      78              :                       Position& fgSignPos, double& fgSignRot,
      79              :                       bool secondaryShape) {
      80         3626 :     const double offsetSign = MSGlobals::gLefthand ? -1 : 1;
      81         3626 :     const double lgf = myLane.getLengthGeometryFactor(secondaryShape);
      82         3626 :     fgShape = myLane.getShape(secondaryShape);
      83         7252 :     fgShape = fgShape.getSubpart(lgf * myBegPos, lgf * myEndPos);
      84         3626 :     fgShape.move2side(((myLane.getWidth() + myWidth) * 0.5 - 0.2) * offsetSign);
      85         3626 :     fgShapeRotations.reserve(fgShape.size() - 1);
      86         3626 :     fgShapeLengths.reserve(fgShape.size() - 1);
      87         3626 :     int e = (int) fgShape.size() - 1;
      88         8722 :     for (int i = 0; i < e; ++i) {
      89         5096 :         const Position& f = fgShape[i];
      90         5096 :         const Position& s = fgShape[i + 1];
      91         5096 :         fgShapeLengths.push_back(f.distanceTo(s));
      92         5096 :         fgShapeRotations.push_back((double) atan2((s.x() - f.x()), (f.y() - s.y())) * (double) 180.0 / (double) M_PI);
      93              :     }
      94              :     PositionVector tmp = fgShape;
      95         3626 :     tmp.move2side(myWidth / 2 * offsetSign);
      96         3626 :     fgSignPos = tmp.getLineCenter();
      97         3626 :     fgSignRot = 0;
      98         3626 :     if (tmp.length() != 0) {
      99         3626 :         fgSignRot = fgShape.rotationDegreeAtOffset(double((fgShape.length() / 2.)));
     100         3626 :         const double rotSign = MSGlobals::gLefthand ? -1 : 1;
     101         3626 :         fgSignRot -= 90 * rotSign;
     102              :     }
     103         3626 : }
     104              : 
     105              : 
     106              : void
     107         1810 : GUIBusStop::finishedLoading() {
     108         1810 :     MSStoppingPlace::finishedLoading();
     109         3620 :     if (hasParameter("emptyColor")) {
     110              :         try {
     111            0 :             myEmptyColor = RGBColor::parseColor(getParameter("emptyColor"));
     112            0 :         } catch (ProcessError& e) {
     113            0 :             WRITE_WARNINGF("Could not parse color '%' (%)", getParameter("emptyColor"), e.what());
     114            0 :         }
     115              :     }
     116         1810 : }
     117              : 
     118              : 
     119              : bool
     120          258 : GUIBusStop::addAccess(MSLane* const lane, const double startPos, const double endPos, double length, const MSStoppingPlace::AccessExit exit) {
     121          258 :     const bool added = MSStoppingPlace::addAccess(lane, startPos, endPos, length, exit);
     122          258 :     if (added) {
     123          256 :         myAccessCoords.push_back(lane->geometryPositionAtOffset((startPos + endPos) / 2.));
     124              :     }
     125          258 :     return added;
     126              : }
     127              : 
     128              : 
     129              : GUIGLObjectPopupMenu*
     130            0 : GUIBusStop::getPopUpMenu(GUIMainWindow& app,
     131              :                          GUISUMOAbstractView& parent) {
     132            0 :     GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
     133            0 :     buildPopupHeader(ret, app);
     134            0 :     buildCenterPopupEntry(ret);
     135            0 :     buildNameCopyPopupEntry(ret);
     136            0 :     buildSelectionPopupEntry(ret);
     137            0 :     buildShowParamsPopupEntry(ret);
     138            0 :     buildPositionCopyEntry(ret, app);
     139            0 :     return ret;
     140              : }
     141              : 
     142              : 
     143              : GUIParameterTableWindow*
     144            0 : GUIBusStop::getParameterWindow(GUIMainWindow& app,
     145              :                                GUISUMOAbstractView&) {
     146              :     GUIParameterTableWindow* ret =
     147            0 :         new GUIParameterTableWindow(app, *this);
     148              :     // add items
     149            0 :     ret->mkItem(TL("name"), false, getMyName());
     150            0 :     ret->mkItem(TL("begin position [m]"), false, myBegPos);
     151            0 :     ret->mkItem(TL("end position [m]"), false, myEndPos);
     152            0 :     ret->mkItem(TL("lines"), false, joinToString(myLines, " "));
     153            0 :     ret->mkItem(TL("parking length [m]"), false, (myEndPos - myBegPos) / myParkingFactor);
     154            0 :     const std::string transportable = (myElement == SUMO_TAG_CONTAINER_STOP ? "container" : "person");
     155            0 :     ret->mkItem((transportable + " capacity [#]").c_str(), false, myTransportableCapacity);
     156            0 :     ret->mkItem((transportable + " number [#]").c_str(), true, new FunctionBinding<GUIBusStop, int>(this, &MSStoppingPlace::getTransportableNumber));
     157            0 :     ret->mkItem(TL("stopped vehicles [#]"), true, new FunctionBinding<GUIBusStop, int>(this, &MSStoppingPlace::getStoppedVehicleNumber));
     158            0 :     ret->mkItem(TL("last free pos [m]"), true, new FunctionBinding<GUIBusStop, double>(this, &GUIBusStop::getCroppedLastFreePos));
     159              :     // rides-being-waited-on statistic
     160              :     std::map<std::string, int> stats;
     161            0 :     for (const MSTransportable* t : getTransportables()) {
     162            0 :         MSStageDriving* s = dynamic_cast<MSStageDriving*>(t->getCurrentStage());
     163            0 :         if (s != nullptr) {
     164            0 :             if (s->getIntendedVehicleID() != "") {
     165            0 :                 stats[s->getIntendedVehicleID()] += 1;
     166              :             } else {
     167            0 :                 stats[joinToString(s->getLines(), " ")] += 1;
     168              :             }
     169              :         }
     170            0 :     }
     171            0 :     if (stats.size() > 0) {
     172            0 :         ret->mkItem(TL("waiting for:"), false, "[#]");
     173            0 :         for (auto item : stats) {
     174            0 :             ret->mkItem(item.first.c_str(), false, toString(item.second));
     175              :         }
     176              :     }
     177              : 
     178              :     // close building
     179            0 :     ret->closeBuilding();
     180            0 :     return ret;
     181              : }
     182              : 
     183              : 
     184              : void
     185        60115 : GUIBusStop::drawGL(const GUIVisualizationSettings& s) const {
     186              :     // get colors
     187        60115 :     RGBColor color, colorSign;
     188        60115 :     if (myElement == SUMO_TAG_CONTAINER_STOP) {
     189         7304 :         color = s.colorSettings.containerStopColor;
     190         7304 :         colorSign = s.colorSettings.containerStopColorSign;
     191        52811 :     } else if (myElement == SUMO_TAG_TRAIN_STOP) {
     192         9254 :         color = s.colorSettings.trainStopColor;
     193         9254 :         colorSign = s.colorSettings.trainStopColorSign;
     194              :     } else {
     195        43557 :         color = s.colorSettings.busStopColor;
     196        43557 :         colorSign = s.colorSettings.busStopColorSign;
     197              :     }
     198              :     // set color
     199        60115 :     if (getColor() != RGBColor::INVISIBLE) {
     200           18 :         color = getColor();
     201              :     }
     202        60115 :     if (myEmptyColor != RGBColor::INVISIBLE && myEndPositions.empty() && myWaitingTransportables.empty()) {
     203            0 :         color = myEmptyColor;
     204              :     }
     205        60115 :     const bool s2 = s.secondaryShape;
     206        60115 :     const Position& signPos = s2 ? myFGSignPos2 : myFGSignPos;
     207              :     // recognize full transparency and simply don't draw
     208        60115 :     if (color.alpha() != 0) {
     209        60115 :         GLHelper::pushName(getGlID());
     210        60115 :         GLHelper::pushMatrix();
     211              :         // draw the area
     212        60115 :         glTranslated(0, 0, getType());
     213        60115 :         GLHelper::setColor(color);
     214        60115 :         const double exaggeration = getExaggeration(s);
     215              :         // only shrink the box but never enlarge it (only enlarge the sign)
     216        60115 :         if (s2) {
     217            0 :             GLHelper::drawBoxLines(myFGShape2, myFGShapeRotations2, myFGShapeLengths2, myWidth * 0.5 * MIN2(1.0, exaggeration), 0, 0);
     218              :         } else {
     219       120230 :             GLHelper::drawBoxLines(myFGShape, myFGShapeRotations, myFGShapeLengths, myWidth * 0.5 * MIN2(1.0, exaggeration), 0, 0);
     220              :         }
     221        60115 :         const double signRot = s2 ? myFGSignRot2 : myFGSignRot;
     222              :         // draw details unless zoomed out to far
     223        60115 :         if (s.drawDetail(10, exaggeration)) {
     224           11 :             GLHelper::pushMatrix();
     225              :             // draw the lines
     226           11 :             const double rotSign = MSGlobals::gLefthand ? 1 : -1;
     227           11 :             const double lineAngle = s.getTextAngle(signRot);
     228              :             // Iterate over every line
     229           11 :             RGBColor lineColor = color.changedBrightness(-51);
     230           11 :             const double textOffset = s.flippedTextAngle(rotSign * signRot) ? -1 : 1;
     231           11 :             const double textOffset2 = s.flippedTextAngle(rotSign * signRot) ? -1 : 0.3;
     232           11 :             for (int i = 0; i < (int)myLines.size(); ++i) {
     233              :                 // push a new matrix for every line
     234            0 :                 GLHelper::pushMatrix();
     235              :                 // traslate and rotate
     236            0 :                 glTranslated(signPos.x(), signPos.y(), 0);
     237            0 :                 glRotated(-lineAngle, 0, 0, 1);
     238              :                 // draw line
     239            0 :                 GLHelper::drawText(myLines[i].c_str(), Position(1.2, i * textOffset + textOffset2), .1, 1.f, lineColor, 0, FONS_ALIGN_LEFT);
     240              :                 // pop matrix for every line
     241            0 :                 GLHelper::popMatrix();
     242              :             }
     243           11 :             GLHelper::setColor(color);
     244           11 :             const Position accessOrigin = getCenterPos();
     245           11 :             for (std::vector<Position>::const_iterator i = myAccessCoords.begin(); i != myAccessCoords.end(); ++i) {
     246            0 :                 GLHelper::drawBoxLine(*i, RAD2DEG(accessOrigin.angleTo2D(*i)) - 90, accessOrigin.distanceTo2D(*i), .05);
     247              :             }
     248              :             // draw the sign
     249           11 :             glTranslated(signPos.x(), signPos.y(), 0);
     250              :             int noPoints = 9;
     251           11 :             if (s.scale * exaggeration > 25) {
     252            5 :                 noPoints = MIN2((int)(9.0 + (s.scale * exaggeration) / 10.0), 36);
     253              :             }
     254           11 :             glScaled(exaggeration, exaggeration, 1);
     255           11 :             GLHelper::drawFilledCircle((double) 1.1, noPoints);
     256           11 :             glTranslated(0, 0, .1);
     257           11 :             GLHelper::setColor(colorSign);
     258           11 :             GLHelper::drawFilledCircle((double) 0.9, noPoints);
     259           11 :             if (myElement == SUMO_TAG_CONTAINER_STOP) {
     260            0 :                 GLHelper::drawText("C", Position(), .1, 1.6, color, signRot);
     261           11 :             } else if (myElement == SUMO_TAG_TRAIN_STOP) {
     262            0 :                 GLHelper::drawText("T", Position(), .1, 1.6, color, signRot);
     263              :             } else {
     264           22 :                 GLHelper::drawText("H", Position(), .1, 1.6, color, signRot);
     265              :             }
     266           11 :             GLHelper::popMatrix();
     267              :         }
     268        60115 :         if (s.addFullName.show(this) && getMyName() != "") {
     269            0 :             GLHelper::drawTextSettings(s.addFullName, getMyName(), signPos, s.scale, s.getTextAngle(signRot), GLO_MAX - getType());
     270              :         }
     271        60115 :         GLHelper::popMatrix();
     272        60115 :         GLHelper::popName();
     273              :     }
     274        60115 :     drawName(signPos, s.scale, s.addName, s.angle);
     275        60115 : }
     276              : 
     277              : 
     278              : double
     279        60115 : GUIBusStop::getExaggeration(const GUIVisualizationSettings& s) const {
     280        60115 :     return s.addSize.getExaggeration(s, this);
     281              : }
     282              : 
     283              : 
     284              : Boundary
     285         1810 : GUIBusStop::getCenteringBoundary() const {
     286         1810 :     const PositionVector& shape = GUIGlobals::gSecondaryShape ? myFGShape2 : myFGShape;
     287         1810 :     Boundary b = shape.getBoxBoundary();
     288         1810 :     b.grow(myWidth);
     289         2066 :     for (const Position& p : myAccessCoords) {
     290          256 :         b.add(p);
     291              :     }
     292         1810 :     return b;
     293              : }
     294              : 
     295              : const std::string
     296            0 : GUIBusStop::getOptionalName() const {
     297            0 :     return myName;
     298              : }
     299              : 
     300              : double
     301            0 : GUIBusStop::getCroppedLastFreePos() const {
     302            0 :     return MAX2(0., getLastFreePos());
     303              : }
     304              : 
     305              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1