Path: blob/main/src/netedit/elements/additional/GNEMultiEntryExitDetector.cpp
193671 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GNEMultiEntryExitDetector.cpp14/// @author Pablo Alvarez Lopez15/// @date Nov 201516///17// multi entry-exit (E3) detector18/****************************************************************************/19#include <config.h>2021#include <netedit/changes/GNEChange_Attribute.h>22#include <netedit/elements/moving/GNEMoveElementView.h>23#include <netedit/GNENet.h>24#include <netedit/GNETagProperties.h>2526#include "GNEMultiEntryExitDetector.h"2728// ===========================================================================29// member method definitions30// ===========================================================================3132GNEMultiEntryExitDetector::GNEMultiEntryExitDetector(GNENet* net) :33GNEAdditional(net, SUMO_TAG_ENTRY_EXIT_DETECTOR),34GNEAdditionalSquared(this) {35}363738GNEMultiEntryExitDetector::GNEMultiEntryExitDetector(const std::string& id, GNENet* net, FileBucket* fileBucket, const Position pos, const SUMOTime freq,39const std::string& outputFilename, const std::vector<std::string>& vehicleTypes, const std::vector<std::string>& nextEdges, const std::string& detectPersons,40const std::string& name, const SUMOTime timeThreshold, const double speedThreshold, const bool openEntry, const bool expectedArrival, const Parameterised::Map& parameters) :41GNEAdditional(id, net, SUMO_TAG_ENTRY_EXIT_DETECTOR, fileBucket, name),42GNEAdditionalSquared(this, pos),43Parameterised(parameters),44myPeriod(freq),45myOutputFilename(outputFilename),46myVehicleTypes(vehicleTypes),47myNextEdges(nextEdges),48myDetectPersons(detectPersons),49myTimeThreshold(timeThreshold),50mySpeedThreshold(speedThreshold),51myOpenEntry(openEntry),52myExpectedArrival(expectedArrival) {53// update centering boundary without updating grid54updateCenteringBoundary(false);55// set default output filename56if (outputFilename.empty()) {57myOutputFilename = id + ".xml";58}59}606162GNEMultiEntryExitDetector::~GNEMultiEntryExitDetector() {63}646566GNEMoveElement*67GNEMultiEntryExitDetector::getMoveElement() const {68return myMoveElementView;69}707172Parameterised*73GNEMultiEntryExitDetector::getParameters() {74return this;75}767778const Parameterised*79GNEMultiEntryExitDetector::getParameters() const {80return this;81}828384void85GNEMultiEntryExitDetector::writeAdditional(OutputDevice& device) const {86bool entry = false;87bool exit = false;88// first check if E3 has at least one entry and one exit89for (const auto& additionalChild : getChildAdditionals()) {90if (additionalChild->getTagProperty()->getTag() == SUMO_TAG_DET_ENTRY) {91entry = true;92} else if (additionalChild->getTagProperty()->getTag() == SUMO_TAG_DET_EXIT) {93exit = true;94}95}96// check entry/exits97if (entry && exit) {98device.openTag(getTagProperty()->getTag());99// write common additional attributes100writeAdditionalAttributes(device);101// write move atributes102myMoveElementView->writeMoveAttributes(device);103// write specific attributes104if (getAttribute(SUMO_ATTR_PERIOD).size() > 0) {105device.writeAttr(SUMO_ATTR_PERIOD, time2string(myPeriod));106}107if (myOutputFilename.size() > 0) {108device.writeAttr(SUMO_ATTR_FILE, myOutputFilename);109}110if (myVehicleTypes.size() > 0) {111device.writeAttr(SUMO_ATTR_VTYPES, myVehicleTypes);112}113if (myTimeThreshold != myTagProperty->getDefaultTimeValue(SUMO_ATTR_HALTING_TIME_THRESHOLD)) {114device.writeAttr(SUMO_ATTR_HALTING_TIME_THRESHOLD, time2string(myTimeThreshold));115}116if (mySpeedThreshold != myTagProperty->getDefaultDoubleValue(SUMO_ATTR_HALTING_SPEED_THRESHOLD)) {117device.writeAttr(SUMO_ATTR_HALTING_SPEED_THRESHOLD, mySpeedThreshold);118}119if (myExpectedArrival != myTagProperty->getDefaultBoolValue(SUMO_ATTR_EXPECT_ARRIVAL)) {120device.writeAttr(SUMO_ATTR_EXPECT_ARRIVAL, myExpectedArrival);121}122if (myOpenEntry != myTagProperty->getDefaultBoolValue(SUMO_ATTR_OPEN_ENTRY)) {123device.writeAttr(SUMO_ATTR_OPEN_ENTRY, myOpenEntry);124}125// write all entry/exits126for (const auto& access : getChildAdditionals()) {127access->writeAdditional(device);128}129// write parameters (Always after children to avoid problems with additionals.xsd)130writeParams(device);131device.closeTag();132} else {133WRITE_WARNING("E3 '" + getID() + TL("' needs at least one entry and one exit"));134}135}136137138bool139GNEMultiEntryExitDetector::isAdditionalValid() const {140return true;141}142143144std::string145GNEMultiEntryExitDetector::getAdditionalProblem() const {146return "";147}148149150void151GNEMultiEntryExitDetector::fixAdditionalProblem() {152// nothing to fix153}154155156bool157GNEMultiEntryExitDetector::checkDrawMoveContour() const {158// get edit modes159const auto& editModes = myNet->getViewNet()->getEditModes();160// check if we're in move mode161if (!myNet->getViewNet()->isCurrentlyMovingElements() && editModes.isCurrentSupermodeNetwork() &&162!myNet->getViewNet()->getEditNetworkElementShapes().getEditedNetworkElement() &&163(editModes.networkEditMode == NetworkEditMode::NETWORK_MOVE) && myNet->getViewNet()->checkOverLockedElement(this, mySelected)) {164// only move the first element165return myNet->getViewNet()->getViewObjectsSelector().getGUIGlObjectFront() == this;166} else {167return false;168}169}170171172void173GNEMultiEntryExitDetector::updateGeometry() {174updatedSquaredGeometry();175}176177178Position179GNEMultiEntryExitDetector::getPositionInView() const {180return myPosOverView;181}182183184void185GNEMultiEntryExitDetector::updateCenteringBoundary(const bool updateGrid) {186updatedSquaredCenteringBoundary(updateGrid);187}188189190void191GNEMultiEntryExitDetector::splitEdgeGeometry(const double /*splitPosition*/, const GNENetworkElement* /*originalElement*/, const GNENetworkElement* /*newElement*/, GNEUndoList* /*undoList*/) {192// geometry of this element cannot be splitted193}194195196std::string197GNEMultiEntryExitDetector::getParentName() const {198return myNet->getMicrosimID();199}200201202void203GNEMultiEntryExitDetector::drawGL(const GUIVisualizationSettings& s) const {204// first check if additional has to be drawn205if (myNet->getViewNet()->getDataViewOptions().showAdditionals() &&206!myNet->getViewNet()->selectingDetectorsTLSMode()) {207// draw parent and child lines208drawParentChildLines(s, s.additionalSettings.connectionColor);209// draw E3210drawSquaredAdditional(s, s.detectorSettings.E3Size, GUITexture::E3, GUITexture::E3_SELECTED);211}212}213214215std::string216GNEMultiEntryExitDetector::getAttribute(SumoXMLAttr key) const {217switch (key) {218case SUMO_ATTR_ID:219return getMicrosimID();220case SUMO_ATTR_PERIOD:221if (myPeriod == SUMOTime_MAX_PERIOD) {222return "";223} else {224return time2string(myPeriod);225}226case SUMO_ATTR_NAME:227return myAdditionalName;228case SUMO_ATTR_FILE:229return myOutputFilename;230case SUMO_ATTR_VTYPES:231return toString(myVehicleTypes);232case SUMO_ATTR_NEXT_EDGES:233return toString(myNextEdges);234case SUMO_ATTR_DETECT_PERSONS:235return toString(myDetectPersons);236case SUMO_ATTR_HALTING_TIME_THRESHOLD:237return time2string(myTimeThreshold);238case SUMO_ATTR_HALTING_SPEED_THRESHOLD:239return toString(mySpeedThreshold);240case SUMO_ATTR_OPEN_ENTRY:241return toString(myOpenEntry);242case SUMO_ATTR_EXPECT_ARRIVAL:243return toString(myExpectedArrival);244default:245return myMoveElementView->getMovingAttribute(key);246}247}248249250double251GNEMultiEntryExitDetector::getAttributeDouble(SumoXMLAttr key) const {252return myMoveElementView->getMovingAttributeDouble(key);253}254255256Position257GNEMultiEntryExitDetector::getAttributePosition(SumoXMLAttr key) const {258return myMoveElementView->getMovingAttributePosition(key);259}260261262PositionVector263GNEMultiEntryExitDetector::getAttributePositionVector(SumoXMLAttr key) const {264return myMoveElementView->getMovingAttributePositionVector(key);265}266267268void269GNEMultiEntryExitDetector::setAttribute(SumoXMLAttr key, const std::string& value, GNEUndoList* undoList) {270if (value == getAttribute(key)) {271return; //avoid needless changes, later logic relies on the fact that attributes have changed272}273switch (key) {274case SUMO_ATTR_ID:275case SUMO_ATTR_PERIOD:276case SUMO_ATTR_NAME:277case SUMO_ATTR_FILE:278case SUMO_ATTR_VTYPES:279case SUMO_ATTR_NEXT_EDGES:280case SUMO_ATTR_DETECT_PERSONS:281case SUMO_ATTR_HALTING_TIME_THRESHOLD:282case SUMO_ATTR_HALTING_SPEED_THRESHOLD:283case SUMO_ATTR_OPEN_ENTRY:284case SUMO_ATTR_EXPECT_ARRIVAL:285GNEChange_Attribute::changeAttribute(this, key, value, undoList);286break;287default:288myMoveElementView->setMovingAttribute(key, value, undoList);289break;290}291}292293294bool295GNEMultiEntryExitDetector::isValid(SumoXMLAttr key, const std::string& value) {296switch (key) {297case SUMO_ATTR_ID:298return isValidDetectorID(value);299case SUMO_ATTR_PERIOD:300if (value.empty()) {301return true;302} else {303return (canParse<double>(value) && (parse<double>(value) >= 0));304}305case SUMO_ATTR_NAME:306return SUMOXMLDefinitions::isValidAttribute(value);307case SUMO_ATTR_FILE:308return SUMOXMLDefinitions::isValidFilename(value);309case SUMO_ATTR_VTYPES:310if (value.empty()) {311return true;312} else {313return SUMOXMLDefinitions::isValidListOfTypeID(value);314}315case SUMO_ATTR_NEXT_EDGES:316if (value.empty()) {317return true;318} else {319return SUMOXMLDefinitions::isValidListOfNetIDs(value);320}321case SUMO_ATTR_DETECT_PERSONS:322if (value.empty()) {323return true;324} else {325return SUMOXMLDefinitions::PersonModeValues.hasString(value);326}327case SUMO_ATTR_HALTING_TIME_THRESHOLD:328case SUMO_ATTR_HALTING_SPEED_THRESHOLD:329return canParse<double>(value) && (parse<double>(value) >= 0);330case SUMO_ATTR_OPEN_ENTRY:331case SUMO_ATTR_EXPECT_ARRIVAL:332return canParse<bool>(value);333default:334return myMoveElementView->isMovingAttributeValid(key, value);335}336}337338339bool340GNEMultiEntryExitDetector::checkChildAdditionalRestriction() const {341int numEntrys = 0;342int numExits = 0;343// iterate over additional chidls and obtain number of entrys and exits344for (auto i : getChildAdditionals()) {345if (i->getTagProperty()->getTag() == SUMO_TAG_DET_ENTRY) {346numEntrys++;347} else if (i->getTagProperty()->getTag() == SUMO_TAG_DET_EXIT) {348numExits++;349}350}351// write warnings352if (numEntrys == 0) {353WRITE_WARNING(TL("An entry-exit detector needs at least one entry detector"));354}355if (numExits == 0) {356WRITE_WARNING(TL("An entry-exit detector needs at least one exit detector"));357}358// return false depending of number of Entrys and Exits359return ((numEntrys != 0) && (numExits != 0));360}361362363std::string364GNEMultiEntryExitDetector::getPopUpID() const {365return getTagStr() + ":" + getID();366}367368369std::string370GNEMultiEntryExitDetector::getHierarchyName() const {371return getTagStr();372}373374// ===========================================================================375// private376// ===========================================================================377378void379GNEMultiEntryExitDetector::setAttribute(SumoXMLAttr key, const std::string& value) {380switch (key) {381case SUMO_ATTR_ID:382// update microsimID383setAdditionalID(value);384break;385case SUMO_ATTR_PERIOD:386if (value.empty()) {387myPeriod = SUMOTime_MAX_PERIOD;388} else {389myPeriod = string2time(value);390}391break;392case SUMO_ATTR_NAME:393myAdditionalName = value;394break;395case SUMO_ATTR_FILE:396myOutputFilename = value;397break;398case SUMO_ATTR_VTYPES:399myVehicleTypes = parse<std::vector<std::string> >(value);400break;401case SUMO_ATTR_NEXT_EDGES:402myNextEdges = parse<std::vector<std::string> >(value);403break;404case SUMO_ATTR_DETECT_PERSONS:405myDetectPersons = value;406break;407case SUMO_ATTR_HALTING_TIME_THRESHOLD:408myTimeThreshold = parse<SUMOTime>(value);409break;410case SUMO_ATTR_HALTING_SPEED_THRESHOLD:411mySpeedThreshold = parse<double>(value);412break;413case SUMO_ATTR_OPEN_ENTRY:414myOpenEntry = parse<bool>(value);415break;416case SUMO_ATTR_EXPECT_ARRIVAL:417myExpectedArrival = parse<bool>(value);418break;419default:420myMoveElementView->setMovingAttribute(key, value);421break;422}423// update boundary (except for template)424if (getID().size() > 0) {425updateCenteringBoundary(true);426}427}428429/****************************************************************************/430431432