Path: blob/main/src/netedit/elements/additional/GNEAdditionalHandler.cpp
169685 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file 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/GNENet.h>25#include <netedit/GNETagProperties.h>26#include <netedit/GNEUndoList.h>27#include <netedit/GNEViewNet.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 "GNETAZSourceSink.h"59#include "GNETractionSubstation.h"60#include "GNEVaporizer.h"61#include "GNEVariableSpeedSign.h"62#include "GNEVariableSpeedSignStep.h"63#include "GNEVariableSpeedSignSymbol.h"6465// ===========================================================================66// GNEAdditionalHandler method definitions67// ===========================================================================6869GNEAdditionalHandler::GNEAdditionalHandler(GNENet* net, const std::string& filename, const bool allowUndoRedo) :70AdditionalHandler(filename),71myNet(net),72myAllowUndoRedo(allowUndoRedo) {73}747576GNEAdditionalHandler::~GNEAdditionalHandler() {77}787980bool81GNEAdditionalHandler::postParserTasks() {82// nothing to do83return true;84}858687bool88GNEAdditionalHandler::buildBusStop(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id,89const std::string& laneID, const double startPos, const double endPos, const std::string& name,90const std::vector<std::string>& lines, const int personCapacity, const double parkingLength,91const RGBColor& color, const bool friendlyPosition, const double angle,92const Parameterised::Map& parameters) {93// check conditions94const auto element = retrieveAdditionalElement(NamespaceIDs::busStops, id);95if (!checkElement(SUMO_TAG_BUS_STOP, element)) {96return false;97} else if (!checkValidAdditionalID(SUMO_TAG_BUS_STOP, id)) {98return false;99} else {100// get lane101GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);102// check lane103if (lane == nullptr) {104return writeErrorInvalidParent(SUMO_TAG_BUS_STOP, id, SUMO_TAG_LANE, laneID);105} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {106return writeErrorInvalidPosition(SUMO_TAG_BUS_STOP, id);107} else if (!checkNegative(SUMO_TAG_BUS_STOP, id, SUMO_ATTR_PERSON_CAPACITY, personCapacity, true)) {108return false;109} else if (!checkNegative(SUMO_TAG_BUS_STOP, id, SUMO_ATTR_PARKING_LENGTH, parkingLength, true)) {110return false;111} else {112// build busStop113GNEAdditional* busStop = GNEBusStop::buildBusStop(id, myNet, myFilename, lane, startPos, endPos, name, lines, personCapacity,114parkingLength, color, friendlyPosition, angle, parameters);115// insert depending of allowUndoRedo116if (myAllowUndoRedo) {117myNet->getViewNet()->getUndoList()->begin(busStop, TL("add bus stop '") + id + "'");118myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(busStop, true), true);119myNet->getViewNet()->getUndoList()->end();120} else {121myNet->getAttributeCarriers()->insertAdditional(busStop);122lane->addChildElement(busStop);123busStop->incRef("buildBusStop");124}125return true;126}127}128}129130131bool132GNEAdditionalHandler::buildTrainStop(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id,133const std::string& laneID, const double startPos, const double endPos, const std::string& name,134const std::vector<std::string>& lines, const int personCapacity, const double parkingLength,135const RGBColor& color, const bool friendlyPosition, const double angle,136const Parameterised::Map& parameters) {137// check conditions138const auto element = retrieveAdditionalElement(NamespaceIDs::busStops, id);139if (!checkElement(SUMO_TAG_TRAIN_STOP, element)) {140return false;141} else if (!checkValidAdditionalID(SUMO_TAG_TRAIN_STOP, id)) {142return false;143} else {144// get lane145GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);146// check lane147if (lane == nullptr) {148return writeErrorInvalidParent(SUMO_TAG_TRAIN_STOP, id, SUMO_TAG_LANE, laneID);149} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {150return writeErrorInvalidPosition(SUMO_TAG_TRAIN_STOP, id);151} else if (!checkNegative(SUMO_TAG_TRAIN_STOP, id, SUMO_ATTR_PERSON_CAPACITY, personCapacity, true)) {152return false;153} else if (!checkNegative(SUMO_TAG_TRAIN_STOP, id, SUMO_ATTR_PARKING_LENGTH, parkingLength, true)) {154return false;155} else {156// build trainStop157GNEAdditional* trainStop = GNEBusStop::buildTrainStop(id, myNet, myFilename, lane, startPos, endPos, name, lines, personCapacity,158parkingLength, color, friendlyPosition, angle, parameters);159// insert depending of allowUndoRedo160if (myAllowUndoRedo) {161myNet->getViewNet()->getUndoList()->begin(trainStop, TL("add train stop '") + id + "'");162myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(trainStop, true), true);163myNet->getViewNet()->getUndoList()->end();164} else {165myNet->getAttributeCarriers()->insertAdditional(trainStop);166lane->addChildElement(trainStop);167trainStop->incRef("buildTrainStop");168}169return true;170}171}172}173174175bool176GNEAdditionalHandler::buildAccess(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& laneID,177const std::string& pos, const double length, const bool friendlyPos, const Parameterised::Map& parameters) {178// get lane179GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);180// get busStop (or trainStop)181const auto busStop = getAdditionalParent(sumoBaseObject, SUMO_TAG_BUS_STOP);182const auto trainStop = getAdditionalParent(sumoBaseObject, SUMO_TAG_TRAIN_STOP);183const auto containerStop = getAdditionalParent(sumoBaseObject, SUMO_TAG_CONTAINER_STOP);184// check parent185if ((busStop == nullptr) && (trainStop == nullptr) && (containerStop == nullptr)) {186return writeErrorInvalidParent(SUMO_TAG_ACCESS, "", sumoBaseObject->getParentSumoBaseObject()->getTag(), sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));187}188GNEAdditional* accessParent = busStop ? busStop : trainStop ? trainStop : containerStop;189// pos double190bool validPos = true;191double posDouble = 0;192if (lane) {193if (GNEAttributeCarrier::canParse<double>(pos)) {194posDouble = GNEAttributeCarrier::parse<double>(pos);195validPos = checkLanePosition(posDouble, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos);196} else if (pos == "random" || pos == "doors" || pos == "carriage") {197posDouble = INVALID_DOUBLE;198} else if (pos.empty()) {199posDouble = 0;200} else {201validPos = false;202}203}204// Check if lane is correct205if (lane == nullptr) {206return writeErrorInvalidParent(SUMO_TAG_ACCESS, "", SUMO_TAG_LANE, laneID);207} else if (!validPos) {208return writeErrorInvalidPosition(SUMO_TAG_ACCESS, accessParent->getID());209} else if ((length != -1) && !checkNegative(SUMO_TAG_ACCESS, accessParent->getID(), SUMO_ATTR_LENGTH, length, true)) {210return false;211} else if (!accessCanBeCreated(accessParent, lane->getParentEdge())) {212return writeError(TLF("Could not build access in netedit; % '%' already owns an access in the edge '%'", accessParent->getTagStr(), accessParent->getID(), lane->getParentEdge()->getID()));213} else if (!containerStop && !lane->allowPedestrians()) {214// only for busStops and trainStops215return writeError(TLF("Could not build access in netedit; The lane '%' doesn't support pedestrians", lane->getID()));216} else {217// build access218GNEAdditional* access = new GNEAccess(accessParent, lane, posDouble, pos, friendlyPos, length, parameters);219// insert depending of allowUndoRedo220if (myAllowUndoRedo) {221myNet->getViewNet()->getUndoList()->begin(access, TL("add access in '") + accessParent->getID() + "'");222myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(access, true), true);223myNet->getViewNet()->getUndoList()->end();224} else {225myNet->getAttributeCarriers()->insertAdditional(access);226lane->addChildElement(access);227accessParent->addChildElement(access);228access->incRef("buildAccess");229}230return true;231}232}233234235bool236GNEAdditionalHandler::buildContainerStop(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,237const double startPos, const double endPos, const std::string& name, const std::vector<std::string>& lines, const int containerCapacity,238const double parkingLength, const RGBColor& color, const bool friendlyPosition, const double angle, const Parameterised::Map& parameters) {239// check conditions240const auto element = retrieveAdditionalElement({SUMO_TAG_CONTAINER_STOP}, id);241if (!checkElement(SUMO_TAG_CONTAINER_STOP, element)) {242return false;243} else if (!checkValidAdditionalID(SUMO_TAG_CONTAINER_STOP, id)) {244return false;245} else {246// get lane247GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);248// check lane249if (lane == nullptr) {250return writeErrorInvalidParent(SUMO_TAG_CONTAINER_STOP, id, SUMO_TAG_LANE, laneID);251} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {252return writeErrorInvalidPosition(SUMO_TAG_CONTAINER_STOP, id);253} else if (!checkNegative(SUMO_TAG_CONTAINER_STOP, id, SUMO_ATTR_CONTAINER_CAPACITY, containerCapacity, true)) {254return false;255} else if (!checkNegative(SUMO_TAG_CONTAINER_STOP, id, SUMO_ATTR_PARKING_LENGTH, parkingLength, true)) {256return false;257} else {258// build containerStop259GNEAdditional* containerStop = new GNEContainerStop(id, myNet, myFilename, lane, startPos, endPos, name, lines, containerCapacity, parkingLength,260color, friendlyPosition, angle, parameters);261// insert depending of allowUndoRedo262if (myAllowUndoRedo) {263myNet->getViewNet()->getUndoList()->begin(containerStop, TL("add container stop '") + id + "'");264myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(containerStop, true), true);265myNet->getViewNet()->getUndoList()->end();266} else {267myNet->getAttributeCarriers()->insertAdditional(containerStop);268lane->addChildElement(containerStop);269containerStop->incRef("buildContainerStop");270}271return true;272}273}274}275276277bool278GNEAdditionalHandler::buildChargingStation(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id,279const std::string& laneID, const double startPos, const double endPos, const std::string& name, const double chargingPower,280const double efficiency, const bool chargeInTransit, const SUMOTime chargeDelay, const std::string& chargeType,281const SUMOTime waitingTime, const bool friendlyPosition, const std::string& parkingAreaID, const Parameterised::Map& parameters) {282// check conditions283const auto element = retrieveAdditionalElement({SUMO_TAG_CHARGING_STATION}, id);284if (!checkElement(SUMO_TAG_CHARGING_STATION, element)) {285return false;286} else if (!checkValidAdditionalID(SUMO_TAG_CHARGING_STATION, id)) {287return false;288} else {289// get lane290GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);291// check lane292if (lane == nullptr) {293return writeErrorInvalidParent(SUMO_TAG_CHARGING_STATION, id, SUMO_TAG_LANE, laneID);294} else if (!checkLaneDoublePosition(startPos, endPos, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosition)) {295return writeErrorInvalidPosition(SUMO_TAG_CHARGING_STATION, id);296} else if (!checkNegative(SUMO_TAG_CHARGING_STATION, id, SUMO_ATTR_CHARGINGPOWER, chargingPower, 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, myFilename, lane, startPos, endPos, name, chargingPower, efficiency, chargeInTransit,305chargeDelay, chargeType, waitingTime, parkingAreaID, friendlyPosition, parameters);306// insert depending of allowUndoRedo307if (myAllowUndoRedo) {308myNet->getViewNet()->getUndoList()->begin(chargingStation, TL("add charging station '") + id + "'");309myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(chargingStation, true), true);310myNet->getViewNet()->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, myFilename, 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->getViewNet()->getUndoList()->begin(parkingArea, TL("add parking area '") + id + "'");359myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(parkingArea, true), true);360myNet->getViewNet()->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() ? 0 : GNEAttributeCarrier::parse<double>(width);388const double lengthDouble = length.empty() ? 0 : GNEAttributeCarrier::parse<double>(length);389// check lane390if (parkingArea == nullptr) {391return writeErrorInvalidParent(SUMO_TAG_PARKING_SPACE, "", SUMO_TAG_PARKING_AREA, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));392} else if (!checkNegative(SUMO_TAG_PARKING_SPACE, parkingArea->getID(), SUMO_ATTR_WIDTH, widthDouble, true)) {393return false;394} else if (!checkNegative(SUMO_TAG_PARKING_SPACE, parkingArea->getID(), SUMO_ATTR_LENGTH, lengthDouble, true)) {395return false;396} else {397// build parkingSpace398GNEAdditional* parkingSpace = new GNEParkingSpace(parkingArea, Position(x, y, z), width, length, angle, slope, name, parameters);399// insert depending of allowUndoRedo400if (myAllowUndoRedo) {401myNet->getViewNet()->getUndoList()->begin(parkingSpace, TL("add parking space in '") + parkingArea->getID() + "'");402myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(parkingSpace, true), true);403myNet->getViewNet()->getUndoList()->end();404} else {405myNet->getAttributeCarriers()->insertAdditional(parkingSpace);406parkingArea->addChildElement(parkingSpace);407parkingSpace->incRef("buildParkingSpace");408}409// update geometry (due boundaries)410parkingSpace->updateGeometry();411return true;412}413}414}415416417bool418GNEAdditionalHandler::buildE1Detector(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,419const double position, const SUMOTime period, const std::string& file, const std::vector<std::string>& vehicleTypes,420const std::vector<std::string>& nextEdges, const std::string& detectPersons, const std::string& name,421const bool friendlyPos, const Parameterised::Map& parameters) {422// check conditions423const auto element = retrieveAdditionalElement({SUMO_TAG_INDUCTION_LOOP}, id);424if (!checkElement(SUMO_TAG_INDUCTION_LOOP, element)) {425return false;426} else if (!checkValidDetectorID(SUMO_TAG_INDUCTION_LOOP, id)) {427return false;428} else {429// get lane430GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);431// check lane432if (lane == nullptr) {433return writeErrorInvalidParent(SUMO_TAG_INDUCTION_LOOP, id, SUMO_TAG_LANE, laneID);434} else if (!checkLanePosition(position, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {435return writeErrorInvalidPosition(SUMO_TAG_INDUCTION_LOOP, id);436} else if (!checkNegative(SUMO_TAG_INDUCTION_LOOP, id, SUMO_ATTR_PERIOD, period, true)) {437return false;438} else if (!checkFileName(SUMO_TAG_INDUCTION_LOOP, id, SUMO_ATTR_FILE, file)) {439return false;440} else if (!checkListOfVehicleTypes(SUMO_TAG_INDUCTION_LOOP, id, vehicleTypes)) {441return false;442} else {443// build E1444GNEAdditional* detectorE1 = new GNEInductionLoopDetector(id, myNet, myFilename, lane, position, period, file, vehicleTypes,445nextEdges, detectPersons, name, friendlyPos, parameters);446// insert depending of allowUndoRedo447if (myAllowUndoRedo) {448myNet->getViewNet()->getUndoList()->begin(detectorE1, TL("add induction loop '") + id + "'");449myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(detectorE1, true), true);450myNet->getViewNet()->getUndoList()->end();451} else {452myNet->getAttributeCarriers()->insertAdditional(detectorE1);453lane->addChildElement(detectorE1);454detectorE1->incRef("buildDetectorE1");455}456return true;457}458}459}460461462bool463GNEAdditionalHandler::buildSingleLaneDetectorE2(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID,464const double pos, const double length, const SUMOTime period, const std::string& trafficLight, const std::string& filename,465const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges, const std::string& detectPersons,466const std::string& name, const SUMOTime timeThreshold, const double speedThreshold, const double jamThreshold,467const bool friendlyPos, const bool show, const Parameterised::Map& parameters) {468// check conditions469const auto element = retrieveAdditionalElement(NamespaceIDs::laneAreaDetectors, id);470if (!checkElement(SUMO_TAG_LANE_AREA_DETECTOR, element)) {471return false;472} else if (!checkValidDetectorID(SUMO_TAG_LANE_AREA_DETECTOR, id)) {473return false;474} else {475// get lane476GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);477// check lane478if (lane == nullptr) {479return writeErrorInvalidParent(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_TAG_LANE, laneID);480} else {481// check friendlyPos in small lanes482const bool friendlyPosCheck = checkFriendlyPosSmallLanes(pos, length, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos);483if (!checkLanePosition(pos, length, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPosCheck)) {484return writeErrorInvalidPosition(SUMO_TAG_LANE_AREA_DETECTOR, id);485} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_LENGTH, length, true)) {486return false;487} else if ((period != -1) && !checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_PERIOD, period, true)) {488return false;489} else if ((trafficLight.size() > 0) && !(SUMOXMLDefinitions::isValidNetID(trafficLight))) {490// temporal491return writeError(TLF("Could not build lane area detector with ID '%' in netedit; invalid traffic light ID.", id));492} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {493return false;494} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_SPEED_THRESHOLD, speedThreshold, true)) {495return false;496} else if (!checkNegative(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {497return false;498} else if (!checkFileName(SUMO_TAG_LANE_AREA_DETECTOR, id, SUMO_ATTR_FILE, filename)) {499return false;500} else if (!checkListOfVehicleTypes(SUMO_TAG_LANE_AREA_DETECTOR, id, vehicleTypes)) {501return false;502} else {503// build E2 single lane504GNEAdditional* detectorE2 = new GNELaneAreaDetector(id, myNet, myFilename, lane, pos, length, period, trafficLight, filename,505vehicleTypes, nextEdges, detectPersons, name, timeThreshold,506speedThreshold, jamThreshold, friendlyPosCheck, show, parameters);507// insert depending of allowUndoRedo508if (myAllowUndoRedo) {509myNet->getViewNet()->getUndoList()->begin(detectorE2, TL("add lane area detector '") + id + "'");510myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(detectorE2, true), true);511myNet->getViewNet()->getUndoList()->end();512} else {513myNet->getAttributeCarriers()->insertAdditional(detectorE2);514lane->addChildElement(detectorE2);515detectorE2->incRef("buildDetectorE2");516}517return true;518}519}520}521}522523524bool525GNEAdditionalHandler::buildMultiLaneDetectorE2(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::vector<std::string>& laneIDs,526const double pos, const double endPos, const SUMOTime period, const std::string& trafficLight, const std::string& filename,527const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges, const std::string& detectPersons,528const std::string& name, const SUMOTime timeThreshold, const double speedThreshold, const double jamThreshold,529const bool friendlyPos, const bool show, const Parameterised::Map& parameters) {530// check conditions531const auto element = retrieveAdditionalElement(NamespaceIDs::laneAreaDetectors, id);532if (!checkElement(GNE_TAG_MULTI_LANE_AREA_DETECTOR, element)) {533return false;534} else if (!checkValidDetectorID(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id)) {535return false;536} else {537// get lanes538const auto lanes = parseLanes(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, laneIDs);539// check lanes540if (lanes.empty()) {541return false;542} else {543// calculate path544if (!GNEAdditional::areLaneConsecutives(lanes)) {545return writeError(TLF("Could not build lane area detector with ID '%' in netedit; Lanes aren't consecutives.", id));546} else if (!checkMultiLanePosition(547pos, lanes.front()->getParentEdge()->getNBEdge()->getFinalLength(),548endPos, lanes.back()->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {549return writeErrorInvalidPosition(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id);550} else if ((period != -1) && !checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_PERIOD, period, true)) {551return false;552} else if ((trafficLight.size() > 0) && !(SUMOXMLDefinitions::isValidNetID(trafficLight))) {553// temporal554return writeError(TLF("Could not build lane area detector with ID '%' in netedit; invalid traffic light ID.", id));555} else if (!checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {556return false;557} else if (!checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_HALTING_SPEED_THRESHOLD, speedThreshold, true)) {558return false;559} else if (!checkNegative(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {560return false;561} else if (!checkFileName(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, SUMO_ATTR_FILE, filename)) {562return false;563} else if (!checkListOfVehicleTypes(GNE_TAG_MULTI_LANE_AREA_DETECTOR, id, vehicleTypes)) {564return false;565} else {566// build E2 multilane detector567GNEAdditional* detectorE2 = new GNELaneAreaDetector(id, myNet, myFilename, lanes, pos, endPos, period, trafficLight, filename,568vehicleTypes, nextEdges, detectPersons, name, timeThreshold,569speedThreshold, jamThreshold, friendlyPos, show, parameters);570// insert depending of allowUndoRedo571if (myAllowUndoRedo) {572myNet->getViewNet()->getUndoList()->begin(detectorE2, TL("add lane area detector '") + id + "'");573myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(detectorE2, true), true);574myNet->getViewNet()->getUndoList()->end();575} else {576myNet->getAttributeCarriers()->insertAdditional(detectorE2);577for (const auto& lane : lanes) {578lane->addChildElement(detectorE2);579}580detectorE2->incRef("buildDetectorE2Multilane");581}582return true;583}584}585}586}587588589bool590GNEAdditionalHandler::buildDetectorE3(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos, const SUMOTime period,591const std::string& filename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,592const std::string& detectPersons, const std::string& name, const SUMOTime timeThreshold, const double speedThreshold,593const bool openEntry, const bool expectedArrival, const Parameterised::Map& parameters) {594// check conditions595const auto element = retrieveAdditionalElement({SUMO_TAG_ENTRY_EXIT_DETECTOR}, id);596if (!checkElement(SUMO_TAG_ENTRY_EXIT_DETECTOR, element)) {597return false;598} else if (!checkValidDetectorID(SUMO_TAG_ENTRY_EXIT_DETECTOR, id)) {599return false;600} else if (!checkNegative(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_PERIOD, period, true)) {601return false;602} else if (!checkNegative(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {603return false;604} else if (!checkNegative(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_HALTING_SPEED_THRESHOLD, speedThreshold, true)) {605return false;606} else if (!checkFileName(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, SUMO_ATTR_FILE, filename)) {607return false;608} else if (!checkListOfVehicleTypes(SUMO_TAG_ENTRY_EXIT_DETECTOR, id, vehicleTypes)) {609return false;610} else {611// build E3612GNEAdditional* E3 = new GNEMultiEntryExitDetector(id, myNet, myFilename, pos, period, filename, vehicleTypes, nextEdges, detectPersons,613name, timeThreshold, speedThreshold, openEntry, expectedArrival, parameters);614// insert depending of allowUndoRedo615if (myAllowUndoRedo) {616myNet->getViewNet()->getUndoList()->begin(E3, TL("add entry-exit detector '") + id + "'");617myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(E3, true), true);618myNet->getViewNet()->getUndoList()->end();619} else {620myNet->getAttributeCarriers()->insertAdditional(E3);621E3->incRef("buildDetectorE3");622}623return true;624}625}626627628bool629GNEAdditionalHandler::buildDetectorEntry(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& laneID, const double pos,630const bool friendlyPos, const Parameterised::Map& parameters) {631// get lane632GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);633// get E3 parent634GNEAdditional* E3 = getAdditionalParent(sumoBaseObject, SUMO_TAG_ENTRY_EXIT_DETECTOR);635// Check if Detector E3 parent and lane is correct636if (lane == nullptr) {637return writeErrorInvalidParent(SUMO_TAG_DET_ENTRY, "", SUMO_TAG_LANE, laneID);638} else if (E3 == nullptr) {639return writeErrorInvalidParent(SUMO_TAG_DET_ENTRY, "", SUMO_TAG_ENTRY_EXIT_DETECTOR, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));640} else if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {641return writeErrorInvalidPosition(SUMO_TAG_DET_ENTRY, E3->getID());642} else {643// build entry instant644GNEAdditional* entry = new GNEEntryExitDetector(SUMO_TAG_DET_ENTRY, E3, lane, pos, friendlyPos, parameters);645// insert depending of allowUndoRedo646if (myAllowUndoRedo) {647myNet->getViewNet()->getUndoList()->begin(entry, TL("add entry detector in '") + E3->getID() + "'");648myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(entry, true), true);649myNet->getViewNet()->getUndoList()->end();650} else {651myNet->getAttributeCarriers()->insertAdditional(entry);652lane->addChildElement(entry);653E3->addChildElement(entry);654entry->incRef("buildDetectorEntry");655}656return true;657}658}659660661bool662GNEAdditionalHandler::buildDetectorExit(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& laneID, const double pos,663const bool friendlyPos, const Parameterised::Map& parameters) {664// get lane665GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);666// get E3 parent667GNEAdditional* E3 = getAdditionalParent(sumoBaseObject, SUMO_TAG_ENTRY_EXIT_DETECTOR);668// Check if Detector E3 parent and lane is correct669if (lane == nullptr) {670return writeErrorInvalidParent(SUMO_TAG_DET_EXIT, "", SUMO_TAG_LANE, laneID);671} else if (E3 == nullptr) {672return writeErrorInvalidParent(SUMO_TAG_DET_EXIT, "", SUMO_TAG_ENTRY_EXIT_DETECTOR, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));673} else if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {674return writeErrorInvalidPosition(SUMO_TAG_DET_EXIT, E3->getID());675} else {676// build exit instant677GNEAdditional* exit = new GNEEntryExitDetector(SUMO_TAG_DET_EXIT, E3, lane, pos, friendlyPos, parameters);678// insert depending of allowUndoRedo679if (myAllowUndoRedo) {680myNet->getViewNet()->getUndoList()->begin(exit, TL("add exit detector in '") + E3->getID() + "'");681myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(exit, true), true);682myNet->getViewNet()->getUndoList()->end();683} else {684myNet->getAttributeCarriers()->insertAdditional(exit);685lane->addChildElement(exit);686E3->addChildElement(exit);687exit->incRef("buildDetectorExit");688}689return true;690}691}692693694bool695GNEAdditionalHandler::buildDetectorE1Instant(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& laneID, double pos,696const std::string& filename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges,697const std::string& detectPersons, const std::string& name, const bool friendlyPos, const Parameterised::Map& parameters) {698// check conditions699const auto element = retrieveAdditionalElement({SUMO_TAG_INSTANT_INDUCTION_LOOP}, id);700if (!checkElement(SUMO_TAG_INSTANT_INDUCTION_LOOP, element)) {701return false;702} else if (!checkValidDetectorID(SUMO_TAG_INSTANT_INDUCTION_LOOP, id)) {703return false;704} else {705// get lane706GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);707// check lane708if (lane == nullptr) {709return writeErrorInvalidParent(SUMO_TAG_INSTANT_INDUCTION_LOOP, id, SUMO_TAG_LANE, laneID);710} else if (!checkFileName(SUMO_TAG_INSTANT_INDUCTION_LOOP, id, SUMO_ATTR_FILE, filename)) {711return false;712} else if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {713return writeErrorInvalidPosition(SUMO_TAG_INSTANT_INDUCTION_LOOP, id);714} else {715// build E1 instant716GNEAdditional* detectorE1Instant = new GNEInstantInductionLoopDetector(id, myNet, myFilename, lane, pos, filename, vehicleTypes, nextEdges,717detectPersons, name, friendlyPos, parameters);718// insert depending of allowUndoRedo719if (myAllowUndoRedo) {720myNet->getViewNet()->getUndoList()->begin(detectorE1Instant, TL("add instant induction loop '") + id + "'");721myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(detectorE1Instant, true), true);722myNet->getViewNet()->getUndoList()->end();723} else {724myNet->getAttributeCarriers()->insertAdditional(detectorE1Instant);725lane->addChildElement(detectorE1Instant);726detectorE1Instant->incRef("buildDetectorE1Instant");727}728return true;729}730}731}732733734bool735GNEAdditionalHandler::buildLaneCalibrator(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& laneID, const double pos,736const std::string& name, const std::string& outfile, const SUMOTime period, const std::string& routeprobeID, const double jamThreshold, const std::vector<std::string>& vTypes,737const Parameterised::Map& parameters) {738// get lane739GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);740// get routeProbe741GNEAdditional* routeProbe = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, routeprobeID, false);742// check conditions743const auto element = retrieveAdditionalElement(NamespaceIDs::calibrators, id);744if (!checkElement(GNE_TAG_CALIBRATOR_LANE, element)) {745return false;746} else if (!checkValidAdditionalID(GNE_TAG_CALIBRATOR_LANE, id)) {747return false;748} else if ((routeprobeID.size() > 0) && (routeProbe == nullptr)) {749return writeErrorInvalidParent(GNE_TAG_CALIBRATOR_LANE, id, SUMO_TAG_ROUTEPROBE, routeprobeID);750} else if (lane == nullptr) {751return writeErrorInvalidParent(GNE_TAG_CALIBRATOR_LANE, id, SUMO_TAG_LANE, laneID);752} else {753// check lane754if (!checkLanePosition(pos, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), false)) {755return writeErrorInvalidPosition(GNE_TAG_CALIBRATOR_LANE, id);756} else if (!checkNegative(GNE_TAG_CALIBRATOR_LANE, id, SUMO_ATTR_PERIOD, period, true)) {757return false;758} else if (!checkNegative(GNE_TAG_CALIBRATOR_LANE, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {759return false;760} else {761// build Calibrator762GNEAdditional* calibrator = (routeProbe == nullptr) ?763new GNECalibrator(id, myNet, myFilename, lane, pos, period, name, outfile, jamThreshold, vTypes, parameters) :764new GNECalibrator(id, myNet, myFilename, lane, pos, period, name, outfile, routeProbe, jamThreshold, vTypes, parameters);765// insert depending of allowUndoRedo766if (myAllowUndoRedo) {767myNet->getViewNet()->getUndoList()->begin(calibrator, TL("add lane calibrator '") + id + "'");768myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(calibrator, true), true);769myNet->getViewNet()->getUndoList()->end();770// check if center after creation771if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&772sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {773myNet->getViewNet()->centerTo(calibrator->getPositionInView(), false);774}775} else {776myNet->getAttributeCarriers()->insertAdditional(calibrator);777lane->addChildElement(calibrator);778if (routeProbe) {779routeProbe->addChildElement(calibrator);780}781calibrator->incRef("buildCalibrator");782}783return true;784}785}786}787788789bool790GNEAdditionalHandler::buildEdgeCalibrator(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& edgeID, const double pos,791const std::string& name, const std::string& outfile, const SUMOTime period, const std::string& routeprobeID, const double jamThreshold, const std::vector<std::string>& vTypes,792const Parameterised::Map& parameters) {793// get edge794GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);795// get routeProbe796GNEAdditional* routeProbe = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_ROUTEPROBE, routeprobeID, false);797// check conditions798const auto element = retrieveAdditionalElement(NamespaceIDs::calibrators, id);799if (!checkElement(SUMO_TAG_CALIBRATOR, element)) {800return false;801} else if (!checkValidAdditionalID(SUMO_TAG_CALIBRATOR, id)) {802return false;803} else if ((routeprobeID.size() > 0) && (routeProbe == nullptr)) {804return writeErrorInvalidParent(SUMO_TAG_CALIBRATOR, id, SUMO_TAG_ROUTEPROBE, routeprobeID);805} else if (edge == nullptr) {806return writeErrorInvalidParent(SUMO_TAG_CALIBRATOR, id, SUMO_TAG_EDGE, edgeID);807} else {808if (!checkLanePosition(pos, 0, edge->getChildLanes().front()->getParentEdge()->getNBEdge()->getFinalLength(), false)) {809return writeErrorInvalidPosition(SUMO_TAG_CALIBRATOR, id);810} else if (!checkNegative(SUMO_TAG_CALIBRATOR, id, SUMO_ATTR_PERIOD, period, true)) {811return false;812} else if (!checkNegative(SUMO_TAG_CALIBRATOR, id, SUMO_ATTR_JAM_DIST_THRESHOLD, jamThreshold, true)) {813return false;814} else {815// build Calibrator816GNEAdditional* calibrator = (routeProbe == nullptr) ?817new GNECalibrator(id, myNet, myFilename, edge, pos, period, name, outfile, jamThreshold, vTypes, parameters) :818new GNECalibrator(id, myNet, myFilename, edge, pos, period, name, outfile, routeProbe, jamThreshold, vTypes, parameters);819// insert depending of allowUndoRedo820if (myAllowUndoRedo) {821myNet->getViewNet()->getUndoList()->begin(calibrator, TL("add calibrator '") + id + "'");822myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(calibrator, true), true);823myNet->getViewNet()->getUndoList()->end();824// check if center after creation825if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&826sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {827myNet->getViewNet()->centerTo(calibrator->getPositionInView(), false);828}829} else {830myNet->getAttributeCarriers()->insertAdditional(calibrator);831edge->addChildElement(calibrator);832if (routeProbe) {833routeProbe->addChildElement(calibrator);834}835calibrator->incRef("buildCalibrator");836}837return true;838}839}840}841842843bool844GNEAdditionalHandler::buildCalibratorFlow(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const SUMOVehicleParameter& vehicleParameter) {845// get vType846GNEDemandElement* vType = myNet->getAttributeCarriers()->retrieveDemandElement(SUMO_TAG_VTYPE, vehicleParameter.vtypeid.empty() ? DEFAULT_VTYPE_ID : vehicleParameter.vtypeid, false);847// get route848GNEDemandElement* route = myNet->getAttributeCarriers()->retrieveDemandElement(SUMO_TAG_ROUTE, vehicleParameter.routeid, false);849// get calibrator parent850GNEAdditional* calibrator = myNet->getAttributeCarriers()->retrieveAdditional(sumoBaseObject->getParentSumoBaseObject()->getTag(), sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID), false);851// check parents852if (vType == nullptr) {853return writeErrorInvalidParent(SUMO_TAG_FLOW, "", SUMO_TAG_VTYPE, vehicleParameter.vtypeid);854} else if (route == nullptr) {855return writeErrorInvalidParent(SUMO_TAG_FLOW, "", SUMO_TAG_ROUTE, vehicleParameter.routeid);856} else if (calibrator == nullptr) {857return writeErrorInvalidParent(SUMO_TAG_FLOW, "", SUMO_TAG_CALIBRATOR, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));858} else {859// create calibrator flow860GNEAdditional* flow = new GNECalibratorFlow(calibrator, vType, route, vehicleParameter);861// insert depending of allowUndoRedo862if (myAllowUndoRedo) {863myNet->getViewNet()->getUndoList()->begin(flow, TL("add calibrator flow in '") + calibrator->getID() + "'");864myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(flow, true), true);865myNet->getViewNet()->getUndoList()->end();866} else {867myNet->getAttributeCarriers()->insertAdditional(flow);868calibrator->addChildElement(flow);869route->addChildElement(flow);870vType->addChildElement(flow);871flow->incRef("buildCalibratorFlow");872}873return true;874}875}876877878bool879GNEAdditionalHandler::buildRerouter(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos,880const std::vector<std::string>& edgeIDs, const double prob, const std::string& name,881const bool off, const bool optional, const SUMOTime timeThreshold,882const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) {883// check conditions884const auto element = retrieveAdditionalElement({SUMO_TAG_REROUTER}, id);885if (!checkElement(SUMO_TAG_REROUTER, element)) {886return false;887} else if (!checkValidAdditionalID(SUMO_TAG_REROUTER, id)) {888return false;889} else if (!checkNegative(SUMO_TAG_REROUTER, id, SUMO_ATTR_PROB, prob, true)) {890return false;891} else if (!checkNegative(SUMO_TAG_REROUTER, id, SUMO_ATTR_HALTING_TIME_THRESHOLD, timeThreshold, true)) {892return false;893} else if (!checkListOfVehicleTypes(SUMO_TAG_REROUTER, id, vTypes)) {894return false;895} else {896// parse edges897std::vector<GNEEdge*> edges = parseEdges(SUMO_TAG_REROUTER, id, edgeIDs);898// check edges899if (edges.empty()) {900return false;901} else {902GNEAdditional* rerouter = nullptr;903// continue depending of position904if (pos == Position::INVALID) {905if (edges.size() > 0) {906PositionVector laneShape = edges.front()->getChildLanes().front()->getLaneShape();907// move to side908laneShape.move2side(3);909// create rerouter910rerouter = new GNERerouter(id, myNet, myFilename, laneShape.positionAtOffset2D(laneShape.length2D() - 6), name, prob, off, optional, timeThreshold, vTypes, parameters);911} else {912rerouter = new GNERerouter(id, myNet, myFilename, Position(0, 0), name, prob, off, optional, timeThreshold, vTypes, parameters);913}914} else {915rerouter = new GNERerouter(id, myNet, myFilename, pos, name, prob, off, optional, timeThreshold, vTypes, parameters);916}917// create rerouter Symbols918std::vector<GNEAdditional*> rerouterSymbols;919for (const auto& edge : edges) {920rerouterSymbols.push_back(new GNERerouterSymbol(rerouter, edge));921}922// insert depending of allowUndoRedo923if (myAllowUndoRedo) {924myNet->getViewNet()->getUndoList()->begin(rerouter, TL("add rerouter '") + id + "'");925myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(rerouter, true), true);926// add symbols927for (const auto& rerouterSymbol : rerouterSymbols) {928myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(rerouterSymbol, true), true);929}930myNet->getViewNet()->getUndoList()->end();931} else {932myNet->getAttributeCarriers()->insertAdditional(rerouter);933rerouter->incRef("buildRerouter");934// add symbols into rerouter935for (const auto& rerouterSymbol : rerouterSymbols) {936rerouter->addChildElement(rerouterSymbol);937}938// add symbols into edges939for (int i = 0; i < (int)edges.size(); i++) {940edges.at(i)->addChildElement(rerouterSymbols.at(i));941}942}943return true;944}945}946}947948949bool950GNEAdditionalHandler::buildRerouterInterval(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const SUMOTime begin, const SUMOTime end) {951// get rerouter parent952GNEAdditional* rerouter = getAdditionalParent(sumoBaseObject, SUMO_TAG_REROUTER);953// check if rerouter exist954if (rerouter == nullptr) {955return writeErrorInvalidParent(SUMO_TAG_INTERVAL, "", SUMO_TAG_REROUTER, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));956} else if (!checkNegative(SUMO_TAG_INTERVAL, rerouter->getID(), SUMO_ATTR_BEGIN, begin, true)) {957return false;958} else if (!checkNegative(SUMO_TAG_INTERVAL, rerouter->getID(), SUMO_ATTR_END, end, true)) {959return false;960} else if (end < begin) {961return writeError(TLF("Could not build interval with ID '%' in netedit; begin is greater than end.", rerouter->getID()));962} else {963// check if new interval will produce a overlapping964if (checkOverlappingRerouterIntervals(rerouter, begin, end)) {965// create rerouter interval and add it into rerouter parent966GNEAdditional* rerouterInterval = new GNERerouterInterval(rerouter, begin, end);967// insert depending of allowUndoRedo968if (myAllowUndoRedo) {969myNet->getViewNet()->getUndoList()->begin(rerouterInterval, TL("add rerouter interval in '") + rerouter->getID() + "'");970myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(rerouterInterval, true), true);971myNet->getViewNet()->getUndoList()->end();972} else {973rerouter->addChildElement(rerouterInterval);974rerouterInterval->incRef("buildRerouterInterval");975}976} else {977return writeError(TLF("Could not build interval with begin '%' and end '%' in '%' due overlapping.", toString(begin), toString(end), rerouter->getID()));978}979return true;980}981}982983984bool985GNEAdditionalHandler::buildClosingLaneReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& closedLaneID, SVCPermissions permissions) {986// get rerouter interval parent987GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);988// get closed lane989GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(closedLaneID, false);990// check parents991if (lane == nullptr) {992return writeErrorInvalidParent(SUMO_TAG_CLOSING_LANE_REROUTE, "", SUMO_TAG_LANE, closedLaneID);993} else if (rerouterInterval == nullptr) {994return writeErrorInvalidParent(SUMO_TAG_CLOSING_LANE_REROUTE, "", SUMO_TAG_INTERVAL, "");995} else {996// create closing lane reroute997GNEAdditional* closingLaneReroute = new GNEClosingLaneReroute(rerouterInterval, lane, permissions);998// add it to interval parent depending of allowUndoRedo999if (myAllowUndoRedo) {1000myNet->getViewNet()->getUndoList()->begin(closingLaneReroute, TL("add closing lane reroute in '") + lane->getID() + "'");1001myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(closingLaneReroute, true), true);1002myNet->getViewNet()->getUndoList()->end();1003} else {1004rerouterInterval->addChildElement(closingLaneReroute);1005closingLaneReroute->incRef("buildClosingLaneReroute");1006}1007return true;1008}1009}101010111012bool1013GNEAdditionalHandler::buildClosingReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& closedEdgeID, SVCPermissions permissions) {1014// get rerouter interval parent1015GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1016// get closed edge1017GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(closedEdgeID, false);1018// check parents1019if (edge == nullptr) {1020return writeErrorInvalidParent(SUMO_TAG_CLOSING_REROUTE, "", SUMO_TAG_EDGE, closedEdgeID);1021} else if (rerouterInterval == nullptr) {1022return writeErrorInvalidParent(SUMO_TAG_CLOSING_REROUTE, "", SUMO_TAG_INTERVAL, "");1023} else {1024// create closing reroute1025GNEAdditional* closingLaneReroute = new GNEClosingReroute(rerouterInterval, edge, permissions);1026// add it to interval parent depending of allowUndoRedo1027if (myAllowUndoRedo) {1028myNet->getViewNet()->getUndoList()->begin(closingLaneReroute, TL("add closing reroute in '") + edge->getID() + "'");1029myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(closingLaneReroute, true), true);1030myNet->getViewNet()->getUndoList()->end();1031} else {1032rerouterInterval->addChildElement(closingLaneReroute);1033closingLaneReroute->incRef("buildClosingLaneReroute");1034}1035return true;1036}1037}10381039bool1040GNEAdditionalHandler::buildDestProbReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& newEdgeDestinationID, const double probability) {1041// get rerouter interval parent1042GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1043// get edge1044GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(newEdgeDestinationID, false);1045// check parents1046if (edge == nullptr) {1047return writeErrorInvalidParent(SUMO_TAG_DEST_PROB_REROUTE, "", SUMO_TAG_EDGE, newEdgeDestinationID);1048} else if (rerouterInterval == nullptr) {1049return writeErrorInvalidParent(SUMO_TAG_DEST_PROB_REROUTE, "", SUMO_TAG_INTERVAL, "");1050} else {1051// create dest probability reroute1052GNEAdditional* destProbReroute = new GNEDestProbReroute(rerouterInterval, edge, probability);1053// add it to interval parent depending of allowUndoRedo1054if (myAllowUndoRedo) {1055myNet->getViewNet()->getUndoList()->begin(destProbReroute, TL("add dest prob reroute in '") + edge->getID() + "'");1056myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(destProbReroute, true), true);1057myNet->getViewNet()->getUndoList()->end();1058} else {1059rerouterInterval->addChildElement(destProbReroute);1060destProbReroute->incRef("builDestProbReroute");1061}1062return true;1063}1064}106510661067bool1068GNEAdditionalHandler::buildParkingAreaReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& newParkignAreaID, const double probability, const bool visible) {1069// get rerouter interval parent1070GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1071// get parking area1072GNEAdditional* parkingArea = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_PARKING_AREA, newParkignAreaID, false);1073// check parents1074if (parkingArea == nullptr) {1075return writeErrorInvalidParent(SUMO_TAG_PARKING_AREA_REROUTE, "", SUMO_TAG_PARKING_AREA, newParkignAreaID);1076} else if (rerouterInterval == nullptr) {1077return writeErrorInvalidParent(SUMO_TAG_PARKING_AREA_REROUTE, "", SUMO_TAG_INTERVAL, "");1078} else {1079// create parking area reroute1080GNEAdditional* parkingAreaReroute = new GNEParkingAreaReroute(rerouterInterval, parkingArea, probability, visible);1081// add it to interval parent depending of allowUndoRedo1082if (myAllowUndoRedo) {1083myNet->getViewNet()->getUndoList()->begin(parkingAreaReroute, TL("add parking area reroute in '") + parkingArea->getID() + "'");1084myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(parkingAreaReroute, true), true);1085myNet->getViewNet()->getUndoList()->end();1086} else {1087rerouterInterval->addChildElement(parkingAreaReroute);1088parkingAreaReroute->incRef("builParkingAreaReroute");1089}1090return true;1091}1092}109310941095bool1096GNEAdditionalHandler::buildRouteProbReroute(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& newRouteID, const double probability) {1097// get rerouter interval parent1098GNEAdditional* rerouterInterval = getRerouterIntervalParent(sumoBaseObject);1099// get route parent1100GNEDemandElement* route = myNet->getAttributeCarriers()->retrieveDemandElement(SUMO_TAG_ROUTE, newRouteID, false);1101// check parents1102if (route == nullptr) {1103return writeErrorInvalidParent(SUMO_TAG_ROUTE_PROB_REROUTE, "", SUMO_TAG_ROUTE, newRouteID);1104} else if (rerouterInterval == nullptr) {1105return writeErrorInvalidParent(SUMO_TAG_ROUTE_PROB_REROUTE, "", SUMO_TAG_INTERVAL, "");1106} else {1107// create rout prob reroute1108GNEAdditional* routeProbReroute = new GNERouteProbReroute(rerouterInterval, route, probability);1109// add it to interval parent depending of allowUndoRedo1110if (myAllowUndoRedo) {1111myNet->getViewNet()->getUndoList()->begin(routeProbReroute, TL("add route prob reroute in '") + route->getID() + "'");1112myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(routeProbReroute, true), true);1113myNet->getViewNet()->getUndoList()->end();1114} else {1115rerouterInterval->addChildElement(routeProbReroute);1116routeProbReroute->incRef("buildRouteProbReroute");1117}1118return true;1119}1120}112111221123bool1124GNEAdditionalHandler::buildRouteProbe(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& edgeID, const SUMOTime period,1125const std::string& name, const std::string& file, const SUMOTime begin, const std::vector<std::string>& vTypes,1126const Parameterised::Map& parameters) {1127// check conditions1128const auto element = retrieveAdditionalElement({SUMO_TAG_ROUTEPROBE}, id);1129if (!checkElement(SUMO_TAG_ROUTEPROBE, element)) {1130return false;1131} else if (!checkValidAdditionalID(SUMO_TAG_ROUTEPROBE, id)) {1132return false;1133} else {1134// get edge1135GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1136// check lane1137if (edge == nullptr) {1138return writeErrorInvalidParent(SUMO_TAG_ROUTEPROBE, id, SUMO_TAG_EDGE, edgeID);1139} else if (!checkNegative(SUMO_TAG_ROUTEPROBE, id, SUMO_ATTR_PERIOD, period, true)) {1140return false;1141} else if (!checkNegative(SUMO_TAG_ROUTEPROBE, id, SUMO_ATTR_BEGIN, begin, true)) {1142return false;1143} else if (!checkFileName(SUMO_TAG_ROUTEPROBE, id, SUMO_ATTR_FILE, file)) {1144return false;1145} else {1146// build route probe1147GNEAdditional* routeProbe = new GNERouteProbe(id, myNet, myFilename, edge, period, name, file, begin, vTypes, parameters);1148// insert depending of allowUndoRedo1149if (myAllowUndoRedo) {1150myNet->getViewNet()->getUndoList()->begin(routeProbe, TL("add route probe '") + id + "'");1151myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(routeProbe, true), true);1152myNet->getViewNet()->getUndoList()->end();1153// check if center after creation1154if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&1155sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {1156myNet->getViewNet()->centerTo(routeProbe->getPositionInView(), false);1157}1158} else {1159myNet->getAttributeCarriers()->insertAdditional(routeProbe);1160edge->addChildElement(routeProbe);1161routeProbe->incRef("buildRouteProbe");1162}1163return true;1164}1165}1166}116711681169bool1170GNEAdditionalHandler::buildVariableSpeedSign(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos,1171const std::vector<std::string>& laneIDs, const std::string& name, const std::vector<std::string>& vTypes, const Parameterised::Map& parameters) {1172// check conditions1173const auto element = retrieveAdditionalElement({SUMO_TAG_VSS}, id);1174if (!checkElement(SUMO_TAG_VSS, element)) {1175return false;1176} else if (!checkValidAdditionalID(SUMO_TAG_VSS, id)) {1177return false;1178} else {1179// parse lanes1180std::vector<GNELane*> lanes = parseLanes(SUMO_TAG_VSS, id, laneIDs);1181// check lane1182if (lanes.empty()) {1183return false;1184} else {1185// check vTypes1186if (!checkListOfVehicleTypes(SUMO_TAG_VSS, id, vTypes)) {1187return false;1188} else {1189// create VSS1190GNEAdditional* variableSpeedSign = new GNEVariableSpeedSign(id, myNet, myFilename, pos, name, vTypes, parameters);1191// create VSS Symbols1192std::vector<GNEAdditional*> VSSSymbols;1193for (const auto& lane : lanes) {1194VSSSymbols.push_back(new GNEVariableSpeedSignSymbol(variableSpeedSign, lane));1195}1196// insert depending of allowUndoRedo1197if (myAllowUndoRedo) {1198myNet->getViewNet()->getUndoList()->begin(variableSpeedSign, TL("add Variable Speed Sign '") + id + "'");1199myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(variableSpeedSign, true), true);1200for (const auto& VSSSymbol : VSSSymbols) {1201myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(VSSSymbol, true), true);1202}1203myNet->getViewNet()->getUndoList()->end();1204} else {1205myNet->getAttributeCarriers()->insertAdditional(variableSpeedSign);1206variableSpeedSign->incRef("buildVariableSpeedSign");1207// add symbols into VSS1208for (const auto& VSSSymbol : VSSSymbols) {1209variableSpeedSign->addChildElement(VSSSymbol);1210}1211// add symbols into lanes1212for (int i = 0; i < (int)lanes.size(); i++) {1213lanes.at(i)->addChildElement(VSSSymbols.at(i));1214}1215}1216}1217return true;1218}1219}1220}122112221223bool1224GNEAdditionalHandler::buildVariableSpeedSignStep(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const SUMOTime time, const double speed) {1225// get VSS parent1226GNEAdditional* VSS = getAdditionalParent(sumoBaseObject, SUMO_TAG_VSS);1227// check lane1228if (VSS == nullptr) {1229return writeErrorInvalidParent(SUMO_TAG_STEP, "", SUMO_TAG_VSS, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));1230} else if (!checkNegative(SUMO_TAG_STEP, VSS->getID(), SUMO_ATTR_TIME, time, true)) {1231return false;1232} else {1233// create Variable Speed Sign1234GNEAdditional* variableSpeedSignStep = new GNEVariableSpeedSignStep(VSS, time, speed);1235// add it depending of allow undoRedo1236if (myAllowUndoRedo) {1237myNet->getViewNet()->getUndoList()->begin(variableSpeedSignStep, TL("add VSS Step in '") + VSS->getID() + "'");1238myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(variableSpeedSignStep, true), true);1239myNet->getViewNet()->getUndoList()->end();1240} else {1241VSS->addChildElement(variableSpeedSignStep);1242variableSpeedSignStep->incRef("buildVariableSpeedSignStep");1243}1244return true;1245}1246}124712481249bool1250GNEAdditionalHandler::buildVaporizer(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& edgeID, const SUMOTime beginTime,1251const SUMOTime endTime, const std::string& name, const Parameterised::Map& parameters) {1252// check conditions1253const auto element = retrieveAdditionalElement({SUMO_TAG_VAPORIZER}, edgeID);1254if (!checkElement(SUMO_TAG_VAPORIZER, element)) {1255return false;1256} else if (!checkValidAdditionalID(SUMO_TAG_VAPORIZER, edgeID)) {1257return false;1258} else {1259// get edge1260GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1261// check lane1262if (edge == nullptr) {1263return writeErrorInvalidParent(SUMO_TAG_VAPORIZER, "", SUMO_TAG_EDGE, edgeID);1264} else if (!checkNegative(SUMO_TAG_VAPORIZER, edge->getID(), SUMO_ATTR_BEGIN, beginTime, true)) {1265return false;1266} else if (!checkNegative(SUMO_TAG_VAPORIZER, edge->getID(), SUMO_ATTR_END, endTime, true)) {1267return false;1268} else if (endTime < beginTime) {1269return writeError(TLF("Could not build Vaporizer with ID '%' in netedit; begin is greater than end.", edge->getID()));1270} else {1271// build vaporizer1272GNEAdditional* vaporizer = new GNEVaporizer(myNet, myFilename, edge, beginTime, endTime, name, parameters);1273// add it depending of allow undoRed1274if (myAllowUndoRedo) {1275myNet->getViewNet()->getUndoList()->begin(vaporizer, TL("add vaporizer in '") + edge->getID() + "'");1276myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(vaporizer, true), true);1277myNet->getViewNet()->getUndoList()->end();1278// check if center after creation1279if (sumoBaseObject->hasBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION) &&1280sumoBaseObject->getBoolAttribute(GNE_ATTR_CENTER_AFTER_CREATION)) {1281myNet->getViewNet()->centerTo(vaporizer->getPositionInView(), false);1282}1283} else {1284myNet->getAttributeCarriers()->insertAdditional(vaporizer);1285edge->addChildElement(vaporizer);1286vaporizer->incRef("buildVaporizer");1287}1288return true;1289}1290}1291}129212931294bool1295GNEAdditionalHandler::buildTAZ(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const PositionVector& shape,1296const Position& center, const bool fill, const RGBColor& color, const std::vector<std::string>& edgeIDs,1297const std::string& name, const Parameterised::Map& parameters) {1298// parse edges1299const std::vector<GNEEdge*> edges = parseEdges(SUMO_TAG_TAZ, id, edgeIDs);1300if (edges.size() != edgeIDs.size()) {1301return false;1302} else {1303// check TAZShape1304PositionVector TAZShape = shape;1305if (TAZShape.size() == 0) {1306// declare boundary1307Boundary TAZBoundary;1308for (const auto& edge : edges) {1309TAZBoundary.add(edge->getCenteringBoundary());1310}1311// iterate over children and add sourceSinkEdge boundaries to make a taz shape1312for (const auto& sourceSink : sumoBaseObject->getSumoBaseObjectChildren()) {1313// check that child is a source or sink elements (to avoid other elements)1314if ((sourceSink->getTag() == SUMO_TAG_TAZSOURCE) || (sourceSink->getTag() == SUMO_TAG_TAZSINK)) {1315const GNEEdge* sourceSinkEdge = myNet->getAttributeCarriers()->retrieveEdge(sourceSink->getStringAttribute(SUMO_ATTR_ID), false);1316if (sourceSinkEdge) {1317TAZBoundary.add(sourceSinkEdge->getCenteringBoundary());1318}1319}1320}1321// update TAZShape1322TAZShape = TAZBoundary.getShape(true);1323}1324// check TAZ1325const auto element = retrieveAdditionalElement({SUMO_TAG_TAZ}, id);1326if (!checkElement(SUMO_TAG_TAZ, element)) {1327return false;1328} else if (!checkValidAdditionalID(SUMO_TAG_TAZ, id)) {1329return false;1330} else if (TAZShape.size() == 0) {1331return writeError(TLF("Could not build TAZ with ID '%' in netedit; Invalid Shape.", id));1332} else {1333// build TAZ with the given shape1334const Position center2 = center == Position::INVALID ? TAZShape.getCentroid() : center;1335GNEAdditional* TAZ = new GNETAZ(id, myNet, myFilename, TAZShape, center2, fill, color, name, parameters);1336// disable updating geometry of TAZ children during insertion (because in large nets provokes slowdowns)1337myNet->disableUpdateGeometry();1338// add it depending of allow undoRed1339if (myAllowUndoRedo) {1340myNet->getViewNet()->getUndoList()->begin(TAZ, TL("add TAZ '") + id + "'");1341myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(TAZ, true), true);1342// create TAZEdges1343for (const auto& edge : edges) {1344// create TAZ Source using GNEChange_Additional1345GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, 1);1346myNet->getViewNet()->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSource, true), true);1347// create TAZ Sink using GNEChange_Additional1348GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, 1);1349myNet->getViewNet()->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSink, true), true);1350}1351myNet->getViewNet()->getUndoList()->end();1352} else {1353myNet->getAttributeCarriers()->insertAdditional(TAZ);1354TAZ->incRef("buildTAZ");1355for (const auto& edge : edges) {1356// create TAZ Source1357GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, 1);1358myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSource);1359TAZSource->incRef("buildTAZ");1360TAZ->addChildElement(TAZSource);1361edge->addChildElement(TAZSource);1362// create TAZ Sink1363GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, 1);1364myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSink);1365TAZSink->incRef("buildTAZ");1366TAZ->addChildElement(TAZSink);1367edge->addChildElement(TAZSink);1368}1369}1370// enable updating geometry again and update geometry of TAZ1371myNet->enableUpdateGeometry();1372// update TAZ parent1373TAZ->updateGeometry();1374return true;1375}1376}1377}137813791380bool1381GNEAdditionalHandler::buildTAZSource(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& edgeID, const double departWeight) {1382// get TAZ parent1383GNEAdditional* TAZ = getAdditionalParent(sumoBaseObject, SUMO_TAG_TAZ);1384// get edge1385GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1386// check parents1387if (TAZ == nullptr) {1388return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, SUMO_TAG_TAZ, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));1389} else if (edge == nullptr) {1390return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, SUMO_TAG_EDGE, TAZ->getID());1391} else {1392// declare TAZ Source1393GNETAZSourceSink* existentTAZSource = nullptr;1394// first check if already exist a TAZ Source for the given edge and TAZ1395for (auto it = edge->getChildTAZSourceSinks().begin(); (it != edge->getChildTAZSourceSinks().end()) && !existentTAZSource; it++) {1396if (((*it)->getTagProperty()->getTag() == SUMO_TAG_TAZSOURCE) && ((*it)->getParentAdditionals().front() == TAZ)) {1397existentTAZSource = (*it);1398}1399}1400// check if TAZSource has to be created1401if (existentTAZSource == nullptr) {1402// Create TAZ only with departWeight1403GNETAZSourceSink* TAZSource = new GNETAZSourceSink(SUMO_TAG_TAZSOURCE, TAZ, edge, departWeight);1404// add it depending of allow undoRed1405if (myAllowUndoRedo) {1406myNet->getViewNet()->getUndoList()->begin(TAZ, TL("add TAZ Source in '") + TAZ->getID() + "'");1407myNet->getViewNet()->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSource, true), true);1408myNet->getViewNet()->getUndoList()->end();1409} else {1410myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSource);1411TAZ->addChildElement(TAZSource);1412edge->addChildElement(TAZSource);1413TAZSource->incRef("buildTAZSource");1414}1415} else {1416// update TAZ Attribute depending of allow undoRed1417if (myAllowUndoRedo) {1418myNet->getViewNet()->getUndoList()->begin(TAZ, TL("update TAZ Source in '") + TAZ->getID() + "'");1419existentTAZSource->setAttribute(SUMO_ATTR_WEIGHT, toString(departWeight), myNet->getViewNet()->getUndoList());1420myNet->getViewNet()->getUndoList()->end();1421} else {1422existentTAZSource->setAttribute(SUMO_ATTR_WEIGHT, toString(departWeight), nullptr);1423}1424}1425return true;1426}1427}142814291430bool1431GNEAdditionalHandler::buildTAZSink(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& edgeID, const double arrivalWeight) {1432// get TAZ parent1433GNEAdditional* TAZ = getAdditionalParent(sumoBaseObject, SUMO_TAG_TAZ);1434// get edge1435GNEEdge* edge = myNet->getAttributeCarriers()->retrieveEdge(edgeID, false);1436// check parents1437if (TAZ == nullptr) {1438return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, SUMO_TAG_TAZ, sumoBaseObject->getParentSumoBaseObject()->getStringAttribute(SUMO_ATTR_ID));1439} else if (edge == nullptr) {1440return writeErrorInvalidParent(SUMO_TAG_SOURCE, edgeID, SUMO_TAG_EDGE, TAZ->getID());1441} else {1442// declare TAZ Sink1443GNETAZSourceSink* existentTAZSink = nullptr;1444// first check if already exist a TAZ Sink for the given edge and TAZ1445for (auto it = edge->getChildTAZSourceSinks().begin(); (it != edge->getChildTAZSourceSinks().end()) && !existentTAZSink; it++) {1446if (((*it)->getTagProperty()->getTag() == SUMO_TAG_TAZSINK) && ((*it)->getParentAdditionals().front() == TAZ)) {1447existentTAZSink = (*it);1448}1449}1450// check if TAZSink has to be created1451if (existentTAZSink == nullptr) {1452// Create TAZ only with departWeight1453GNETAZSourceSink* TAZSink = new GNETAZSourceSink(SUMO_TAG_TAZSINK, TAZ, edge, arrivalWeight);1454// add it depending of allow undoRed1455if (myAllowUndoRedo) {1456myNet->getViewNet()->getUndoList()->begin(TAZ, TL("add TAZ Sink in '") + TAZ->getID() + "'");1457myNet->getViewNet()->getUndoList()->add(new GNEChange_TAZSourceSink(TAZSink, true), true);1458myNet->getViewNet()->getUndoList()->end();1459} else {1460myNet->getAttributeCarriers()->insertTAZSourceSink(TAZSink);1461TAZ->addChildElement(TAZSink);1462edge->addChildElement(TAZSink);1463TAZSink->incRef("buildTAZSink");1464}1465} else {1466// update TAZ Attribute depending of allow undoRed1467if (myAllowUndoRedo) {1468myNet->getViewNet()->getUndoList()->begin(TAZ, TL("update TAZ Sink in '") + TAZ->getID() + "'");1469existentTAZSink->setAttribute(SUMO_ATTR_WEIGHT, toString(arrivalWeight), myNet->getViewNet()->getUndoList());1470myNet->getViewNet()->getUndoList()->end();1471} else {1472existentTAZSink->setAttribute(SUMO_ATTR_WEIGHT, toString(arrivalWeight), nullptr);1473}1474}1475return true;1476}1477}147814791480bool1481GNEAdditionalHandler::buildTractionSubstation(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const Position& pos,1482const double voltage, const double currentLimit, const Parameterised::Map& parameters) {1483// check conditions1484const auto element = retrieveAdditionalElement({SUMO_TAG_TRACTION_SUBSTATION}, id);1485if (!checkElement(SUMO_TAG_TRACTION_SUBSTATION, element)) {1486return false;1487} else if (!checkValidAdditionalID(SUMO_TAG_TRACTION_SUBSTATION, id)) {1488return false;1489} else if (!checkNegative(SUMO_TAG_TRACTION_SUBSTATION, id, SUMO_ATTR_VOLTAGE, voltage, true)) {1490return false;1491} else if (!checkNegative(SUMO_TAG_TRACTION_SUBSTATION, id, SUMO_ATTR_CURRENTLIMIT, currentLimit, true)) {1492return false;1493} else {1494// build traction substation1495GNEAdditional* tractionSubstation = new GNETractionSubstation(id, myNet, myFilename, pos, voltage, currentLimit, parameters);1496// insert depending of allowUndoRedo1497if (myAllowUndoRedo) {1498myNet->getViewNet()->getUndoList()->begin(tractionSubstation, TL("add traction substation '") + id + "'");1499myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(tractionSubstation, true), true);1500myNet->getViewNet()->getUndoList()->end();1501} else {1502myNet->getAttributeCarriers()->insertAdditional(tractionSubstation);1503tractionSubstation->incRef("buildTractionSubstation");1504}1505return true;1506}1507}150815091510bool1511GNEAdditionalHandler::buildOverheadWire(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& substationId,1512const std::vector<std::string>& laneIDs, const double startPos, const double endPos, const bool friendlyPos,1513const std::vector<std::string>& forbiddenInnerLanes, const Parameterised::Map& parameters) {1514// check conditions1515const auto element = retrieveAdditionalElement({SUMO_TAG_OVERHEAD_WIRE_SECTION}, id);1516if (!checkElement(SUMO_TAG_OVERHEAD_WIRE_SECTION, element)) {1517return false;1518} else if (!checkValidAdditionalID(SUMO_TAG_OVERHEAD_WIRE_SECTION, id)) {1519return false;1520} else {1521// get lanes1522const auto lanes = parseLanes(SUMO_TAG_OVERHEAD_WIRE_SECTION, id, laneIDs);1523// get traction substation1524const auto tractionSubstation = myNet->getAttributeCarriers()->retrieveAdditional(SUMO_TAG_TRACTION_SUBSTATION, substationId, false);1525// check lanes1526if (lanes.empty()) {1527return false;1528} else {1529// calculate path1530if (!GNEAdditional::areLaneConsecutives(lanes)) {1531return writeError(TLF("Could not build overhead wire with ID '%' in netedit; Lanes aren't consecutives.", id));1532} else if (!checkMultiLanePosition(1533startPos, lanes.front()->getParentEdge()->getNBEdge()->getFinalLength(),1534endPos, lanes.back()->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {1535return writeErrorInvalidPosition(SUMO_TAG_OVERHEAD_WIRE_SECTION, id);1536} else if (tractionSubstation == nullptr) {1537return writeErrorInvalidParent(SUMO_TAG_OVERHEAD_WIRE_SECTION, "", SUMO_TAG_TRACTION_SUBSTATION, substationId);1538} else {1539// build Overhead Wire1540GNEAdditional* overheadWire = new GNEOverheadWire(id, myNet, myFilename, lanes, tractionSubstation, startPos, endPos, friendlyPos, forbiddenInnerLanes, parameters);1541// insert depending of allowUndoRedo1542if (myAllowUndoRedo) {1543myNet->getViewNet()->getUndoList()->begin(overheadWire, TL("add overhead wire '") + id + "'");1544myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(overheadWire, true), true);1545myNet->getViewNet()->getUndoList()->end();1546} else {1547myNet->getAttributeCarriers()->insertAdditional(overheadWire);1548for (const auto& lane : lanes) {1549lane->addChildElement(overheadWire);1550}1551overheadWire->incRef("buildOverheadWire");1552}1553}1554return true;1555}1556}1557}155815591560bool1561GNEAdditionalHandler::buildOverheadWireClamp(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& /* id */, const std::string& /* overheadWireIDStartClamp */,1562const std::string& /* laneIDStartClamp */, const std::string& /* overheadWireIDEndClamp */, const std::string& /* laneIDEndClamp */,1563const Parameterised::Map& /* parameters */) {1564//1565return false;1566}156715681569bool1570GNEAdditionalHandler::buildPolygon(const CommonXMLStructure::SumoBaseObject* sumoBaseObject, const std::string& id, const std::string& type,1571const RGBColor& color, double layer, double angle, const std::string& imgFile, const PositionVector& shape,1572bool geo, bool fill, double lineWidth, const std::string& name, const Parameterised::Map& parameters) {1573// check conditions1574if (type == "jupedsim.walkable_area") {1575return buildJpsWalkableArea(sumoBaseObject, id, shape, geo, name, parameters);1576} else if (type == "jupedsim.obstacle") {1577return buildJpsObstacle(sumoBaseObject, id, shape, geo, name, parameters);1578} else {1579// check conditions1580const auto element = retrieveAdditionalElement(NamespaceIDs::polygons, id);1581if (!checkElement(SUMO_TAG_POLY, element)) {1582return false;1583} else if (!checkValidAdditionalID(SUMO_TAG_POLY, id)) {1584return false;1585} else if (!checkNegative(SUMO_TAG_POLY, id, SUMO_ATTR_LINEWIDTH, lineWidth, true)) {1586return false;1587} else {1588// create poly1589GNEPoly* poly = new GNEPoly(id, myNet, myFilename, type, shape, geo, fill, lineWidth, color, layer, angle, imgFile, name, parameters);1590// add it depending of allow undoRed1591if (myAllowUndoRedo) {1592myNet->getViewNet()->getUndoList()->begin(poly, TL("add polygon '") + id + "'");1593myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(poly, true), true);1594myNet->getViewNet()->getUndoList()->end();1595} else {1596// insert shape without allowing undo/redo1597myNet->getAttributeCarriers()->insertAdditional(poly);1598poly->incRef("addPolygon");1599}1600return true;1601}1602}1603}160416051606bool1607GNEAdditionalHandler::buildPOI(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& type,1608const RGBColor& color, const double x, const double y, const std::string& icon, double layer, double angle,1609const std::string& imgFile, double width, double height, const std::string& name, const Parameterised::Map& parameters) {1610// check conditions1611const auto element = retrieveAdditionalElement(NamespaceIDs::POIs, id);1612if (!checkElement(SUMO_TAG_POI, element)) {1613return false;1614} else if (!checkValidAdditionalID(SUMO_TAG_POI, id)) {1615return false;1616} else if (!checkNegative(SUMO_TAG_POI, id, SUMO_ATTR_WIDTH, width, true)) {1617return false;1618} else if (!checkNegative(SUMO_TAG_POI, id, SUMO_ATTR_HEIGHT, height, true)) {1619return false;1620} else if (!checkFileName(SUMO_TAG_POI, id, SUMO_ATTR_IMGFILE, imgFile)) {1621return false;1622} else {1623// create POI1624GNEPOI* POI = new GNEPOI(id, myNet, myFilename, type, color, x, y, false, icon, layer, angle, imgFile, width, height, name, parameters);1625// add it depending of allow undoRed1626if (myAllowUndoRedo) {1627myNet->getViewNet()->getUndoList()->begin(POI, TL("add POI '") + id + "'");1628myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(POI, true), true);1629myNet->getViewNet()->getUndoList()->end();1630} else {1631// insert shape without allowing undo/redo1632myNet->getAttributeCarriers()->insertAdditional(POI);1633POI->incRef("addPOI");1634}1635return true;1636}1637}163816391640bool1641GNEAdditionalHandler::buildPOILane(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& type,1642const RGBColor& color, const std::string& laneID, double posOverLane, const bool friendlyPos, double posLat,1643const std::string& icon, double layer, double angle, const std::string& imgFile, double width, double height,1644const std::string& name, const Parameterised::Map& parameters) {1645// check conditions1646const auto element = retrieveAdditionalElement(NamespaceIDs::POIs, id);1647if (!checkElement(GNE_TAG_POILANE, element)) {1648return false;1649} else if (!checkValidAdditionalID(GNE_TAG_POILANE, id)) {1650return false;1651} else if (!checkNegative(GNE_TAG_POILANE, id, SUMO_ATTR_WIDTH, width, true)) {1652return false;1653} else if (!checkNegative(GNE_TAG_POILANE, id, SUMO_ATTR_HEIGHT, height, true)) {1654return false;1655} else if (!checkFileName(GNE_TAG_POILANE, id, SUMO_ATTR_IMGFILE, imgFile)) {1656return false;1657} else {1658// get lane1659GNELane* lane = myNet->getAttributeCarriers()->retrieveLane(laneID, false);1660// check lane1661if (lane == nullptr) {1662return writeErrorInvalidParent(GNE_TAG_POILANE, id, SUMO_TAG_LANE, laneID);1663} else if (!checkLanePosition(posOverLane, 0, lane->getParentEdge()->getNBEdge()->getFinalLength(), friendlyPos)) {1664return writeErrorInvalidPosition(GNE_TAG_POILANE, id);1665} else {1666// create POI (use GNEAdditional instead GNEPOI for add child references)1667GNEAdditional* POILane = new GNEPOI(id, myNet, myFilename, type, color, lane, posOverLane, friendlyPos, posLat, icon, layer,1668angle, imgFile, width, height, name, parameters);1669// add it depending of allow undoRed1670if (myAllowUndoRedo) {1671myNet->getViewNet()->getUndoList()->begin(POILane, TL("add POI '") + id + "'");1672myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(POILane, true), true);1673myNet->getViewNet()->getUndoList()->end();1674} else {1675// insert shape without allowing undo/redo1676myNet->getAttributeCarriers()->insertAdditional(POILane);1677lane->addChildElement(POILane);1678POILane->incRef("buildPOILane");1679}1680}1681return true;1682}1683}168416851686bool1687GNEAdditionalHandler::buildPOIGeo(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const std::string& type,1688const RGBColor& color, const double lon, const double lat, const std::string& icon, double layer,1689double angle, const std::string& imgFile, double width, double height, const std::string& name,1690const Parameterised::Map& parameters) {1691// check conditions1692const auto element = retrieveAdditionalElement(NamespaceIDs::POIs, id);1693if (!checkElement(GNE_TAG_POIGEO, element)) {1694return false;1695} else if (!checkValidAdditionalID(GNE_TAG_POIGEO, id)) {1696return false;1697} else if (!checkNegative(GNE_TAG_POIGEO, id, SUMO_ATTR_WIDTH, width, true)) {1698return false;1699} else if (!checkNegative(GNE_TAG_POIGEO, id, SUMO_ATTR_HEIGHT, height, true)) {1700return false;1701} else if (!checkFileName(GNE_TAG_POIGEO, id, SUMO_ATTR_IMGFILE, imgFile)) {1702return false;1703} else if (GeoConvHelper::getFinal().getProjString() == "!") {1704return writeError(TLF("Could not build POI with ID '%' in netedit", id) + std::string("; ") + TL("Network requires a geo projection."));1705} else {1706// create POIGEO1707GNEPOI* POIGEO = new GNEPOI(id, myNet, myFilename, type, color, lon, lat, true, icon, layer, angle, imgFile, width, height, name, parameters);1708// add it depending of allow undoRed1709if (myAllowUndoRedo) {1710myNet->getViewNet()->getUndoList()->begin(POIGEO, TL("add POI '") + id + "'");1711myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(POIGEO, true), true);1712myNet->getViewNet()->getUndoList()->end();1713} else {1714// insert shape without allowing undo/redo1715myNet->getAttributeCarriers()->insertAdditional(POIGEO);1716POIGEO->incRef("buildPOIGeo");1717}1718return true;1719}1720}172117221723bool1724GNEAdditionalHandler::buildJpsWalkableArea(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const PositionVector& shape,1725bool geo, const std::string& name, const Parameterised::Map& parameters) {1726// check conditions1727const auto element = retrieveAdditionalElement(NamespaceIDs::polygons, id);1728if (!checkElement(GNE_TAG_JPS_WALKABLEAREA, element)) {1729return false;1730} else if (!checkValidAdditionalID(GNE_TAG_JPS_WALKABLEAREA, id)) {1731return false;1732} else {1733// create walkable area1734GNEPoly* walkableArea = new GNEPoly(GNE_TAG_JPS_WALKABLEAREA, id, myNet, myFilename, shape, geo, name, parameters);1735// add it depending of allow undoRed1736if (myAllowUndoRedo) {1737myNet->getViewNet()->getUndoList()->begin(walkableArea, TL("add jps walkable area '") + id + "'");1738myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(walkableArea, true), true);1739myNet->getViewNet()->getUndoList()->end();1740} else {1741// insert shape without allowing undo/redo1742myNet->getAttributeCarriers()->insertAdditional(walkableArea);1743walkableArea->incRef("addWalkableArea");1744}1745return true;1746}1747}174817491750bool1751GNEAdditionalHandler::buildJpsObstacle(const CommonXMLStructure::SumoBaseObject* /*sumoBaseObject*/, const std::string& id, const PositionVector& shape,1752bool geo, const std::string& name, const Parameterised::Map& parameters) {1753// check conditions1754const auto element = retrieveAdditionalElement(NamespaceIDs::polygons, id);1755if (!checkElement(GNE_TAG_JPS_OBSTACLE, element)) {1756return false;1757} else if (!checkValidAdditionalID(GNE_TAG_JPS_OBSTACLE, id)) {1758return false;1759} else {1760// create walkable area1761GNEPoly* obstacle = new GNEPoly(GNE_TAG_JPS_OBSTACLE, id, myNet, myFilename, shape, geo, name, parameters);1762// add it depending of allow undoRed1763if (myAllowUndoRedo) {1764myNet->getViewNet()->getUndoList()->begin(obstacle, TL("add jps obstacle '") + id + "'");1765myNet->getViewNet()->getUndoList()->add(new GNEChange_Additional(obstacle, true), true);1766myNet->getViewNet()->getUndoList()->end();1767} else {1768// insert shape without allowing undo/redo1769myNet->getAttributeCarriers()->insertAdditional(obstacle);1770obstacle->incRef("addObstacle");1771}1772return true;1773}1774}177517761777bool1778GNEAdditionalHandler::accessCanBeCreated(GNEAdditional* busStopParent, GNEEdge* edge) {1779// check if exist another access for the same busStop in the given edge1780for (const auto& additional : busStopParent->getChildAdditionals()) {1781for (const auto& lane : edge->getChildLanes()) {1782if (additional->getAttribute(SUMO_ATTR_LANE) == lane->getID()) {1783return false;1784}1785}1786}1787return true;1788}178917901791bool1792GNEAdditionalHandler::checkOverlappingRerouterIntervals(GNEAdditional* rerouter, SUMOTime newBegin, SUMOTime newEnd) {1793// declare a vector to keep sorted rerouter children1794std::vector<std::pair<SUMOTime, SUMOTime>> sortedIntervals;1795// iterate over child additional1796for (const auto& rerouterChild : rerouter->getChildAdditionals()) {1797if (!rerouterChild->getTagProperty()->isSymbol()) {1798sortedIntervals.push_back(std::make_pair((SUMOTime)0., (SUMOTime)0.));1799// set begin and end1800sortedIntervals.back().first = TIME2STEPS(rerouterChild->getAttributeDouble(SUMO_ATTR_BEGIN));1801sortedIntervals.back().second = TIME2STEPS(rerouterChild->getAttributeDouble(SUMO_ATTR_END));1802}1803}1804// add new intervals1805sortedIntervals.push_back(std::make_pair(newBegin, newEnd));1806// sort children1807std::sort(sortedIntervals.begin(), sortedIntervals.end());1808// check overlapping after sorting1809for (int i = 0; i < (int)sortedIntervals.size() - 1; i++) {1810if (sortedIntervals.at(i).second > sortedIntervals.at(i + 1).first) {1811return false;1812}1813}1814return true;1815}181618171818bool1819GNEAdditionalHandler::checkLanePosition(double pos, const double length, const double laneLength, const bool friendlyPos) {1820if (friendlyPos) {1821return true;1822}1823// adjust from and to (negative means that start at the end of lane and count backward)1824if (pos < 0) {1825pos += laneLength;1826}1827// check extremes1828if ((pos < 0) || (pos > laneLength)) {1829return false;1830}1831// check pos + length1832if ((pos + length) > laneLength) {1833return false;1834}1835// all OK1836return true;1837}183818391840void1841GNEAdditionalHandler::fixLanePosition(double& pos, double& length, const double laneLength) {1842// negative pos means that start at the end of lane and count backward)1843if (pos < 0) {1844pos += laneLength;1845}1846// set position at the start1847if (pos < 0) {1848pos = 0;1849}1850// adjust pos1851if (pos >= laneLength) {1852pos = (laneLength - POSITION_EPS);1853}1854// adjust length1855if ((length < 0) || ((pos + length) > laneLength)) {1856length = POSITION_EPS;1857}1858}185918601861bool1862GNEAdditionalHandler::checkFriendlyPosSmallLanes(double pos, const double length, const double laneLength, const bool friendlyPos) {1863if (friendlyPos == true) {1864return true;1865} else if (OptionsCont::getOptions().getBool("e2.friendlyPos.automatic")) {1866// adjust from and to (negative means that start at the end of lane and count backward)1867if (pos < 0) {1868pos += laneLength;1869}1870// check extremes1871if ((pos < 0) || (pos > laneLength)) {1872return true;1873}1874// check pos + length1875if ((pos + length) > laneLength) {1876return true;1877}1878}1879return false;1880}188118821883bool1884GNEAdditionalHandler::checkLaneDoublePosition(double from, double to, const double laneLength, const bool friendlyPos) {1885if (friendlyPos) {1886return true;1887}1888// adjust from and to (negative means that start at the end of lane and count backward)1889if (from == INVALID_DOUBLE) {1890from = 0;1891}1892if (to == INVALID_DOUBLE) {1893to = laneLength;1894}1895if (from < 0) {1896from += laneLength;1897}1898if (to < 0) {1899to += laneLength;1900}1901if ((to - from) < POSITION_EPS) {1902return false;1903}1904if ((from < 0) || (from > laneLength)) {1905return false;1906}1907if ((to < 0) || (to > laneLength)) {1908return false;1909}1910return true;1911}191219131914void1915GNEAdditionalHandler::fixLaneDoublePosition(double& from, double& to, const double laneLength) {1916// adjust from (negative means that start at the end of lane and count backward)1917if (from == INVALID_DOUBLE) {1918from = 0;1919}1920if (to == INVALID_DOUBLE) {1921to = laneLength;1922}1923if (from < 0) {1924from += laneLength;1925}1926if (from < 0) {1927from = 0;1928} else if (from > laneLength) {1929from = laneLength;1930}1931// adjust to1932if (to < 0) {1933to += laneLength;1934}1935if (to < 0) {1936to = 0;1937} else if (to > laneLength) {1938to = laneLength;1939}1940// to has more priorty as from, and distance between from and to must be >= POSITION_EPS1941if ((to - from) < POSITION_EPS) {1942if (to >= POSITION_EPS) {1943from = to - POSITION_EPS;1944} else {1945from = 0;1946to = POSITION_EPS;1947}1948}1949}195019511952bool1953GNEAdditionalHandler::checkMultiLanePosition(double fromPos, const double fromLaneLength, const double toPos, const double tolaneLength, const bool friendlyPos) {1954if (friendlyPos) {1955return true;1956} else {1957return (checkLanePosition(fromPos, 0, fromLaneLength, false) && checkLanePosition(toPos, 0, tolaneLength, false));1958}1959}196019611962void1963GNEAdditionalHandler::fixMultiLanePosition(double fromPos, const double fromLaneLength, double toPos, const double tolaneLength) {1964double length = 0;1965fixLanePosition(fromPos, length, fromLaneLength);1966fixLanePosition(toPos, length, tolaneLength);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->getViewNet()->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->getViewNet()->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