Path: blob/main/src/netedit/elements/additional/GNEAdditionalHandler.cpp
193678 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 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 GNEAdditionalHandler.cpp14/// @author Pablo Alvarez Lopez15/// @date Nov 201516///17// Builds trigger objects for netedit18/****************************************************************************/19#include <config.h>2021#include <netedit/changes/GNEChange_Additional.h>22#include <netedit/changes/GNEChange_TAZSourceSink.h>23#include <netedit/dialogs/basic/GNEOverwriteElement.h>24#include <netedit/GNEApplicationWindow.h>25#include <netedit/GNENet.h>26#include <netedit/GNETagProperties.h>27#include <netedit/GNEUndoList.h>28#include <utils/options/OptionsCont.h>29#include <utils/xml/NamespaceIDs.h>3031#include "GNEAccess.h"32#include "GNEAdditionalHandler.h"33#include "GNEBusStop.h"34#include "GNECalibrator.h"35#include "GNECalibratorFlow.h"36#include "GNEChargingStation.h"37#include "GNEClosingLaneReroute.h"38#include "GNEClosingReroute.h"39#include "GNEContainerStop.h"40#include "GNEDestProbReroute.h"41#include "GNEEntryExitDetector.h"42#include "GNEInductionLoopDetector.h"43#include "GNEInstantInductionLoopDetector.h"44#include "GNELaneAreaDetector.h"45#include "GNEMultiEntryExitDetector.h"46#include "GNEOverheadWire.h"47#include "GNEPOI.h"48#include "GNEParkingArea.h"49#include "GNEParkingAreaReroute.h"50#include "GNEParkingSpace.h"51#include "GNEPoly.h"52#include "GNERerouter.h"53#include "GNERerouterInterval.h"54#include "GNERerouterSymbol.h"55#include "GNERouteProbReroute.h"56#include "GNERouteProbe.h"57#include "GNETAZ.h"58#include "GNETractionSubstation.h"59#include "GNEVaporizer.h"60#include "GNEVariableSpeedSign.h"61#include "GNEVariableSpeedSignStep.h"62#include "GNEVariableSpeedSignSymbol.h"6364// ===========================================================================65// GNEAdditionalHandler method definitions66// ===========================================================================6768GNEAdditionalHandler::GNEAdditionalHandler(GNENet* net, FileBucket* fileBucket, const bool allowUndoRedo) :69AdditionalHandler(fileBucket),70myNet(net),71myAllowUndoRedo(allowUndoRedo) {72}737475GNEAdditionalHandler::~GNEAdditionalHandler() {76// update options based in current buckets77myNet->getGNEApplicationWindow()->getFileBucketHandler()->updateOptions();78}798081bool82GNEAdditionalHandler::buildBusStop(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id,83const std::string& laneID, const double startPos, const double endPos, const std::string& name,84const std::vector<std::string>& lines, const int personCapacity, const double parkingLength,85const RGBColor& color, const bool friendlyPosition, const double angle,86const Parameterised::Map& parameters) {87// check conditions88const auto element = retrieveAdditionalElement(NamespaceIDs::busStops, id);89if (!checkElement(SUMO_TAG_BUS_STOP, element)) {90return false;91} else if (!checkValidAdditionalID(SUMO_TAG_BUS_STOP, id)) {92return false;93} else {94// get lane95GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);96// check lane97if (lane == nullptr) {98return writeErrorInvalidParent(SUMO_TAG_BUS_STOP, id, {SUMO_TAG_LANE}, laneID);99} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {100return writeErrorInvalidPosition(SUMO_TAG_BUS_STOP, id);101} else if (!checkNegative(SUMO_TAG_BUS_STOP, id, SUMO_ATTR_PERSON_CAPACITY, personCapacity, true)) {102return false;103} else if (!checkNegative(SUMO_TAG_BUS_STOP, id, SUMO_ATTR_PARKING_LENGTH, parkingLength, true)) {104return false;105} else {106// build busStop107GNEAdditional* busStop = GNEBusStop::buildBusStop(id, myNet, myFileBucket, lane, startPos, endPos, name, lines, personCapacity,108parkingLength, color, friendlyPosition, angle, parameters);109// insert depending of allowUndoRedo110if (myAllowUndoRedo) {111myNet->getUndoList()->begin(busStop, TL("add bus stop '") + id + "'");112myNet->getUndoList()->add(new GNEChange_Additional(busStop, true), true);113myNet->getUndoList()->end();114} else {115myNet->getAttributeCarriers()->insertAdditional(busStop);116lane->addChildElement(busStop);117busStop->incRef("buildBusStop");118}119return true;120}121}122}123124125bool126GNEAdditionalHandler::buildTrainStop(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id,127const std::string& laneID, const double startPos, const double endPos, const std::string& name,128const std::vector<std::string>& lines, const int personCapacity, const double parkingLength,129const RGBColor& color, const bool friendlyPosition, const double angle,130const Parameterised::Map& parameters) {131// check conditions132const auto element = retrieveAdditionalElement(NamespaceIDs::busStops, id);133if (!checkElement(SUMO_TAG_TRAIN_STOP, element)) {134return false;135} else if (!checkValidAdditionalID(SUMO_TAG_TRAIN_STOP, id)) {136return false;137} else {138// get lane139GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);140// check lane141if (lane == nullptr) {142return writeErrorInvalidParent(SUMO_TAG_TRAIN_STOP, id, {SUMO_TAG_LANE}, laneID);143} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {144return writeErrorInvalidPosition(SUMO_TAG_TRAIN_STOP, id);145} else if (!checkNegative(SUMO_TAG_TRAIN_STOP, id, SUMO_ATTR_PERSON_CAPACITY, personCapacity, true)) {146return false;147} else if (!checkNegative(SUMO_TAG_TRAIN_STOP, id, SUMO_ATTR_PARKING_LENGTH, parkingLength, true)) {148return false;149} else {150// build trainStop151GNEAdditional* trainStop = GNEBusStop::buildTrainStop(id, myNet, myFileBucket, lane, startPos, endPos, name, lines, personCapacity,152parkingLength, color, friendlyPosition, angle, parameters);153// insert depending of allowUndoRedo154if (myAllowUndoRedo) {155myNet->getUndoList()->begin(trainStop, TL("add train stop '") + id + "'");156myNet->getUndoList()->add(new GNEChange_Additional(trainStop, true), true);157myNet->getUndoList()->end();158} else {159myNet->getAttributeCarriers()->insertAdditional(trainStop);160lane->addChildElement(trainStop);161trainStop->incRef("buildTrainStop");162}163return true;164}165}166}167168169bool170GNEAdditionalHandler::buildAccess(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& laneID,171const std::string& pos, const double length, const bool friendlyPos, const Parameterised::Map& parameters) {172// get lane173GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);174// get busStop (or trainStop)175const auto busStop = getAdditionalParent(sumoBaseObject, SUMO_TAG_BUS_STOP);176const auto trainStop = getAdditionalParent(sumoBaseObject, SUMO_TAG_TRAIN_STOP);177const auto containerStop = getAdditionalParent(sumoBaseObject, SUMO_TAG_CONTAINER_STOP);178// check parent179if ((busStop == nullptr) && (trainStop == nullptr) && (containerStop == nullptr)) {180if (sumoBaseObject->getParentSumoBaseObject()->hasStringAttribute(SUMO_ATTR_ID)) {181return writeErrorInvalidParent(SUMO_TAG_ACCESS, {SUMO_TAG_BUS_STOP, SUMO_TAG_TRAIN_STOP, SUMO_TAG_CONTAINER_STOP}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));182} else {183return writeErrorInvalidParent(SUMO_TAG_ACCESS, {SUMO_TAG_BUS_STOP, SUMO_TAG_TRAIN_STOP, SUMO_TAG_CONTAINER_STOP});184}185}186GNEAdditional* accessParent = busStop ? busStop : trainStop ? trainStop : containerStop;187// pos double188bool validPos = true;189double posDouble = 0;190if (lane) {191if (GNEAttributeCarrier::canParse<double>(pos)) {192posDouble = GNEAttributeCarrier::parse<double>(pos);193validPos = checkLanePosition(posDouble, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos);194} else if (pos == "random" || pos == "doors" || pos == "carriage") {195posDouble = INVALID_DOUBLE;196} else if (pos.empty()) {197posDouble = 0;198} else {199validPos = false;200}201}202// Check if lane is correct203if (lane == nullptr) {204return writeErrorInvalidParent(SUMO_TAG_ACCESS, "", {SUMO_TAG_LANE}, laneID);205} else if (!validPos) {206return writeErrorInvalidPosition(SUMO_TAG_ACCESS, accessParent->getID());207} else if ((length != -1) && !checkNegative(SUMO_TAG_ACCESS, accessParent->getID(), SUMO_ATTR_LENGTH, length, true)) {208return false;209} else if (!accessExists(accessParent, lane->getParentEdge())) {210return writeError(TLF("Could not build access in netedit; % '%' already owns an access in the edge '%'", accessParent->getTagStr(), accessParent->getID(), lane->getParentEdge()->getID()));211} else if (!containerStop && !lane->allowPedestrians()) {212// only for busStops and trainStops213return writeError(TLF("Could not build access in netedit; The lane '%' doesn't support pedestrians", lane->getID()));214} else {215// build access216GNEAdditional* access = new GNEAccess(accessParent, lane, posDouble, pos, friendlyPos, length, parameters);217// insert depending of allowUndoRedo218if (myAllowUndoRedo) {219myNet->getUndoList()->begin(access, TL("add access in '") + accessParent->getID() + "'");220myNet->getUndoList()->add(new GNEChange_Additional(access, true), true);221myNet->getUndoList()->end();222} else {223myNet->getAttributeCarriers()->insertAdditional(access);224lane->addChildElement(access);225accessParent->addChildElement(access);226access->incRef("buildAccess");227}228return true;229}230}231232233bool234GNEAdditionalHandler::buildContainerStop(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,235const double startPos, const double endPos, const std::string& name, const std::vector<std::string>& lines, const int containerCapacity,236const double parkingLength, const RGBColor& color, const bool friendlyPosition, const double angle, const Parameterised::Map& parameters) {237// check conditions238const auto element = retrieveAdditionalElement({SUMO_TAG_CONTAINER_STOP}, id);239if (!checkElement(SUMO_TAG_CONTAINER_STOP, element)) {240return false;241} else if (!checkValidAdditionalID(SUMO_TAG_CONTAINER_STOP, id)) {242return false;243} else {244// get lane245GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);246// check lane247if (lane == nullptr) {248return writeErrorInvalidParent(SUMO_TAG_CONTAINER_STOP, id, {SUMO_TAG_LANE}, laneID);249} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {250return writeErrorInvalidPosition(SUMO_TAG_CONTAINER_STOP, id);251} else if (!checkNegative(SUMO_TAG_CONTAINER_STOP, id, SUMO_ATTR_CONTAINER_CAPACITY, containerCapacity, true)) {252return false;253} else if (!checkNegative(SUMO_TAG_CONTAINER_STOP, id, SUMO_ATTR_PARKING_LENGTH, parkingLength, true)) {254return false;255} else {256// build containerStop257GNEAdditional* containerStop = new GNEContainerStop(id, myNet, myFileBucket, lane, startPos, endPos, name, lines, containerCapacity, parkingLength,258color, friendlyPosition, angle, parameters);259// insert depending of allowUndoRedo260if (myAllowUndoRedo) {261myNet->getUndoList()->begin(containerStop, TL("add container stop '") + id + "'");262myNet->getUndoList()->add(new GNEChange_Additional(containerStop, true), true);263myNet->getUndoList()->end();264} else {265myNet->getAttributeCarriers()->insertAdditional(containerStop);266lane->addChildElement(containerStop);267containerStop->incRef("buildContainerStop");268}269return true;270}271}272}273274275bool276GNEAdditionalHandler::buildChargingStation(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id,277const std::string& laneID, const double startPos, const double endPos, const std::string& name, const double chargingPower,278const double totalPower, const double efficiency, const bool chargeInTransit, const SUMOTime chargeDelay, const std::string& chargeType,279const SUMOTime waitingTime, const bool friendlyPosition, const std::string& parkingAreaID, const Parameterised::Map& parameters) {280// check conditions281const auto element = retrieveAdditionalElement({SUMO_TAG_CHARGING_STATION}, id);282if (!checkElement(SUMO_TAG_CHARGING_STATION, element)) {283return false;284} else if (!checkValidAdditionalID(SUMO_TAG_CHARGING_STATION, id)) {285return false;286} else {287// get lane288GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);289// check lane290if (lane == nullptr) {291return writeErrorInvalidParent(SUMO_TAG_CHARGING_STATION, id, {SUMO_TAG_LANE}, laneID);292} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {293return writeErrorInvalidPosition(SUMO_TAG_CHARGING_STATION, id);294} else if (!checkNegative(SUMO_TAG_CHARGING_STATION, id, SUMO_ATTR_CHARGINGPOWER, chargingPower, true)) {295return false;296} else if (!checkNegative(SUMO_TAG_CHARGING_STATION, id, SUMO_ATTR_TOTALPOWER, totalPower, true)) {297return false;298} else if (!checkNegative(SUMO_TAG_CHARGING_STATION, id, SUMO_ATTR_CHARGEDELAY, chargeDelay, true)) {299return false;300} else if (!SUMOXMLDefinitions::ChargeTypes.hasString(chargeType)) {301return writeError(TLF("Could not build % with ID '%' in netedit; Invalid charge type '%' .", toString(SUMO_TAG_CHARGING_STATION), id, chargeType));302} else {303// build chargingStation304GNEAdditional* chargingStation = new GNEChargingStation(id, myNet, myFileBucket, lane, startPos, endPos, name, chargingPower, totalPower, efficiency, chargeInTransit,305chargeDelay, chargeType, waitingTime, parkingAreaID, friendlyPosition, parameters);306// insert depending of allowUndoRedo307if (myAllowUndoRedo) {308myNet->getUndoList()->begin(chargingStation, TL("add charging station '") + id + "'");309myNet->getUndoList()->add(new GNEChange_Additional(chargingStation, true), true);310myNet->getUndoList()->end();311} else {312myNet->getAttributeCarriers()->insertAdditional(chargingStation);313lane->addChildElement(chargingStation);314chargingStation->incRef("buildChargingStation");315}316return true;317}318}319}320321322bool323GNEAdditionalHandler::buildParkingArea(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,324const double startPos, const double endPos, const std::string& departPos, const std::string& name,325const std::vector<std::string>& badges, const bool friendlyPosition, const int roadSideCapacity, const bool onRoad,326const double width, const double length, const double angle, const bool lefthand, const Parameterised::Map& parameters) {327// check conditions328const auto element = retrieveAdditionalElement({SUMO_TAG_PARKING_AREA}, id);329if (!checkElement(SUMO_TAG_PARKING_AREA, element)) {330return false;331} else if (!checkValidAdditionalID(SUMO_TAG_PARKING_AREA, id)) {332return false;333} else {334// get lane335GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);336// get departPos double337const double departPosDouble = GNEAttributeCarrier::canParse<double>(departPos) ? GNEAttributeCarrier::parse<double>(departPos) : 0;338// check lane339if (lane == nullptr) {340return writeErrorInvalidParent(SUMO_TAG_PARKING_AREA, id, {SUMO_TAG_LANE}, laneID);341} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {342return writeErrorInvalidPosition(SUMO_TAG_PARKING_AREA, id);343} else if (!checkNegative(SUMO_TAG_PARKING_AREA, id, SUMO_ATTR_ROADSIDE_CAPACITY, roadSideCapacity, true)) {344return false;345} else if (!checkNegative(SUMO_TAG_PARKING_AREA, id, SUMO_ATTR_WIDTH, width, true)) {346return false;347} else if (!checkNegative(SUMO_TAG_PARKING_AREA, id, SUMO_ATTR_LENGTH, length, true)) {348return false;349} else if ((departPosDouble < 0) || (departPosDouble > lane->getParentEdge()->getNBEdge()->getFinalLength())) {350return writeError(TLF("Could not build parking area with ID '%' in netedit; Invalid departPos over lane.", id));351} else {352// build parkingArea353GNEAdditional* parkingArea = new GNEParkingArea(id, myNet, myFileBucket, lane, startPos, endPos, GNEAttributeCarrier::canParse<double>(departPos) ? departPos : "",354name, badges, friendlyPosition, roadSideCapacity, onRoad,355(width == 0) ? SUMO_const_laneWidth : width, length, angle, lefthand, parameters);356// insert depending of allowUndoRedo357if (myAllowUndoRedo) {358myNet->getUndoList()->begin(parkingArea, TL("add parking area '") + id + "'");359myNet->getUndoList()->add(new GNEChange_Additional(parkingArea, true), true);360myNet->getUndoList()->end();361} else {362myNet->getAttributeCarriers()->insertAdditional(parkingArea);363lane->addChildElement(parkingArea);364parkingArea->incRef("buildParkingArea");365}366return true;367}368}369}370371372bool373GNEAdditionalHandler::buildParkingSpace(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const double x, const double y, const double z,374const std::string& name, const std::string& width, const std::string& length, const std::string& angle, const double slope,375const Parameterised::Map& parameters) {376// check width and heights377if (!width.empty() && !GNEAttributeCarrier::canParse<double>(width)) {378return writeError(TL("Could not build parking space in netedit; attribute width cannot be parse to float."));379} else if (!length.empty() && !GNEAttributeCarrier::canParse<double>(length)) {380return writeError(TL("Could not build parking space in netedit; attribute length cannot be parse to float."));381} else if (!angle.empty() && !GNEAttributeCarrier::canParse<double>(angle)) {382return writeError(TL("Could not build parking space in netedit; attribute angle cannot be parse to float."));383} else {384// get lane385GNEAdditional* parkingArea = getAdditionalParent(sumoBaseObject, SUMO_TAG_PARKING_AREA);386// get double values387const double widthDouble = width.empty() ? INVALID_DOUBLE : GNEAttributeCarrier::parse<double>(width);388const double lengthDouble = length.empty() ? INVALID_DOUBLE : GNEAttributeCarrier::parse<double>(length);389const double angleDouble = angle.empty() ? INVALID_DOUBLE : GNEAttributeCarrier::parse<double>(angle);390// check lane391if (parkingArea == nullptr) {392return writeErrorInvalidParent(SUMO_TAG_PARKING_SPACE, "", {SUMO_TAG_PARKING_AREA}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));393} else if ((widthDouble != INVALID_DOUBLE) && !checkNegative(SUMO_TAG_PARKING_SPACE, parkingArea->getID(), SUMO_ATTR_WIDTH, widthDouble, true)) {394return false;395} else if ((lengthDouble != INVALID_DOUBLE) && !checkNegative(SUMO_TAG_PARKING_SPACE, parkingArea->getID(), SUMO_ATTR_LENGTH, lengthDouble, true)) {396return false;397} else {398// build parkingSpace399GNEAdditional* parkingSpace = new GNEParkingSpace(parkingArea, Position(x, y, z), widthDouble, lengthDouble, angleDouble, slope, name, parameters);400// insert depending of allowUndoRedo401if (myAllowUndoRedo) {402myNet->getUndoList()->begin(parkingSpace, TL("add parking space in '") + parkingArea->getID() + "'");403myNet->getUndoList()->add(new GNEChange_Additional(parkingSpace, true), true);404myNet->getUndoList()->end();405} else {406myNet->getAttributeCarriers()->insertAdditional(parkingSpace);407parkingArea->addChildElement(parkingSpace);408parkingSpace->incRef("buildParkingSpace");409}410// update geometry (due boundaries)411parkingSpace->updateGeometry();412return true;413}414}415}416417418bool419GNEAdditionalHandler::buildE1Detector(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,420const double position, const SUMOTime period, const std::string& file, const std::vector<std::string>& vehicleTypes,421const std::vector<std::string>& nextEdges, const std::string& detectPersons, const std::string& name,422const bool friendlyPos, const Parameterised::Map& parameters) {423// check conditions424const auto element = retrieveAdditionalElement({SUMO_TAG_INDUCTION_LOOP}, id);425if (!checkElement(SUMO_TAG_INDUCTION_LOOP, element)) {426return false;427} else if (!checkValidDetectorID(SUMO_TAG_INDUCTION_LOOP, id)) {428return false;429} else {430// get lane431GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);432// check lane433if (lane == nullptr) {434return writeErrorInvalidParent(SUMO_TAG_INDUCTION_LOOP, id, {SUMO_TAG_LANE}, laneID);435} else if (!checkLanePosition(position, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {436return writeErrorInvalidPosition(SUMO_TAG_INDUCTION_LOOP, id);437} else if (!checkNegative(SUMO_TAG_INDUCTION_LOOP, id, SUMO_ATTR_PERIOD, period, true)) {438return false;439} else if (!checkFileName(SUMO_TAG_INDUCTION_LOOP, id, SUMO_ATTR_FILE, file)) {440return false;441} else if (!checkListOfVehicleTypes(SUMO_TAG_INDUCTION_LOOP, id, vehicleTypes)) {442return false;443} else {444// build E1445GNEAdditional* detectorE1 = new GNEInductionLoopDetector(id, myNet, myFileBucket, lane, position, period, file, vehicleTypes,446nextEdges, detectPersons, name, friendlyPos, parameters);447// insert depending of allowUndoRedo448if (myAllowUndoRedo) {449myNet->getUndoList()->begin(detectorE1, TL("add induction loop '") + id + "'");450myNet->getUndoList()->add(new GNEChange_Additional(detectorE1, true), true);451myNet->getUndoList()->end();452} else {453myNet->getAttributeCarriers()->insertAdditional(detectorE1);454lane->addChildElement(detectorE1);455detectorE1->incRef("buildDetectorE1");456}457return true;458}459}460}461462463bool464GNEAdditionalHandler::buildSingleLaneDetectorE2(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,465const double pos, const double length, const SUMOTime period, const std::string& trafficLight, const std::string& filename,466const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges, const std::string& detectPersons,467const std::string& name, const SUMOTime timeThreshold, const double speedThreshold, const double jamThreshold,468const bool friendlyPos, const bool show, const Parameterised::Map& parameters) {469// check conditions470const auto element = retrieveAdditionalElement(NamespaceIDs::laneAreaDetectors, id);471if (!checkElement(SUMO_TAG_LANE_AREA_DETECTOR, element)) {472return false;473} else if (!checkValidDetectorID(SUMO_TAG_LANE_AREA_DETECTOR, id)) {474return false;475} else {476// get lane477GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);478// check lane479if (lane == nullptr) {480return writeErrorInvalidParent(SUMO_TAG_LANE_AREA_DETECTOR, id, {SUMO_TAG_LANE}, laneID);481} else {482// check friendlyPos in small lanes483const bool friendlyPosCheck = checkFriendlyPosSmallLanes(pos, length, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos);484if (!checkLanePosition(pos, length, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosCheck)) {485return writeErrorInvalidPosition(SUMO_TAG_LANE_AREA_DETECTOR, id);486} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_LENGTH, length, true)) {487return false;488} else if ((period != -1) && !checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_PERIOD, period, true)) {489return false;490} else if ((trafficLight.size() > 0) && !(SUMOXMLDefinitions::isValidNetID(trafficLight))) {491// temporal492return writeError(TLF("Could not build lane area detector with ID '%' in netedit; invalid traffic light ID.", id));493} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {494return false;495} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_SPEED_THRESHOLD, speedThreshold, true)) {496return false;497} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {498return false;499} else if (!checkFileName(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_FILE, filename)) {500return false;501} else if (!checkListOfVehicleTypes(SUMO_TAG_LANE_AREA_DETECTOR, id, vehicleTypes)) {502return false;503} else {504// build E2 single lane505GNEAdditional* detectorE2 = new GNELaneAreaDetector(id, myNet, myFileBucket, lane, pos, length, period, trafficLight, filename,506vehicleTypes, nextEdges, detectPersons, name, timeThreshold,507speedThreshold, jamThreshold, friendlyPosCheck, show, parameters);508// insert depending of allowUndoRedo509if (myAllowUndoRedo) {510myNet->getUndoList()->begin(detectorE2, TL("add lane area detector '") + id + "'");511myNet->getUndoList()->add(new GNEChange_Additional(detectorE2, true), true);512myNet->getUndoList()->end();513} else {514myNet->getAttributeCarriers()->insertAdditional(detectorE2);515lane->addChildElement(detectorE2);516detectorE2->incRef("buildDetectorE2");517}518return true;519}520}521}522}523524525bool526GNEAdditionalHandler::buildMultiLaneDetectorE2(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::vector<std::string>& laneIDs,527const double pos, const double endPos, const SUMOTime period, const std::string& trafficLight, const std::string& filename,528const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges, const std::string& detectPersons,529const std::string& name, const SUMOTime timeThreshold, const double speedThreshold, const double jamThreshold,530const bool friendlyPos, const bool show, const Parameterised::Map& parameters) {531// check conditions532const auto element = retrieveAdditionalElement(NamespaceIDs::laneAreaDetectors, id);533if (!checkElement(GNE_TAG_MULTI_LANE_AREA_DETECTOR, element)) {534return false;535} else if (!checkValidDetectorID(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id)) {536return false;537} else {538// get lanes539const auto lanes = parseLanes(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, laneIDs);540// check lanes541if (lanes.empty()) {542return false;543} else {544// calculate path545if (!GNEAdditional::areLaneConsecutives(lanes)) {546return writeError(TLF("Could not build lane area detector with ID '%' in netedit; Lanes aren't consecutives.", id));547} else if (!checkMultiLanePosition(548pos, lanes.front()->getParentEdge()->getNBEdge()->getFinalLength(),549endPos, lanes.back()->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {550return writeErrorInvalidPosition(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id);551} else if ((period != -1) && !checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_PERIOD, period, true)) {552return false;553} else if ((trafficLight.size() > 0) && !(SUMOXMLDefinitions::isValidNetID(trafficLight))) {554// temporal555return writeError(TLF("Could not build lane area detector with ID '%' in netedit; invalid traffic light ID.", id));556} else if (!checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {557return false;558} else if (!checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_SPEED_THRESHOLD, speedThreshold, true)) {559return false;560} else if (!checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {561return false;562} else if (!checkFileName(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_FILE, filename)) {563return false;564} else if (!checkListOfVehicleTypes(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, vehicleTypes)) {565return false;566} else {567// build E2 multilane detector568GNEAdditional* detectorE2 = new GNELaneAreaDetector(id, myNet, myFileBucket, lanes, pos, endPos, period, trafficLight, filename,569vehicleTypes, nextEdges, detectPersons, name, timeThreshold,570speedThreshold, jamThreshold, friendlyPos, show, parameters);571// insert depending of allowUndoRedo572if (myAllowUndoRedo) {573myNet->getUndoList()->begin(detectorE2, TL("add lane area detector '") + id + "'");574myNet->getUndoList()->add(new GNEChange_Additional(detectorE2, true), true);575myNet->getUndoList()->end();576} else {577myNet->getAttributeCarriers()->insertAdditional(detectorE2);578for (const auto& lane : lanes) {579lane->addChildElement(detectorE2);580}581detectorE2->incRef("buildDetectorE2Multilane");582}583return true;584}585}586}587}588589590bool591GNEAdditionalHandler::buildDetectorE3(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos, const SUMOTime period,592const std::string& filename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,593const std::string& detectPersons, const std::string& name, const SUMOTime timeThreshold, const double speedThreshold,594const bool openEntry, const bool expectedArrival, const Parameterised::Map& parameters) {595// check conditions596const auto element = retrieveAdditionalElement({SUMO_TAG_ENTRY_EXIT_DETECTOR}, id);597if (!checkElement(SUMO_TAG_ENTRY_EXIT_DETECTOR, element)) {598return false;599} else if (!checkValidDetectorID(SUMO_TAG_ENTRY_EXIT_DETECTOR, id)) {600return false;601} else if (!checkNegative(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_PERIOD, period, true)) {602return false;603} else if (!checkNegative(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {604return false;605} else if (!checkNegative(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_HALTING_SPEED_THRESHOLD, speedThreshold, true)) {606return false;607} else if (!checkFileName(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_FILE, filename)) {608return false;609} else if (!checkListOfVehicleTypes(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, vehicleTypes)) {610return false;611} else {612// build E3613GNEAdditional* E3 = new GNEMultiEntryExitDetector(id, myNet, myFileBucket, pos, period, filename, vehicleTypes, nextEdges, detectPersons,614name, timeThreshold, speedThreshold, openEntry, expectedArrival, parameters);615// insert depending of allowUndoRedo616if (myAllowUndoRedo) {617myNet->getUndoList()->begin(E3, TL("add entry-exit detector '") + id + "'");618myNet->getUndoList()->add(new GNEChange_Additional(E3, true), true);619myNet->getUndoList()->end();620} else {621myNet->getAttributeCarriers()->insertAdditional(E3);622E3->incRef("buildDetectorE3");623}624return true;625}626}627628629bool630GNEAdditionalHandler::buildDetectorEntry(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& laneID, const double pos,631const bool friendlyPos, const Parameterised::Map& parameters) {632// get lane633GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);634// get E3 parent635GNEAdditional* E3 = getAdditionalParent(sumoBaseObject, SUMO_TAG_ENTRY_EXIT_DETECTOR);636// Check if Detector E3 parent and lane is correct637if (lane == nullptr) {638return writeErrorInvalidParent(SUMO_TAG_DET_ENTRY, "", {SUMO_TAG_LANE}, laneID);639} else if (E3 == nullptr) {640return writeErrorInvalidParent(SUMO_TAG_DET_ENTRY, "", {SUMO_TAG_ENTRY_EXIT_DETECTOR}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));641} else if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {642return writeErrorInvalidPosition(SUMO_TAG_DET_ENTRY, E3->getID());643} else {644// build entry instant645GNEAdditional* entry = new GNEEntryExitDetector(SUMO_TAG_DET_ENTRY, E3, lane, pos, friendlyPos, parameters);646// insert depending of allowUndoRedo647if (myAllowUndoRedo) {648myNet->getUndoList()->begin(entry, TL("add entry detector in '") + E3->getID() + "'");649myNet->getUndoList()->add(new GNEChange_Additional(entry, true), true);650myNet->getUndoList()->end();651} else {652myNet->getAttributeCarriers()->insertAdditional(entry);653lane->addChildElement(entry);654E3->addChildElement(entry);655entry->incRef("buildDetectorEntry");656}657return true;658}659}660661662bool663GNEAdditionalHandler::buildDetectorExit(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& laneID, const double pos,664const bool friendlyPos, const Parameterised::Map& parameters) {665// get lane666GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);667// get E3 parent668GNEAdditional* E3 = getAdditionalParent(sumoBaseObject, SUMO_TAG_ENTRY_EXIT_DETECTOR);669// Check if Detector E3 parent and lane is correct670if (lane == nullptr) {671return writeErrorInvalidParent(SUMO_TAG_DET_EXIT, "", {SUMO_TAG_LANE}, laneID);672} else if (E3 == nullptr) {673return writeErrorInvalidParent(SUMO_TAG_DET_EXIT, "", {SUMO_TAG_ENTRY_EXIT_DETECTOR}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));674} else if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {675return writeErrorInvalidPosition(SUMO_TAG_DET_EXIT, E3->getID());676} else {677// build exit instant678GNEAdditional* exit = new GNEEntryExitDetector(SUMO_TAG_DET_EXIT, E3, lane, pos, friendlyPos, parameters);679// insert depending of allowUndoRedo680if (myAllowUndoRedo) {681myNet->getUndoList()->begin(exit, TL("add exit detector in '") + E3->getID() + "'");682myNet->getUndoList()->add(new GNEChange_Additional(exit, true), true);683myNet->getUndoList()->end();684} else {685myNet->getAttributeCarriers()->insertAdditional(exit);686lane->addChildElement(exit);687E3->addChildElement(exit);688exit->incRef("buildDetectorExit");689}690return true;691}692}693694695bool696GNEAdditionalHandler::buildDetectorE1Instant(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID, double pos,697const std::string& filename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,698const std::string& detectPersons, const std::string& name, const bool friendlyPos, const Parameterised::Map& parameters) {699// check conditions700const auto element = retrieveAdditionalElement({SUMO_TAG_INSTANT_INDUCTION_LOOP}, id);701if (!checkElement(SUMO_TAG_INSTANT_INDUCTION_LOOP, element)) {702return false;703} else if (!checkValidDetectorID(SUMO_TAG_INSTANT_INDUCTION_LOOP, id)) {704return false;705} else {706// get lane707GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);708// check lane709if (lane == nullptr) {710return writeErrorInvalidParent(SUMO_TAG_INSTANT_INDUCTION_LOOP, id, {SUMO_TAG_LANE}, laneID);711} else if (!checkFileName(SUMO_TAG_INSTANT_INDUCTION_LOOP, id, SUMO_ATTR_FILE, filename)) {712return false;713} else if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {714return writeErrorInvalidPosition(SUMO_TAG_INSTANT_INDUCTION_LOOP, id);715} else {716// build E1 instant717GNEAdditional* detectorE1Instant = new GNEInstantInductionLoopDetector(id, myNet, myFileBucket, lane, pos, filename, vehicleTypes, nextEdges,718detectPersons, name, friendlyPos, parameters);719// insert depending of allowUndoRedo720if (myAllowUndoRedo) {721myNet->getUndoList()->begin(detectorE1Instant, TL("add instant induction loop '") + id + "'");722myNet->getUndoList()->add(new GNEChange_Additional(detectorE1Instant, true), true);723myNet->getUndoList()->end();724} else {725myNet->getAttributeCarriers()->insertAdditional(detectorE1Instant);726lane->addChildElement(detectorE1Instant);727detectorE1Instant->incRef("buildDetectorE1Instant");728}729return true;730}731}732}733734735bool736GNEAdditionalHandler::buildLaneCalibrator(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& laneID, const double pos,737const std::string& name, const std::string& outfile, const SUMOTime period, const std::string& routeprobeID, const double jamThreshold, const std::vector<std::string>& vTypes,738const Parameterised::Map& parameters) {739// get lane740GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);741// get routeProbe742GNEAdditional* routeProbe = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, routeprobeID, false);743// check conditions744const auto element = retrieveAdditionalElement(NamespaceIDs::calibrators, id);745if (!checkElement(GNE_TAG_CALIBRATOR_LANE, element)) {746return false;747} else if (!checkValidAdditionalID(GNE_TAG_CALIBRATOR_LANE, id)) {748return false;749} else if ((routeprobeID.size() > 0) && (routeProbe == nullptr)) {750return writeErrorInvalidParent(GNE_TAG_CALIBRATOR_LANE, id, {SUMO_TAG_ROUTEPROBE}, routeprobeID);751} else if (lane == nullptr) {752return writeErrorInvalidParent(GNE_TAG_CALIBRATOR_LANE, id, {SUMO_TAG_LANE}, laneID);753} else {754// check lane755if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), false)) {756return writeErrorInvalidPosition(GNE_TAG_CALIBRATOR_LANE, id);757} else if (!checkNegative(GNE_TAG_CALIBRATOR_LANE, id, SUMO_ATTR_PERIOD, period, true)) {758return false;759} else if (!checkNegative(GNE_TAG_CALIBRATOR_LANE, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {760return false;761} else {762// build Calibrator763GNEAdditional* calibrator = (routeProbe == nullptr) ?764new GNECalibrator(id, myNet, myFileBucket, lane, pos, period, name, outfile, jamThreshold, vTypes, parameters) :765new GNECalibrator(id, myNet, myFileBucket, lane, pos, period, name, outfile, routeProbe, jamThreshold, vTypes, parameters);766// insert depending of allowUndoRedo767if (myAllowUndoRedo) {768myNet->getUndoList()->begin(calibrator, TL("add lane calibrator '") + id + "'");769myNet->getUndoList()->add(new GNEChange_Additional(calibrator, true), true);770myNet->getUndoList()->end();771// check if center after creation772if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&773sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {774myNet->getViewNet()->centerTo(calibrator->getPositionInView(), false);775}776} else {777myNet->getAttributeCarriers()->insertAdditional(calibrator);778lane->addChildElement(calibrator);779if (routeProbe) {780routeProbe->addChildElement(calibrator);781}782calibrator->incRef("buildCalibrator");783}784return true;785}786}787}788789790bool791GNEAdditionalHandler::buildEdgeCalibrator(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& edgeID, const double pos,792const std::string& name, const std::string& outfile, const SUMOTime period, const std::string& routeprobeID, const double jamThreshold, const std::vector<std::string>& vTypes,793const Parameterised::Map& parameters) {794// get edge795GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);796// get routeProbe797GNEAdditional* routeProbe = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, routeprobeID, false);798// check conditions799const auto element = retrieveAdditionalElement(NamespaceIDs::calibrators, id);800if (!checkElement(SUMO_TAG_CALIBRATOR, element)) {801return false;802} else if (!checkValidAdditionalID(SUMO_TAG_CALIBRATOR, id)) {803return false;804} else if ((routeprobeID.size() > 0) && (routeProbe == nullptr)) {805return writeErrorInvalidParent(SUMO_TAG_CALIBRATOR, id, {SUMO_TAG_ROUTEPROBE}, routeprobeID);806} else if (edge == nullptr) {807return writeErrorInvalidParent(SUMO_TAG_CALIBRATOR, id, {SUMO_TAG_EDGE}, edgeID);808} else {809if (!checkLanePosition(pos, 0, edge->getChildLanes().front()->getParentEdge()->getNBEdge()->getFinalLength(), false)) {810return writeErrorInvalidPosition(SUMO_TAG_CALIBRATOR, id);811} else if (!checkNegative(SUMO_TAG_CALIBRATOR, id, SUMO_ATTR_PERIOD, period, true)) {812return false;813} else if (!checkNegative(SUMO_TAG_CALIBRATOR, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {814return false;815} else {816// build Calibrator817GNEAdditional* calibrator = (routeProbe == nullptr) ?818new GNECalibrator(id, myNet, myFileBucket, edge, pos, period, name, outfile, jamThreshold, vTypes, parameters) :819new GNECalibrator(id, myNet, myFileBucket, edge, pos, period, name, outfile, routeProbe, jamThreshold, vTypes, parameters);820// insert depending of allowUndoRedo821if (myAllowUndoRedo) {822myNet->getUndoList()->begin(calibrator, TL("add calibrator '") + id + "'");823myNet->getUndoList()->add(new GNEChange_Additional(calibrator, true), true);824myNet->getUndoList()->end();825// check if center after creation826if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&827sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {828myNet->getViewNet()->centerTo(calibrator->getPositionInView(), false);829}830} else {831myNet->getAttributeCarriers()->insertAdditional(calibrator);832edge->addChildElement(calibrator);833if (routeProbe) {834routeProbe->addChildElement(calibrator);835}836calibrator->incRef("buildCalibrator");837}838return true;839}840}841}842843844bool845GNEAdditionalHandler::buildCalibratorFlow(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const SUMOVehicleParameter& vehicleParameter) {846// get vType847GNEDemandElement* vType = myNet->getAttributeCarriers()->retrieveDemandElement(SUMO_TAG_VTYPE, vehicleParameter.vtypeid.empty() ? DEFAULT_VTYPE_ID : vehicleParameter.vtypeid, false);848// get route849GNEDemandElement* route = myNet->getAttributeCarriers()->retrieveDemandElement(SUMO_TAG_ROUTE, vehicleParameter.routeid, false);850// get calibrator parent851GNEAdditional* calibrator = myNet->getAttributeCarriers()->retrieveAdditional(sumoBaseObject->getParentSumoBaseObject()->getTag(), sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID), false);852// check parents853if (vType == nullptr) {854return writeErrorInvalidParent(SUMO_TAG_FLOW, "", {SUMO_TAG_VTYPE}, vehicleParameter.vtypeid);855} else if (route == nullptr) {856return writeErrorInvalidParent(SUMO_TAG_FLOW, "", {SUMO_TAG_ROUTE}, vehicleParameter.routeid);857} else if (calibrator == nullptr) {858return writeErrorInvalidParent(SUMO_TAG_FLOW, "", {SUMO_TAG_CALIBRATOR}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));859} else {860// create calibrator flow861GNEAdditional* flow = new GNECalibratorFlow(calibrator, vType, route, vehicleParameter);862// insert depending of allowUndoRedo863if (myAllowUndoRedo) {864myNet->getUndoList()->begin(flow, TL("add calibrator flow in '") + calibrator->getID() + "'");865myNet->getUndoList()->add(new GNEChange_Additional(flow, true), true);866myNet->getUndoList()->end();867} else {868myNet->getAttributeCarriers()->insertAdditional(flow);869calibrator->addChildElement(flow);870route->addChildElement(flow);871vType->addChildElement(flow);872flow->incRef("buildCalibratorFlow");873}874return true;875}876}877878879bool880GNEAdditionalHandler::buildRerouter(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos,881const std::vector<std::string>& edgeIDs, const double prob, const std::string& name,882const bool off, const bool optional, const SUMOTime timeThreshold,883const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) {884// check conditions885const auto element = retrieveAdditionalElement({SUMO_TAG_REROUTER}, id);886if (!checkElement(SUMO_TAG_REROUTER, element)) {887return false;888} else if (!checkValidAdditionalID(SUMO_TAG_REROUTER, id)) {889return false;890} else if (!checkNegative(SUMO_TAG_REROUTER, id, SUMO_ATTR_PROB, prob, true)) {891return false;892} else if (!checkNegative(SUMO_TAG_REROUTER, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {893return false;894} else if (!checkListOfVehicleTypes(SUMO_TAG_REROUTER, id, vTypes)) {895return false;896} else {897// parse edges898std::vector<GNEEdge*> edges = parseEdges(SUMO_TAG_REROUTER, id, edgeIDs);899// check edges900if (edges.empty()) {901return false;902} else {903GNEAdditional* rerouter = nullptr;904// continue depending of position905if (pos == Position::INVALID) {906if (edges.size() > 0) {907PositionVector laneShape = edges.front()->getChildLanes().front()->getLaneShape();908// move to side909laneShape.move2side(3);910// create rerouter911rerouter = new GNERerouter(id, myNet, myFileBucket, laneShape.positionAtOffset2D(laneShape.length2D() - 6), name, prob, off, optional, timeThreshold, vTypes, parameters);912} else {913rerouter = new GNERerouter(id, myNet, myFileBucket, Position(0, 0), name, prob, off, optional, timeThreshold, vTypes, parameters);914}915} else {916rerouter = new GNERerouter(id, myNet, myFileBucket, pos, name, prob, off, optional, timeThreshold, vTypes, parameters);917}918// create rerouter Symbols919std::vector<GNEAdditional*> rerouterSymbols;920for (const auto& edge : edges) {921rerouterSymbols.push_back(new GNERerouterSymbol(rerouter, edge));922}923// insert depending of allowUndoRedo924if (myAllowUndoRedo) {925myNet->getUndoList()->begin(rerouter, TL("add rerouter '") + id + "'");926myNet->getUndoList()->add(new GNEChange_Additional(rerouter, true), true);927// add symbols928for (const auto& rerouterSymbol : rerouterSymbols) {929myNet->getUndoList()->add(new GNEChange_Additional(rerouterSymbol, true), true);930}931myNet->getUndoList()->end();932} else {933myNet->getAttributeCarriers()->insertAdditional(rerouter);934rerouter->incRef("buildRerouter");935// add symbols into rerouter936for (const auto& rerouterSymbol : rerouterSymbols) {937rerouter->addChildElement(rerouterSymbol);938}939// add symbols into edges940for (int i = 0; i < (int)edges.size(); i++) {941edges.at(i)->addChildElement(rerouterSymbols.at(i));942}943}944return true;945}946}947}948949950bool951GNEAdditionalHandler::buildRerouterInterval(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const SUMOTime begin, const SUMOTime end) {952// get rerouter parent953GNEAdditional* rerouter = getAdditionalParent(sumoBaseObject, SUMO_TAG_REROUTER);954// check if rerouter exist955if (rerouter == nullptr) {956return writeErrorInvalidParent(SUMO_TAG_INTERVAL, "", {SUMO_TAG_REROUTER}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));957} else if (!checkNegative(SUMO_TAG_INTERVAL, rerouter->getID(), SUMO_ATTR_BEGIN, begin, true)) {958return false;959} else if (!checkNegative(SUMO_TAG_INTERVAL, rerouter->getID(), SUMO_ATTR_END, end, true)) {960return false;961} else if (end < begin) {962return writeError(TLF("Could not build interval with ID '%' in netedit; begin is greater than end.", rerouter->getID()));963} else {964// check if new interval will produce a overlapping965if (checkOverlappingRerouterIntervals(rerouter, begin, end)) {966// create rerouter interval and add it into rerouter parent967GNEAdditional* rerouterInterval = new GNERerouterInterval(rerouter, begin, end);968// insert depending of allowUndoRedo969if (myAllowUndoRedo) {970myNet->getUndoList()->begin(rerouterInterval, TL("add rerouter interval in '") + rerouter->getID() + "'");971myNet->getUndoList()->add(new GNEChange_Additional(rerouterInterval, true), true);972myNet->getUndoList()->end();973} else {974rerouter->addChildElement(rerouterInterval);975rerouterInterval->incRef("buildRerouterInterval");976}977} else {978return writeError(TLF("Could not build interval with begin '%' and end '%' in '%' due overlapping.", toString(begin), toString(end), rerouter->getID()));979}980// update centering boundary of rerouter parent981rerouter->updateCenteringBoundary(true);982return true;983}984}985986987bool988GNEAdditionalHandler::buildClosingLaneReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& closedLaneID, SVCPermissions permissions) {989// get rerouter interval parent990GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);991// get closed lane992GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(closedLaneID, false);993// check parents994if (lane == nullptr) {995return writeErrorInvalidParent(SUMO_TAG_CLOSING_LANE_REROUTE, "", {SUMO_TAG_LANE}, closedLaneID);996} else if (rerouterInterval == nullptr) {997return writeErrorInvalidParent(SUMO_TAG_CLOSING_LANE_REROUTE, "", {SUMO_TAG_INTERVAL}, "");998} else {999// create closing lane reroute1000GNEAdditional* closingLaneReroute = new GNEClosingLaneReroute(rerouterInterval, lane, permissions);1001// add it to interval parent depending of allowUndoRedo1002if (myAllowUndoRedo) {1003myNet->getUndoList()->begin(closingLaneReroute, TL("add closing lane reroute in '") + lane->getID() + "'");1004myNet->getUndoList()->add(new GNEChange_Additional(closingLaneReroute, true), true);1005myNet->getUndoList()->end();1006} else {1007rerouterInterval->addChildElement(closingLaneReroute);1008closingLaneReroute->incRef("buildClosingLaneReroute");1009}1010// update centering boundary of rerouter parent1011rerouterInterval->getParentAdditionals().front()->updateCenteringBoundary(true);1012return true;1013}1014}101510161017bool1018GNEAdditionalHandler::buildClosingReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& closedEdgeID, SVCPermissions permissions) {1019// get rerouter interval parent1020GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1021// get closed edge1022GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(closedEdgeID, false);1023// check parents1024if (edge == nullptr) {1025return writeErrorInvalidParent(SUMO_TAG_CLOSING_REROUTE, "", {SUMO_TAG_EDGE}, closedEdgeID);1026} else if (rerouterInterval == nullptr) {1027return writeErrorInvalidParent(SUMO_TAG_CLOSING_REROUTE, "", {SUMO_TAG_INTERVAL}, "");1028} else {1029// create closing reroute1030GNEAdditional* closingLaneReroute = new GNEClosingReroute(rerouterInterval, edge, permissions);1031// add it to interval parent depending of allowUndoRedo1032if (myAllowUndoRedo) {1033myNet->getUndoList()->begin(closingLaneReroute, TL("add closing reroute in '") + edge->getID() + "'");1034myNet->getUndoList()->add(new GNEChange_Additional(closingLaneReroute, true), true);1035myNet->getUndoList()->end();1036} else {1037rerouterInterval->addChildElement(closingLaneReroute);1038closingLaneReroute->incRef("buildClosingLaneReroute");1039}1040// update centering boundary of rerouter parent1041rerouterInterval->getParentAdditionals().front()->updateCenteringBoundary(true);1042return true;1043}1044}10451046bool1047GNEAdditionalHandler::buildDestProbReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& newEdgeDestinationID, const double probability) {1048// get rerouter interval parent1049GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1050// get edge1051GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(newEdgeDestinationID, false);1052// check parents1053if (edge == nullptr) {1054return writeErrorInvalidParent(SUMO_TAG_DEST_PROB_REROUTE, "", {SUMO_TAG_EDGE}, newEdgeDestinationID);1055} else if (rerouterInterval == nullptr) {1056return writeErrorInvalidParent(SUMO_TAG_DEST_PROB_REROUTE, "", {SUMO_TAG_INTERVAL}, "");1057} else {1058// create dest probability reroute1059GNEAdditional* destProbReroute = new GNEDestProbReroute(rerouterInterval, edge, probability);1060// add it to interval parent depending of allowUndoRedo1061if (myAllowUndoRedo) {1062myNet->getUndoList()->begin(destProbReroute, TL("add dest prob reroute in '") + edge->getID() + "'");1063myNet->getUndoList()->add(new GNEChange_Additional(destProbReroute, true), true);1064myNet->getUndoList()->end();1065} else {1066rerouterInterval->addChildElement(destProbReroute);1067destProbReroute->incRef("builDestProbReroute");1068}1069// update centering boundary of rerouter parent1070rerouterInterval->getParentAdditionals().front()->updateCenteringBoundary(true);1071return true;1072}1073}107410751076bool1077GNEAdditionalHandler::buildParkingAreaReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& newParkignAreaID, const double probability, const bool visible) {1078// get rerouter interval parent1079GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1080// get parking area1081GNEAdditional* parkingArea = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_PARKING_AREA, newParkignAreaID, false);1082// check parents1083if (parkingArea == nullptr) {1084return writeErrorInvalidParent(SUMO_TAG_PARKING_AREA_REROUTE, "", {SUMO_TAG_PARKING_AREA}, newParkignAreaID);1085} else if (rerouterInterval == nullptr) {1086return writeErrorInvalidParent(SUMO_TAG_PARKING_AREA_REROUTE, "", {SUMO_TAG_INTERVAL}, "");1087} else {1088// create parking area reroute1089GNEAdditional* parkingAreaReroute = new GNEParkingAreaReroute(rerouterInterval, parkingArea, probability, visible);1090// add it to interval parent depending of allowUndoRedo1091if (myAllowUndoRedo) {1092myNet->getUndoList()->begin(parkingAreaReroute, TL("add parking area reroute in '") + parkingArea->getID() + "'");1093myNet->getUndoList()->add(new GNEChange_Additional(parkingAreaReroute, true), true);1094myNet->getUndoList()->end();1095} else {1096rerouterInterval->addChildElement(parkingAreaReroute);1097parkingAreaReroute->incRef("builParkingAreaReroute");1098}1099// update centering boundary of rerouter parent1100rerouterInterval->getParentAdditionals().front()->updateCenteringBoundary(true);1101return true;1102}1103}110411051106bool1107GNEAdditionalHandler::buildRouteProbReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& newRouteID, const double probability) {1108// get rerouter interval parent1109GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1110// get route parent1111GNEDemandElement* route = myNet->getAttributeCarriers()->retrieveDemandElement(SUMO_TAG_ROUTE, newRouteID, false);1112// check parents1113if (route == nullptr) {1114return writeErrorInvalidParent(SUMO_TAG_ROUTE_PROB_REROUTE, "", {SUMO_TAG_ROUTE}, newRouteID);1115} else if (rerouterInterval == nullptr) {1116return writeErrorInvalidParent(SUMO_TAG_ROUTE_PROB_REROUTE, "", {SUMO_TAG_INTERVAL}, "");1117} else {1118// create rout prob reroute1119GNEAdditional* routeProbReroute = new GNERouteProbReroute(rerouterInterval, route, probability);1120// add it to interval parent depending of allowUndoRedo1121if (myAllowUndoRedo) {1122myNet->getUndoList()->begin(routeProbReroute, TL("add route prob reroute in '") + route->getID() + "'");1123myNet->getUndoList()->add(new GNEChange_Additional(routeProbReroute, true), true);1124myNet->getUndoList()->end();1125} else {1126rerouterInterval->addChildElement(routeProbReroute);1127routeProbReroute->incRef("buildRouteProbReroute");1128}1129// update centering boundary of rerouter parent1130rerouterInterval->getParentAdditionals().front()->updateCenteringBoundary(true);1131return true;1132}1133}113411351136bool1137GNEAdditionalHandler::buildRouteProbe(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& edgeID, const SUMOTime period,1138const std::string& name, const std::string& file, const SUMOTime begin, const std::vector<std::string>& vTypes,1139const Parameterised::Map& parameters) {1140// check conditions1141const auto element = retrieveAdditionalElement({SUMO_TAG_ROUTEPROBE}, id);1142if (!checkElement(SUMO_TAG_ROUTEPROBE, element)) {1143return false;1144} else if (!checkValidAdditionalID(SUMO_TAG_ROUTEPROBE, id)) {1145return false;1146} else {1147// get edge1148GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1149// check lane1150if (edge == nullptr) {1151return writeErrorInvalidParent(SUMO_TAG_ROUTEPROBE, id, {SUMO_TAG_EDGE}, edgeID);1152} else if (!checkNegative(SUMO_TAG_ROUTEPROBE, id, SUMO_ATTR_PERIOD, period, true)) {1153return false;1154} else if (!checkNegative(SUMO_TAG_ROUTEPROBE, id, SUMO_ATTR_BEGIN, begin, true)) {1155return false;1156} else if (!checkFileName(SUMO_TAG_ROUTEPROBE, id, SUMO_ATTR_FILE, file)) {1157return false;1158} else {1159// build route probe1160GNEAdditional* routeProbe = new GNERouteProbe(id, myNet, myFileBucket, edge, period, name, file, begin, vTypes, parameters);1161// insert depending of allowUndoRedo1162if (myAllowUndoRedo) {1163myNet->getUndoList()->begin(routeProbe, TL("add route probe '") + id + "'");1164myNet->getUndoList()->add(new GNEChange_Additional(routeProbe, true), true);1165myNet->getUndoList()->end();1166// check if center after creation1167if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&1168sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {1169myNet->getViewNet()->centerTo(routeProbe->getPositionInView(), false);1170}1171} else {1172myNet->getAttributeCarriers()->insertAdditional(routeProbe);1173edge->addChildElement(routeProbe);1174routeProbe->incRef("buildRouteProbe");1175}1176return true;1177}1178}1179}118011811182bool1183GNEAdditionalHandler::buildVariableSpeedSign(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos,1184const std::vector<std::string>& laneIDs, const std::string& name, const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) {1185// check conditions1186const auto element = retrieveAdditionalElement({SUMO_TAG_VSS}, id);1187if (!checkElement(SUMO_TAG_VSS, element)) {1188return false;1189} else if (!checkValidAdditionalID(SUMO_TAG_VSS, id)) {1190return false;1191} else {1192// parse lanes1193std::vector<GNELane*> lanes = parseLanes(SUMO_TAG_VSS, id, laneIDs);1194// check lane1195if (lanes.empty()) {1196return false;1197} else {1198// check vTypes1199if (!checkListOfVehicleTypes(SUMO_TAG_VSS, id, vTypes)) {1200return false;1201} else {1202// create VSS1203GNEAdditional* variableSpeedSign = new GNEVariableSpeedSign(id, myNet, myFileBucket, pos, name, vTypes, parameters);1204// create VSS Symbols1205std::vector<GNEAdditional*> VSSSymbols;1206for (const auto& lane : lanes) {1207VSSSymbols.push_back(new GNEVariableSpeedSignSymbol(variableSpeedSign, lane));1208}1209// insert depending of allowUndoRedo1210if (myAllowUndoRedo) {1211myNet->getUndoList()->begin(variableSpeedSign, TL("add Variable Speed Sign '") + id + "'");1212myNet->getUndoList()->add(new GNEChange_Additional(variableSpeedSign, true), true);1213for (const auto& VSSSymbol : VSSSymbols) {1214myNet->getUndoList()->add(new GNEChange_Additional(VSSSymbol, true), true);1215}1216myNet->getUndoList()->end();1217} else {1218myNet->getAttributeCarriers()->insertAdditional(variableSpeedSign);1219variableSpeedSign->incRef("buildVariableSpeedSign");1220// add symbols into VSS1221for (const auto& VSSSymbol : VSSSymbols) {1222variableSpeedSign->addChildElement(VSSSymbol);1223}1224// add symbols into lanes1225for (int i = 0; i < (int)lanes.size(); i++) {1226lanes.at(i)->addChildElement(VSSSymbols.at(i));1227}1228}1229}1230return true;1231}1232}1233}123412351236bool1237GNEAdditionalHandler::buildVariableSpeedSignStep(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const SUMOTime time, const double speed) {1238// get VSS parent1239GNEAdditional* VSS = getAdditionalParent(sumoBaseObject, SUMO_TAG_VSS);1240// check lane1241if (VSS == nullptr) {1242return writeErrorInvalidParent(SUMO_TAG_STEP, "", {SUMO_TAG_VSS}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));1243} else if (!checkNegative(SUMO_TAG_STEP, VSS->getID(), SUMO_ATTR_TIME, time, true)) {1244return false;1245} else {1246// create Variable Speed Sign1247GNEAdditional* variableSpeedSignStep = new GNEVariableSpeedSignStep(VSS, time, speed);1248// add it depending of allow undoRedo1249if (myAllowUndoRedo) {1250myNet->getUndoList()->begin(variableSpeedSignStep, TL("add VSS Step in '") + VSS->getID() + "'");1251myNet->getUndoList()->add(new GNEChange_Additional(variableSpeedSignStep, true), true);1252myNet->getUndoList()->end();1253} else {1254VSS->addChildElement(variableSpeedSignStep);1255variableSpeedSignStep->incRef("buildVariableSpeedSignStep");1256}1257// update centering boundary of VSS parent1258VSS->updateCenteringBoundary(true);1259return true;1260}1261}126212631264bool1265GNEAdditionalHandler::buildVaporizer(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& edgeID, const SUMOTime beginTime,1266const SUMOTime endTime, const std::string& name, const Parameterised::Map& parameters) {1267// check conditions1268const auto element = retrieveAdditionalElement({SUMO_TAG_VAPORIZER}, edgeID);1269if (!checkElement(SUMO_TAG_VAPORIZER, element)) {1270return false;1271} else if (!checkValidAdditionalID(SUMO_TAG_VAPORIZER, edgeID)) {1272return false;1273} else {1274// get edge1275GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1276// check lane1277if (edge == nullptr) {1278return writeErrorInvalidParent(SUMO_TAG_VAPORIZER, "", {SUMO_TAG_EDGE}, edgeID);1279} else if (!checkNegative(SUMO_TAG_VAPORIZER, edge->getID(), SUMO_ATTR_BEGIN, beginTime, true)) {1280return false;1281} else if (!checkNegative(SUMO_TAG_VAPORIZER, edge->getID(), SUMO_ATTR_END, endTime, true)) {1282return false;1283} else if (endTime < beginTime) {1284return writeError(TLF("Could not build Vaporizer with ID '%' in netedit; begin is greater than end.", edge->getID()));1285} else {1286// build vaporizer1287GNEAdditional* vaporizer = new GNEVaporizer(myNet, myFileBucket, edge, beginTime, endTime, name, parameters);1288// add it depending of allow undoRed1289if (myAllowUndoRedo) {1290myNet->getUndoList()->begin(vaporizer, TL("add vaporizer in '") + edge->getID() + "'");1291myNet->getUndoList()->add(new GNEChange_Additional(vaporizer, true), true);1292myNet->getUndoList()->end();1293// check if center after creation1294if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&1295sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {1296myNet->getViewNet()->centerTo(vaporizer->getPositionInView(), false);1297}1298} else {1299myNet->getAttributeCarriers()->insertAdditional(vaporizer);1300edge->addChildElement(vaporizer);1301vaporizer->incRef("buildVaporizer");1302}1303return true;1304}1305}1306}130713081309bool1310GNEAdditionalHandler::buildTAZ(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const PositionVector& shape,1311const Position& center, const bool fill, const RGBColor& color, const std::vector<std::string>& edgeIDs,1312const std::string& name, const Parameterised::Map& parameters) {1313// parse edges1314const std::vector<GNEEdge*> edges = parseEdges(SUMO_TAG_TAZ, id, edgeIDs);1315if (edges.size() != edgeIDs.size()) {1316return false;1317} else {1318// check TAZShape1319PositionVector TAZShape = shape;1320if (TAZShape.size() == 0) {1321// declare boundary1322Boundary TAZBoundary;1323for (const auto& edge : edges) {1324TAZBoundary.add(edge->getCenteringBoundary());1325}1326// iterate over children and add sourceSinkEdge boundaries to make a taz shape1327for (const auto& sourceSink : sumoBaseObject->getSumoBaseObjectChildren()) {1328// check that child is a source or sink elements (to avoid other elements)1329if ((sourceSink->getTag() == SUMO_TAG_TAZSOURCE) || (sourceSink->getTag() == SUMO_TAG_TAZSINK)) {1330const GNEEdge* sourceSinkEdge = myNet->getAttributeCarriers()->retrieveEdge(sourceSink->getStringAttribute(SUMO_ATTR_ID), false);1331if (sourceSinkEdge) {1332TAZBoundary.add(sourceSinkEdge->getCenteringBoundary());1333}1334}1335}1336// update TAZShape1337TAZShape = TAZBoundary.getShape(true);1338}1339// check TAZ1340const auto element = retrieveAdditionalElement({SUMO_TAG_TAZ}, id);1341if (!checkElement(SUMO_TAG_TAZ, element)) {1342return false;1343} else if (!checkValidAdditionalID(SUMO_TAG_TAZ, id)) {1344return false;1345} else if (TAZShape.size() == 0) {1346return writeError(TLF("Could not build TAZ with ID '%' in netedit; Invalid Shape.", id));1347} else {1348// build TAZ with the given shape1349const Position center2 = center == Position::INVALID ? TAZShape.getCentroid() : center;1350GNEAdditional* TAZ = new GNETAZ(id, myNet, myFileBucket, TAZShape, center2, fill, color, name, parameters);1351// disable updating geometry of TAZ children during insertion (because in large nets provokes slowdowns)1352myNet->disableUpdateGeometry();1353// add it depending of allow undoRed1354if (myAllowUndoRedo) {1355myNet->getUndoList()->begin(TAZ, TL("add TAZ '") + id + "'");1356myNet->getUndoList()->add(new GNEChange_Additional(TAZ, true), true);1357// create TAZEdges1358for (const auto& edge : edges) {1359// create TAZ Source using GNEChange_Additional1360GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, 1);1361myNet->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSource, true), true);1362// create TAZ Sink using GNEChange_Additional1363GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, 1);1364myNet->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSink, true), true);1365}1366myNet->getUndoList()->end();1367} else {1368myNet->getAttributeCarriers()->insertAdditional(TAZ);1369TAZ->incRef("buildTAZ");1370for (const auto& edge : edges) {1371// create TAZ Source1372GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, 1);1373myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSource);1374TAZSource->incRef("buildTAZ");1375TAZ->addChildElement(TAZSource);1376edge->addChildElement(TAZSource);1377// create TAZ Sink1378GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, 1);1379myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSink);1380TAZSink->incRef("buildTAZ");1381TAZ->addChildElement(TAZSink);1382edge->addChildElement(TAZSink);1383}1384}1385// enable updating geometry again and update geometry of TAZ1386myNet->enableUpdateGeometry();1387// update TAZ parent1388TAZ->updateGeometry();1389return true;1390}1391}1392}139313941395bool1396GNEAdditionalHandler::buildTAZSource(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& edgeID, const double departWeight) {1397// get TAZ parent1398GNEAdditional* TAZ = getAdditionalParent(sumoBaseObject, SUMO_TAG_TAZ);1399// get edge1400GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1401// check parents1402if (TAZ == nullptr) {1403return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, {SUMO_TAG_TAZ}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));1404} else if (edge == nullptr) {1405return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, {SUMO_TAG_EDGE}, TAZ->getID());1406} else {1407// declare TAZ Source1408GNETAZSourceSink* existentTAZSource = nullptr;1409// first check if already exist a TAZ Source for the given edge and TAZ1410for (auto it = edge->getChildTAZSourceSinks().begin(); (it != edge->getChildTAZSourceSinks().end()) && !existentTAZSource; it++) {1411if (((*it)->getTagProperty()->getTag() == SUMO_TAG_TAZSOURCE) && ((*it)->getParentAdditionals().front() == TAZ)) {1412existentTAZSource = (*it);1413}1414}1415// check if TAZSource has to be created1416if (existentTAZSource == nullptr) {1417// Create TAZ only with departWeight1418GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, departWeight);1419// add it depending of allow undoRed1420if (myAllowUndoRedo) {1421myNet->getUndoList()->begin(TAZ, TL("add TAZ Source in '") + TAZ->getID() + "'");1422myNet->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSource, true), true);1423myNet->getUndoList()->end();1424} else {1425myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSource);1426TAZ->addChildElement(TAZSource);1427edge->addChildElement(TAZSource);1428TAZSource->incRef("buildTAZSource");1429}1430} else {1431// update TAZ Attribute depending of allow undoRed1432if (myAllowUndoRedo) {1433myNet->getUndoList()->begin(TAZ, TL("update TAZ Source in '") + TAZ->getID() + "'");1434existentTAZSource->setAttribute(SUMO_ATTR_WEIGHT, toString(departWeight), myNet->getUndoList());1435myNet->getUndoList()->end();1436} else {1437existentTAZSource->setAttribute(SUMO_ATTR_WEIGHT, toString(departWeight), nullptr);1438}1439}1440return true;1441}1442}144314441445bool1446GNEAdditionalHandler::buildTAZSink(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& edgeID, const double arrivalWeight) {1447// get TAZ parent1448GNEAdditional* TAZ = getAdditionalParent(sumoBaseObject, SUMO_TAG_TAZ);1449// get edge1450GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1451// check parents1452if (TAZ == nullptr) {1453return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, {SUMO_TAG_TAZ}, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));1454} else if (edge == nullptr) {1455return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, {SUMO_TAG_EDGE}, TAZ->getID());1456} else {1457// declare TAZ Sink1458GNETAZSourceSink* existentTAZSink = nullptr;1459// first check if already exist a TAZ Sink for the given edge and TAZ1460for (auto it = edge->getChildTAZSourceSinks().begin(); (it != edge->getChildTAZSourceSinks().end()) && !existentTAZSink; it++) {1461if (((*it)->getTagProperty()->getTag() == SUMO_TAG_TAZSINK) && ((*it)->getParentAdditionals().front() == TAZ)) {1462existentTAZSink = (*it);1463}1464}1465// check if TAZSink has to be created1466if (existentTAZSink == nullptr) {1467// Create TAZ only with departWeight1468GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, arrivalWeight);1469// add it depending of allow undoRed1470if (myAllowUndoRedo) {1471myNet->getUndoList()->begin(TAZ, TL("add TAZ Sink in '") + TAZ->getID() + "'");1472myNet->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSink, true), true);1473myNet->getUndoList()->end();1474} else {1475myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSink);1476TAZ->addChildElement(TAZSink);1477edge->addChildElement(TAZSink);1478TAZSink->incRef("buildTAZSink");1479}1480} else {1481// update TAZ Attribute depending of allow undoRed1482if (myAllowUndoRedo) {1483myNet->getUndoList()->begin(TAZ, TL("update TAZ Sink in '") + TAZ->getID() + "'");1484existentTAZSink->setAttribute(SUMO_ATTR_WEIGHT, toString(arrivalWeight), myNet->getUndoList());1485myNet->getUndoList()->end();1486} else {1487existentTAZSink->setAttribute(SUMO_ATTR_WEIGHT, toString(arrivalWeight), nullptr);1488}1489}1490return true;1491}1492}149314941495bool1496GNEAdditionalHandler::buildTractionSubstation(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos,1497const double voltage, const double currentLimit, const Parameterised::Map& parameters) {1498// check conditions1499const auto element = retrieveAdditionalElement({SUMO_TAG_TRACTION_SUBSTATION}, id);1500if (!checkElement(SUMO_TAG_TRACTION_SUBSTATION, element)) {1501return false;1502} else if (!checkValidAdditionalID(SUMO_TAG_TRACTION_SUBSTATION, id)) {1503return false;1504} else if (!checkNegative(SUMO_TAG_TRACTION_SUBSTATION, id, SUMO_ATTR_VOLTAGE, voltage, true)) {1505return false;1506} else if (!checkNegative(SUMO_TAG_TRACTION_SUBSTATION, id, SUMO_ATTR_CURRENTLIMIT, currentLimit, true)) {1507return false;1508} else {1509// build traction substation1510GNEAdditional* tractionSubstation = new GNETractionSubstation(id, myNet, myFileBucket, pos, voltage, currentLimit, parameters);1511// insert depending of allowUndoRedo1512if (myAllowUndoRedo) {1513myNet->getUndoList()->begin(tractionSubstation, TL("add traction substation '") + id + "'");1514myNet->getUndoList()->add(new GNEChange_Additional(tractionSubstation, true), true);1515myNet->getUndoList()->end();1516} else {1517myNet->getAttributeCarriers()->insertAdditional(tractionSubstation);1518tractionSubstation->incRef("buildTractionSubstation");1519}1520return true;1521}1522}152315241525bool1526GNEAdditionalHandler::buildOverheadWire(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& substationId,1527const std::vector<std::string>& laneIDs, const double startPos, const double endPos, const bool friendlyPos,1528const std::vector<std::string>& forbiddenInnerLanes, const Parameterised::Map& parameters) {1529// check conditions1530const auto element = retrieveAdditionalElement({SUMO_TAG_OVERHEAD_WIRE_SECTION}, id);1531if (!checkElement(SUMO_TAG_OVERHEAD_WIRE_SECTION, element)) {1532return false;1533} else if (!checkValidAdditionalID(SUMO_TAG_OVERHEAD_WIRE_SECTION, id)) {1534return false;1535} else {1536// get lanes1537const auto lanes = parseLanes(SUMO_TAG_OVERHEAD_WIRE_SECTION, id, laneIDs);1538// get traction substation1539const auto tractionSubstation = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_TRACTION_SUBSTATION, substationId, false);1540// check lanes1541if (lanes.empty()) {1542return false;1543} else {1544// calculate path1545if (!GNEAdditional::areLaneConsecutives(lanes)) {1546return writeError(TLF("Could not build overhead wire with ID '%' in netedit; Lanes aren't consecutives.", id));1547} else if (!checkMultiLanePosition(1548startPos, lanes.front()->getParentEdge()->getNBEdge()->getFinalLength(),1549endPos, lanes.back()->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {1550return writeErrorInvalidPosition(SUMO_TAG_OVERHEAD_WIRE_SECTION, id);1551} else if (tractionSubstation == nullptr) {1552return writeErrorInvalidParent(SUMO_TAG_OVERHEAD_WIRE_SECTION, "", {SUMO_TAG_TRACTION_SUBSTATION}, substationId);1553} else {1554// build Overhead Wire1555GNEAdditional* overheadWire = new GNEOverheadWire(id, myNet, myFileBucket, lanes, tractionSubstation, startPos, endPos, friendlyPos, forbiddenInnerLanes, parameters);1556// insert depending of allowUndoRedo1557if (myAllowUndoRedo) {1558myNet->getUndoList()->begin(overheadWire, TL("add overhead wire '") + id + "'");1559myNet->getUndoList()->add(new GNEChange_Additional(overheadWire, true), true);1560myNet->getUndoList()->end();1561} else {1562myNet->getAttributeCarriers()->insertAdditional(overheadWire);1563for (const auto& lane : lanes) {1564lane->addChildElement(overheadWire);1565}1566overheadWire->incRef("buildOverheadWire");1567}1568}1569return true;1570}1571}1572}157315741575bool1576GNEAdditionalHandler::buildOverheadWireClamp(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& /* id */, const std::string& /* overheadWireIDStartClamp */,1577const std::string& /* laneIDStartClamp */, const std::string& /* overheadWireIDEndClamp */, const std::string& /* laneIDEndClamp */,1578const Parameterised::Map& /* parameters */) {1579//1580return false;1581}158215831584bool1585GNEAdditionalHandler::buildPolygon(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& type,1586const RGBColor& color, double layer, double angle, const std::string& imgFile, const PositionVector& shape,1587bool geo, bool fill, double lineWidth, const std::string& name, const Parameterised::Map& parameters) {1588// check conditions1589if (type == "jupedsim.walkable_area") {1590return buildJpsWalkableArea(sumoBaseObject, id, shape, geo, name, parameters);1591} else if (type == "jupedsim.obstacle") {1592return buildJpsObstacle(sumoBaseObject, id, shape, geo, name, parameters);1593} else {1594// check conditions1595const auto element = retrieveAdditionalElement(NamespaceIDs::polygons, id);1596if (!checkElement(SUMO_TAG_POLY, element)) {1597return false;1598} else if (!checkValidAdditionalID(SUMO_TAG_POLY, id)) {1599return false;1600} else if (!checkNegative(SUMO_TAG_POLY, id, SUMO_ATTR_LINEWIDTH, lineWidth, true)) {1601return false;1602} else {1603// create poly1604GNEPoly* poly = new GNEPoly(id, myNet, myFileBucket, type, shape, geo, fill, lineWidth, color, layer, angle, imgFile, name, parameters);1605// add it depending of allow undoRed1606if (myAllowUndoRedo) {1607myNet->getUndoList()->begin(poly, TL("add polygon '") + id + "'");1608myNet->getUndoList()->add(new GNEChange_Additional(poly, true), true);1609myNet->getUndoList()->end();1610} else {1611// insert shape without allowing undo/redo1612myNet->getAttributeCarriers()->insertAdditional(poly);1613poly->incRef("addPolygon");1614}1615return true;1616}1617}1618}161916201621bool1622GNEAdditionalHandler::buildPOI(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& type,1623const RGBColor& color, const double x, const double y, const std::string& icon, double layer, double angle,1624const std::string& imgFile, double width, double height, const std::string& name, const Parameterised::Map& parameters) {1625// check conditions1626const auto element = retrieveAdditionalElement(NamespaceIDs::POIs, id);1627if (!checkElement(SUMO_TAG_POI, element)) {1628return false;1629} else if (!checkValidAdditionalID(SUMO_TAG_POI, id)) {1630return false;1631} else if (!checkNegative(SUMO_TAG_POI, id, SUMO_ATTR_WIDTH, width, true)) {1632return false;1633} else if (!checkNegative(SUMO_TAG_POI, id, SUMO_ATTR_HEIGHT, height, true)) {1634return false;1635} else if (!checkFileName(SUMO_TAG_POI, id, SUMO_ATTR_IMGFILE, imgFile)) {1636return false;1637} else {1638// parse position1639const auto pos = Position(x, y);1640// parse icon1641const POIIcon ic = SUMOXMLDefinitions::POIIcons.hasString(icon) ? SUMOXMLDefinitions::POIIcons.get(icon) : POIIcon::NONE;1642// create POI1643GNEPOI* POI = new GNEPOI(id, myNet, myFileBucket, type, color, pos, false, ic, layer, angle, imgFile, width, height, name, parameters);1644// add it depending of allow undoRed1645if (myAllowUndoRedo) {1646myNet->getUndoList()->begin(POI, TLF("add POI '%'", id));1647myNet->getUndoList()->add(new GNEChange_Additional(POI, true), true);1648myNet->getUndoList()->end();1649} else {1650// insert shape without allowing undo/redo1651myNet->getAttributeCarriers()->insertAdditional(POI);1652POI->incRef("addPOI");1653}1654return true;1655}1656}165716581659bool1660GNEAdditionalHandler::buildPOILane(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& type,1661const RGBColor& color, const std::string& laneID, double posOverLane, const bool friendlyPos, double posLat,1662const std::string& icon, double layer, double angle, const std::string& imgFile, double width, double height,1663const std::string& name, const Parameterised::Map& parameters) {1664// check conditions1665const auto element = retrieveAdditionalElement(NamespaceIDs::POIs, id);1666if (!checkElement(GNE_TAG_POILANE, element)) {1667return false;1668} else if (!checkValidAdditionalID(GNE_TAG_POILANE, id)) {1669return false;1670} else if (!checkNegative(GNE_TAG_POILANE, id, SUMO_ATTR_WIDTH, width, true)) {1671return false;1672} else if (!checkNegative(GNE_TAG_POILANE, id, SUMO_ATTR_HEIGHT, height, true)) {1673return false;1674} else if (!checkFileName(GNE_TAG_POILANE, id, SUMO_ATTR_IMGFILE, imgFile)) {1675return false;1676} else {1677// get lane1678GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);1679// check lane1680if (lane == nullptr) {1681return writeErrorInvalidParent(GNE_TAG_POILANE, id, {SUMO_TAG_LANE}, laneID);1682} else if (!checkLanePosition(posOverLane, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {1683return writeErrorInvalidPosition(GNE_TAG_POILANE, id);1684} else {1685// parse icon1686const POIIcon ic = SUMOXMLDefinitions::POIIcons.hasString(icon) ? SUMOXMLDefinitions::POIIcons.get(icon) : POIIcon::NONE;1687// create POI (use GNEAdditional instead GNEPOI for add child references)1688GNEAdditional* POILane = new GNEPOI(id, myNet, myFileBucket, type, color, lane, posOverLane, friendlyPos, posLat, ic, layer,1689angle, imgFile, width, height, name, parameters);1690// add it depending of allow undoRed1691if (myAllowUndoRedo) {1692myNet->getUndoList()->begin(POILane, TLF("add POI lane '%'", id));1693myNet->getUndoList()->add(new GNEChange_Additional(POILane, true), true);1694myNet->getUndoList()->end();1695} else {1696// insert shape without allowing undo/redo1697myNet->getAttributeCarriers()->insertAdditional(POILane);1698lane->addChildElement(POILane);1699POILane->incRef("buildPOILane");1700}1701}1702return true;1703}1704}170517061707bool1708GNEAdditionalHandler::buildPOIGeo(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& type,1709const RGBColor& color, const double lon, const double lat, const std::string& icon, double layer,1710double angle, const std::string& imgFile, double width, double height, const std::string& name,1711const Parameterised::Map& parameters) {1712// check conditions1713const auto element = retrieveAdditionalElement(NamespaceIDs::POIs, id);1714if (!checkElement(GNE_TAG_POIGEO, element)) {1715return false;1716} else if (!checkValidAdditionalID(GNE_TAG_POIGEO, id)) {1717return false;1718} else if (!checkNegative(GNE_TAG_POIGEO, id, SUMO_ATTR_WIDTH, width, true)) {1719return false;1720} else if (!checkNegative(GNE_TAG_POIGEO, id, SUMO_ATTR_HEIGHT, height, true)) {1721return false;1722} else if (!checkFileName(GNE_TAG_POIGEO, id, SUMO_ATTR_IMGFILE, imgFile)) {1723return false;1724} else if (GeoConvHelper::getFinal().getProjString() == "!") {1725return writeError(TLF("Could not build POI with ID '%' in netedit", id) + std::string("; ") + TL("Network requires a geo projection."));1726} else {1727// parse position1728const auto pos = Position(lon, lat);1729// parse icon1730const POIIcon ic = SUMOXMLDefinitions::POIIcons.hasString(icon) ? SUMOXMLDefinitions::POIIcons.get(icon) : POIIcon::NONE;1731// create POIGEO1732GNEPOI* POIGEO = new GNEPOI(id, myNet, myFileBucket, type, color, pos, true, ic, layer, angle, imgFile, width, height, name, parameters);1733// add it depending of allow undoRed1734if (myAllowUndoRedo) {1735myNet->getUndoList()->begin(POIGEO, TLF("add POI GEO '%'", id));1736myNet->getUndoList()->add(new GNEChange_Additional(POIGEO, true), true);1737myNet->getUndoList()->end();1738} else {1739// insert shape without allowing undo/redo1740myNet->getAttributeCarriers()->insertAdditional(POIGEO);1741POIGEO->incRef("buildPOIGeo");1742}1743return true;1744}1745}174617471748bool1749GNEAdditionalHandler::buildJpsWalkableArea(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const PositionVector& shape,1750bool geo, const std::string& name, const Parameterised::Map& parameters) {1751// check conditions1752const auto element = retrieveAdditionalElement(NamespaceIDs::polygons, id);1753if (!checkElement(GNE_TAG_JPS_WALKABLEAREA, element)) {1754return false;1755} else if (!checkValidAdditionalID(GNE_TAG_JPS_WALKABLEAREA, id)) {1756return false;1757} else {1758// create walkable area1759GNEPoly* walkableArea = new GNEPoly(GNE_TAG_JPS_WALKABLEAREA, id, myNet, myFileBucket, shape, geo, name, parameters);1760// add it depending of allow undoRed1761if (myAllowUndoRedo) {1762myNet->getUndoList()->begin(walkableArea, TL("add jps walkable area '") + id + "'");1763myNet->getUndoList()->add(new GNEChange_Additional(walkableArea, true), true);1764myNet->getUndoList()->end();1765} else {1766// insert shape without allowing undo/redo1767myNet->getAttributeCarriers()->insertAdditional(walkableArea);1768walkableArea->incRef("addWalkableArea");1769}1770return true;1771}1772}177317741775bool1776GNEAdditionalHandler::buildJpsObstacle(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const PositionVector& shape,1777bool geo, const std::string& name, const Parameterised::Map& parameters) {1778// check conditions1779const auto element = retrieveAdditionalElement(NamespaceIDs::polygons, id);1780if (!checkElement(GNE_TAG_JPS_OBSTACLE, element)) {1781return false;1782} else if (!checkValidAdditionalID(GNE_TAG_JPS_OBSTACLE, id)) {1783return false;1784} else {1785// create walkable area1786GNEPoly* obstacle = new GNEPoly(GNE_TAG_JPS_OBSTACLE, id, myNet, myFileBucket, shape, geo, name, parameters);1787// add it depending of allow undoRed1788if (myAllowUndoRedo) {1789myNet->getUndoList()->begin(obstacle, TL("add jps obstacle '") + id + "'");1790myNet->getUndoList()->add(new GNEChange_Additional(obstacle, true), true);1791myNet->getUndoList()->end();1792} else {1793// insert shape without allowing undo/redo1794myNet->getAttributeCarriers()->insertAdditional(obstacle);1795obstacle->incRef("addObstacle");1796}1797return true;1798}1799}180018011802bool1803GNEAdditionalHandler::accessExists(const GNEAdditional* stoppingPlaceParent, const GNEEdge* edge) {1804// check if exist another access for the same parent in the given edge1805for (const auto& access : stoppingPlaceParent->getChildAdditionals()) {1806// check tag1807if (access->getTagProperty()->getTag() == SUMO_TAG_ACCESS) {1808// check all siblings of the lane1809for (const auto& lane : edge->getChildLanes()) {1810if (access->getAttribute(SUMO_ATTR_LANE) == lane->getID()) {1811return false;1812}1813}1814}1815}1816return true;1817}181818191820bool1821GNEAdditionalHandler::checkOverlappingRerouterIntervals(GNEAdditional* rerouter, SUMOTime newBegin, SUMOTime newEnd) {1822// declare a vector to keep sorted rerouter children1823std::vector<std::pair<SUMOTime, SUMOTime>> sortedIntervals;1824// iterate over child additional1825for (const auto& rerouterChild : rerouter->getChildAdditionals()) {1826if (!rerouterChild->getTagProperty()->isSymbol()) {1827sortedIntervals.push_back(std::make_pair((SUMOTime)0., (SUMOTime)0.));1828// set begin and end1829sortedIntervals.back().first = TIME2STEPS(rerouterChild->getAttributeDouble(SUMO_ATTR_BEGIN));1830sortedIntervals.back().second = TIME2STEPS(rerouterChild->getAttributeDouble(SUMO_ATTR_END));1831}1832}1833// add new intervals1834sortedIntervals.push_back(std::make_pair(newBegin, newEnd));1835// sort children1836std::sort(sortedIntervals.begin(), sortedIntervals.end());1837// check overlapping after sorting1838for (int i = 0; i < (int)sortedIntervals.size() - 1; i++) {1839if (sortedIntervals.at(i).second > sortedIntervals.at(i + 1).first) {1840return false;1841}1842}1843return true;1844}184518461847bool1848GNEAdditionalHandler::checkLanePosition(double pos, const double length, const double laneLength, const bool friendlyPos) {1849if (friendlyPos) {1850return true;1851}1852// adjust from and to (negative means that start at the end of lane and count backward)1853if (pos < 0) {1854pos += laneLength;1855}1856// check extremes1857if ((pos < 0) || (pos > laneLength)) {1858return false;1859}1860// check pos + length1861if ((pos + length) > laneLength) {1862return false;1863}1864// all OK1865return true;1866}186718681869bool1870GNEAdditionalHandler::checkFriendlyPosSmallLanes(double pos, const double length, const double laneLength, const bool friendlyPos) {1871if (friendlyPos == true) {1872return true;1873} else if (OptionsCont::getOptions().getBool("e2.friendlyPos.automatic")) {1874// adjust from and to (negative means that start at the end of lane and count backward)1875if (pos < 0) {1876pos += laneLength;1877}1878// check extremes1879if ((pos < 0) || (pos > laneLength)) {1880return true;1881}1882// check pos + length1883if ((pos + length) > laneLength) {1884return true;1885}1886}1887return false;1888}188918901891bool1892GNEAdditionalHandler::checkLaneDoublePosition(double from, double to, const double laneLength, const bool friendlyPos) {1893if (friendlyPos) {1894return true;1895}1896// adjust from and to (negative means that start at the end of lane and count backward)1897if (from == INVALID_DOUBLE) {1898from = 0;1899}1900if (to == INVALID_DOUBLE) {1901to = laneLength;1902}1903if (from < 0) {1904from += laneLength;1905}1906if (to < 0) {1907to += laneLength;1908}1909if ((to - from) < POSITION_EPS) {1910return false;1911}1912if ((from < 0) || (from > laneLength)) {1913return false;1914}1915if ((to < 0) || (to > laneLength)) {1916return false;1917}1918return true;1919}192019211922void1923GNEAdditionalHandler::fixLaneDoublePosition(double& from, double& to, const double laneLength) {1924// adjust from (negative means that start at the end of lane and count backward)1925if (from == INVALID_DOUBLE) {1926from = 0;1927}1928if (to == INVALID_DOUBLE) {1929to = laneLength;1930}1931if (from < 0) {1932from += laneLength;1933}1934if (from < 0) {1935from = 0;1936} else if (from > laneLength) {1937from = laneLength;1938}1939// adjust to1940if (to < 0) {1941to += laneLength;1942}1943if (to < 0) {1944to = 0;1945} else if (to > laneLength) {1946to = laneLength;1947}1948// to has more priorty as from, and distance between from and to must be >= POSITION_EPS1949if ((to - from) < POSITION_EPS) {1950if (to >= POSITION_EPS) {1951from = to - POSITION_EPS;1952} else {1953from = 0;1954to = POSITION_EPS;1955}1956}1957}195819591960bool1961GNEAdditionalHandler::checkMultiLanePosition(double fromPos, const double fromLaneLength, const double toPos, const double tolaneLength, const bool friendlyPos) {1962if (friendlyPos) {1963return true;1964} else {1965return (checkLanePosition(fromPos, 0, fromLaneLength, false) && checkLanePosition(toPos, 0, tolaneLength, false));1966}1967}196819691970GNEAdditional*1971GNEAdditionalHandler::getAdditionalParent(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, SumoXMLTag tag) const {1972if (sumoBaseObject->getParentSumoBaseObject() == nullptr) {1973return nullptr;1974} else if (!sumoBaseObject->getParentSumoBaseObject()->hasStringAttribute(SUMO_ATTR_ID)) {1975return nullptr;1976} else {1977return myNet->getAttributeCarriers()->retrieveAdditional(tag, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID), false);1978}1979}198019811982GNEAdditional*1983GNEAdditionalHandler::getRerouterIntervalParent(const CommonXMLStructure::SumoBaseObject* sumoBaseObject) const {1984if (sumoBaseObject->getParentSumoBaseObject() == nullptr) {1985// parent interval doesn't exist1986return nullptr;1987} else if (sumoBaseObject->getParentSumoBaseObject()->getParentSumoBaseObject() == nullptr) {1988// rerouter parent doesn't exist1989return nullptr;1990} else if (!sumoBaseObject->getParentSumoBaseObject()->getParentSumoBaseObject()->hasStringAttribute(SUMO_ATTR_ID) || // rerouter ID1991!sumoBaseObject->getParentSumoBaseObject()->hasTimeAttribute(SUMO_ATTR_BEGIN) || // interval begin1992!sumoBaseObject->getParentSumoBaseObject()->hasTimeAttribute(SUMO_ATTR_END)) { // interval end1993return nullptr;1994} else {1995return myNet->getAttributeCarriers()->retrieveRerouterInterval(1996sumoBaseObject->getParentSumoBaseObject()->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID),1997sumoBaseObject->getParentSumoBaseObject()->getTimeAttribute(SUMO_ATTR_BEGIN),1998sumoBaseObject->getParentSumoBaseObject()->getTimeAttribute(SUMO_ATTR_END));1999}2000}200120022003std::vector<GNEEdge*>2004GNEAdditionalHandler::parseEdges(const SumoXMLTag tag, const std::string& id, const std::vector<std::string>& edgeIDs) {2005std::vector<GNEEdge*> edges;2006for (const auto& edgeID : edgeIDs) {2007GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);2008// empty edges aren't allowed. If edge is empty, write error, clear edges and stop2009if (edge == nullptr) {2010writeError(TLF("Could not build % with ID '%' in netedit; % with ID '%' doesn't exist.", toString(tag), id, toString(SUMO_TAG_EDGE), edgeID));2011edges.clear();2012return edges;2013} else {2014edges.push_back(edge);2015}2016}2017return edges;2018}201920202021std::vector<GNELane*>2022GNEAdditionalHandler::parseLanes(const SumoXMLTag tag, const std::string& id, const std::vector<std::string>& laneIDs) {2023std::vector<GNELane*> lanes;2024for (const auto& laneID : laneIDs) {2025GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);2026// empty lanes aren't allowed. If lane is empty, write error, clear lanes and stop2027if (lane == nullptr) {2028writeError(TLF("Could not build % with ID '%' in netedit; % with ID '%' doesn't exist.", toString(tag), id, toString(SUMO_TAG_LANE), laneID));2029lanes.clear();2030return lanes;2031} else {2032lanes.push_back(lane);2033}2034}2035return lanes;2036}203720382039GNEAdditional*2040GNEAdditionalHandler::retrieveAdditionalElement(const std::vector<SumoXMLTag> tags, const std::string& id) {2041for (const auto& tag : tags) {2042// retrieve additional element2043auto additionalElement = myNet->getAttributeCarriers()->retrieveAdditional(tag, id, false);2044if (additionalElement) {2045return additionalElement;2046}2047}2048return nullptr;2049}205020512052bool2053GNEAdditionalHandler::checkElement(const SumoXMLTag tag, GNEAdditional* additionalElement) {2054if (additionalElement) {2055if (myOverwriteElements) {2056// delete element2057myNet->deleteAdditional(additionalElement, myNet->getUndoList());2058} else if (myRemainElements) {2059// duplicated demand2060return writeWarningDuplicated(tag, additionalElement->getID(), additionalElement->getTagProperty()->getTag());2061} else {2062// open overwrite dialog2063GNEOverwriteElement overwriteElementDialog(this, additionalElement);2064// continue depending of result2065if (overwriteElementDialog.getResult() == GNEOverwriteElement::Result::ACCEPT) {2066// delete element2067myNet->deleteAdditional(additionalElement, myNet->getUndoList());2068} else if (overwriteElementDialog.getResult() == GNEOverwriteElement::Result::CANCEL) {2069// duplicated demand2070return writeWarningDuplicated(tag, additionalElement->getID(), additionalElement->getTagProperty()->getTag());2071} else {2072return false;2073}2074}2075}2076return true;2077}20782079/****************************************************************************/208020812082