/****************************************************************************/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 FlippedEdge.h14/// @author Ruediger Ebendt15/// @date 01.12.202316///17// Extension of ReversedEdge, which is a wrapper around a ROEdge18// or an MSEdge used for backward search. In contrast to reversed19// edges, flipped edges have flipped nodes instead of standard nodes.20// Introduced for the arc flag router.21/****************************************************************************/22#pragma once23#include <config.h>24#include <utils/common/SUMOVehicleClass.h>25#ifdef HAVE_FOX26#include <utils/foxtools/MsgHandlerSynchronized.h>27#endif28#include "ReversedEdge.h"293031// ===========================================================================32// class declarations33// ===========================================================================34template<class E, class N, class V>35class FlippedNode;3637// ===========================================================================38// class definitions39// ===========================================================================40/// @brief The edge type representing backward edges with flipped nodes41template<class E, class N, class V>42class FlippedEdge : public ReversedEdge<E, V> {43public:4445typedef std::vector<std::pair<const FlippedEdge<E, N, V>*, const FlippedEdge<E, N, V>*> > ConstFlippedEdgePairVector;4647/** @brief Constructor48* @param[in] originalEdge The original (forward) edge49*/50FlippedEdge(const E* originalEdge) :51ReversedEdge<E, V>(originalEdge),52myFromJunction(originalEdge->getToJunction()->getFlippedRoutingNode()),53myToJunction(originalEdge->getFromJunction()->getFlippedRoutingNode())54{}5556/// @brief Destructor57~FlippedEdge() {}5859/// @brief Initialize the flipped edge60void init();6162/// @brief Returns the from-junction63const FlippedNode<E, N, V>* getFromJunction() const {64return myFromJunction;65}6667/// @brief Returns the to-junction68const FlippedNode<E, N, V>* getToJunction() const {69return myToJunction;70}7172/** @brief Returns the time for travelling on the given edge with the given vehicle at the given time73* @param[in] edge The edge74* @param[in] veh The vehicle75* @param[in] time The time76* @return The time for travelling on the given edge with the given vehicle at the given time77*/78static double getTravelTimeStatic(const FlippedEdge<E, N, V>* const edge, const V* const veh, double time) {79return edge->getOriginalEdge()->getTravelTime(veh, time);80}8182/** @brief Returns the randomized time for travelling on the given edge with the given vehicle at the given time83* @param[in] edge The edge84* @param[in] veh The vehicle85* @param[in] time The time86* @return The randomized time for travelling on the given edge with the given vehicle at the given time87*/88static double getTravelTimeStaticRandomized(const FlippedEdge<E, N, V>* const edge, const V* const veh, double time) {89return edge->getOriginalEdge()->getTravelTimeStaticRandomized(edge->getOriginalEdge(), veh, time);90}9192/** @brief Returns the via successors93* @param[in] vClass The vehicle class94* @param[in] ignoreTransientPermissions Unused parameter95* @return The via successors96*/97const ConstFlippedEdgePairVector& getViaSuccessors(SUMOVehicleClass vClass = SVC_IGNORING, bool ignoreTransientPermissions = false) const {98UNUSED_PARAMETER(ignoreTransientPermissions); // @todo this should be changed (somewhat hidden by #14756)99if (vClass == SVC_IGNORING || this->getOriginalEdge()->isTazConnector()) { // || !MSNet::getInstance()->hasPermissions()) {100return myViaSuccessors;101}102#ifdef HAVE_FOX103FXMutexLock lock(mySuccessorMutex);104#endif105auto i = myClassesViaSuccessorMap.find(vClass);106if (i != myClassesViaSuccessorMap.end()) {107// can use cached value108return i->second;109}110// instantiate vector111ConstFlippedEdgePairVector& result = myClassesViaSuccessorMap[vClass];112// this vClass is requested for the first time. rebuild all successors113for (const auto& viaPair : myViaSuccessors) {114if (viaPair.first->getOriginalEdge()->isTazConnector()115|| viaPair.first->getOriginalEdge()->isConnectedTo(*(this->getOriginalEdge()), vClass)) {116result.push_back(viaPair);117}118}119return result;120}121122/** @brief Returns the bidirectional edge123* @return The bidirectional edge124*/125const FlippedEdge<E, N, V>* getBidiEdge() const {126return this->getOriginalEdge()->getBidiEdge()->getFlippedRoutingEdge();127}128129/** @brief Returns the distance to another flipped edge130* param[in] other The other flipped edge131* param[in] doBoundaryEstimate The boolean flag indicating whether the distance is estimated using both boundaries or not132* @return The distance to another flipped edge133*/134double getDistanceTo(const FlippedEdge<E, N, V>* other, const bool doBoundaryEstimate = false) const {135return this->getOriginalEdge()->getDistanceTo(other->getOriginalEdge(), doBoundaryEstimate);136}137138/** @brief Returns the minimum travel time139* @param[in] veh The vehicle140* @return The minimum travel time141*/142double getMinimumTravelTime(const V* const veh) const {143return this->getOriginalEdge()->getMinimumTravelTime(veh);144}145146/** @brief Returns the time penalty147* @return The time penalty148*/149double getTimePenalty() const {150return this->getOriginalEdge()->getTimePenalty();151}152153/** @brief Returns a boolean flag indicating whether this edge has loaded travel times or not154* @return true iff this edge has loaded travel times155*/156bool hasLoadedTravelTimes() const {157return this->getOriginalEdge()->hasLoadedTravelTimes();158}159160/** @brief Returns the speed allowed on this edge161* @return The speed allowed on this edge162*/163double getSpeedLimit() const {164return this->getOriginalEdge()->getSpeedLimit();165}166167/** @brief Returns a lower bound on shape.length() / myLength168* @note The bound is sufficient for the astar air-distance heuristic169* @return A lower bound on shape.length() / myLength170*/171double getLengthGeometryFactor() const {172return this->getOriginalEdge()->getLengthGeometryFactor();173}174175/** @brief Returns the edge priority (road class)176* @return The edge priority (road class)177*/178int getPriority() const {179return this->getOriginalEdge()->getPriority();180}181182protected:183/// @brief The junctions for this edge184FlippedNode<E, N, V>* myFromJunction;185FlippedNode<E, N, V>* myToJunction;186187private:188/// @brief The successors available for a given vClass189mutable std::map<SUMOVehicleClass, ConstFlippedEdgePairVector> myClassesViaSuccessorMap;190mutable ConstFlippedEdgePairVector myViaSuccessors;191192#ifdef HAVE_FOX193/// @brief Mutex for accessing successor edges194mutable FXMutex mySuccessorMutex;195#endif196};197198// ===========================================================================199// method definitions200// ===========================================================================201202template<class E, class N, class V>203void FlippedEdge<E, N, V>::init() {204if (!this->getOriginalEdge()->isInternal()) {205for (const auto& viaPair : this->getOriginalEdge()->getViaSuccessors()) {206const FlippedEdge<E, N, V>* revSource = viaPair.first->getFlippedRoutingEdge();207const E* via = viaPair.second;208const FlippedEdge<E, N, V>* preVia = nullptr;209while (via != nullptr && via->isInternal()) {210via->getFlippedRoutingEdge()->myViaSuccessors.push_back(std::make_pair(this, preVia));211preVia = via->getFlippedRoutingEdge();212via = via->getViaSuccessors().front().second;213}214revSource->myViaSuccessors.push_back(std::make_pair(this, preVia));215}216}217}218219220