/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2012-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 NBAlgorithms.h14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @date 02. March 201217///18// Algorithms for network computation19/****************************************************************************/20#pragma once21#include <config.h>2223#include <map>24#include "NBEdgeCont.h"25#include "NBNodeCont.h"2627// ===========================================================================28// class declarations29// ===========================================================================30class NBEdge;31class NBNode;3233// ===========================================================================34// class definitions35// ===========================================================================36// ---------------------------------------------------------------------------37// NBTurningDirectionsComputer38// ---------------------------------------------------------------------------39/* @class NBTurningDirectionsComputer40* @brief Computes turnaround destinations for all edges (if exist)41*/42class NBTurningDirectionsComputer {43public:44/** @brief Computes turnaround destinations for all edges (if exist)45* @param[in] nc The container of nodes to loop along46* @param[in] warn Whether warnings shall be issued47*/48static void computeTurnDirections(NBNodeCont& nc, bool warn = true);4950/** @brief Computes turnaround destinations for all incoming edges of the given nodes (if any)51* @param[in] node The node for which to compute turnaround destinations52* @param[in] warn Whether warnings shall be issued53* @note: This is needed by netedit54*/55static void computeTurnDirectionsForNode(NBNode* node, bool warn);5657/// @brief compute angle to junction at a point further away58static double getFarAngleAtNode(const NBEdge* e, const NBNode* n, double dist = 50);5960private:61/** @struct Combination62* @brief Stores the information about the angle between an incoming ("from") and an outgoing ("to") edge63*64* Note that the angle is increased by 360 if the edges connect the same two nodes in65* opposite direction.66*/67struct Combination {68NBEdge* from;69NBEdge* to;70double angle;71};727374/** @class combination_by_angle_sorter75* @brief Sorts "Combination"s by decreasing angle76*/77class combination_by_angle_sorter {78public:79explicit combination_by_angle_sorter() { }80int operator()(const Combination& c1, const Combination& c2) const {81if (c1.angle != c2.angle) {82return c1.angle > c2.angle;83}84if (c1.from != c2.from) {85if (c1.to == c2.to && c1.from->getPermissions() != c2.from->getPermissions()) {86if (c1.from->getPermissions() == c1.to->getPermissions()) {87return true;88} else if (c2.from->getPermissions() == c1.to->getPermissions()) {89return false;90}91}92return c1.from->getID() < c2.from->getID();93}94if (c1.to->getPermissions() != c2.to->getPermissions()) {95if (c1.to->getPermissions() == c1.from->getPermissions()) {96return true;97} else if (c2.to->getPermissions() == c1.from->getPermissions()) {98return false;99}100}101return c1.to->getID() < c2.to->getID();102}103};104};105106107108// ---------------------------------------------------------------------------109// NBNodesEdgesSorter110// ---------------------------------------------------------------------------111/* @class NBNodesEdgesSorter112* @brief Sorts a node's edges clockwise regarding driving direction113*/114class NBNodesEdgesSorter {115public:116/** @brief Sorts a node's edges clockwise regarding driving direction117* @param[in] nc The container of nodes to loop along118* @param[in] useNodeShape Whether to sort based on the node shape (instead of only the edge angle)119*/120static void sortNodesEdges(NBNodeCont& nc, bool useNodeShape = false);121122/** @class crossing_by_junction_angle_sorter123* @brief Sorts crossings by minimum clockwise clockwise edge angle. Use the124* ordering found in myAllEdges of the given node125*/126class crossing_by_junction_angle_sorter {127public:128explicit crossing_by_junction_angle_sorter(const NBNode* node, const EdgeVector& ordering);129130int operator()(const std::unique_ptr<NBNode::Crossing>& c1, const std::unique_ptr<NBNode::Crossing>& c2) const {131const int r1 = getMinRank(c1->edges);132const int r2 = getMinRank(c2->edges);133if (r1 == r2) {134return c1->edges.size() > c2->edges.size();135} else {136return (int)(r1 < r2);137}138}139140private:141/// @brief retrieves the minimum index in myAllEdges142int getMinRank(const EdgeVector& e) const {143int result = (int)myOrdering.size();144for (EdgeVector::const_iterator it = e.begin(); it != e.end(); ++it) {145int rank = (int)std::distance(myOrdering.begin(), std::find(myOrdering.begin(), myOrdering.end(), *it));146result = MIN2(result, rank);147}148return result;149}150151private:152EdgeVector myOrdering;153};154155/** @brief Assures correct order for same-angle opposite-direction edges156* @param[in] n The currently processed node157* @param[in] i1 Pointer to first edge158* @param[in] i2 Pointer to second edge159*/160static void swapWhenReversed(const NBNode* const n,161const std::vector<NBEdge*>::iterator& i1,162const std::vector<NBEdge*>::iterator& i2);163164165/** @class edge_by_junction_angle_sorter166* @brief Sorts incoming and outgoing edges clockwise around the given node167*/168class edge_by_junction_angle_sorter {169public:170explicit edge_by_junction_angle_sorter(NBNode* n) : myNode(n) {}171int operator()(NBEdge* e1, NBEdge* e2) const {172const double a1 = e1->getAngleAtNodeNormalized(myNode);173const double a2 = e2->getAngleAtNodeNormalized(myNode);174return a1 < a2 || (a1 == a2 && e1->getNumericalID() < e2->getNumericalID());175}176177private:178/// @brief The node to compute the relative angle of179NBNode* myNode;180181};182183};184185186187// ---------------------------------------------------------------------------188// NBNodeTypeComputer189// ---------------------------------------------------------------------------190/* @class NBNodeTypeComputer191* @brief Computes node types192*/193class NBNodeTypeComputer {194public:195/** @brief Computes node types196* @param[in] nc The container of nodes to loop along197*/198static void computeNodeTypes(NBNodeCont& nc, NBTrafficLightLogicCont& tlc);199200/** @brief Checks rail_crossing for validity201* @param[in] nc The container of nodes to loop along202*/203static void validateRailCrossings(NBNodeCont& nc, NBTrafficLightLogicCont& tlc);204205/// @brief whether the given node only has rail edges206static bool isRailwayNode(const NBNode* n);207};208209210211// ---------------------------------------------------------------------------212// NBEdgePriorityComputer213// ---------------------------------------------------------------------------214/* @class NBEdgePriorityComputer215* @brief Computes edge priorities within a node216*/217class NBEdgePriorityComputer {218public:219/** @brief Computes edge priorities within a node220* @param[in] nc The container of nodes to loop along221*/222static void computeEdgePriorities(NBNodeCont& nc);223224private:225/** @brief Sets the priorites in case of a priority junction226* @param[in] n The node to set edges' priorities227*/228static void setPriorityJunctionPriorities(NBNode& n, bool forceStraight = false);229230/// @brief score pair of edges for multi-criteria evaluatoin of angle, priority, laneNumber and speed231static double getScore(const NBEdge* e1, const NBEdge* e2, int minPrio, int maxPrio, int maxNumLanes, double maxSpeed, SVCPermissions permissions);232233/// @brief set priority for edges that are parallel to the best edges234static void markBestParallel(const NBNode& n, NBEdge* bestFirst, NBEdge* bestSecond);235236/** @brief Sets the priorites in case of a priority junction237* @param[in] n The node to set edges' priorities238* @param[in] s The vector of edges to get and mark the first from239* @param[in] prio The priority to assign240* @return The vector's first edge241*/242static NBEdge* extractAndMarkFirst(NBNode& n, std::vector<NBEdge*>& s, int prio = 1);243244/** @brief Returns whether both edges have the same priority245* @param[in] e1 The first edge246* @param[in] e2 The second edge247* Whether both edges have the same priority248*/249static bool samePriority(const NBEdge* const e1, const NBEdge* const e2, SVCPermissions permissions);250251/// @brief return whether the priorite attribute can be used to distinguish the edges252static bool hasDifferentPriorities(const EdgeVector& edges, const NBEdge* excluded);253254};255256257