/****************************************************************************/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 NBNodeCont.h14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Yun-Pang Floetteroed17/// @author Michael Behrisch18/// @author Walter Bamberger19/// @date Tue, 20 Nov 200120///21// Container for nodes during the netbuilding process22/****************************************************************************/23#pragma once24#include <config.h>2526#include <string>27#include <map>28#include <vector>29#include <set>30#include <utils/common/NamedRTree.h>31#include <utils/geom/Position.h>32#include "NBCont.h"33#include "NBEdgeCont.h"34#include "NBNode.h"35#include <utils/common/UtilExceptions.h>363738// ===========================================================================39// class declarations40// ===========================================================================41class NBDistrict;42class OptionsCont;43class OutputDevice;44class NBParkingCont;45class NBPTLineCont;46class NBPTStopCont;474849// ===========================================================================50// class definitions51// ===========================================================================52/**53* @class NBNodeCont54* @brief Container for nodes during the netbuilding process55*/56class NBNodeCont {5758public:59/// @brief Definition of a node cluster container60typedef std::vector<NodeSet> NodeClusters;61typedef std::pair<NBNode*, double> NodeAndDist;6263/// @brief Constructor64NBNodeCont() {}6566/// @brief Destructor67~NBNodeCont();6869/// @name Insertion/removal/retrieval of nodes70/// @{71/** @brief Inserts a node into the map72* @param[in] id The node's id73* @param[in] position The node's position74* @param[in] A district assigned to the node75* @return Whether the node could be added (no other with the same id or position is stored)76*/77bool insert(const std::string& id, const Position& position, NBDistrict* district = 0);7879/** @brief Inserts a node into the map80* @param[in] node The node to insert81* @return Whether the node could be added (no other with the same id or position is stored)82*/83bool insert(NBNode* node);8485/** @brief Removes the given node, deleting it86* @param[in] node The node to delete and remove87* @return Whether the node could be removed (existed)88*/89bool erase(NBNode* node);9091/** @brief Removes the given node but does not delete it92* @param[in] node The node to delete and remove93* @param[in] remember Whether to keep the node for future reference94* @return Whether the node could be removed (existed)95*/96bool extract(NBNode* node, bool remember = false);9798/** @brief Returns the node with the given name99* @param[in] id The id of the node to retrieve100* @return The node with the given id, or 0 if no such node exists101*/102NBNode* retrieve(const std::string& id) const;103104/** @brief Returns the node with the given coordinates105* @param[in] position The position at which the node to retrieve lies106* @param[in] offset An offset which can be applied in the case positions are blurred107* @return The node at the given position, or 0 if no such node exists108*/109std::vector<NBNode*> retrieveByPos(const Position& position, const double offset = 0.) const;110111/// @brief Returns the pointer to the begin of the stored nodes112std::map<std::string, NBNode*>::const_iterator begin() const {113return myNodes.begin();114}115116/// @brief Returns the pointer to the end of the stored nodes117std::map<std::string, NBNode*>::const_iterator end() const {118return myNodes.end();119}120/// @}121122/// @name Methods for joining nodes123/// @{124/* @brief add ids of nodes wich shall not be joined125* @param[in] ids A list of ids to exclude from joining126* @note it does not check whether the nodes exist because all nodes may not have been loaded yet127*/128void addJoinExclusion(const std::vector<std::string>& ids);129130/** @brief generate id from cluster node ids131* @param[in] cluster The cluster ids132* @param[in] prefix The cluster prefix133* @return the generated id134*/135std::string createClusterId(const NodeSet& cluster, const std::string& prefix = "cluster_") {136std::set<std::string> clusterIds;137for (NBNode* j : cluster) {138clusterIds.insert(j->getID());139}140return createClusterId(clusterIds, prefix);141}142143/** @brief generate id from cluster node ids144* @param[in] cluster The cluster ids145* @param[in] prefix The cluster prefix146* @return the generated id147*/148std::string createClusterId(const std::set<std::string>& cluster, const std::string& prefix = "cluster_");149150/** @brief add ids of nodes which shall be joined into a single node151* @param[in] cluster The cluster to add152*/153void addCluster2Join(const std::set<std::string>& cluster, NBNode* node);154155/// @brief Joins loaded junction clusters (see NIXMLNodesHandler)156int joinLoadedClusters(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc);157158/// @brief Joins junctions that are very close together159int joinJunctions(double maxDist, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc, NBPTStopCont& sc);160161/// @brief Joins junctions with similar coordinates regardless of topology162int joinSameJunctions(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc, double maxDist);163164/// @brief return all cluster neighbors for the given node165static NodeSet getClusterNeighbors(const NBNode* n, double longThreshold, NodeSet& cluster);166167/// @brief whether the given node may continue a slip lane168static bool isSlipLaneContinuation(const NBNode* cont);169170/// @brief check whether the given node maybe the start of a slip lane171bool maybeSlipLaneStart(const NBNode* n, EdgeVector& outgoing, double& inAngle) const;172/// @brief check whether the given node maybe the end of a slip lane173bool maybeSlipLaneEnd(const NBNode* n, EdgeVector& incoming, double& outAngle) const;174175/// @brief try to find a joinable subset (recursively)176bool reduceToCircle(NodeSet& cluster, int circleSize, NodeSet startNodes, double maxDist, std::vector<NBNode*> cands = std::vector<NBNode*>()) const;177178/// @brief find closest neighbor for building circle179NBEdge* shortestEdge(const NodeSet& cluster, const NodeSet& startNodes, const std::vector<NBNode*>& exclude) const;180/// @}181182/// @name Adapting the input183/// @{184/** @brief Removes self-loop edges (edges where the source and the destination node are the same)185* @param[in, opt. changed] dc The districts container to update186* @param[in, opt. changed] ec The edge container to remove the edges from187* @param[in, opt. changed] tc The traffic lights container to update188* @post Each edge is a uni-directional connection between two different nodes189* @return The number of removed edges190*/191int removeSelfLoops(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tc);192193/** @brief Joins edges connecting the same nodes194* @param[in, opt. changed] dc The districts container to update195* @param[in, opt. changed] ec The edge container to remove the edges from196* @param[in, opt. changed] tc The traffic lights container to update197* @post No two edges with same geometry connecting same nodes exist198*/199void joinSimilarEdges(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc, bool removeDuplicates);200201/// @brief fix overlap202void avoidOverlap();203204/** @brief Removes sequences of edges that are not connected with a junction.205* Simple roads without junctions sometimes remain when converting from OpenStreetMap,206* but they make no sense. Remaining empty nodes are also deleted.207*208* @param[in, opt. changed] dc The district container needed if edges shall be removed209* @param[in, opt. changed] ec The container with the edge to be tested210* @return The number of removed edges211*/212int removeIsolatedRoads(NBDistrictCont& dc, NBEdgeCont& ec);213214/** @brief Checks the network for weak connectivity and removes all but the largest components.215* The connectivity check is done regardless of edge direction and vclass.216*217* @param[in, opt. changed] dc The district container needed if edges shall be removed218* @param[in, opt. changed] ec The container with the edge to be tested219* @param[in] numKeep The number of components to keep220* @return The number of removed edges221*/222int removeComponents(NBDistrictCont& dc, NBEdgeCont& ec, const int numKeep, bool hasPTStops);223224/* @brief remove rail components after ptstops are built225* @return The number of removed edges226*/227int removeRailComponents(NBDistrictCont& dc, NBEdgeCont& ec, NBPTStopCont& sc);228229/** @brief Removes "unwished" nodes230*231* Removes nodes if a) no incoming/outgoing edges exist or232* b) if the node is a "geometry" node. In the second case,233* edges that participate at the node will be joined.234* Whether the node is a geometry node or not, is determined235* by a call to NBNode::checkIsRemovable.236* The node is removed from the list of tls-controlled nodes.237* @param[in, opt. changed] dc The district container needed if a node shall be removed238* @param[in, opt. changed] ec The edge container needed for joining edges239* @param[in, opt. changed] tlc The traffic lights container to remove nodes from240* @param[in, opt. changed] sc The pt stops container to update stop edges241* @param[in, opt. changed] pc The pt stops container to update stop edges242* @param[in] removeGeometryNodes Whether geometry nodes shall also be removed243* @return The number of removed nodes244*/245int removeUnwishedNodes(NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc,246NBPTStopCont& sc, NBPTLineCont& lc, NBParkingCont& pc,247bool removeGeometryNodes);248/// @}249250/// @name Methods for guessing/computing traffic lights251/// @{252/** @brief Guesses which junctions or junction clusters shall be controlled by tls253* @param[in] oc The options that steer the guessing process254* @param[filled] tlc The traffic lights control into which new traffic light definitions shall be stored255* @todo Recheck exception handling256*/257void guessTLs(OptionsCont& oc, NBTrafficLightLogicCont& tlc);258259/// @brief recheck myGuessedTLS after node logics are computed260void recheckGuessedTLS(NBTrafficLightLogicCont& tlc);261262/// @brief check whether a specific guessed tls should keep its type263bool recheckTLSThreshold(NBNode* node);264265/// @brief compute keepClear status for all connections266void computeKeepClear();267268/** @brief Builds clusters of tls-controlled junctions and joins the control if possible269* @param[changed] tlc The traffic lights control for adding/removing new/prior tls270* @param[in] maxdist The maximum distance between nodes for clustering271* @todo Recheck exception handling272*/273void joinTLS(NBTrafficLightLogicCont& tlc, double maxdist);274275/** @brief Sets the given node as being controlled by a tls276* @param[in] node The node that shall be controlled by a tls277* @param[in] tlc The traffic lights control into which the new traffic light definition shall be stored278* @param[in] type The type of the new tls279* @param[in] id The id of the tls to add280* @todo Recheck exception handling281*/282void setAsTLControlled(NBNode* node, NBTrafficLightLogicCont& tlc, TrafficLightType type, std::string id = "");283/// @}284285/// @brief Returns whether the node with the id was deleted explicitly286bool wasRemoved(std::string id) const {287return myExtractedNodes.count(id) != 0;288}289290/// @brief add prefix to all nodes291void addPrefix(const std::string& prefix);292293/// @brief Renames the node. Throws exception if newID already exists294void rename(NBNode* node, const std::string& newID);295296/// divides the incoming lanes on outgoing lanes297void computeLanes2Lanes();298299/// @brief build the list of outgoing edges and lanes300void computeLogics(const NBEdgeCont& ec);301302/// @brief compute right-of-way logic for all lane-to-lane connections303void computeLogics2(const NBEdgeCont& ec, OptionsCont& oc);304305/// @brief Returns the number of nodes stored in this container306int size() const {307return (int) myNodes.size();308}309310/// @brief deletes all nodes311void clear();312313/// @brief generates a new node ID314std::string getFreeID();315316/** @brief Compute the junction shape for this node317* @param[in] mismatchThreshold The threshold for warning about shapes which are away from myPosition318*/319void computeNodeShapes(double mismatchThreshold = -1);320321/** @brief Prints statistics about built nodes322*323* Goes through stored nodes, computes the numbers of unregulated, priority and right-before-left324* junctions and prints them.325*/326void printBuiltNodesStatistics() const;327328/// @brief get all node names329std::vector<std::string> getAllNames() const;330331/* @brief analyzes a cluster of nodes which shall be joined332* @param[in] cluster The nodes to be joined333* @param[out] id The name for the new node334* @param[out] pos The position of the new node335* @param[out] hasTLS Whether the new node has a traffic light336* @param[out] tlType The type of traffic light (if any)337*/338void analyzeCluster(NodeSet cluster, std::string& id, Position& pos,339bool& hasTLS, TrafficLightType& type, SumoXMLNodeType& nodeType);340341/// @brief gets all joined clusters (see doc for myClusters2Join)342void registerJoinedCluster(const NodeSet& cluster);343void registerJoinedCluster(const std::set<std::string>& cluster);344345/// @brief remove cluster from list (on netedit-undo)346void unregisterJoinedCluster(const std::set<std::string>& cluster);347348/// @brief gets all joined clusters (see doc for myClusters2Join)349const std::vector<std::set<std::string> >& getJoinedClusters() const {350return myJoinedClusters;351}352353/* @brief discards traffic lights354* @param[in] geometryLike Whether only tls at geometry-like nodes shall be discarded355*/356void discardTrafficLights(NBTrafficLightLogicCont& tlc, bool geometryLike);357358/// @brief discards rail signals359void discardRailSignals();360361/// @brief mark a node as being created form a split362void markAsSplit(const NBNode* node) {363mySplit.insert(node);364}365366/// @brief mark a node as explicitly not controlled by a TLS367void markAsNotTLS(const NBNode* node) {368myUnsetTLS.insert(node);369}370371/// @brief remap node IDs according to options --numerical-ids and --reserved-ids372int remapIDs(bool numericaIDs, bool reservedIDs, bool keptIDs, const std::string& prefix, NBTrafficLightLogicCont& tlc);373374/// @brief guess and mark fringe nodes375int guessFringe();376377/// @brief apply default values after loading378void applyConditionalDefaults();379380/// @brief reset all node shapes381bool resetNodeShapes();382383private:384385/// @name Helper methods for for joining nodes386/// @{387/** @brief Builds node clusters388*389* A node cluster is made up from nodes which are near by (distance<maxDist) and connected.390*391* @param[in] maxDist The maximum distance between two nodes for clustering392* @param[in, filled] into The container to store the clusters in393*/394void generateNodeClusters(double maxDist, NodeClusters& into) const;395396/// @brief remove geometry-like fringe nodes from cluster397void pruneClusterFringe(NodeSet& cluster, double maxDist, bool remove2TLS = false) const;398399/// @brief avoid removal of long edges when joining junction clusters400static int pruneLongEdges(NodeSet& cluster, double maxDist, const bool dryRun = false);401402/// @brief compute the maximum distance between any two cluster nodes403static double getDiameter(const NodeSet& cluster);404405/// @brief check whether the node is geometryLike when only considering edges that support the given permissions406static bool geometryLikeForClass(const NBNode* n, SVCPermissions permissions);407408/// @brief remove nodes that form a slip lane from cluster409void pruneSlipLaneNodes(NodeSet& cluster, double maxDist) const;410411/// @brief determine wether the cluster is not too complex for joining412bool feasibleCluster(const NodeSet& cluster, const std::map<const NBNode*, std::vector<NBNode*> >& ptStopEnds,413double maxDist, std::string& reason, NBNode*& tryRemove) const;414415/// @brief joins the given node clusters416void joinNodeClusters(NodeClusters clusters, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc, bool resetConnections = false);417void joinNodeCluster(NodeSet clusters, NBDistrictCont& dc, NBEdgeCont& ec, NBTrafficLightLogicCont& tlc,418NBNode* predefined = nullptr, bool resetConnections = false);419420/// @}421422/// @name Helper methods for guessing/computing traffic lights423/// @{424/** @brief Returns whethe the given node cluster should be controlled by a tls425* @param[in] c The node cluster426* @param[in] laneSpeedThreshold threshold for determining whether a node or cluster should be tls controlled427* @return Whether this node cluster shall be controlled by a tls428*/429bool shouldBeTLSControlled(const NodeSet& c, double laneSpeedThreshold, bool recheck = false) const;430431/// @brief check wheter the set of nodes only contains pedestrian crossings432bool onlyCrossings(const NodeSet& c) const;433434/// @brief check wheter the set of nodes contains traffic lights with custom id435bool customTLID(const NodeSet& c) const;436/// @}437438/// @brief update pareto frontier with the given node439void paretoCheck(NBNode* node, NodeSet& frontier, int xSign, int ySign);440441/// @brief Definition of the map of names to nodes442typedef std::map<std::string, NBNode*> NodeCont;443444/// @brief The map of names to nodes445NodeCont myNodes;446447/// @brief The extracted nodes which are kept for reference448NodeCont myExtractedNodes;449450/// @brief set of node ids which should not be joined451std::set<std::string> myJoinExclusions;452453/// @brief loaded sets of node ids to join (cleared after use)454std::vector<std::pair<std::set<std::string>, NBNode*> > myClusters2Join;455456/// @brief sets of node ids which were joined457std::vector<std::set<std::string> > myJoinedClusters;458459/// @brief ids found in loaded join clusters used for error checking460std::set<std::string> myJoined;461462/// @brief nodes that were created when splitting an edge463std::set<const NBNode*> mySplit;464465/// @brief nodes that received a traffic light due to guessing (--tls.guess)466std::set<NBNode*, ComparatorIdLess> myGuessedTLS;467468/// @brief nodes that are excluded from tls-guessing469std::set<const NBNode*> myUnsetTLS;470471/// @brief node positions for faster lookup472NamedRTree myRTree;473474/// @brief network components that must be removed if not connected to the road network via stop access475std::vector<std::vector<std::string> > myRailComponents;476477/// @brief invalidated copy constructor478NBNodeCont(const NBNodeCont& s) = delete;479480/// @brief invalidated assignment operator481NBNodeCont& operator=(const NBNodeCont& s) = delete;482};483484485