Path: blob/main/src/netedit/elements/additional/GNEAdditional.cpp
169684 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 GNEAdditional.cpp14/// @author Pablo Alvarez Lopez15/// @date Dec 201516///17// A abstract class for representation of additional elements18/****************************************************************************/19#include <config.h>2021#include <foreign/fontstash/fontstash.h>22#include <netedit/GNENet.h>23#include <netedit/GNESegment.h>24#include <netedit/GNETagPropertiesDatabase.h>25#include <netedit/GNEViewParent.h>26#include <netedit/frames/GNEAttributesEditor.h>27#include <netedit/frames/GNEPathCreator.h>28#include <netedit/frames/GNEPlanCreator.h>29#include <netedit/frames/common/GNEInspectorFrame.h>30#include <netedit/frames/common/GNEMoveFrame.h>31#include <netedit/frames/common/GNESelectorFrame.h>32#include <netedit/frames/data/GNETAZRelDataFrame.h>33#include <netedit/frames/demand/GNEContainerFrame.h>34#include <netedit/frames/demand/GNEContainerPlanFrame.h>35#include <netedit/frames/demand/GNEPersonFrame.h>36#include <netedit/frames/demand/GNEPersonPlanFrame.h>37#include <netedit/frames/demand/GNEVehicleFrame.h>38#include <utils/gui/div/GLHelper.h>39#include <utils/gui/div/GUIDesigns.h>40#include <utils/gui/div/GUIParameterTableWindow.h>41#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>4243#include "GNEAdditional.h"44#include "GNETAZ.h"4546// ===========================================================================47// member method definitions48// ===========================================================================4950GNEAdditional::GNEAdditional(const std::string& id, GNENet* net, const std::string& filename,51SumoXMLTag tag, const std::string& additionalName) :52GNEAttributeCarrier(tag, net, filename, id.empty()),53GUIGlObject(net->getTagPropertiesDatabase()->getTagProperty(tag, true)->getGLType(), id,54GUIIconSubSys::getIcon(net->getTagPropertiesDatabase()->getTagProperty(tag, true)->getGUIIcon())),55GNEPathElement(GNEPathElement::Options::ADDITIONAL_ELEMENT),56myAdditionalName(additionalName) {57}585960GNEAdditional::GNEAdditional(GNEAdditional* additionalParent, SumoXMLTag tag, const std::string& additionalName) :61GNEAttributeCarrier(tag, additionalParent->getNet(), additionalParent->getFilename(), false),62GUIGlObject(additionalParent->getNet()->getTagPropertiesDatabase()->getTagProperty(tag, true)->getGLType(), additionalParent->getID(),63GUIIconSubSys::getIcon(additionalParent->getNet()->getTagPropertiesDatabase()->getTagProperty(tag, true)->getGUIIcon())),64GNEPathElement(GNEPathElement::Options::ADDITIONAL_ELEMENT),65myAdditionalName(additionalName) {66}676869GNEAdditional::~GNEAdditional() {}707172GNEHierarchicalElement*73GNEAdditional::getHierarchicalElement() {74return this;75}767778void79GNEAdditional::removeGeometryPoint(const Position /*clickedPosition*/, GNEUndoList* /*undoList*/) {80// currently there isn't additionals with removable geometry points81}828384GUIGlObject*85GNEAdditional::getGUIGlObject() {86return this;87}888990const GUIGlObject*91GNEAdditional::getGUIGlObject() const {92return this;93}949596const std::string97GNEAdditional::getOptionalName() const {98try {99return getAttribute(SUMO_ATTR_NAME);100} catch (InvalidArgument&) {101return "";102}103}104105106const GUIGeometry&107GNEAdditional::getAdditionalGeometry() const {108return myAdditionalGeometry;109}110111112void113GNEAdditional::setSpecialColor(const RGBColor* color) {114mySpecialColor = color;115}116117118void119GNEAdditional::resetAdditionalContour() {120myAdditionalContour.clearContour();121}122123124bool125GNEAdditional::isAdditionalValid() const {126return true;127}128129130std::string131GNEAdditional::getAdditionalProblem() const {132return "";133}134135136void137GNEAdditional::fixAdditionalProblem() {138throw InvalidArgument(getTagStr() + " cannot fix any problem");139}140141142void143GNEAdditional::openAdditionalDialog() {144throw InvalidArgument(getTagStr() + " doesn't have an additional dialog");145}146147148double149GNEAdditional::getExaggeration(const GUIVisualizationSettings& s) const {150return s.addSize.getExaggeration(s, this);151}152153154Boundary155GNEAdditional::getCenteringBoundary() const {156if (myAdditionalBoundary.isInitialised()) {157return myAdditionalBoundary;158} else {159Boundary contourBoundary = myAdditionalContour.getContourBoundary();160if (contourBoundary.isInitialised()) {161contourBoundary.grow(5);162return contourBoundary;163} else if (myAdditionalGeometry.getShape().size() > 0) {164Boundary geometryBoundary = myAdditionalGeometry.getShape().getBoxBoundary();165geometryBoundary.grow(5);166return geometryBoundary;167} else if (getParentAdditionals().size() > 0) {168return getParentAdditionals().front()->getCenteringBoundary();169} else {170Boundary centerBoundary(0, 0, 0, 0);171centerBoundary.grow(5);172return centerBoundary;173}174}175}176177178bool179GNEAdditional::checkDrawFromContour() const {180// get modes and viewParent (for code legibility)181const auto& modes = myNet->getViewNet()->getEditModes();182const auto& viewParent = myNet->getViewNet()->getViewParent();183const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();184// continue depending of current status185if (inspectedElements.isInspectingSingleElement()) {186const auto inspectedAC = inspectedElements.getFirstAC();187// check conditions188if (inspectedAC->hasAttribute(SUMO_ATTR_FROM_TAZ)) {189return (inspectedAC->getAttribute(SUMO_ATTR_FROM_TAZ) == getID());190} else if ((inspectedAC->getTagProperty()->getTag() == SUMO_TAG_TAZREL)) {191return (inspectedAC->getAttribute(SUMO_ATTR_FROM) == getID());192}193} else if (modes.isCurrentSupermodeDemand()) {194// get current GNEPlanCreator195GNEPlanCreator* planCreator = nullptr;196if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {197planCreator = viewParent->getPersonFrame()->getPlanCreator();198} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {199planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();200} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {201planCreator = viewParent->getContainerFrame()->getPlanCreator();202} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {203planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();204}205// continue depending of planCreator206if (planCreator) {207// check if this is the from additional208const auto additionalID = getID();209if ((planCreator->getPlanParameteres().fromBusStop == additionalID) ||210(planCreator->getPlanParameteres().fromTrainStop == additionalID) ||211(planCreator->getPlanParameteres().fromContainerStop == additionalID) ||212(planCreator->getPlanParameteres().fromChargingStation == additionalID) ||213(planCreator->getPlanParameteres().fromParkingArea == additionalID) ||214(planCreator->getPlanParameteres().fromTAZ == additionalID)) {215return true;216}217} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {218// get selected TAZs219const auto& selectedTAZs = viewParent->getVehicleFrame()->getPathCreator()->getSelectedTAZs();220// check if this is the first selected TAZ221if ((selectedTAZs.size() > 0) && (selectedTAZs.front() == this)) {222return true;223}224}225} else if (modes.isCurrentSupermodeData()) {226// get TAZRelDataFrame227const auto& TAZRelDataFrame = viewParent->getTAZRelDataFrame();228if (TAZRelDataFrame->shown() && (TAZRelDataFrame->getFirstTAZ() == this)) {229return true;230}231}232// nothing to draw233return false;234}235236237bool238GNEAdditional::checkDrawToContour() const {239// get modes and viewParent (for code legibility)240const auto& modes = myNet->getViewNet()->getEditModes();241const auto& viewParent = myNet->getViewNet()->getViewParent();242const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();243// check conditions244if (myNet->getViewNet()->getViewParent()->getInspectorFrame()->getAttributesEditor()->isReparenting()) {245return false;246} else if (inspectedElements.isInspectingSingleElement()) {247const auto inspectedAC = inspectedElements.getFirstAC();248// check conditions249if (inspectedAC->hasAttribute(SUMO_ATTR_TO_TAZ)) {250return (inspectedAC->getAttribute(SUMO_ATTR_TO_TAZ) == getID());251} else if (inspectedAC->getTagProperty()->getTag() == SUMO_TAG_TAZREL) {252return (inspectedAC->getAttribute(SUMO_ATTR_TO) == getID());253} else if (inspectedAC->hasAttribute(GNE_ATTR_PARENT)) {254// check all parent tags255const auto& parentTags = inspectedAC->getTagProperty()->getXMLParentTags();256if (std::find(parentTags.begin(), parentTags.end(), myTagProperty->getTag()) != parentTags.end()) {257return (inspectedAC->getAttribute(GNE_ATTR_PARENT) == getID());258}259}260} else if (modes.isCurrentSupermodeDemand()) {261// get current GNEPlanCreator262GNEPlanCreator* planCreator = nullptr;263if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {264planCreator = viewParent->getPersonFrame()->getPlanCreator();265} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {266planCreator = viewParent->getPersonPlanFrame()->getPlanCreator();267} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {268planCreator = viewParent->getContainerFrame()->getPlanCreator();269} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {270planCreator = viewParent->getContainerPlanFrame()->getPlanCreator();271}272// continue depending of planCreator273if (planCreator) {274// check if this is the from additional275const auto additionalID = getID();276if ((planCreator->getPlanParameteres().toBusStop == additionalID) ||277(planCreator->getPlanParameteres().toTrainStop == additionalID) ||278(planCreator->getPlanParameteres().toContainerStop == additionalID) ||279(planCreator->getPlanParameteres().toChargingStation == additionalID) ||280(planCreator->getPlanParameteres().toParkingArea == additionalID) ||281(planCreator->getPlanParameteres().toTAZ == additionalID)) {282return true;283}284} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {285// get selected TAZs286const auto& selectedTAZs = viewParent->getVehicleFrame()->getPathCreator()->getSelectedTAZs();287// check if this is the first selected TAZ288if ((selectedTAZs.size() > 1) && (selectedTAZs.back() == this)) {289return true;290}291}292} else if (modes.isCurrentSupermodeData()) {293// get TAZRelDataFrame294const auto& TAZRelDataFrame = viewParent->getTAZRelDataFrame();295if (TAZRelDataFrame->shown() && (TAZRelDataFrame->getSecondTAZ() == this)) {296return true;297}298}299// nothing to draw300return false;301}302303304bool305GNEAdditional::checkDrawRelatedContour() const {306const auto& neteditAttributesEditor = myNet->getViewNet()->getViewParent()->getInspectorFrame()->getAttributesEditor();307if (neteditAttributesEditor->isReparenting()) {308return neteditAttributesEditor->checkNewParent(this);309}310// check opened popup311if (myNet->getViewNet()->getPopup()) {312return myNet->getViewNet()->getPopup()->getGLObject() == this;313}314return false;315}316317318bool319GNEAdditional::checkDrawOverContour() const {320const auto& modes = myNet->getViewNet()->getEditModes();321if (myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() != this) {322return false;323} else {324const auto& viewParent = myNet->getViewNet()->getViewParent();325if (modes.isCurrentSupermodeDemand()) {326// get current plan selector327GNEPlanSelector* planSelector = nullptr;328if (modes.demandEditMode == DemandEditMode::DEMAND_PERSON) {329planSelector = viewParent->getPersonFrame()->getPlanSelector();330} else if (modes.demandEditMode == DemandEditMode::DEMAND_PERSONPLAN) {331planSelector = viewParent->getPersonPlanFrame()->getPlanSelector();332} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINER) {333planSelector = viewParent->getContainerFrame()->getPlanSelector();334} else if (modes.demandEditMode == DemandEditMode::DEMAND_CONTAINERPLAN) {335planSelector = viewParent->getContainerPlanFrame()->getPlanSelector();336}337// continue depending of plan selector338if (planSelector) {339if ((myTagProperty->isStoppingPlace() && planSelector->markStoppingPlaces()) ||340(myTagProperty->isTAZElement() && planSelector->markTAZs())) {341return true;342}343} else if (modes.demandEditMode == DemandEditMode::DEMAND_VEHICLE) {344// get current vehicle template345const auto& vehicleTemplate = viewParent->getVehicleFrame()->getVehicleTagSelector()->getCurrentTemplateAC();346// check if vehicle can be placed over from-to TAZs347if (vehicleTemplate && vehicleTemplate->getTagProperty()->vehicleTAZs()) {348return true;349}350}351} else if (modes.isCurrentSupermodeData()) {352// get TAZRelDataFrame353const auto& TAZRelDataFrame = viewParent->getTAZRelDataFrame();354if (TAZRelDataFrame->shown()) {355if (TAZRelDataFrame->getFirstTAZ() && TAZRelDataFrame->getSecondTAZ()) {356return false;357} else if (TAZRelDataFrame->getFirstTAZ() == this) {358return false;359} else if (TAZRelDataFrame->getSecondTAZ() == this) {360return false;361} else {362return true;363}364}365}366return false;367}368}369370371bool372GNEAdditional::checkDrawDeleteContour() const {373// get edit modes374const auto& editModes = myNet->getViewNet()->getEditModes();375// check if we're in delete mode376if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE)) {377return myNet->getViewNet()->checkOverLockedElement(this, mySelected);378} else {379return false;380}381}382383384bool385GNEAdditional::checkDrawDeleteContourSmall() const {386// get edit modes387const auto& editModes = myNet->getViewNet()->getEditModes();388// check if we're in delete mode and this additional has a parent389if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_DELETE) && (getParentAdditionals().size() > 0)) {390const auto additional = myNet->getViewNet()->getViewObjectsSelector().getAdditionalFront();391if (additional && (additional == myNet->getViewNet()->getViewObjectsSelector().getAttributeCarrierFront())) {392return (getParentAdditionals().front() == additional);393}394}395return false;396}397398399bool400GNEAdditional::checkDrawSelectContour() const {401// get edit modes402const auto& editModes = myNet->getViewNet()->getEditModes();403// check if we're in select mode404if (editModes.isCurrentSupermodeNetwork() && (editModes.networkEditMode == NetworkEditMode::NETWORK_SELECT)) {405return myNet->getViewNet()->checkOverLockedElement(this, mySelected);406} else {407return false;408}409}410411412GUIGLObjectPopupMenu*413GNEAdditional::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {414// create popup415GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);416// build common options417buildPopUpMenuCommonOptions(ret, app, myNet->getViewNet(), myTagProperty->getTag(), mySelected);418// show option to open additional dialog419if (myTagProperty->hasDialog()) {420GUIDesigns::buildFXMenuCommand(ret, TL("Open ") + getTagStr() + TL(" Dialog"), getACIcon(), &parent, MID_OPEN_ADDITIONAL_DIALOG);421new FXMenuSeparator(ret);422}423// Show position parameters424if (myTagProperty->hasAttribute(SUMO_ATTR_LANE) && (myAdditionalGeometry.getShape().size() > 1)) {425const GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(getAttribute(SUMO_ATTR_LANE));426// Show menu command inner position427const double innerPos = myAdditionalGeometry.getShape().nearest_offset_to_point2D(parent.getPositionInformation());428GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position over additional shape: ") + toString(innerPos), nullptr, nullptr, 0);429// If shape isn't empty, show menu command lane position430if (myAdditionalGeometry.getShape().size() > 0) {431const double lanePos = lane->getLaneShape().nearest_offset_to_point2D(myAdditionalGeometry.getShape().front());432GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position over lane: ") + toString(innerPos + lanePos), nullptr, nullptr, 0);433}434} else if (myTagProperty->hasAttribute(SUMO_ATTR_EDGE) && (myAdditionalGeometry.getShape().size() > 1)) {435const GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(getAttribute(SUMO_ATTR_EDGE));436// Show menu command inner position437const double innerPos = myAdditionalGeometry.getShape().nearest_offset_to_point2D(parent.getPositionInformation());438GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position over additional shape: ") + toString(innerPos), nullptr, nullptr, 0);439// If shape isn't empty, show menu command edge position440if (myAdditionalGeometry.getShape().size() > 0) {441const double edgePos = edge->getChildLanes().at(0)->getLaneShape().nearest_offset_to_point2D(myAdditionalGeometry.getShape().front());442GUIDesigns::buildFXMenuCommand(ret, TL("Mouse position over edge: ") + toString(innerPos + edgePos), nullptr, nullptr, 0);443}444} else {445const auto mousePos = myNet->getViewNet()->getPositionInformation();446GUIDesigns::buildFXMenuCommand(ret, TL("Cursor position in view: ") + toString(mousePos.x()) + "," + toString(mousePos.y()), nullptr, nullptr, 0);447}448return ret;449}450451452GUIParameterTableWindow*453GNEAdditional::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView&) {454// Create table455GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);456// Iterate over attributes457for (const auto& attributeProperty : myTagProperty->getAttributeProperties()) {458// Add attribute and set it dynamic if aren't unique459if (attributeProperty->isUnique()) {460ret->mkItem(attributeProperty->getAttrStr().c_str(), false, getAttribute(attributeProperty->getAttr()));461} else {462ret->mkItem(attributeProperty->getAttrStr().c_str(), true, getAttribute(attributeProperty->getAttr()));463}464}465// close building466ret->closeBuilding();467return ret;468}469470471const std::string&472GNEAdditional::getOptionalAdditionalName() const {473return myAdditionalName;474}475476477bool478GNEAdditional::isGLObjectLocked() const {479if (myNet->getViewNet()->getEditModes().isCurrentSupermodeNetwork()) {480return myNet->getViewNet()->getLockManager().isObjectLocked(getType(), isAttributeCarrierSelected());481} else {482return true;483}484}485486487void488GNEAdditional::markAsFrontElement() {489markForDrawingFront();490}491492493void494GNEAdditional::deleteGLObject() {495myNet->deleteAdditional(this, myNet->getViewNet()->getUndoList());496}497498499void500GNEAdditional::selectGLObject() {501if (isAttributeCarrierSelected()) {502unselectAttributeCarrier();503} else {504selectAttributeCarrier();505}506// update information label507myNet->getViewNet()->getViewParent()->getSelectorFrame()->getSelectionInformation()->updateInformationLabel();508}509510511void GNEAdditional::updateGLObject() {512updateGeometry();513}514515516void517GNEAdditional::computePathElement() {518// Nothing to compute519}520521522bool523GNEAdditional::isPathElementSelected() const {524return mySelected;525}526527528void529GNEAdditional::drawLanePartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {530// Nothing to draw531}532533534void535GNEAdditional::drawJunctionPartialGL(const GUIVisualizationSettings& /*s*/, const GNESegment* /*segment*/, const double /*offsetFront*/) const {536// Nothing to draw537}538539// ---------------------------------------------------------------------------540// GNEAdditional - protected methods541// ---------------------------------------------------------------------------542543bool544GNEAdditional::isValidAdditionalID(const std::string& value) const {545if (!isTemplate() && (value == getID())) {546return true;547} else if (SUMOXMLDefinitions::isValidAdditionalID(value)) {548return (myNet->getAttributeCarriers()->retrieveAdditional(myTagProperty->getTag(), value, false) == nullptr);549} else {550return false;551}552}553554555bool556GNEAdditional::isValidAdditionalID(const std::vector<SumoXMLTag>& tags, const std::string& value) const {557if (isTemplate() && value.empty()) {558return true;559} else if (!isTemplate() && (value == getID())) {560return true;561} else if (SUMOXMLDefinitions::isValidAdditionalID(value)) {562return (myNet->getAttributeCarriers()->retrieveAdditionals(tags, value, false) == nullptr);563} else {564return false;565}566}567568569bool570GNEAdditional::isValidDetectorID(const std::string& value) const {571if (isTemplate() && value.empty()) {572return true;573} else if (!isTemplate() && (value == getID())) {574return true;575} else if (SUMOXMLDefinitions::isValidDetectorID(value)) {576return (myNet->getAttributeCarriers()->retrieveAdditional(myTagProperty->getTag(), value, false) == nullptr);577} else {578return false;579}580}581582583bool584GNEAdditional::isValidDetectorID(const std::vector<SumoXMLTag>& tags, const std::string& value) const {585if (!isTemplate() && (value == getID())) {586return true;587} else if (SUMOXMLDefinitions::isValidDetectorID(value)) {588return (myNet->getAttributeCarriers()->retrieveAdditionals(tags, value, false) == nullptr);589} else {590return false;591}592}593594595void596GNEAdditional::setAdditionalID(const std::string& newID) {597// update ID598if (isTemplate()) {599setMicrosimID(newID);600} else if ((myTagProperty->getTag() == SUMO_TAG_VAPORIZER) || !myTagProperty->hasAttribute(SUMO_ATTR_ID)) {601setMicrosimID(newID);602} else {603myNet->getAttributeCarriers()->updateAdditionalID(this, newID);604}605// change IDs of certain children606for (const auto& additionalChild : getChildAdditionals()) {607// get tag608const auto tag = additionalChild->getTagProperty()->getTag();609if ((tag == SUMO_TAG_ACCESS) || (tag == SUMO_TAG_PARKING_SPACE) ||610(tag == SUMO_TAG_DET_ENTRY) || (tag == SUMO_TAG_DET_EXIT)) {611additionalChild->setAdditionalID(getID());612}613}614// enable save demand elements if this additional has children615if (getChildDemandElements().size() > 0) {616myNet->getSavingStatus()->requireSaveDemandElements();617}618// enable save data elements if this additional has children619if (getChildGenericDatas().size() > 0) {620myNet->getSavingStatus()->requireSaveDataElements();621}622}623624625void626GNEAdditional::drawAdditionalID(const GUIVisualizationSettings& s) const {627if (s.addName.show(this) && (myAdditionalGeometry.getShape().size() > 0)) {628// calculate middle point629const double middlePoint = (myAdditionalGeometry.getShape().length2D() * 0.5);630// calculate position631const Position pos = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShape().front() : myAdditionalGeometry.getShape().positionAtOffset2D(middlePoint);632// calculate rotation633const double rot = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShapeRotations().front() : myAdditionalGeometry.getShape().rotationDegreeAtOffset(middlePoint);634// draw additional ID635if (myTagProperty->hasAttribute(SUMO_ATTR_LANE)) {636GLHelper::drawText(getMicrosimID(), pos, GLO_MAX - getType(), s.addName.scaledSize(s.scale), s.addName.color, s.getTextAngle(rot - 90));637} else {638GLHelper::drawText(getMicrosimID(), pos, GLO_MAX - getType(), s.addName.scaledSize(s.scale), s.addName.color, 0);639}640}641}642643644void645GNEAdditional::drawAdditionalName(const GUIVisualizationSettings& s) const {646if (s.addFullName.show(this) && (myAdditionalGeometry.getShape().size() > 0) && (myAdditionalName != "")) {647// calculate middle point648const double middlePoint = (myAdditionalGeometry.getShape().length2D() * 0.5);649// calculate position650const Position pos = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShape().front() : myAdditionalGeometry.getShape().positionAtOffset2D(middlePoint);651// calculate rotation652const double rot = (myAdditionalGeometry.getShape().size() == 1) ? myAdditionalGeometry.getShapeRotations().front() : myAdditionalGeometry.getShape().rotationDegreeAtOffset(middlePoint);653// draw additional name654if (myTagProperty->hasAttribute(SUMO_ATTR_LANE)) {655GLHelper::drawText(myAdditionalName, pos, GLO_MAX - getType(), s.addFullName.scaledSize(s.scale), s.addFullName.color, s.getTextAngle(rot - 90));656} else {657GLHelper::drawText(myAdditionalName, pos, GLO_MAX - getType(), s.addFullName.scaledSize(s.scale), s.addFullName.color, 0);658}659}660}661662663void664GNEAdditional::replaceAdditionalParentEdges(const std::string& value) {665GNEHierarchicalElement::updateParents(this, parse<GNEHierarchicalContainerParents<GNEEdge*> >(getNet(), value));666}667668669void670GNEAdditional::replaceAdditionalParentLanes(const std::string& value) {671GNEHierarchicalElement::updateParents(this, parse<GNEHierarchicalContainerParents<GNELane*> >(getNet(), value));672673}674675676void677GNEAdditional::replaceAdditionalChildEdges(const std::string& value) {678GNEHierarchicalElement::updateChildren(this, parse<GNEHierarchicalContainerParents<GNEEdge*> >(getNet(), value));679}680681682void683GNEAdditional::replaceAdditionalChildLanes(const std::string& value) {684GNEHierarchicalElement::updateChildren(this, parse<GNEHierarchicalContainerParents<GNELane*> >(getNet(), value));685686}687688689void690GNEAdditional::replaceAdditionalParent(SumoXMLTag tag, const std::string& value, const int parentIndex) {691std::vector<GNEAdditional*> newParentAdditionals;692// special case for calibrators and routeprobes693if (value.size() > 0) {694newParentAdditionals = getParentAdditionals();695if ((newParentAdditionals.size() == 0) && (parentIndex == 0)) {696newParentAdditionals.push_back(myNet->getAttributeCarriers()->retrieveAdditional(tag, value));697} else {698newParentAdditionals[parentIndex] = myNet->getAttributeCarriers()->retrieveAdditional(tag, value);699}700}701GNEHierarchicalElement::updateParents(this, newParentAdditionals);702}703704705void706GNEAdditional::replaceDemandElementParent(SumoXMLTag tag, const std::string& value, const int parentIndex) {707auto newDemandElement = myNet->getAttributeCarriers()->retrieveDemandElement(tag, value);708GNEHierarchicalElement::updateParent(this, parentIndex, newDemandElement);709}710711712void713GNEAdditional::shiftLaneIndex() {714const std::vector<GNELane*> newLanes = {getParentLanes().front()->getParentEdge()->getChildLanes().at(getParentLanes().front()->getIndex() + 1)};715GNEHierarchicalElement::updateParents(this, newLanes);716}717718719void720GNEAdditional::calculatePerpendicularLine(const double endLaneposition) {721if (getParentEdges().empty()) {722throw ProcessError(TL("Invalid number of edges"));723} else {724// get lanes725const GNELane* firstLane = getParentEdges().front()->getChildLanes().front();726const GNELane* lastLane = getParentEdges().front()->getChildLanes().back();727// get first and back lane shapes728PositionVector firstLaneShape = firstLane->getLaneShape();729PositionVector lastLaneShape = lastLane->getLaneShape();730// move shapes731firstLaneShape.move2side((firstLane->getParentEdge()->getNBEdge()->getLaneWidth(firstLane->getIndex()) * 0.5) + 1);732lastLaneShape.move2side(lastLane->getParentEdge()->getNBEdge()->getLaneWidth(lastLane->getIndex()) * -0.5);733// calculate lane postion734const double lanePosition = firstLaneShape.length2D() >= endLaneposition ? endLaneposition : firstLaneShape.length2D();735// update geometry736myAdditionalGeometry.updateGeometry({firstLaneShape.positionAtOffset2D(lanePosition), lastLaneShape.positionAtOffset2D(lanePosition)});737}738}739740741void742GNEAdditional::drawSquaredAdditional(const GUIVisualizationSettings& s, const Position& pos, const double size, GUITexture texture, GUITexture selectedTexture) const {743// draw boundaries744GLHelper::drawBoundary(s, getCenteringBoundary());745// Obtain drawing exaggeration746const double exaggeration = getExaggeration(s);747// get detail level748const auto d = s.getDetailLevel(exaggeration);749// draw geometry only if we'rent in drawForObjectUnderCursor mode750if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {751// Add layer matrix752GLHelper::pushMatrix();753// translate to front754drawInLayer(getType());755// translate to position756glTranslated(pos.x(), pos.y(), 0);757// scale758glScaled(exaggeration, exaggeration, 1);759// set White color760glColor3d(1, 1, 1);761// rotate762glRotated(180, 0, 0, 1);763// draw texture764if (drawUsingSelectColor()) {765GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(selectedTexture), size);766} else {767GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(texture), size);768}769// Pop layer matrix770GLHelper::popMatrix();771// draw lock icon772GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), pos, exaggeration, 0.4, 0.5, 0.5);773// Draw additional ID774drawAdditionalID(s);775// draw additional name776drawAdditionalName(s);777// draw dotted contour778myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);779}780// calculate contour781myAdditionalContour.calculateContourRectangleShape(s, d, this, pos, size, size, getType(), 0, 0, 0, exaggeration, nullptr);782}783784785void786GNEAdditional::drawListedAdditional(const GUIVisualizationSettings& s, const Position& parentPosition, const double offsetX,787const double extraOffsetY, const RGBColor baseCol, const RGBColor textCol, GUITexture texture,788const std::string text) const {789// check if additional has to be drawn790if (myNet->getViewNet()->getDataViewOptions().showAdditionals()) {791// draw boundaries792GLHelper::drawBoundary(s, getCenteringBoundary());793// get detail level794const auto d = s.getDetailLevel(1);795// declare offsets796const double lineOffset = 0.1875;797const double baseOffsetX = 6.25;798const double baseOffsetY = 0.6;799// get draw position index800const int drawPositionIndex = getDrawPositionIndex();801// calculate lineA position (from parent to middle)802Position positionLineA = parentPosition;803const double positionLineA_Y = (0 - extraOffsetY + baseOffsetY);804// set position depending of indexes805positionLineA.add(1 + lineOffset + (baseOffsetX * offsetX), positionLineA_Y, 0);806// calculate lineC position (From middle until current listenAdditional807Position positionLineB = parentPosition;808const double positionLineB_Y = ((drawPositionIndex * -1) - extraOffsetY + baseOffsetY);809// set position depending of indexes810positionLineB.add(1 + lineOffset + (baseOffsetX * offsetX) + (2 * lineOffset), positionLineB_Y, 0);811// calculate signPosition position812Position signPosition = parentPosition;813// draw geometry only if we'rent in drawForObjectUnderCursor mode814if (s.checkDrawAdditional(d, isAttributeCarrierSelected())) {815// set position depending of indexes816signPosition.add(4.5 + (baseOffsetX * offsetX), (drawPositionIndex * -1) - extraOffsetY + 1, 0);817// calculate colors818const RGBColor baseColor = isAttributeCarrierSelected() ? s.colorSettings.selectedAdditionalColor : baseCol;819const RGBColor secondColor = baseColor.changedBrightness(-30);820const RGBColor textColor = isAttributeCarrierSelected() ? s.colorSettings.selectedAdditionalColor.changedBrightness(30) : textCol;821// Add layer matrix822GLHelper::pushMatrix();823// translate to front824drawInLayer(getType());825// set line color826GLHelper::setColor(s.additionalSettings.connectionColor);827// draw both lines828GLHelper::drawBoxLine(positionLineA, 0, 0.1, lineOffset);829GLHelper::drawBoxLine(positionLineB, 0, 0.1, lineOffset);830// check if draw middle lane831if (drawPositionIndex != 0) {832// calculate length833const double length = std::abs(positionLineA_Y - positionLineB_Y);834// push middle lane matrix835GLHelper::pushMatrix();836//move and rotate837glTranslated(positionLineA.x() + lineOffset, positionLineA.y(), 0);838glRotated(90, 0, 0, 1);839glTranslated((length * -0.5), 0, 0);840// draw line841GLHelper::drawBoxLine(Position(0, 0), 0, 0.1, length * 0.5);842// pop middle lane matrix843GLHelper::popMatrix();844}845// draw extern rectangle846GLHelper::setColor(secondColor);847GLHelper::drawBoxLine(signPosition, 0, 0.96, 2.75);848// move to front849glTranslated(0, -0.06, 0.1);850// draw intern rectangle851GLHelper::setColor(baseColor);852GLHelper::drawBoxLine(signPosition, 0, 0.84, 2.69);853// move position down854signPosition.add(-2, -0.43, 0);855// draw interval856GLHelper::drawText(adjustListedAdditionalText(text), signPosition, .1, 0.5, textColor, 0, (FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE));857// move to icon position858signPosition.add(-0.3, 0);859// check if draw lock icon or rerouter interval icon860if (GNEViewNetHelper::LockIcon::checkDrawing(d, this, getType(), 1)) {861// pop layer matrix862GLHelper::popMatrix();863// draw lock icon864GNEViewNetHelper::LockIcon::drawLockIcon(d, this, getType(), signPosition, 1, 0.4, 0.0, -0.05);865} else {866// translate to front867glTranslated(signPosition.x(), signPosition.y(), 0.1);868// set White color869glColor3d(1, 1, 1);870// rotate871glRotated(180, 0, 0, 1);872// draw texture873GUITexturesHelper::drawTexturedBox(GUITextureSubSys::getTexture(texture), 0.25);874// pop layer matrix875GLHelper::popMatrix();876}877// draw dotted contour878myAdditionalContour.drawDottedContours(s, d, this, s.dottedContourSettings.segmentWidth, true);879}880// calculate contour881myAdditionalContour.calculateContourRectangleShape(s, d, this, signPosition, 0.56, 2.75, getType(), 0, -2.3, 0, 1, nullptr);882}883}884885886bool887GNEAdditional::drawMovingGeometryPoints(const bool ignoreShift) const {888// get modes889const auto& modes = myNet->getViewNet()->getEditModes();890// check conditions891if (modes.isCurrentSupermodeNetwork() && (modes.networkEditMode == NetworkEditMode::NETWORK_MOVE) &&892(ignoreShift || myNet->getViewNet()->getMouseButtonKeyPressed().shiftKeyPressed())) {893return true;894} else {895return false;896}897}898899900void901GNEAdditional::drawDemandElementChildren(const GUIVisualizationSettings& s) const {902// draw child demand elements903for (const auto& demandElement : getChildDemandElements()) {904if (!demandElement->getTagProperty()->isPlacedInRTree()) {905demandElement->drawGL(s);906}907}908}909910911GNEMoveOperation*912GNEAdditional::getMoveOperationSingleLane(const double startPos, const double endPos) {913// get allow change lane914const bool allowChangeLane = myNet->getViewNet()->getViewParent()->getMoveFrame()->getCommonMoveOptions()->getAllowChangeLane();915// fist check if we're moving only extremes916if (myNet->getViewNet()->getMouseButtonKeyPressed().shiftKeyPressed()) {917// get snap radius918const double snap_radius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;919// get mouse position920const Position mousePosition = myNet->getViewNet()->getPositionInformation();921// check if we clicked over start or end position922if (myAdditionalGeometry.getShape().front().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {923// move only start position924return new GNEMoveOperation(this, getParentLanes().front(), startPos, endPos,925allowChangeLane, GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_FIRST);926} else if (myAdditionalGeometry.getShape().back().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {927// move only end position928return new GNEMoveOperation(this, getParentLanes().front(), startPos, endPos,929allowChangeLane, GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_LAST);930} else {931return nullptr;932}933} else {934// move both start and end positions935return new GNEMoveOperation(this, getParentLanes().front(), startPos, endPos,936allowChangeLane, GNEMoveOperation::OperationType::SINGLE_LANE_MOVE_BOTH);937}938}939940941GNEMoveOperation*942GNEAdditional::getMoveOperationMultiLane(const double startPos, const double endPos) {943// get snap radius944const double snap_radius = myNet->getViewNet()->getVisualisationSettings().neteditSizeSettings.additionalGeometryPointRadius;945// get mouse position946const Position mousePosition = myNet->getViewNet()->getPositionInformation();947// calculate both geometries948GUIGeometry fromGeometry, toGeometry;949fromGeometry.updateGeometry(getParentLanes().front()->getLaneGeometry().getShape(), startPos, 0);950toGeometry.updateGeometry(getParentLanes().back()->getLaneGeometry().getShape(), endPos, 0);951// check if we clicked over start or end position952if (myNet->getViewNet()->getMouseButtonKeyPressed().shiftKeyPressed()) {953if (fromGeometry.getShape().front().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {954// move first position955return new GNEMoveOperation(this, getParentLanes().front(), startPos, getParentLanes().back(), endPos,956false, GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_FIRST);957} else if (toGeometry.getShape().back().distanceSquaredTo2D(mousePosition) <= (snap_radius * snap_radius)) {958// move last position959return new GNEMoveOperation(this, getParentLanes().front(), startPos, getParentLanes().back(), endPos,960false, GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_LAST);961}962} else {963auto segment = gViewObjectsHandler.getSelectedSegment(this);964if (segment) {965if (segment->getLaneIndex() == 0) {966return new GNEMoveOperation(this, getParentLanes().front(), startPos, getParentLanes().back(), endPos,967false, GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_FIRST);968} else if (segment->getLaneIndex() == ((int)getParentLanes().size() - 1)) {969return new GNEMoveOperation(this, getParentLanes().front(), startPos, getParentLanes().back(), endPos,970false, GNEMoveOperation::OperationType::MULTIPLE_LANES_MOVE_BOTH_LAST);971}972}973}974return nullptr;975}976977978std::string979GNEAdditional::getJuPedSimType(SumoXMLTag tag) {980// continue depending of tag981switch (tag) {982case GNE_TAG_JPS_WALKABLEAREA:983return "jupedsim.walkable_area";984case GNE_TAG_JPS_OBSTACLE:985return "jupedsim.obstacle";986default:987throw InvalidArgument("Invalid JuPedSim tag");988}989}990991992RGBColor993GNEAdditional::getJuPedSimColor(SumoXMLTag tag) {994// continue depending of tag995switch (tag) {996case GNE_TAG_JPS_WALKABLEAREA:997return RGBColor(179, 217, 255);998case GNE_TAG_JPS_OBSTACLE:999return RGBColor(255, 204, 204);1000default:1001throw InvalidArgument("Invalid JuPedSim tag");1002}1003}100410051006bool1007GNEAdditional::getJuPedSimFill(SumoXMLTag tag) {1008// continue depending of tag1009switch (tag) {1010case GNE_TAG_JPS_WALKABLEAREA:1011case GNE_TAG_JPS_OBSTACLE:1012return true;1013default:1014throw InvalidArgument("Invalid JuPedSim tag");1015}1016}101710181019double1020GNEAdditional::getJuPedSimLayer(SumoXMLTag tag) {1021// continue depending of tag1022switch (tag) {1023case GNE_TAG_JPS_WALKABLEAREA:1024return 1;1025case GNE_TAG_JPS_OBSTACLE:1026return 2;1027default:1028throw InvalidArgument("Invalid JuPedSim tag");1029}1030}103110321033void1034GNEAdditional::calculateContourPolygons(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,1035const double layer, const double exaggeration, const bool filledShape) const {1036// calculate contour depending of contoured shape1037if (filledShape) {1038myAdditionalContour.calculateContourClosedShape(s, d, this, myAdditionalGeometry.getShape(), layer, 1, nullptr);1039} else {1040myAdditionalContour.calculateContourExtrudedShape(s, d, this, myAdditionalGeometry.getShape(), layer,1041s.neteditSizeSettings.polylineWidth, exaggeration, true, true, 0, nullptr, nullptr);1042}1043// get edit modes1044const auto& editModes = myNet->getViewNet()->getEditModes();1045// check if draw geometry points1046if (editModes.isCurrentSupermodeNetwork() && !myNet->getViewNet()->getViewParent()->getMoveFrame()->getNetworkMoveOptions()->getMoveWholePolygons()) {1047// check if we're in move mode1048const bool moveMode = (editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE);1049// get geometry point radius (size depends if we're in move mode)1050const double geometryPointRaidus = s.neteditSizeSettings.polygonGeometryPointRadius * (moveMode ? 1 : 0.5);1051// calculate contour geometry points1052myAdditionalContour.calculateContourAllGeometryPoints(s, d, this, myAdditionalGeometry.getShape(), layer, geometryPointRaidus, exaggeration, moveMode);1053}1054}105510561057GNELane*1058GNEAdditional::getFirstPathLane() const {1059return getParentLanes().front();1060}106110621063GNELane*1064GNEAdditional::getLastPathLane() const {1065return getParentLanes().back();1066}106710681069Position1070GNEAdditional::getAttributePosition(SumoXMLAttr key) const {1071throw InvalidArgument(getTagStr() + " doesn't have an attribute of type '" + toString(key) + "'");1072}107310741075void1076GNEAdditional::drawParentChildLines(const GUIVisualizationSettings& s, const RGBColor& color, const bool onlySymbols) const {1077const auto& inspectedElements = myNet->getViewNet()->getInspectedElements();1078// check if current additional is inspected, front or selected1079const bool currentDrawEntire = inspectedElements.isACInspected(this) || myDrawInFront || isAttributeCarrierSelected();1080// push layer matrix1081GLHelper::pushMatrix();1082// translate to parentChildLine layer1083glTranslated(0, 0, GLO_PARENTCHILDLINE);1084// iterate over parent additionals1085for (const auto& parent : getParentAdditionals()) {1086// get inspected flag1087const bool parentInspected = inspectedElements.isACInspected(parent);1088// draw parent lines1089GUIGeometry::drawParentLine(s, getPositionInView(), parent->getPositionInView(),1090(isAttributeCarrierSelected() || parent->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,1091currentDrawEntire || parentInspected || parent->isAttributeCarrierSelected(), .05);1092}1093// special case for Parking area reroutes1094if (getTagProperty()->getTag() == SUMO_TAG_REROUTER) {1095// iterate over rerouter elements1096for (const auto& rerouterInterval : getChildAdditionals()) {1097for (const auto& rerouterElement : rerouterInterval->getChildAdditionals()) {1098if (rerouterElement->getTagProperty()->getTag() == SUMO_TAG_PARKING_AREA_REROUTE) {1099// get parking area1100const auto parkingArea = rerouterElement->getParentAdditionals().at(1);1101// get inspected flag1102const bool parkingAreaInspected = inspectedElements.isACInspected(parkingArea);1103// draw parent lines1104GUIGeometry::drawParentLine(s, getPositionInView(), parkingArea->getPositionInView(),1105(isAttributeCarrierSelected() || parkingArea->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,1106currentDrawEntire || parkingAreaInspected || parkingArea->isAttributeCarrierSelected(), .05);1107}1108}1109}1110}1111// iterate over child additionals1112for (const auto& child : getChildAdditionals()) {1113// get inspected flag1114const bool childInspected = inspectedElements.isACInspected(child);1115// special case for parking zone reroute1116if (child->getTagProperty()->getTag() == SUMO_TAG_PARKING_AREA_REROUTE) {1117// draw child line between parking area and rerouter1118GUIGeometry::drawChildLine(s, getPositionInView(), child->getParentAdditionals().front()->getParentAdditionals().front()->getPositionInView(),1119(isAttributeCarrierSelected() || child->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,1120currentDrawEntire || childInspected || child->isAttributeCarrierSelected(), .05);1121} else if (!onlySymbols || child->getTagProperty()->isSymbol()) {1122// draw child line1123GUIGeometry::drawChildLine(s, getPositionInView(), child->getPositionInView(),1124(isAttributeCarrierSelected() || child->isAttributeCarrierSelected()) ? s.additionalSettings.connectionColorSelected : color,1125currentDrawEntire || childInspected || child->isAttributeCarrierSelected(), .05);1126}1127}1128// pop layer matrix1129GLHelper::popMatrix();1130}113111321133void1134GNEAdditional::drawUpGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,1135const double rot, const RGBColor& baseColor, const bool ignoreShift) const {1136drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, -90, 90, ignoreShift);1137}11381139void1140GNEAdditional::drawDownGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,1141const double rot, const RGBColor& baseColor, const bool ignoreShift) const {1142drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, 90, 270, ignoreShift);1143}11441145void1146GNEAdditional::drawLeftGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,1147const double rot, const RGBColor& baseColor, const bool ignoreShift) const {1148drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, -90, 90, ignoreShift);1149}115011511152void1153GNEAdditional::drawRightGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d, const Position& pos,1154const double rot, const RGBColor& baseColor, const bool ignoreShift) const {1155drawSemiCircleGeometryPoint(s, d, pos, rot, baseColor, 270, 90, ignoreShift);1156}115711581159int1160GNEAdditional::getDrawPositionIndex() const {1161// filter symbols1162std::vector<GNEAdditional*> children;1163for (const auto& child : getParentAdditionals().front()->getChildAdditionals()) {1164if (!child->getTagProperty()->isSymbol()) {1165children.push_back(child);1166}1167}1168// now get index1169for (int i = 0; i < (int)children.size(); i++) {1170if (children.at(i) == this) {1171return i;1172}1173}1174return 0;1175}117611771178bool1179GNEAdditional::areLaneConsecutives(const std::vector<GNELane*>& lanes) {1180// declare lane iterator1181int laneIt = 0;1182// iterate over all lanes1183while (laneIt < ((int)lanes.size() - 1)) {1184// we assume that lanes aren't consecutive1185bool consecutiveFound = false;1186// get lanes1187const auto lane = lanes.at(laneIt);1188const auto nextLane = lanes.at(laneIt + 1);1189// if there is a connection between "from" lane and "to" lane of connection, change connectionFound to true1190for (const auto& outgoingEdge : lane->getParentEdge()->getToJunction()->getGNEOutgoingEdges()) {1191for (const auto& outgoingLane : outgoingEdge->getChildLanes()) {1192if (outgoingLane == nextLane) {1193consecutiveFound = true;1194}1195}1196}1197// abort if consecutiveFound is false1198if (!consecutiveFound) {1199return false;1200}1201// update iterator1202laneIt++;1203}1204// lanes are consecutive, then return true1205return true;1206}120712081209bool1210GNEAdditional::areLaneConnected(const std::vector<GNELane*>& lanes) {1211// declare lane iterator1212int laneIt = 0;1213// iterate over all lanes, and stop if myE2valid is false1214while (laneIt < ((int)lanes.size() - 1)) {1215// we assume that E2 is invalid1216bool connectionFound = false;1217// get lanes1218const auto lane = lanes.at(laneIt);1219const auto nextLane = lanes.at(laneIt + 1);1220// check if both lanes are sidewalks1221if ((lane->getAttribute(SUMO_ATTR_ALLOW) == "pedestrian") && (nextLane->getAttribute(SUMO_ATTR_ALLOW) == "pedestrian")) {1222connectionFound = true;1223}1224// if there is a connection between "from" lane and "to" lane of connection, change connectionFound to true1225for (const auto& connection : lane->getParentEdge()->getNBEdge()->getConnections()) {1226if ((connection.toEdge == nextLane->getParentEdge()->getNBEdge()) &&1227(connection.fromLane == lane->getIndex()) &&1228(connection.toLane == nextLane->getIndex())) {1229connectionFound = true;1230}1231}1232// abort if connectionFound is false1233if (!connectionFound) {1234return false;1235}1236// update iterator1237laneIt++;1238}1239// there are connections between all lanes, then return true1240return true;1241}124212431244bool1245GNEAdditional::checkChildAdditionalRestriction() const {1246// throw exception because this function mus be implemented in child (see GNEE3Detector)1247throw ProcessError(StringUtils::format("Calling non-implemented function checkChildAdditionalRestriction during saving of %. It muss be reimplemented in child class", getTagStr()));1248}124912501251void1252GNEAdditional::drawSemiCircleGeometryPoint(const GUIVisualizationSettings& s, const GUIVisualizationSettings::Detail d,1253const Position& pos, const double rot, const RGBColor& baseColor, const double fromAngle, const double toAngle,1254const bool /* ignoreShift */) const {1255// check if draw geometry point1256if (!s.drawForViewObjectsHandler && (d <= GUIVisualizationSettings::Detail::GeometryPoint)) {1257// push matrix1258GLHelper::pushMatrix();1259// translated to front1260glTranslated(0, 0, 0.1);1261// set color depending if check if mouse is over element1262GLHelper::setColor(baseColor.changedBrightness(-50));1263// translate and rotate1264glTranslated(pos.x(), pos.y(), 0.1);1265glRotated(rot, 0, 0, 1);1266// draw geometry point1267GLHelper::drawFilledCircleDetailled(d, s.neteditSizeSettings.additionalGeometryPointRadius, fromAngle, toAngle);1268// pop geometry point matrix1269GLHelper::popMatrix();1270}1271}127212731274std::string1275GNEAdditional::adjustListedAdditionalText(const std::string& text) const {1276// 10 + 3 + 101277if (text.size() <= 23) {1278return text;1279} else {1280// get text size1281const int textPosition = (int)text.size() - 10;1282// declare strings1283std::string partA, partB;1284// resize1285partA.reserve(10);1286partB.reserve(10);1287// fill both1288for (int i = 0; i < 10; i++) {1289partA.push_back(text.at(i));1290partB.push_back(text.at(textPosition + i));1291}1292// return composition1293return (partA + "..." + partB);1294}1295}12961297/****************************************************************************/129812991300