Path: blob/main/src/netedit/elements/demand/GNEStopPlan.cpp
185790 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GNEStopPlan.cpp14/// @author Pablo Alvarez Lopez15/// @date Oct 202316///17// Representation of Stops in netedit18/****************************************************************************/1920#include <netedit/changes/GNEChange_Attribute.h>21#include <netedit/changes/GNEChange_ToggleAttribute.h>22#include <netedit/GNENet.h>23#include <netedit/GNEUndoList.h>24#include <utils/gui/div/GLHelper.h>25#include <utils/gui/images/GUITextureSubSys.h>2627#include "GNEStopPlan.h"2829// ===========================================================================30// member method definitions31// ===========================================================================32#ifdef _MSC_VER33#pragma warning(push)34#pragma warning(disable: 4355) // mask warning about "this" in initializers35#endif36GNEStopPlan::GNEStopPlan(SumoXMLTag tag, GNENet* net) :37GNEDemandElement(net, tag),38GNEDemandElementPlan(this, -1, -1) {39}404142GNEStopPlan::GNEStopPlan(SumoXMLTag tag, GNEDemandElement* personParent, const GNEPlanParents& planParameters,43const double endPos, const SUMOTime duration, const SUMOTime until, const std::string& actType,44const bool friendlyPos, const int parameterSet) :45GNEDemandElement(personParent, tag),46GNEDemandElementPlan(this, -1, endPos),47myDuration(duration),48myUntil(until),49myActType(actType),50myFriendlyPos(friendlyPos),51myParametersSet(parameterSet) {52// set parents53setParents<GNEJunction*>(planParameters.getJunctions());54setParents<GNEEdge*>(planParameters.getEdges());55setParents<GNEAdditional*>(planParameters.getAdditionalElements());56setParents<GNEDemandElement*>(planParameters.getDemandElements(personParent));57// update centering boundary without updating grid58updatePlanCenteringBoundary(false);59}60#ifdef _MSC_VER61#pragma warning(pop)62#endif636465GNEStopPlan::~GNEStopPlan() {}666768GNEMoveElement*69GNEStopPlan::getMoveElement() const {70return myMoveElementPlan;71}727374Parameterised*75GNEStopPlan::getParameters() {76return nullptr;77}787980const Parameterised*81GNEStopPlan::getParameters() const {82return nullptr;83}848586void87GNEStopPlan::writeDemandElement(OutputDevice& device) const {88device.openTag(SUMO_TAG_STOP);89writeLocationAttributes(device);90// write stop attributes91if (isAttributeEnabled(SUMO_ATTR_DURATION)) {92device.writeAttr(SUMO_ATTR_DURATION, getAttribute(SUMO_ATTR_DURATION));93}94if (isAttributeEnabled(SUMO_ATTR_UNTIL)) {95device.writeAttr(SUMO_ATTR_UNTIL, getAttribute(SUMO_ATTR_UNTIL));96}97if (myActType.size() > 0) {98device.writeAttr(SUMO_ATTR_ACTTYPE, myActType);99}100if (myFriendlyPos) {101device.writeAttr(SUMO_ATTR_FRIENDLY_POS, myFriendlyPos);102}103device.closeTag();104}105106107GNEDemandElement::Problem108GNEStopPlan::isDemandElementValid() const {109return isPlanPersonValid();110}111112113std::string114GNEStopPlan::getDemandElementProblem() const {115return getPersonPlanProblem();116}117118119void120GNEStopPlan::fixDemandElementProblem() {121// currently the only solution is removing stop122}123124125SUMOVehicleClass126GNEStopPlan::getVClass() const {127return SVC_PASSENGER;128}129130131const RGBColor&132GNEStopPlan::getColor() const {133return myNet->getViewNet()->getVisualisationSettings().colorSettings.stopPersonColor;134}135136137void138GNEStopPlan::updateGeometry() {139const auto& viewSettings = myNet->getViewNet()->getVisualisationSettings();140PositionVector shape;141// update geometry depending of parent142if (getParentAdditionals().size() > 0) {143const double stopWidth = (getParentAdditionals().front()->getTagProperty()->getTag() == SUMO_TAG_BUS_STOP) ?144viewSettings.stoppingPlaceSettings.busStopWidth : viewSettings.stoppingPlaceSettings.trainStopWidth;145// get busStop shape146const PositionVector& busStopShape = getParentAdditionals().front()->getAdditionalGeometry().getShape();147PositionVector shapeA = {busStopShape[-1], busStopShape[-2]};148PositionVector shapeB = {busStopShape[-1], busStopShape[-2]};149shapeA.rotateAroundFirstElement2D(DEG2RAD(90));150shapeB.rotateAroundFirstElement2D(-DEG2RAD(90));151shape = {shapeA.positionAtOffset2D(stopWidth), shapeB.positionAtOffset2D(stopWidth)};152} else if (getParentEdges().size() > 0) {153// get front and back lane154const GNELane* frontLane = getParentEdges().front()->getChildLanes().front();155const GNELane* backLane = getParentEdges().front()->getChildLanes().back();156// calculate front position157const Position frontPosition = frontLane->getLaneShape().positionAtOffset2D(getAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS),158frontLane->getDrawingConstants()->getDrawingWidth());159// calulate length between both shapes160const double length = backLane->getLaneShape().distance2D(frontPosition, true);161// calculate back position162const Position backPosition = frontLane->getLaneShape().positionAtOffset2D(getAttributeDouble(GNE_ATTR_PLAN_GEOMETRY_ENDPOS),163(length + backLane->getDrawingConstants()->getDrawingWidth() - frontLane->getDrawingConstants()->getDrawingWidth()) * -1);164// update demand element geometry using both positions165shape = {frontPosition, backPosition};166}167// extrapolate for sign168shape.extrapolate(0.1, true);169myDemandElementGeometry.updateGeometry(shape);170shape.extrapolate(viewSettings.additionalSettings.stopEdgeSize - 0.1, true);171mySignPosition = shape.front();172}173174175Position176GNEStopPlan::getPositionInView() const {177return getPlanPositionInView();178}179180181std::string182GNEStopPlan::getParentName() const {183return getParentDemandElements().front()->getID();184}185186187double188GNEStopPlan::getExaggeration(const GUIVisualizationSettings& s) const {189return s.addSize.getExaggeration(s, this);190}191192193Boundary194GNEStopPlan::getCenteringBoundary() const {195return getPlanCenteringBoundary();196}197198199void200GNEStopPlan::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {201// geometry of this element cannot be splitted202}203204205void206GNEStopPlan::drawGL(const GUIVisualizationSettings& s) const {207// check if stop can be draw208if ((getTagProperty()->isPlanStopPerson() && checkDrawPersonPlan()) ||209(getTagProperty()->isPlanStopContainer() && checkDrawContainerPlan())) {210// Obtain exaggeration of the draw211const double exaggeration = getExaggeration(s);212// get detail level213const auto d = s.getDetailLevel(exaggeration);214// draw geometry only if we'rent in drawForObjectUnderCursor mode215if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {216// declare stop color217const RGBColor stopColor = drawUsingSelectColor() ? s.colorSettings.selectedPersonPlanColor : s.colorSettings.stopColor;218// Add layer matrix matrix219GLHelper::pushMatrix();220// translate to front221drawInLayer(getType());222// declare stop color223// declare central line color224const RGBColor centralLineColor = drawUsingSelectColor() ? stopColor.changedBrightness(-32) : RGBColor::WHITE;225// set base color226GLHelper::setColor(stopColor);227// Draw the area using shape, shapeRotations, shapeLengths and value of exaggeration228GUIGeometry::drawGeometry(d, myDemandElementGeometry, 0.3 * exaggeration);229// move to front230glTranslated(0, 0, .1);231// set central color232GLHelper::setColor(centralLineColor);233// Draw the area using shape, shapeRotations, shapeLengths and value of exaggeration234GUIGeometry::drawGeometry(d, myDemandElementGeometry, 0.05 * exaggeration);235// move to icon position and front236glTranslated(mySignPosition.x(), mySignPosition.y(), .1);237// rotate over lane238GUIGeometry::rotateOverLane((myDemandElementGeometry.getShapeRotations().front() * -1) + 90);239// draw icon depending of detail level240if (d <= GUIVisualizationSettings::Detail::AdditionalDetails) {241// set color242glColor3d(1, 1, 1);243// rotate texture244glRotated(180, 0, 0, 1);245// draw texture246if (drawUsingSelectColor()) {247GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::STOPPERSON_SELECTED), s.additionalSettings.stopEdgeSize * exaggeration);248} else {249GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(GUITexture::STOPPERSON), s.additionalSettings.stopEdgeSize * exaggeration);250}251} else {252// set stop color253GLHelper::setColor(stopColor);254// draw filled circle255GLHelper::drawFilledCircleDetailled(d, 0.1 + s.additionalSettings.stopEdgeSize);256}257// pop layer matrix258GLHelper::popMatrix();259// draw lock icon260GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), mySignPosition, exaggeration);261// draw dotted contour262myStopContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);263myStopSignContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidthSmall, true);264}265// calculate contour and draw dotted geometry266if (getParentLanes().size() > 0) {267myStopContour.calculateContourExtrudedShape(s, d, this, myDemandElementGeometry.getShape(), getType(), 0.3, exaggeration, false, true, 0, nullptr, getParentLanes().front()->getParentEdge());268myStopSignContour.calculateContourCircleShape(s, d, this, mySignPosition, s.additionalSettings.stopEdgeSize, getType(), exaggeration, getParentLanes().front()->getParentEdge());269} else if (getParentEdges().size() > 0) {270myStopContour.calculateContourExtrudedShape(s, d, this, myDemandElementGeometry.getShape(), getType(), 0.3, exaggeration, false, true, 0, nullptr, getParentEdges().front());271myStopSignContour.calculateContourCircleShape(s, d, this, mySignPosition, s.additionalSettings.stopEdgeSize, getType(), exaggeration, getParentEdges().front());272} else {273myStopContour.calculateContourExtrudedShape(s, d, this, myDemandElementGeometry.getShape(), getType(), 0.3, exaggeration, false, true, 0, nullptr, getParentAdditionals().front());274myStopSignContour.calculateContourCircleShape(s, d, this, mySignPosition, s.additionalSettings.stopEdgeSize, getType(), exaggeration, getParentAdditionals().front());275}276}277// check if draw plan parent278if (getParentDemandElements().at(0)->getPreviousChildDemandElement(this) == nullptr) {279getParentDemandElements().at(0)->drawGL(s);280}281}282283284void285GNEStopPlan::computePathElement() {286// only update geometry287updateGeometry();288}289290291void292GNEStopPlan::drawLanePartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {293// Stops don't use drawJunctionPartialGL294}295296297void298GNEStopPlan::drawJunctionPartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {299// Stops don't use drawJunctionPartialGL300}301302303GNELane*304GNEStopPlan::getFirstPathLane() const {305return getFirstPlanPathLane();306}307308309GNELane*310GNEStopPlan::getLastPathLane() const {311return getLastPlanPathLane();312}313314315std::string316GNEStopPlan::getAttribute(SumoXMLAttr key) const {317switch (key) {318case SUMO_ATTR_DURATION:319if (isAttributeEnabled(key)) {320return time2string(myDuration);321} else {322return "";323}324case SUMO_ATTR_UNTIL:325if (isAttributeEnabled(key)) {326return time2string(myUntil);327} else {328return "";329}330case SUMO_ATTR_ACTTYPE:331return myActType;332case SUMO_ATTR_FRIENDLY_POS:333return toString(myFriendlyPos);334default:335return getPlanAttribute(key);336}337}338339340double341GNEStopPlan::getAttributeDouble(SumoXMLAttr key) const {342return getPlanAttributeDouble(key);343}344345346Position347GNEStopPlan::getAttributePosition(SumoXMLAttr key) const {348return getPlanAttributePosition(key);349}350351352void353GNEStopPlan::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {354switch (key) {355case SUMO_ATTR_DURATION:356case SUMO_ATTR_UNTIL:357case SUMO_ATTR_ACTTYPE:358case SUMO_ATTR_FRIENDLY_POS:359GNEChange_Attribute::changeAttribute(this, key, value, undoList);360break;361default:362setPlanAttribute(key, value, undoList);363break;364}365}366367368bool369GNEStopPlan::isValid(SumoXMLAttr key, const std::string& value) {370switch (key) {371case SUMO_ATTR_DURATION:372case SUMO_ATTR_UNTIL:373if (canParse<SUMOTime>(value)) {374return parse<SUMOTime>(value) >= 0;375} else {376return false;377}378case SUMO_ATTR_ACTTYPE:379return true;380case SUMO_ATTR_FRIENDLY_POS:381return canParse<bool>(value);382default:383return isPlanValid(key, value);384}385}386387388void389GNEStopPlan::enableAttribute(SumoXMLAttr key, GNEUndoList* undoList) {390switch (key) {391case SUMO_ATTR_DURATION:392case SUMO_ATTR_UNTIL:393undoList->add(new GNEChange_ToggleAttribute(this, key, true), true);394break;395default:396throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");397}398}399400401void402GNEStopPlan::disableAttribute(SumoXMLAttr key, GNEUndoList* undoList) {403switch (key) {404case SUMO_ATTR_DURATION:405case SUMO_ATTR_UNTIL:406undoList->add(new GNEChange_ToggleAttribute(this, key, false), true);407break;408default:409throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");410}411}412413414bool415GNEStopPlan::isAttributeEnabled(SumoXMLAttr key) const {416switch (key) {417case SUMO_ATTR_DURATION:418return (myParametersSet & STOP_DURATION_SET) != 0;419case SUMO_ATTR_UNTIL:420return (myParametersSet & STOP_UNTIL_SET) != 0;421default:422return isPlanAttributeEnabled(key);423}424}425426427std::string428GNEStopPlan::getPopUpID() const {429return getTagStr();430}431432433std::string434GNEStopPlan::getHierarchyName() const {435return getPlanHierarchyName();436}437438// ===========================================================================439// private440// ===========================================================================441442void443GNEStopPlan::setAttribute(SumoXMLAttr key, const std::string& value) {444switch (key) {445case SUMO_ATTR_DURATION:446if (value.empty()) {447toggleAttribute(key, false);448} else {449toggleAttribute(key, true);450myDuration = string2time(value);451}452break;453case SUMO_ATTR_UNTIL:454if (value.empty()) {455toggleAttribute(key, false);456} else {457toggleAttribute(key, true);458myUntil = string2time(value);459}460break;461case SUMO_ATTR_ACTTYPE:462myActType = value;463break;464case SUMO_ATTR_FRIENDLY_POS:465myFriendlyPos = parse<bool>(value);466break;467default:468setPlanAttribute(key, value);469break;470}471}472473474void475GNEStopPlan::toggleAttribute(SumoXMLAttr key, const bool value) {476switch (key) {477case SUMO_ATTR_DURATION:478if (value) {479myParametersSet |= STOP_DURATION_SET;480} else {481myParametersSet &= ~STOP_DURATION_SET;482}483break;484case SUMO_ATTR_UNTIL:485if (value) {486myParametersSet |= STOP_UNTIL_SET;487} else {488myParametersSet &= ~STOP_UNTIL_SET;489}490break;491default:492throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");493}494}495496/****************************************************************************/497498499