Path: blob/main/src/netedit/elements/demand/GNEDemandElement.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 GNEDemandElement.cpp14/// @author Pablo Alvarez Lopez15/// @date Dec 201816///17// A abstract class for demand elements18/****************************************************************************/1920#include <netedit/frames/common/GNESelectorFrame.h>21#include <netedit/frames/demand/GNEContainerFrame.h>22#include <netedit/frames/demand/GNEContainerPlanFrame.h>23#include <netedit/frames/demand/GNEPersonFrame.h>24#include <netedit/frames/demand/GNEPersonPlanFrame.h>25#include <netedit/frames/demand/GNEVehicleFrame.h>26#include <netedit/frames/GNEPlanSelector.h>27#include <netedit/GNEApplicationWindow.h>28#include <netedit/GNENet.h>29#include <netedit/GNESegment.h>30#include <netedit/GNETagPropertiesDatabase.h>31#include <netedit/GNEViewParent.h>32#include <utils/gui/div/GLHelper.h>33#include <utils/gui/div/GUIDesigns.h>34#include <utils/gui/div/GUIParameterTableWindow.h>35#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>3637#include "GNEDemandElement.h"38#include "GNERouteHandler.h"3940// ===========================================================================41// member method definitions42// ===========================================================================43#ifdef _MSC_VER44#pragma warning(push)45#pragma warning(disable: 4355) // mask warning about "this" in initializers46#endif4748GNEDemandElement::GNEDemandElement(GNENet* net, SumoXMLTag tag) :49GNEAttributeCarrier(tag, net),50GUIGlObject(myTagProperty->getGLType(), "", GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),51GNEPathElement(myTagProperty->isRoute() ? GNEPathElement::Options::DEMAND_ELEMENT | GNEPathElement::Options::ROUTE :52GNEPathElement::Options::DEMAND_ELEMENT) {53}545556GNEDemandElement::GNEDemandElement(const std::string& id, GNENet* net, SumoXMLTag tag, FileBucket* fileBucket) :57GNEAttributeCarrier(tag, net, fileBucket),58GUIGlObject(myTagProperty->getGLType(), id, GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),59GNEPathElement(myTagProperty->isRoute() ? GNEPathElement::Options::DEMAND_ELEMENT | GNEPathElement::Options::ROUTE :60GNEPathElement::Options::DEMAND_ELEMENT) {61}626364GNEDemandElement::GNEDemandElement(GNEDemandElement* demandElementParent, SumoXMLTag tag) :65GNEAttributeCarrier(tag, demandElementParent->getNet(), demandElementParent->getFileBucket()),66GUIGlObject(myTagProperty->getGLType(), demandElementParent->getID(), GUIIconSubSys::getIcon(myTagProperty->getGUIIcon())),67GNEPathElement(myTagProperty->isRoute() ? GNEPathElement::Options::DEMAND_ELEMENT | GNEPathElement::Options::ROUTE :68GNEPathElement::Options::DEMAND_ELEMENT) {69}70#ifdef _MSC_VER71#pragma warning(pop)72#endif7374GNEDemandElement::~GNEDemandElement() {}757677GNEHierarchicalElement*78GNEDemandElement::getHierarchicalElement() {79return this;80}818283GUIGlObject*84GNEDemandElement::getGUIGlObject() {85return this;86}878889const GUIGlObject*90GNEDemandElement::getGUIGlObject() const {91return this;92}939495FileBucket*96GNEDemandElement::getFileBucket() const {97if (myTagProperty->saveInParentFile()) {98if (isTemplate()) {99return nullptr;100} else {101return getParentDemandElements().front()->getFileBucket();102}103} else {104return myFileBucket;105}106}107108109void110GNEDemandElement::changeFileBucket(FileBucket* fileBucket) {111myFileBucket->removeElement(false);112myFileBucket = fileBucket;113myFileBucket->addElement(false);114// update options115myNet->getGNEApplicationWindow()->getFileBucketHandler()->updateOptions();116// mark demand elements to save117myNet->getSavingStatus()->requireSaveAdditionals();118myNet->getSavingStatus()->requireSaveDemandElements();119}120121122const GUIGeometry&123GNEDemandElement::getDemandElementGeometry() {124return myDemandElementGeometry;125}126127128GNEDemandElement*129GNEDemandElement::getPreviousChildDemandElement(const GNEDemandElement* demandElement) const {130// first check if there are demand elements131if (getChildDemandElements().empty()) {132return nullptr;133} else {134// find child demand element135auto it = std::find(getChildDemandElements().begin(), getChildDemandElements().end(), demandElement);136// return element or null depending of iterator137if (it == getChildDemandElements().end()) {138// in this case, we assume that the last child is the previos child139return getChildDemandElements().back();140} else if (it == getChildDemandElements().begin()) {141return nullptr;142} else {143return *(it - 1);144}145}146}147148149GNEDemandElement*150GNEDemandElement::getNextChildDemandElement(const GNEDemandElement* demandElement) const {151// find child demand element152auto it = std::find(getChildDemandElements().begin(), getChildDemandElements().end(), demandElement);153// return element or null depending of iterator154if (it == getChildDemandElements().end()) {155return nullptr;156} else if (it == (getChildDemandElements().end() - 1)) {157return nullptr;158} else {159return *(it + 1);160}161}162163164void165GNEDemandElement::updateDemandElementGeometry(const GNELane* lane, const double posOverLane) {166myDemandElementGeometry.updateGeometry(lane->getLaneShape(), posOverLane, /*myMovingLateralOffset*/ 0);167}168169170void171GNEDemandElement::updateDemandElementStackLabel(const int stack) {172myStackedLabelNumber = stack;173}174175176void177GNEDemandElement::updateDemandElementSpreadGeometry(const GNELane* lane, const double posOverLane) {178mySpreadGeometry.updateGeometry(lane->getLaneShape(), posOverLane, /*myMovingLateralOffset*/ 0);179}180181182const GUIGeometry&183GNEDemandElement::getDemandElementGeometry() const {184return myDemandElementGeometry;185}186187188bool189GNEDemandElement::checkDrawFromContour() const {190return false;191}192193194bool195GNEDemandElement::checkDrawToContour() const {196return false;197}198199200bool201GNEDemandElement::checkDrawRelatedContour() const {202if (myTagProperty->getTag() == GNE_TAG_ROUTE_EMBEDDED) {203// check if inspected parent is inspected204for (const auto& inspectedAC : myNet->getViewNet()->getInspectedElements().getACs()) {205if (inspectedAC->getTagProperty()->vehicleRouteEmbedded()) {206const auto demandElement = dynamic_cast<GNEDemandElement*>(inspectedAC);207if (demandElement && (demandElement->getChildDemandElements().size() > 0) &&208(demandElement->getChildDemandElements().at(0) == this)) {209return true;210}211}212}213}214// check opened popup215if (myNet->getViewNet()->getPopup()) {216return myNet->getViewNet()->getPopup()->getGLObject() == this;217}218return false;219}220221222bool223GNEDemandElement::checkDrawOverContour() const {224// get modes225const auto& modes = myNet->getViewNet()->getEditModes();226// get frames227const auto& personFramePlanSelector = myNet->getViewParent()->getPersonFrame()->getPlanSelector();228const auto& personPlanFramePlanSelector = myNet->getViewParent()->getPersonPlanFrame()->getPlanSelector();229const auto& containerFramePlanSelector = myNet->getViewParent()->getContainerFrame()->getPlanSelector();230const auto& containerPlanFramePlanSelector = myNet->getViewParent()->getContainerPlanFrame()->getPlanSelector();231// special case for Route232if (myTagProperty->getTag() == SUMO_TAG_ROUTE) {233// get vehicle frame234const auto& vehicleFrame = myNet->getViewParent()->getVehicleFrame();235// check if we're in vehicle mode236if (vehicleFrame->shown()) {237// get current vehicle template238const auto& vehicleTemplate = vehicleFrame->getVehicleTagSelector()->getCurrentTemplateAC();239// check if vehicle can be placed over route240if (vehicleTemplate && vehicleTemplate->getTagProperty()->vehicleRoute()) {241return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;242}243} else if (modes.isCurrentSupermodeDemand()) {244// check if we're in person or personPlan modes245if (((modes.demandEditMode == DemandEditMode::DEMAND_PERSON) && personFramePlanSelector->markRoutes()) ||246((modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) && personPlanFramePlanSelector->markRoutes()) ||247((modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) && containerFramePlanSelector->markRoutes()) ||248((modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) && containerPlanFramePlanSelector->markRoutes())) {249return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;250}251}252}253return false;254}255256257bool258GNEDemandElement::checkDrawDeleteContour() const {259// get edit modes260const auto& editModes = myNet->getViewNet()->getEditModes();261// check if we're in delete mode262if (editModes.isCurrentSupermodeDemand() && (editModes.demandEditMode == DemandEditMode::DEMAND_DELETE)) {263return myNet->getViewNet()->checkOverLockedElement(this, mySelected);264} else {265return false;266}267}268269270bool271GNEDemandElement::checkDrawDeleteContourSmall() const {272if (myTagProperty->vehicleRoute()) {273const auto route = myNet->getViewNet()->getViewObjectsSelector().getDemandElementFront();274if (route && (route == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront())) {275return (getParentDemandElements().at(1) == route);276}277} else if (myTagProperty->getTag() == GNE_TAG_ROUTE_EMBEDDED) {278const auto vehicle = myNet->getViewNet()->getViewObjectsSelector().getDemandElementFront();279if (vehicle && (vehicle == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront())) {280return (getParentDemandElements().front() == vehicle);281}282}283return false;284}285286287bool288GNEDemandElement::checkDrawSelectContour() const {289// get edit modes290const auto& editModes = myNet->getViewNet()->getEditModes();291// check if we're in select mode292if (editModes.isCurrentSupermodeDemand() && (editModes.demandEditMode == DemandEditMode::DEMAND_SELECT)) {293return myNet->getViewNet()->checkOverLockedElement(this, mySelected);294} else {295return false;296}297}298299300bool301GNEDemandElement::checkDrawMoveContour() const {302// get edit modes303const auto& editModes = myNet->getViewNet()->getEditModes();304// check first set of conditions305if (!myNet->getViewNet()->isCurrentlyMovingElements() && // another elements are not currently moved306editModes.isCurrentSupermodeDemand() && // supermode demand307(editModes.demandEditMode == DemandEditMode::DEMAND_MOVE) && // move mode308myNet->getViewNet()->checkOverLockedElement(this, mySelected) && // no locked309myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this) { // first element310// continue depending of subtype311if (myTagProperty->isVehicle()) {312// only vehicles over edges can be moved313if (myTagProperty->vehicleEdges() || myTagProperty->vehicleRoute() || myTagProperty->vehicleRouteEmbedded()) {314return true;315} else {316return false;317}318} else if ((myTagProperty->isPerson() || myTagProperty->isContainer()) && (getChildDemandElements().size() > 0)) {319// only persons/containers with their first plan over edge can be moved320return getChildDemandElements().front()->getTagProperty()->planFromEdge();321} else {322return false;323}324} else {325return false;326}327}328329330void331GNEDemandElement::openDemandElementDialog() {332throw InvalidArgument(getTagStr() + " doesn't have a demand element dialog");333}334335336GUIGLObjectPopupMenu*337GNEDemandElement::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {338// create popup339GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);340// build common options341buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);342// show option to open demand element dialog343if (myTagProperty->hasDialog()) {344GUIDesigns::buildFXMenuCommand(ret, ("Open " + getTagStr() + " Dialog").c_str(), getACIcon(), &parent, MID_OPEN_ADDITIONAL_DIALOG);345new FXMenuSeparator(ret);346}347GUIDesigns::buildFXMenuCommand(ret, "Cursor position in view: " + toString(getPositionInView().x()) + "," + toString(getPositionInView().y()), nullptr, nullptr, 0);348return ret;349}350351352GUIParameterTableWindow*353GNEDemandElement::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {354// Create table355GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);356// Iterate over attributes357for (const auto& attrProperty : myTagProperty->getAttributeProperties()) {358// Add attribute and set it dynamic if aren't unique359if (attrProperty->isUnique()) {360ret->mkItem(attrProperty->getAttrStr().c_str(), false, getAttribute(attrProperty->getAttr()));361} else {362ret->mkItem(attrProperty->getAttrStr().c_str(), true, getAttribute(attrProperty->getAttr()));363}364}365// close building366ret->closeBuilding();367return ret;368}369370371bool372GNEDemandElement::isGLObjectLocked() const {373if (myNet->getViewNet()->getEditModes().isCurrentSupermodeDemand()) {374return myNet->getViewNet()->getLockManager().isObjectLocked(getType(), isAttributeCarrierSelected());375} else {376return true;377}378}379380381void382GNEDemandElement::markAsFrontElement() {383markForDrawingFront();384}385386387void388GNEDemandElement::deleteGLObject() {389// we need an special checks due hierarchies390if (myTagProperty->isPlan()) {391// get person/container plarent392GNEDemandElement* planParent = getParentDemandElements().front();393// if this is the last person/container plan element, remove parent instead plan394if (planParent->getChildDemandElements().size() == 1) {395planParent->deleteGLObject();396} else {397myNet->deleteDemandElement(this, myNet->getUndoList());398}399} else if (myTagProperty->getTag() == GNE_TAG_ROUTE_EMBEDDED) {400// remove parent demand element401getParentDemandElements().front()->deleteGLObject();402} else {403myNet->deleteDemandElement(this, myNet->getUndoList());404}405}406407408void409GNEDemandElement::selectGLObject() {410if (isAttributeCarrierSelected()) {411unselectAttributeCarrier();412} else {413selectAttributeCarrier();414}415// update information label416myNet->getViewParent()->getSelectorFrame()->getSelectionInformation()->updateInformationLabel();417}418419420void421GNEDemandElement::updateGLObject() {422updateGeometry();423}424425426Position427GNEDemandElement::getAttributePosition(SumoXMLAttr key) const {428return getCommonAttributePosition(key);429}430431432PositionVector433GNEDemandElement::getAttributePositionVector(SumoXMLAttr key) const {434return getCommonAttributePositionVector(key);435}436437438bool439GNEDemandElement::isPathElementSelected() const {440return mySelected;441}442443// ---------------------------------------------------------------------------444// GNEDemandElement - protected methods445// ---------------------------------------------------------------------------446447bool448GNEDemandElement::isValidDemandElementID(const std::string& value) const {449if (!isTemplate() && (value == getID())) {450return true;451} else if (SUMOXMLDefinitions::isValidVehicleID(value)) {452return (myNet->getAttributeCarriers()->retrieveDemandElement(myTagProperty->getTag(), value, false) == nullptr);453} else {454return false;455}456}457458459bool460GNEDemandElement::isValidDemandElementID(const std::vector<SumoXMLTag>& tags, const std::string& value) const {461if (isTemplate() && value.empty()) {462return true;463} else if (!isTemplate() && (value == getID())) {464return true;465} else if (SUMOXMLDefinitions::isValidVehicleID(value)) {466return (myNet->getAttributeCarriers()->retrieveDemandElements(tags, value, false) == nullptr);467} else {468return false;469}470}471472473void474GNEDemandElement::setDemandElementID(const std::string& newID) {475// update ID476if (isTemplate() || !myTagProperty->hasAttribute(SUMO_ATTR_ID)) {477setMicrosimID(newID);478} else {479myNet->getAttributeCarriers()->updateDemandElementID(this, newID);480}481// check if update ids of child elements482if (myTagProperty->isPerson() || myTagProperty->isContainer()) {483// Change IDs of all person plans children (stops, embedded routes...)484for (const auto& childDemandElement : getChildDemandElements()) {485childDemandElement->setDemandElementID(getID());486}487}488}489490491GNEDemandElement*492GNEDemandElement::getTypeParent() const {493if (getParentDemandElements().size() < 1) {494throw InvalidArgument("This demand element doesn't have a type parent");495} else if ((getParentDemandElements().at(0)->getTagProperty()->isType()) ||496(getParentDemandElements().at(0)->getTagProperty()->isTypeDistribution())) {497return getParentDemandElements().at(0);498} else {499throw InvalidArgument("The first parent isn't a type");500}501}502503504GNEDemandElement*505GNEDemandElement::getRouteParent() const {506if (getParentDemandElements().size() < 2) {507throw InvalidArgument("This demand element doesn't have a route parent");508} else if ((getParentDemandElements().at(1)->getTagProperty()->isRoute()) ||509(getParentDemandElements().at(1)->getTagProperty()->isRouteDistribution())) {510return getParentDemandElements().at(1);511} else {512throw InvalidArgument("The second parent isn't a route");513}514}515516517std::vector<GNEDemandElement*>518GNEDemandElement::getInvalidStops() const {519if (myTagProperty->isVehicleStop()) {520// get stops521std::vector<GNEDemandElement*> invalidStops;522// get edge stop index523const auto edgeStopIndex = getEdgeStopIndex();524// take all stops/waypoints with index = -1525for (const auto& edgeStop : edgeStopIndex) {526if (edgeStop.stopIndex == -1) {527for (const auto& stop : edgeStop.stops) {528invalidStops.push_back(stop);529}530}531}532return invalidStops;533} else {534return {};535}536}537538539void540GNEDemandElement::drawJunctionLine(const GNEDemandElement* element) const {541// get two points542const Position posA = element->getParentJunctions().front()->getPositionInView();543const Position posB = element->getParentJunctions().back()->getPositionInView();544const double rot = ((double)atan2((posB.x() - posA.x()), (posA.y() - posB.y())) * (double) 180.0 / (double)M_PI);545const double len = posA.distanceTo2D(posB);546// push draw matrix547GLHelper::pushMatrix();548// Start with the drawing of the area traslating matrix to origin549drawInLayer(element->getType() + 0.1);550// set trip color551GLHelper::setColor(RGBColor::RED);552// draw line553GLHelper::drawBoxLine(posA, rot, len, 0.25);554// pop draw matrix555GLHelper::popMatrix();556}557558559void560GNEDemandElement::drawStackLabel(const int number, const std::string& element, const Position& position, const double rotation,561const double width, const double length, const double exaggeration) const {562// declare contour width563const double contourWidth = (0.05 * exaggeration);564// Push matrix565GLHelper::pushMatrix();566// Traslate to top567glTranslated(position.x(), position.y(), GLO_VEHICLELABELS);568glRotated(rotation, 0, 0, -1);569glTranslated((width * exaggeration * 0.5) + (0.35 * exaggeration) + 0.05, 0, 0);570// draw external box571GLHelper::setColor(RGBColor::GREY);572GLHelper::drawBoxLine(Position(), 0, (length * exaggeration), 0.3 * exaggeration);573// draw internal box574glTranslated(0, 0, 0.1);575GLHelper::setColor(RGBColor(0, 128, 0));576GLHelper::drawBoxLine(Position(0, -contourWidth), Position(0, -contourWidth), 0, (length * exaggeration) - (contourWidth * 2), (0.3 * exaggeration) - contourWidth);577// draw stack label578GLHelper::drawText(element + "s stacked: " + toString(number), Position(0, length * exaggeration * -0.5), (.1 * exaggeration), (0.6 * exaggeration), RGBColor::WHITE, 90, 0, -1);579// pop draw matrix580GLHelper::popMatrix();581}582583584void585GNEDemandElement::replaceParentEdges(const std::string& value) {586auto newEdges = parse<GNEHierarchicalContainerParents<GNEEdge*> >(getNet(), value);587GNEHierarchicalElement::updateParents(this, newEdges);;588}589590591void592GNEDemandElement::replaceFirstParentLane(const std::string& value) {593auto newLane = myNet->getAttributeCarriers()->retrieveLane(value);594GNEHierarchicalElement::updateParent(this, 0, newLane);595}596597598void599GNEDemandElement::replaceFirstParentJunction(const std::string& value) {600auto newJunction = myNet->getAttributeCarriers()->retrieveJunction(value);601GNEHierarchicalElement::updateParent(this, 0, newJunction);602}603604605void606GNEDemandElement::replaceLastParentJunction(const std::string& value) {607auto newJunction = myNet->getAttributeCarriers()->retrieveJunction(value);608GNEHierarchicalElement::updateParent(this, (int)getParentJunctions().size() - 1, newJunction);609}610611612void613GNEDemandElement::replaceFirstParentEdge(const std::string& value) {614auto newEdge = myNet->getAttributeCarriers()->retrieveEdge(value);615GNEHierarchicalElement::updateParent(this, 0, newEdge);616}617618619void620GNEDemandElement::replaceLastParentEdge(const std::string& value) {621auto newEdge = myNet->getAttributeCarriers()->retrieveEdge(value);622GNEHierarchicalElement::updateParent(this, (int)getParentEdges().size() - 1, newEdge);623}624625626void627GNEDemandElement::replaceFirstParentAdditional(SumoXMLTag tag, const std::string& value) {628auto newAdditional = myNet->getAttributeCarriers()->retrieveAdditional(tag, value);629GNEHierarchicalElement::updateParent(this, 0, newAdditional);630}631632633void634GNEDemandElement::replaceLastParentAdditional(SumoXMLTag tag, const std::string& value) {635auto newAdditional = myNet->getAttributeCarriers()->retrieveAdditional(tag, value);636GNEHierarchicalElement::updateParent(this, (int)getParentAdditionals().size() - 1, newAdditional);637}638639640void641GNEDemandElement::replaceDemandElementParent(const std::vector<SumoXMLTag> tags, const std::string& value, const int parentIndex) {642GNEDemandElement* newDemandElement = nullptr;643// search demand element644for (auto it = tags.begin(); (it != tags.end()) && (newDemandElement == nullptr); it++) {645newDemandElement = myNet->getAttributeCarriers()->retrieveDemandElement(*it, value, false);646}647if (newDemandElement) {648GNEHierarchicalElement::updateParent(this, parentIndex, newDemandElement);649} else {650throw ProcessError("Attempted to replace with non-existant demand element " + value);651}652}653654655bool656GNEDemandElement::checkChildDemandElementRestriction() const {657// throw exception because this function mus be implemented in child (see GNEE3Detector)658throw ProcessError(StringUtils::format("Calling non-implemented function checkChildDemandElementRestriction during saving of %. It muss be reimplemented in child class", getTagStr()));659}660661662std::vector<GNEDemandElement::EdgeStopIndex>663GNEDemandElement::getEdgeStopIndex() const {664std::vector<GNEDemandElement::EdgeStopIndex> edgeStopIndex;665// first check that this stop has parent666if (getParentDemandElements().size() > 0) {667// get path edges depending of parent668std::vector<GNEEdge*> pathEdges;669// get parent demand element670const auto parent = getParentDemandElements().front();671// continue depending of parent672if (parent->getTagProperty()->hasAttribute(SUMO_ATTR_EDGES)) {673pathEdges = parent->getParentEdges();674} else if (parent->getTagProperty()->vehicleRoute()) {675// get route edges676if (parent->getParentDemandElements().size() > 1) {677pathEdges = parent->getParentDemandElements().at(1)->getParentEdges();678}679} else if (parent->getTagProperty()->vehicleRouteEmbedded()) {680// get embedded route edges681pathEdges = parent->getChildDemandElements().front()->getParentEdges();682} else {683// get last parent edge684const auto lastEdge = parent->getParentEdges().back();685bool stop = false;686const auto& pathElementSegments = myNet->getDemandPathManager()->getPathElementSegments(parent);687// extract all edges from pathElement parent688for (auto it = pathElementSegments.begin(); (it != pathElementSegments.end()) && !stop; it++) {689if ((*it)->getLane()) {690pathEdges.push_back((*it)->getLane()->getParentEdge());691// stop if path correspond to last edge692if (pathEdges.back() == lastEdge) {693stop = true;694}695}696}697}698// get all parent's stops and waypoints sorted by position699for (const auto& demandElement : parent->getChildDemandElements()) {700if (demandElement->getTagProperty()->isVehicleStop()) {701// get stop/waypoint edge702GNEEdge* edge = nullptr;703if (demandElement->getParentAdditionals().size() > 0) {704edge = demandElement->getParentAdditionals().front()->getParentLanes().front()->getParentEdge();705} else {706edge = demandElement->getParentLanes().front()->getParentEdge();707}708// check if add a new edgeStopIndex or update last709if ((edgeStopIndex.size() > 0) && (edgeStopIndex.back().edge == edge)) {710edgeStopIndex.back().stops.push_back(demandElement);711} else {712edgeStopIndex.push_back(EdgeStopIndex(edge, demandElement));713}714}715}716// declare index for current stop717int currentEdgeStopIndex = 0;718for (int i = 0; (i < (int)pathEdges.size()) && (currentEdgeStopIndex < (int)edgeStopIndex.size()); i++) {719// check if current edge stop index is in the path720if (edgeStopIndex[currentEdgeStopIndex].edge == pathEdges.at(i)) {721edgeStopIndex[currentEdgeStopIndex].stopIndex = i;722currentEdgeStopIndex++;723} else {724// check if edge exist in the rest of the path725bool next = false;726for (int j = (i + 1); j < (int)pathEdges.size(); j++) {727if (edgeStopIndex[currentEdgeStopIndex].edge == pathEdges.at(j)) {728next = true;729}730}731if (!next) {732// ignore current stops (because is out of path)733currentEdgeStopIndex++;734}735}736}737}738// sort stops by position739for (auto& edgeStop : edgeStopIndex) {740if (edgeStop.stops.size() > 1) {741// copy all stops to a map to sort it by endPos742std::map<double, std::vector<GNEDemandElement*> > sortedStops;743for (const auto& stop : edgeStop.stops) {744if (sortedStops.count(stop->getAttributeDouble(SUMO_ATTR_ENDPOS)) == 0) {745sortedStops[stop->getAttributeDouble(SUMO_ATTR_ENDPOS)] = {stop};746} else {747sortedStops[stop->getAttributeDouble(SUMO_ATTR_ENDPOS)].push_back(stop);748}749}750// update stops with sorted stops751edgeStop.stops.clear();752for (const auto& sortedStop : sortedStops) {753edgeStop.stops.insert(edgeStop.stops.end(), sortedStop.second.begin(), sortedStop.second.end());754}755}756}757return edgeStopIndex;758}759760761RGBColor762GNEDemandElement::getColorByScheme(const GUIColorer& c, const SUMOVehicleParameter* parameters) const {763// set color depending of color active764switch (c.getActive()) {765case 0: {766// test for emergency vehicle767if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "emergency") {768return RGBColor::WHITE;769}770// test for firebrigade771if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "firebrigade") {772return RGBColor::RED;773}774// test for police car775if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "police") {776return RGBColor::BLUE;777}778if (getTypeParent()->getAttribute(SUMO_ATTR_GUISHAPE) == "scooter") {779return RGBColor::WHITE;780}781// check if color was set782if (parameters->wasSet(VEHPARS_COLOR_SET)) {783return parameters->color;784} else {785// take their parent's color)786return getTypeParent()->getColor();787}788}789case 2: {790if (parameters->wasSet(VEHPARS_COLOR_SET)) {791return parameters->color;792} else {793return c.getScheme().getColor(0);794}795}796case 3: {797if (getTypeParent()->isAttributeEnabled(SUMO_ATTR_COLOR)) {798return getTypeParent()->getColor();799} else {800return c.getScheme().getColor(0);801}802}803case 4: {804if (getRouteParent()->getColor() != RGBColor::DEFAULT_COLOR) {805return getRouteParent()->getColor();806} else {807return c.getScheme().getColor(0);808}809}810case 5: {811Position p = getRouteParent()->getParentEdges().at(0)->getChildLanes().at(0)->getLaneShape()[0];812const Boundary& b = myNet->getBoundary();813Position center = b.getCenter();814double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;815double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));816return RGBColor::fromHSV(hue, sat, 1.);817}818case 6: {819Position p = getRouteParent()->getParentEdges().back()->getChildLanes().at(0)->getLaneShape()[-1];820const Boundary& b = myNet->getBoundary();821Position center = b.getCenter();822double hue = 180. + atan2(center.x() - p.x(), center.y() - p.y()) * 180. / M_PI;823double sat = p.distanceTo(center) / center.distanceTo(Position(b.xmin(), b.ymin()));824return RGBColor::fromHSV(hue, sat, 1.);825}826case 7: {827Position pb = getRouteParent()->getParentEdges().at(0)->getChildLanes().at(0)->getLaneShape()[0];828Position pe = getRouteParent()->getParentEdges().back()->getChildLanes().at(0)->getLaneShape()[-1];829const Boundary& b = myNet->getBoundary();830double hue = 180. + atan2(pb.x() - pe.x(), pb.y() - pe.y()) * 180. / M_PI;831Position minp(b.xmin(), b.ymin());832Position maxp(b.xmax(), b.ymax());833double sat = pb.distanceTo(pe) / minp.distanceTo(maxp);834return RGBColor::fromHSV(hue, sat, 1.);835}836case 35: { // color randomly (by pointer hash)837std::hash<const GNEDemandElement*> ptr_hash;838const double hue = (double)(ptr_hash(this) % 360); // [0-360]839const double sat = (double)((ptr_hash(this) / 360) % 67) / 100. + 0.33; // [0.33-1]840return RGBColor::fromHSV(hue, sat, 1.);841}842default: {843return c.getScheme().getColor(0);844}845}846}847848849void850GNEDemandElement::buildMenuCommandRouteLength(GUIGLObjectPopupMenu* ret) const {851std::vector<GNEEdge*> edges;852if (myTagProperty->isRoute()) {853edges = getParentEdges();854} else if (myTagProperty->vehicleRoute()) {855edges = getParentDemandElements().at(1)->getParentEdges();856} else if (myTagProperty->vehicleRouteEmbedded()) {857edges = getChildDemandElements().front()->getParentEdges();858} else if (myTagProperty->vehicleEdges()) {859edges = getParentEdges();860}861// calculate path862const auto path = myNet->getDemandPathManager()->getPathCalculator()->calculateDijkstraPath(getVClass(), edges);863// check path size864if (path.size() > 0) {865double length = 0;866for (const auto& edge : path) {867length += edge->getNBEdge()->getFinalLength();868}869for (int i = 0; i < ((int)path.size() - 1); i++) {870length += path.at(i)->getChildLanes().front()->getLane2laneConnections().getLane2laneGeometry(path.at(i + 1)->getChildLanes().front()).getShape().length();871}872GUIDesigns::buildFXMenuCommand(ret, TL("Route length: ") + toString(length), nullptr, ret, MID_COPY_NAME);873}874}875876877void878GNEDemandElement::buildMenuAddReverse(GUIGLObjectPopupMenu* ret) const {879// create menu pane for transform operations880FXMenuPane* transformOperation = new FXMenuPane(ret);881ret->insertMenuPaneChild(transformOperation);882auto reverseMenuCascade = new FXMenuCascade(ret, TL("reverse"), nullptr, transformOperation);883// build menu commands884GUIDesigns::buildFXMenuCommand(transformOperation, TLF("reverse current %", myTagProperty->getTagStr()), nullptr, myNet->getViewNet(), MID_GNE_REVERSE);885GUIDesigns::buildFXMenuCommand(transformOperation, TLF("Add reverse %", myTagProperty->getTagStr()), nullptr, myNet->getViewNet(), MID_GNE_ADDREVERSE);886// check if reverse can be added887if (GNERouteHandler::canReverse(this)) {888reverseMenuCascade->enable();889} else {890reverseMenuCascade->disable();891}892}893894/****************************************************************************/895896897