LCOV - code coverage report
Current view: top level - src - RssWorldModelCreation.cpp (source / functions) Hit Total Coverage
Test: ad_rss_map_integration Lines: 331 441 75.1 %
Date: 2025-07-22 06:56:19 Functions: 11 11 100.0 %
Branches: 332 762 43.6 %

           Branch data     Line data    Source code
       1                 :            : // ----------------- BEGIN LICENSE BLOCK ---------------------------------
       2                 :            : //
       3                 :            : // Copyright (C) 2018-2022 Intel Corporation
       4                 :            : //
       5                 :            : // SPDX-License-Identifier: LGPL-2.1-only
       6                 :            : //
       7                 :            : // ----------------- END LICENSE BLOCK -----------------------------------
       8                 :            : 
       9                 :            : #include "ad/rss/map/RssWorldModelCreation.hpp"
      10                 :            : #include <ad/map/route/Planning.hpp>
      11                 :            : #include <ad/map/route/RouteOperation.hpp>
      12                 :            : #include <ad/rss/world/WorldModelValidInputRange.hpp>
      13                 :            : #include "ad/rss/map/Logging.hpp"
      14                 :            : #include "ad/rss/map/RssObjectConversion.hpp"
      15                 :            : #include "ad/rss/map/RssWorldModelCreator.hpp"
      16                 :            : 
      17                 :            : /*!
      18                 :            :  * @brief namespace rss
      19                 :            :  */
      20                 :            : namespace ad {
      21                 :            : /*!
      22                 :            :  * @brief namespace rss
      23                 :            :  */
      24                 :            : namespace rss {
      25                 :            : /*!
      26                 :            :  * @brief namespace map
      27                 :            :  */
      28                 :            : namespace map {
      29                 :            : 
      30                 :            : const ::ad::physics::Distance RssWorldModelCreation::cMinConnectedRouteLength(100.);
      31                 :            : const ::ad::physics::Distance cNearTermRoadBoundariesRouteLength(10.);
      32                 :            : 
      33                 :        214 : RssWorldModelCreation::RssWorldModelCreation(world::TimeIndex const &time_index,
      34                 :        214 :                                              world::RssDynamics const &defaultEgoRssDynamics)
      35                 :        214 :   : mFinalized(false)
      36                 :        214 :   , mWorldModelLock()
      37                 :        214 :   , mConnectingRoutesCache(nullptr)
      38                 :            : {
      39                 :        214 :   mWorldModel.time_index = time_index;
      40                 :        214 :   mWorldModel.default_ego_vehicle_rss_dynamics = defaultEgoRssDynamics;
      41                 :        214 : }
      42                 :            : 
      43                 :         28 : RssWorldModelCreation::RssWorldModelCreation(::ad::rss::world::TimeIndex const &time_index,
      44                 :            :                                              ::ad::rss::world::RssDynamics const &defaultEgoRssDynamics,
      45                 :         28 :                                              ConnectingRoutesCache &connecting_routes_cache)
      46                 :         28 :   : mFinalized(false)
      47                 :         28 :   , mWorldModelLock()
      48                 :         28 :   , mConnectingRoutesCache(&connecting_routes_cache)
      49                 :            : {
      50                 :         28 :   mWorldModel.time_index = time_index;
      51                 :         28 :   mWorldModel.default_ego_vehicle_rss_dynamics = defaultEgoRssDynamics;
      52                 :         28 : }
      53                 :            : 
      54                 :        242 : world::WorldModel RssWorldModelCreation::getWorldModel()
      55                 :            : {
      56         [ +  - ]:        242 :   const std::lock_guard<std::mutex> lock(mWorldModelLock);
      57         [ -  + ]:        242 :   if (mFinalized)
      58                 :            :   {
      59   [ #  #  #  #  :          0 :     getLogger()->error("RssWorldModelCreation::getWorldModel[:{}]>> error world model already finalized.", mRouteId);
                   #  # ]
      60         [ #  # ]:          0 :     return world::WorldModel();
      61                 :            :   }
      62                 :            : 
      63                 :        242 :   mFinalized = true;
      64                 :        242 :   return std::move(mWorldModel);
      65                 :        242 : }
      66                 :            : 
      67                 :        217 : bool RssWorldModelCreation::appendConstellations(RssObjectData const &egoObjectData,
      68                 :            :                                                  ::ad::map::route::FullRoute const &egoRouteInput,
      69                 :            :                                                  RssObjectData const &otherObjectData,
      70                 :            :                                                  RssRestrictSpeedLimitMode const &restrict_speed_limit_mode,
      71                 :            :                                                  ::ad::map::landmark::LandmarkIdSet const &greenTrafficLights,
      72                 :            :                                                  map::RssConstellationCreationMode const &mode,
      73                 :            :                                                  ::ad::map::lane::LaneIdSet const &relevantLanes)
      74                 :            : {
      75                 :        217 :   RssRouteList egoObjectPredictionHints;
      76                 :        217 :   RssRouteList otherObjectPredictionHints;
      77         [ +  - ]:        217 :   return appendConstellations(egoObjectData,
      78                 :            :                               egoRouteInput,
      79                 :            :                               otherObjectData,
      80                 :            :                               restrict_speed_limit_mode,
      81                 :            :                               greenTrafficLights,
      82                 :            :                               mode,
      83                 :            :                               egoObjectPredictionHints,
      84                 :            :                               otherObjectPredictionHints,
      85                 :        434 :                               relevantLanes);
      86                 :        217 : }
      87                 :            : 
      88                 :        261 : bool RssWorldModelCreation::appendConstellations(RssObjectData const &egoObjectData,
      89                 :            :                                                  ::ad::map::route::FullRoute const &egoRouteInput,
      90                 :            :                                                  RssObjectData const &otherObjectData,
      91                 :            :                                                  RssRestrictSpeedLimitMode const &restrict_speed_limit_mode,
      92                 :            :                                                  ::ad::map::landmark::LandmarkIdSet const &greenTrafficLights,
      93                 :            :                                                  map::RssConstellationCreationMode const &mode,
      94                 :            :                                                  RssRouteList const &egoObjectPredictionHints,
      95                 :            :                                                  RssRouteList const &otherObjectPredictionHints,
      96                 :            :                                                  ::ad::map::lane::LaneIdSet const &relevantLanes)
      97                 :            : {
      98         [ -  + ]:        261 :   if (mFinalized)
      99                 :            :   {
     100   [ #  #  #  # ]:          0 :     getLogger()->error("RssWorldModelCreation::appendConstellations[{}->{}:{}]>> error world model already finalized.",
     101                 :          0 :                        egoObjectData.id,
     102                 :          0 :                        otherObjectData.id,
     103         [ #  # ]:          0 :                        mRouteId);
     104                 :          0 :     return false;
     105                 :            :   }
     106                 :            : 
     107         [ -  + ]:        261 :   if (mode == map::RssConstellationCreationMode::Ignore)
     108                 :            :   {
     109                 :          0 :     return true;
     110                 :            :   }
     111                 :            : 
     112         [ +  - ]:        261 :   auto egoObject = std::make_shared<RssObjectConversion const>(egoObjectData);
     113         [ +  - ]:        261 :   auto otherObject = std::make_shared<RssObjectConversion const>(otherObjectData);
     114   [ +  -  -  +  :        261 :   if (!bool(egoObject) || !bool(otherObject))
                   -  + ]
     115                 :            :   {
     116   [ #  #  #  # ]:          0 :     getLogger()->error("RssWorldModelCreation::appendConstellations[{}->{}:{}]>> error allocating object data.",
     117                 :          0 :                        egoObjectData.id,
     118                 :          0 :                        otherObjectData.id,
     119         [ #  # ]:          0 :                        mRouteId);
     120                 :          0 :     return false;
     121                 :            :   }
     122         [ +  - ]:        261 :   RssWorldModelCreator constellationCreator(restrict_speed_limit_mode, greenTrafficLights, *this);
     123                 :            : 
     124         [ -  + ]:        261 :   if (mode == map::RssConstellationCreationMode::NotRelevant)
     125                 :            :   {
     126         [ #  # ]:          0 :     return constellationCreator.appendNotRelevantConstellation(egoRouteInput, egoObject, otherObject);
     127                 :            :   }
     128                 :            :   else
     129                 :            :   {
     130                 :        261 :     physics::Distance minEgoStoppingDistance;
     131   [ +  -  -  + ]:        261 :     if (!egoObject->calculateConservativeMinStoppingDistance(minEgoStoppingDistance))
     132                 :            :     {
     133   [ #  #  #  # ]:          0 :       getLogger()->error("RssWorldModelCreation::appendConstellations[{}->{}:{}]>> error calculating ego min "
     134                 :            :                          "stopping distance",
     135   [ #  #  #  # ]:          0 :                          egoObject->getId(),
     136         [ #  # ]:          0 :                          otherObject->getId(),
     137                 :          0 :                          mRouteId);
     138                 :          0 :       return false;
     139                 :            :     }
     140                 :        261 :     physics::Distance minOtherStoppingDistance;
     141   [ +  -  -  + ]:        261 :     if (!otherObject->calculateConservativeMinStoppingDistance(minOtherStoppingDistance))
     142                 :            :     {
     143   [ #  #  #  # ]:          0 :       getLogger()->error("RssWorldModelCreation::appendConstellations[{}->{}:{}]>> error calculating other "
     144                 :            :                          "min stopping distance",
     145   [ #  #  #  # ]:          0 :                          egoObject->getId(),
     146         [ #  # ]:          0 :                          otherObject->getId(),
     147                 :          0 :                          mRouteId);
     148                 :          0 :       return false;
     149                 :            :     }
     150                 :            : 
     151                 :            :     // consider the sum of both stopping distances and some minimum distance
     152                 :            :     auto const maxObjectDistance
     153   [ +  -  +  - ]:        261 :       = std::max(minEgoStoppingDistance + minOtherStoppingDistance, mMinimumDistanceToObjectsThatHaveToBeAnalyzed);
     154                 :            : 
     155   [ +  -  +  -  :        261 :     auto const roughObjectDistance = egoObject->getDistanceEstimate(otherObject) - egoObject->getVehicleLength() / 2.
             +  -  +  - ]
     156   [ +  -  +  -  :        522 :       - egoObject->getVehicleWidth() / 2. - otherObject->getVehicleLength() / 2. - otherObject->getVehicleWidth() / 2.;
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     157                 :            :     // early check on the object distance
     158   [ +  -  +  + ]:        261 :     if (roughObjectDistance > maxObjectDistance)
     159                 :            :     {
     160   [ +  -  +  - ]:          6 :       getLogger()->debug("RssWorldModelCreation::appendConstellations[{}->{}:{}]>> object distance {} larger than {} "
     161                 :            :                          "meters: not relevant",
     162   [ +  -  +  - ]:          3 :                          egoObject->getId(),
     163         [ +  - ]:          6 :                          otherObject->getId(),
     164                 :          3 :                          mRouteId,
     165                 :            :                          roughObjectDistance,
     166                 :            :                          maxObjectDistance);
     167                 :            :       auto const appendResult
     168         [ +  - ]:          3 :         = constellationCreator.appendNotRelevantConstellation(egoRouteInput, egoObject, otherObject);
     169                 :          3 :       return appendResult;
     170                 :            :     }
     171                 :            : 
     172         [ +  + ]:        258 :     if (mode == map::RssConstellationCreationMode::Unstructured)
     173                 :            :     {
     174         [ +  - ]:          2 :       return constellationCreator.appendUnstructuredConstellation(egoObject, otherObject);
     175                 :            :     }
     176                 :            :     else
     177                 :            :     {
     178         [ +  - ]:        256 :       return appendStructuredConstellations(constellationCreator,
     179                 :            :                                             egoObject,
     180                 :            :                                             egoRouteInput,
     181                 :            :                                             otherObject,
     182                 :            :                                             egoObjectPredictionHints,
     183                 :            :                                             otherObjectPredictionHints,
     184                 :            :                                             relevantLanes,
     185                 :        256 :                                             maxObjectDistance);
     186                 :            :     }
     187                 :            :   }
     188                 :        261 : }
     189                 :            : 
     190                 :            : // resize the routes in length and width if required
     191                 :            : 
     192                 :            : enum class ResizeRoutePrefixMode
     193                 :            : {
     194                 :            :   KeepRoutePrefix,
     195                 :            :   ShortenRoutePrefix
     196                 :            : };
     197                 :            : 
     198                 :        637 : ::ad::map::route::FullRouteList resizeRoutesIfRequired(RssRouteList const &rssRoutes,
     199                 :            :                                                        physics::Distance const expectedRoutePreviewDistance,
     200                 :            :                                                        ad::map::route::RouteCreationMode const route_creation_mode,
     201                 :            :                                                        ::ad::map::lane::LaneIdSet const &relevantLanes,
     202                 :            :                                                        ResizeRoutePrefixMode const prefix_mode
     203                 :            :                                                        = ResizeRoutePrefixMode::KeepRoutePrefix)
     204                 :            : {
     205                 :        637 :   ::ad::map::route::FullRouteList expandedRoutes;
     206         [ +  + ]:        884 :   for (auto const &rss_route : rssRoutes)
     207                 :            :   {
     208         [ +  - ]:        247 :     auto expanded_route = ad::map::route::getRouteExpandedTo(rss_route.route, route_creation_mode);
     209                 :            :     // handle potential intersection prefix
     210         [ +  + ]:        247 :     if (prefix_mode == ResizeRoutePrefixMode::ShortenRoutePrefix)
     211                 :            :     {
     212         [ +  - ]:         65 :       ::ad::map::route::shortenRoute(rss_route.progress_on_route, expanded_route);
     213                 :            :     }
     214                 :            : 
     215                 :            :     // in case the route is not long enough, we have to extend is
     216                 :        247 :     ::ad::map::route::FullRouteList additionalRoutes;
     217         [ +  - ]:        247 :     auto const desiredRouteLength = rss_route.progress_on_route + expectedRoutePreviewDistance;
     218         [ +  - ]:        247 :     ::ad::map::route::extendRouteToDistance(expanded_route, desiredRouteLength, additionalRoutes, relevantLanes);
     219                 :            : 
     220                 :            :     // and shorten if it's too long and add to results
     221         [ +  - ]:        247 :     ::ad::map::route::shortenRouteToDistance(expanded_route, desiredRouteLength);
     222         [ +  - ]:        247 :     expandedRoutes.push_back(expanded_route);
     223                 :            :     // shorten potential additional routes and add to results
     224         [ +  + ]:        273 :     for (auto &additionalRoute : additionalRoutes)
     225                 :            :     {
     226         [ +  - ]:         26 :       ::ad::map::route::shortenRouteToDistance(additionalRoute, desiredRouteLength);
     227         [ +  - ]:         26 :       expandedRoutes.push_back(additionalRoute);
     228                 :            :     }
     229                 :        247 :   }
     230                 :            : 
     231                 :        637 :   return expandedRoutes;
     232                 :          0 : }
     233                 :            : 
     234                 :        162 : ::ad::rss::map::RssRoute createRssRoute(::ad::map::route::FullRoute const &route,
     235                 :            :                                         ::ad::map::match::Object const &match_object)
     236                 :            : {
     237         [ +  - ]:        162 :   ::ad::rss::map::RssRoute rss_route;
     238         [ +  - ]:        162 :   rss_route.route = route;
     239                 :        162 :   rss_route.progress_on_route = ad::physics::Distance(0.);
     240         [ +  - ]:        162 :   auto findWaypointResult = ::ad::map::route::findCenterWaypoint(match_object, route);
     241         [ +  - ]:        162 :   if (findWaypointResult.isValid())
     242                 :            :   {
     243         [ +  - ]:        162 :     rss_route.progress_on_route = ::ad::map::route::calcLength(findWaypointResult);
     244                 :            :   }
     245                 :        324 :   return rss_route;
     246                 :          0 : }
     247                 :            : 
     248                 :        256 : bool RssWorldModelCreation::appendStructuredConstellations(
     249                 :            :   map::RssWorldModelCreator &constellationCreator,
     250                 :            :   std::shared_ptr<RssObjectConversion const> const &egoObject,
     251                 :            :   ::ad::map::route::FullRoute const &egoRouteInput,
     252                 :            :   std::shared_ptr<RssObjectConversion const> const &otherObject,
     253                 :            :   RssRouteList const &egoObjectPredictionHints,
     254                 :            :   RssRouteList const &otherObjectPredictionHints,
     255                 :            :   ::ad::map::lane::LaneIdSet const &relevantLanes,
     256                 :            :   ad::physics::Distance const &maxConnectingRouteDistance)
     257                 :            : {
     258                 :        256 :   bool result = false;
     259                 :        256 :   bool constellationAppended = false;
     260                 :            : 
     261   [ +  -  -  +  :        256 :   if ((egoObject->getObjectMapMatchedPosition() == nullptr) || (otherObject->getObjectMapMatchedPosition() == nullptr))
                   -  + ]
     262                 :            :   {
     263         [ #  # ]:          0 :     getLogger()->error(
     264                 :            :       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> invalid RssObjectConversion entity passed",
     265   [ #  #  #  # ]:          0 :       egoObject->getId(),
     266         [ #  # ]:          0 :       otherObject->getId(),
     267                 :          0 :       mRouteId);
     268                 :          0 :     return false;
     269                 :            :   }
     270                 :            : 
     271                 :        256 :   auto const &egoMatchObject = *egoObject->getObjectMapMatchedPosition();
     272                 :        256 :   auto const &objectMatchObject = *otherObject->getObjectMapMatchedPosition();
     273                 :            : 
     274         [ -  + ]:        256 :   if (egoMatchObject.map_matched_bounding_box.lane_occupied_regions.empty())
     275                 :            :   {
     276         [ #  # ]:          0 :     getLogger()->warn(
     277                 :            :       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> ego without occupied regions skipping.",
     278   [ #  #  #  # ]:          0 :       egoObject->getId(),
     279         [ #  # ]:          0 :       otherObject->getId(),
     280                 :          0 :       mRouteId);
     281                 :          0 :     return false;
     282                 :            :   }
     283         [ -  + ]:        256 :   if (objectMatchObject.map_matched_bounding_box.lane_occupied_regions.empty())
     284                 :            :   {
     285         [ #  # ]:          0 :     getLogger()->warn(
     286                 :            :       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object without occupied regions skipping.",
     287   [ #  #  #  # ]:          0 :       egoObject->getId(),
     288         [ #  # ]:          0 :       otherObject->getId(),
     289                 :          0 :       mRouteId);
     290                 :          0 :     return false;
     291                 :            :   }
     292                 :            : 
     293                 :            :   try
     294                 :            :   {
     295                 :        256 :     ::ad::map::route::ConnectingRouteList connectingRoutes;
     296                 :        256 :     bool calculateConnectingRoutes = true;
     297                 :            :     // make use of the connecting routes cache
     298         [ +  + ]:        256 :     if (mConnectingRoutesCache != nullptr)
     299                 :            :     {
     300                 :        129 :       calculateConnectingRoutes = !mConnectingRoutesCache->getConnectingRoutes(
     301   [ +  -  +  -  :         43 :         egoObject->getId(), otherObject->getId(), maxConnectingRouteDistance, connectingRoutes);
                   +  - ]
     302                 :            :     }
     303                 :            : 
     304         [ +  + ]:        256 :     if (calculateConnectingRoutes)
     305                 :            :     {
     306                 :            :       // for calculation of the connecting route, the potential route prefix at intersection must be removed
     307                 :            :       // to prevent from creating of merging routes in the past (predictions are only used for merging route)
     308                 :            :       ::ad::map::route::FullRouteList egoPredictedRoutesConnectingRoutes
     309                 :            :         = resizeRoutesIfRequired(egoObjectPredictionHints,
     310                 :            :                                  maxConnectingRouteDistance,
     311                 :            :                                  ad::map::route::RouteCreationMode::AllRoutableLanes,
     312                 :            :                                  relevantLanes,
     313         [ +  - ]:        232 :                                  ResizeRoutePrefixMode::ShortenRoutePrefix);
     314                 :            :       ::ad::map::route::FullRouteList objectPredictedRoutesConnectingRoutes
     315                 :            :         = resizeRoutesIfRequired(otherObjectPredictionHints,
     316                 :            :                                  maxConnectingRouteDistance,
     317                 :            :                                  ad::map::route::RouteCreationMode::AllRoutableLanes,
     318                 :            :                                  relevantLanes,
     319         [ +  - ]:        232 :                                  ResizeRoutePrefixMode::ShortenRoutePrefix);
     320                 :            :       //   Calculate shortest route (ignore driving direction) between the two objects MapMatchedObjectBoundingBox
     321         [ +  - ]:        464 :       connectingRoutes = ::ad::map::route::planning::calculateConnectingRoutes(egoMatchObject,
     322                 :            :                                                                                objectMatchObject,
     323                 :            :                                                                                maxConnectingRouteDistance,
     324                 :            :                                                                                egoPredictedRoutesConnectingRoutes,
     325                 :            :                                                                                objectPredictedRoutesConnectingRoutes,
     326                 :        232 :                                                                                relevantLanes);
     327         [ +  + ]:        232 :       if (mConnectingRoutesCache != nullptr)
     328                 :            :       {
     329                 :         38 :         mConnectingRoutesCache->addConnectingRoutes(
     330   [ +  -  +  -  :         19 :           egoObject->getId(), otherObject->getId(), connectingRoutes, maxConnectingRouteDistance);
                   +  - ]
     331                 :            :       }
     332                 :        232 :     }
     333                 :            : 
     334                 :        256 :     ad::physics::Distance maxConnectingRouteLength(0.);
     335         [ +  + ]:        561 :     for (auto connectingRouteIter = connectingRoutes.begin(); connectingRouteIter != connectingRoutes.end();)
     336                 :            :     {
     337         [ +  - ]:        305 :       auto const connectingRoute = *connectingRouteIter;
     338         [ +  - ]:        305 :       auto const feasibility = ad::map::route::getHeadingFeasibility(connectingRoute);
     339                 :            :       // drop infeasible routes, but ensure to not drop the last one!
     340   [ +  +  +  -  :        305 :       if ((connectingRoutes.size() > 1u) && (feasibility < ad::physics::Probability(0.1)))
             +  +  +  + ]
     341                 :            :       {
     342   [ +  -  +  - ]:          6 :         getLogger()->trace(
     343                 :            :           "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> ignoring infeasible connecting route "
     344                 :            :           "to object:\n {}",
     345   [ +  -  +  - ]:          3 :           egoObject->getId(),
     346         [ +  - ]:          6 :           otherObject->getId(),
     347                 :          3 :           mRouteId,
     348                 :            :           connectingRoute);
     349         [ +  - ]:          3 :         connectingRouteIter = connectingRoutes.erase(connectingRouteIter);
     350                 :            :       }
     351                 :            :       else
     352                 :            :       {
     353         [ +  - ]:        302 :         auto const connectingRouteLength = ad::map::route::calcLength(connectingRoute);
     354         [ +  - ]:        302 :         maxConnectingRouteLength = std::max(maxConnectingRouteLength, connectingRouteLength);
     355   [ +  -  +  - ]:        604 :         getLogger()->trace(
     356                 :            :           "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> connecting route of length {} "
     357                 :            :           "available to object:\n {}",
     358   [ +  -  +  - ]:        302 :           egoObject->getId(),
     359         [ +  - ]:        604 :           otherObject->getId(),
     360                 :        302 :           mRouteId,
     361                 :            :           connectingRouteLength,
     362                 :            :           connectingRoute);
     363                 :        302 :         connectingRouteIter++;
     364                 :            :       }
     365                 :        305 :     }
     366                 :            : 
     367         [ +  + ]:        256 :     if (connectingRoutes.empty())
     368                 :            :     {
     369   [ +  -  +  - ]:         76 :       getLogger()->debug("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> no connecting route "
     370                 :            :                          "available to object within {} meters",
     371   [ +  -  +  - ]:         38 :                          egoObject->getId(),
     372         [ +  - ]:         76 :                          otherObject->getId(),
     373                 :         38 :                          mRouteId,
     374                 :            :                          maxConnectingRouteDistance);
     375                 :            :       auto const appendResult
     376         [ +  - ]:         38 :         = constellationCreator.appendNotRelevantConstellation(egoRouteInput, egoObject, otherObject);
     377                 :         38 :       return appendResult;
     378                 :            :     }
     379                 :            : 
     380                 :            :     // prepare ego route
     381                 :            :     // ensure the prediction spans at least both vehicles: ego-length + connecting-route-length + other-length
     382                 :            :     // ensure the prediction consideres only the same driving direction, otherwhise also mainly opposite use-cases
     383                 :            :     // (e.g. ego-turning-right, other-from-right) will lead to actual intersection use-cases!
     384                 :            :     // Be aware: if the ego is located outside of its nominal driving lane, the computation might ignore it by this,
     385                 :            :     // because predictions could be incomplete
     386                 :            :     // @todo: add support for ego outside nominal routes
     387                 :            :     auto const predictionLength
     388   [ +  -  +  -  :        218 :       = egoObject->getVehicleLength() + maxConnectingRouteLength + otherObject->getVehicleLength();
             +  -  +  - ]
     389                 :            :     // for the rest of the calculations below we stick to the current egoRouteInput if available
     390                 :        218 :     ::ad::map::route::FullRouteList egoPredictedRoutes;
     391         [ +  + ]:        218 :     if (!egoRouteInput.road_segments.empty())
     392                 :            :     {
     393         [ +  - ]:        162 :       auto const rssRoute = createRssRoute(egoRouteInput, egoMatchObject);
     394   [ +  -  +  -  :        486 :       egoPredictedRoutes = resizeRoutesIfRequired(
          +  -  +  +  -  
                      - ]
     395                 :        162 :         {rssRoute}, predictionLength, ::ad::map::route::RouteCreationMode::SameDrivingDirection, relevantLanes);
     396                 :        162 :     }
     397         [ +  - ]:         56 :     else if (egoObjectPredictionHints.empty())
     398                 :            :     {
     399         [ +  - ]:        112 :       egoPredictedRoutes = ::ad::map::route::planning::predictRoutesOnDistance(
     400                 :            :         egoMatchObject,
     401                 :            :         predictionLength,
     402                 :            :         ::ad::map::route::RouteCreationMode::SameDrivingDirection,
     403                 :            :         ::ad::map::route::planning::FilterDuplicatesMode::SubRoutesPreferLongerOnes,
     404                 :         56 :         relevantLanes);
     405                 :            :     }
     406                 :            :     else
     407                 :            :     {
     408         [ #  # ]:          0 :       egoPredictedRoutes = resizeRoutesIfRequired(egoObjectPredictionHints,
     409                 :            :                                                   predictionLength,
     410                 :            :                                                   ::ad::map::route::RouteCreationMode::SameDrivingDirection,
     411                 :          0 :                                                   relevantLanes);
     412                 :            :     }
     413                 :            : 
     414                 :            :     // reset the result to ensure we don't miss anything
     415                 :        218 :     result = false;
     416         [ +  + ]:        520 :     for (auto const &connectingRoute : connectingRoutes)
     417                 :            :     {
     418   [ +  -  +  - ]:        604 :       getLogger()->trace("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> process connecting route "
     419                 :            :                          "available to object:\n {}",
     420   [ +  -  +  - ]:        302 :                          egoObject->getId(),
     421         [ +  - ]:        604 :                          otherObject->getId(),
     422                 :        302 :                          mRouteId,
     423                 :            :                          connectingRoute);
     424                 :        302 :       bool relevantFollowingConstellationFound = false;
     425         [ +  + ]:        302 :       if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Following)
     426                 :            :       {
     427                 :            :         // vehicle following mode: it doesn't matter if there is an intersection in between or not
     428                 :            :         // as the cars might follow each other through the intersection
     429                 :            : 
     430                 :        222 :         bool objectOnOneOfOurRoutes = false;
     431         [ +  + ]:        222 :         if (connectingRoute.route_a.road_segments.empty())
     432                 :            :         {
     433                 :            :           // we are in front -> constellation has to be considered since the other might follow us in our route
     434                 :         88 :           objectOnOneOfOurRoutes = true;
     435                 :            :         }
     436                 :            :         else
     437                 :            :         {
     438         [ +  + ]:        172 :           for (auto const &egoRoute : egoPredictedRoutes)
     439                 :            :           {
     440                 :            :             auto const findObject
     441         [ +  - ]:        143 :               = ::ad::map::route::objectOnRoute(objectMatchObject.map_matched_bounding_box, egoRoute);
     442         [ +  + ]:        143 :             if (findObject.isValid())
     443                 :            :             {
     444                 :        105 :               objectOnOneOfOurRoutes = true;
     445   [ +  -  +  - ]:        210 :               getLogger()->trace(
     446                 :            :                 "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> driving in front on our route:\n"
     447                 :            :                 " objectMatchObject({})\n egoRoute({})",
     448   [ +  -  +  - ]:        105 :                 egoObject->getId(),
     449         [ +  - ]:        210 :                 otherObject->getId(),
     450                 :        105 :                 mRouteId,
     451                 :            :                 objectMatchObject,
     452                 :            :                 egoRoute);
     453                 :        105 :               break;
     454                 :            :             }
     455                 :            :             else
     456                 :            :             {
     457   [ +  -  +  - ]:        114 :               getLogger()->trace("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> driving in front "
     458                 :            :                                  "but not on route:\n"
     459                 :            :                                  " objectMatchObject({})\n egoRoute({})",
     460   [ +  -  +  - ]:         38 :                                  egoObject->getId(),
     461         [ +  - ]:         76 :                                  otherObject->getId(),
     462                 :         38 :                                  mRouteId,
     463                 :            :                                  objectMatchObject,
     464                 :            :                                  egoRoute);
     465                 :            :             }
     466                 :            :           }
     467                 :            :         }
     468         [ +  + ]:        222 :         if (objectOnOneOfOurRoutes)
     469                 :            :         {
     470   [ +  -  +  - ]:        386 :           getLogger()->debug("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> relevant following "
     471                 :            :                              "connecting route found: create "
     472                 :            :                              "same direction use-case\n {}",
     473   [ +  -  +  - ]:        193 :                              egoObject->getId(),
     474         [ +  - ]:        386 :                              otherObject->getId(),
     475                 :        193 :                              mRouteId,
     476                 :            :                              connectingRoute);
     477                 :        386 :           auto const appendResult = constellationCreator.appendNonIntersectionConstellation(
     478         [ +  - ]:        193 :             connectingRoute, world::ConstellationType::SameDirection, egoObject, otherObject);
     479                 :        193 :           result = appendResult;
     480                 :        193 :           constellationAppended = appendResult;
     481                 :        193 :           relevantFollowingConstellationFound = true;
     482                 :            :         }
     483                 :            :         else
     484                 :            :         {
     485                 :            :           // no relevant object found for the following use-case, but still intersection use-case has to be analyzed
     486                 :            :         }
     487                 :            :       }
     488         [ +  + ]:        302 :       if (!relevantFollowingConstellationFound)
     489                 :            :       {
     490   [ +  -  +  + ]:        109 :         if (!::ad::map::route::isConnectedRoutePartOfAnIntersection(connectingRoute))
     491                 :            :         {
     492         [ -  + ]:         14 :           if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Following)
     493                 :            :           {
     494                 :            :             // no relevant object found for the following use-case, without intersection no problem
     495                 :          0 :             result = true;
     496                 :            :           }
     497         [ +  - ]:         14 :           else if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Opposing)
     498                 :            :           {
     499   [ +  -  +  - ]:         28 :             getLogger()->debug("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> no intersections on "
     500                 :            :                                "opposing connecting "
     501                 :            :                                "route found: create "
     502                 :            :                                "opposite direction use-case\n {}",
     503   [ +  -  +  - ]:         14 :                                egoObject->getId(),
     504         [ +  - ]:         28 :                                otherObject->getId(),
     505                 :         14 :                                mRouteId,
     506                 :            :                                connectingRoute);
     507                 :         28 :             auto const appendResult = constellationCreator.appendNonIntersectionConstellation(
     508         [ +  - ]:         14 :               connectingRoute, world::ConstellationType::OppositeDirection, egoObject, otherObject);
     509                 :         14 :             result = appendResult;
     510                 :         14 :             constellationAppended = appendResult;
     511                 :            :           }
     512                 :            :           else
     513                 :            :           {
     514                 :            :             // ConnectingRouteType::Merging
     515                 :            :             // no intersection in between, but merging
     516                 :            :             // we interpret this now as intersection case
     517                 :            :             // @todo: analyze in more detail how such constellations have to be handled, keep as info message for now
     518   [ #  #  #  # ]:          0 :             getLogger()->info("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> no intersections on "
     519                 :            :                               "merging connecting "
     520                 :            :                               "route found: create "
     521                 :            :                               "merging-intersection same prio use-case\n {}",
     522   [ #  #  #  # ]:          0 :                               egoObject->getId(),
     523         [ #  # ]:          0 :                               otherObject->getId(),
     524                 :          0 :                               mRouteId,
     525                 :            :                               connectingRoute);
     526                 :          0 :             auto const appendResult = constellationCreator.appendMergingConstellation(
     527         [ #  # ]:          0 :               connectingRoute, world::ConstellationType::IntersectionSamePriority, egoObject, otherObject);
     528                 :          0 :             result = appendResult;
     529                 :          0 :             constellationAppended = appendResult;
     530                 :            :           }
     531                 :            :         }
     532                 :            :         else
     533                 :            :         {
     534                 :         95 :           result = true;
     535                 :            :           // case: ConnectingRouteType::Following with intersections
     536                 :            :           // case: ConnectingRouteType::Opposing with intersections
     537                 :            :           // or:   ConnectingRouteType::Merging with intersections
     538                 :         95 :           bool objectPredictedRoutesProcessed = false;
     539                 :         95 :           ::ad::map::route::FullRouteList objectPredictedRoutes;
     540         [ +  + ]:        198 :           for (auto const &egoRoute : egoPredictedRoutes)
     541                 :            :           {
     542   [ +  -  +  - ]:        206 :             getLogger()->trace(
     543                 :            :               "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> investigate egoRoute({})",
     544   [ +  -  +  - ]:        103 :               egoObject->getId(),
     545         [ +  - ]:        206 :               otherObject->getId(),
     546                 :        103 :               mRouteId,
     547                 :            :               egoRoute);
     548                 :            :             // @todo: intersection creation has to support also creation of already entered intersections
     549                 :            :             // to get intersections currently driving in also considered appropriate!!
     550                 :            :             // The below is calculated wrong if there is -- besides the currently ignored entered intersection another
     551                 :            :             // one
     552                 :            :             // ...
     553                 :            :             //
     554         [ +  - ]:        103 :             auto intersectionsOnEgoRoute = ::ad::map::intersection::Intersection::getIntersectionsForRoute(egoRoute);
     555                 :        103 :             if (intersectionsOnEgoRoute.empty()
     556   [ +  +  -  +  :        103 :                 && (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Merging))
                   -  + ]
     557                 :            :             {
     558   [ #  #  #  # ]:          0 :               getLogger()->debug(
     559                 :            :                 "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> no intersections on "
     560                 :            :                 "route found: create"
     561                 :            :                 "merging-intersection same prio use-case:\n egoRoute({})",
     562   [ #  #  #  # ]:          0 :                 egoObject->getId(),
     563         [ #  # ]:          0 :                 otherObject->getId(),
     564                 :          0 :                 mRouteId,
     565                 :            :                 egoRoute);
     566                 :          0 :               auto const appendResult = constellationCreator.appendMergingConstellation(
     567         [ #  # ]:          0 :                 connectingRoute, world::ConstellationType::IntersectionSamePriority, egoObject, otherObject);
     568   [ #  #  #  # ]:          0 :               result = result && appendResult;
     569                 :          0 :               constellationAppended |= appendResult;
     570                 :            :             }
     571                 :        103 :             else if (intersectionsOnEgoRoute.empty()
     572   [ +  +  -  +  :        103 :                      && (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Following))
                   +  - ]
     573                 :            :             {
     574                 :            :               // no intersection for the following use-case, then irrelevant
     575                 :            :             }
     576                 :            :             else
     577                 :            :             {
     578         [ +  + ]:        103 :               if (!objectPredictedRoutesProcessed)
     579                 :            :               {
     580                 :         95 :                 objectPredictedRoutesProcessed = true;
     581                 :            :                 // ensure the prediction consideres only the same driving direction, otherwhise also mainly opposite
     582                 :            :                 // use-cases (e.g. ego-turning-right, other-from-right) will lead to actual intersection use-cases! Be
     583                 :            :                 // aware: if the object is located outside of its nominal driving lane, the computation might ignore it
     584                 :            :                 // by this, because predictions might be incomplete
     585                 :            :                 // @todo: add support for objects outside nominal routes
     586         [ +  + ]:         95 :                 if (otherObjectPredictionHints.empty())
     587                 :            :                 {
     588                 :            :                   // no hints, so predict on our own
     589         [ +  - ]:        168 :                   objectPredictedRoutes = ::ad::map::route::planning::predictRoutesOnDistance(
     590                 :            :                     objectMatchObject,
     591                 :            :                     predictionLength,
     592                 :            :                     ::ad::map::route::RouteCreationMode::SameDrivingDirection,
     593                 :            :                     ::ad::map::route::planning::FilterDuplicatesMode::SubRoutesPreferLongerOnes,
     594                 :         84 :                     relevantLanes);
     595                 :            :                 }
     596                 :            :                 else
     597                 :            :                 {
     598                 :            :                   objectPredictedRoutes
     599         [ +  - ]:         22 :                     = resizeRoutesIfRequired(otherObjectPredictionHints,
     600                 :            :                                              predictionLength,
     601                 :            :                                              ::ad::map::route::RouteCreationMode::SameDrivingDirection,
     602                 :         11 :                                              relevantLanes);
     603                 :            :                 }
     604                 :            :               }
     605         [ +  + ]:        314 :               for (auto const &objectRoute : objectPredictedRoutes)
     606                 :            :               {
     607   [ +  -  +  - ]:        422 :                 getLogger()->trace(
     608                 :            :                   "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> investigate objectRoute({})",
     609   [ +  -  +  - ]:        211 :                   egoObject->getId(),
     610         [ +  - ]:        422 :                   otherObject->getId(),
     611                 :        211 :                   mRouteId,
     612                 :            :                   objectRoute);
     613         [ +  - ]:        211 :                 auto intersectionsOnRoute = intersectionsOnEgoRoute;
     614                 :        211 :                 auto const *intersectionOtherRoute = &objectRoute;
     615         [ +  + ]:        211 :                 if (intersectionsOnRoute.empty())
     616                 :            :                 {
     617                 :            :                   // no intersection on ego route, but within opposing connectingRoute
     618                 :            :                   // Currently this can happen if the ego vehicle route starts inside the intersection,
     619                 :            :                   // and the object is outside, let's then take the intersections on the object route
     620         [ +  - ]:         16 :                   intersectionsOnRoute = ::ad::map::intersection::Intersection::getIntersectionsForRoute(objectRoute);
     621         [ -  + ]:         16 :                   if (intersectionsOnRoute.empty())
     622                 :            :                   {
     623                 :            :                     // looks like not a straight forward road layout, but
     624                 :            :                     // need to ensure we don't miss this constellation
     625                 :            :                     // @todo: analyze when this can happen and if the created constellation is appropriate
     626   [ #  #  #  # ]:          0 :                     getLogger()->debug(
     627                 :            :                       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> no intersections "
     628                 :            :                       "on route found: create "
     629                 :            :                       "opposite direction use-case:\n"
     630                 :            :                       " egoRoute({})",
     631   [ #  #  #  # ]:          0 :                       egoObject->getId(),
     632         [ #  # ]:          0 :                       otherObject->getId(),
     633                 :          0 :                       mRouteId,
     634                 :            :                       egoRoute);
     635                 :          0 :                     auto const appendResult = constellationCreator.appendNonIntersectionConstellation(
     636         [ #  # ]:          0 :                       connectingRoute, world::ConstellationType::OppositeDirection, egoObject, otherObject);
     637   [ #  #  #  # ]:          0 :                     result = result && appendResult;
     638                 :          0 :                     constellationAppended |= appendResult;
     639                 :            :                   }
     640                 :            :                   else
     641                 :            :                   {
     642                 :         16 :                     intersectionOtherRoute = &egoRoute;
     643   [ +  -  +  - ]:         48 :                     getLogger()->trace("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> no "
     644                 :            :                                        "intersection on ego route, but"
     645                 :            :                                        "opposite connecting route; checking intersections in object route:\n"
     646                 :            :                                        " egoRoute({})\n objectRoute({})",
     647   [ +  -  +  - ]:         16 :                                        egoObject->getId(),
     648         [ +  - ]:         32 :                                        otherObject->getId(),
     649                 :         16 :                                        mRouteId,
     650                 :            :                                        egoRoute,
     651                 :            :                                        objectRoute);
     652                 :            :                   }
     653                 :            :                 }
     654                 :            : 
     655         [ +  + ]:        422 :                 for (auto const &intersection : intersectionsOnRoute)
     656                 :            :                 {
     657   [ +  -  +  + ]:        211 :                   if (!intersection->objectRouteCrossesIntersection(*intersectionOtherRoute))
     658                 :            :                   {
     659   [ +  -  +  - ]:         90 :                     getLogger()->trace(
     660                 :            :                       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> found object "
     661                 :            :                       "route not crossing "
     662                 :            :                       "intersection on route:\n"
     663                 :            :                       " egoRoute({})\n objectRoute({})\n intersection({})",
     664   [ +  -  +  - ]:         30 :                       egoObject->getId(),
     665         [ +  - ]:         60 :                       otherObject->getId(),
     666                 :         30 :                       mRouteId,
     667                 :            :                       egoRoute,
     668                 :            :                       objectRoute,
     669         [ +  - ]:         30 :                       intersection->entryParaPoints());
     670                 :            :                   }
     671   [ +  -  +  + ]:        181 :                   else if (intersection->objectRouteFromSameArmAsIntersectionRoute(*intersectionOtherRoute))
     672                 :            :                   {
     673         [ +  + ]:         16 :                     if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Opposing)
     674                 :            :                     {
     675                 :            :                       // This happens e.g. if the object has an opposite connecting route, but the current considered
     676                 :            :                       // prediction starts on ego intersection arm and the object route is still touching the ego's
     677                 :            :                       // route could be modeled as following case, but then we would require the actual following route.
     678                 :            :                       // And the object should still be safely considered by the actual opposite case predictions.
     679                 :            :                       // -> this case is just ignored for now: requires more thorough analysis in future
     680   [ +  -  +  - ]:          9 :                       getLogger()->trace(
     681                 :            :                         "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route from "
     682                 :            :                         "same arm as intersection and opposing connecting route: ignore\n"
     683                 :            :                         " egoRoute({})\n objectRoute({})\n intersection({})\n {}",
     684   [ +  -  +  - ]:          3 :                         egoObject->getId(),
     685         [ +  - ]:          6 :                         otherObject->getId(),
     686                 :          3 :                         mRouteId,
     687                 :            :                         egoRoute,
     688                 :            :                         objectRoute,
     689         [ +  - ]:          3 :                         intersection->entryParaPoints(),
     690                 :            :                         connectingRoute);
     691                 :            :                     }
     692         [ -  + ]:         13 :                     else if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Merging)
     693                 :            :                     {
     694                 :            :                       // This can happen if the intersection is not necessarily the first intersection of both vehicles
     695                 :            :                       // and so being a secondary merging use-case at that far intersection
     696                 :            :                       // Therefore, later this constellation might switch to an actual merging connected route or
     697                 :            :                       // following use case from above. Now: Create an intersection constellation
     698                 :            :                       // @todo: find out more here: is it required now to search the two routes for a merge even before
     699                 :            :                       // the intersection?
     700   [ #  #  #  # ]:          0 :                       getLogger()->debug(
     701                 :            :                         "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route from "
     702                 :            :                         "same arm as intersection "
     703                 :            :                         "looks like merging constellation far in future: create intersection constellation\n"
     704                 :            :                         " egoRoute({})\n objectRoute({})\n intersection({})\n {}",
     705   [ #  #  #  # ]:          0 :                         egoObject->getId(),
     706         [ #  # ]:          0 :                         otherObject->getId(),
     707                 :          0 :                         mRouteId,
     708                 :            :                         egoRoute,
     709                 :            :                         objectRoute,
     710         [ #  # ]:          0 :                         intersection->entryParaPoints(),
     711                 :            :                         connectingRoute);
     712         [ #  # ]:          0 :                       auto const appendResult = constellationCreator.appendIntersectionConstellation(
     713                 :            :                         intersection, egoRoute, objectRoute, *intersectionOtherRoute, egoObject, otherObject);
     714   [ #  #  #  # ]:          0 :                       result = result && appendResult;
     715                 :          0 :                       constellationAppended |= appendResult;
     716                 :            :                     }
     717                 :            :                     else
     718                 :            :                     {
     719                 :            :                       // intersection following use-case, should have been found in the following use case above
     720                 :            :                       // ignore for now
     721   [ +  -  +  - ]:         39 :                       getLogger()->trace(
     722                 :            :                         "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route from "
     723                 :            :                         "same arm as intersection and follwing connecting route: ignore\n"
     724                 :            :                         " egoRoute({})\n objectRoute({})\n intersection({})\n {}",
     725   [ +  -  +  - ]:         13 :                         egoObject->getId(),
     726         [ +  - ]:         26 :                         otherObject->getId(),
     727                 :         13 :                         mRouteId,
     728                 :            :                         egoRoute,
     729                 :            :                         objectRoute,
     730         [ +  - ]:         13 :                         intersection->entryParaPoints(),
     731                 :            :                         connectingRoute);
     732                 :            :                     }
     733                 :            :                   }
     734         [ +  - ]:        165 :                   else if (intersection->objectRouteOppositeToIntersectionRoute(*intersectionOtherRoute)
     735   [ +  +  +  -  :        165 :                            || !intersection->objectRouteCrossesIntersectionRoute(*intersectionOtherRoute))
             +  +  +  + ]
     736                 :            :                   {
     737         [ +  + ]:        134 :                     if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Opposing)
     738                 :            :                     {
     739                 :            :                       // here, the connecting route should be correct; otherwise we would not oppose to each other
     740   [ +  -  +  - ]:        242 :                       getLogger()->debug(
     741                 :            :                         "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route "
     742                 :            :                         "opposite and not crossing: "
     743                 :            :                         "opposite direction constellation:\n"
     744                 :            :                         " egoRoute({})\n objectRoute({})\n intersection({})",
     745   [ +  -  +  - ]:        121 :                         egoObject->getId(),
     746         [ +  - ]:        242 :                         otherObject->getId(),
     747                 :        121 :                         mRouteId,
     748                 :            :                         egoRoute,
     749                 :            :                         objectRoute,
     750         [ +  - ]:        121 :                         intersection->entryParaPoints());
     751                 :        242 :                       auto const appendResult = constellationCreator.appendNonIntersectionConstellation(
     752         [ +  - ]:        121 :                         connectingRoute, world::ConstellationType::OppositeDirection, egoObject, otherObject);
     753   [ +  -  +  - ]:        121 :                       result = result && appendResult;
     754                 :        121 :                       constellationAppended |= appendResult;
     755                 :            :                     }
     756         [ -  + ]:         13 :                     else if (connectingRoute.type == ::ad::map::route::ConnectingRouteType::Merging)
     757                 :            :                     {
     758                 :            :                       // This can happen if the cars are too far away from each other for creating an opposing
     759                 :            :                       // connecting route, but we find two predictions of the two vehicles ending at the same
     760                 :            :                       // intersection
     761                 :            :                       // Therefore, later this constellation might switch to the opposite type above.
     762                 :            :                       // Now: Create an intersection constellation
     763   [ #  #  #  # ]:          0 :                       getLogger()->debug(
     764                 :            :                         "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route "
     765                 :            :                         "opposite and not crossing, but "
     766                 :            :                         "merging constellation: create "
     767                 :            :                         "intersection constellation\n"
     768                 :            :                         " egoRoute({})\n objectRoute({})\n intersection({})\n {}",
     769   [ #  #  #  # ]:          0 :                         egoObject->getId(),
     770         [ #  # ]:          0 :                         otherObject->getId(),
     771                 :          0 :                         mRouteId,
     772                 :            :                         egoRoute,
     773                 :            :                         objectRoute,
     774         [ #  # ]:          0 :                         intersection->entryParaPoints(),
     775                 :            :                         connectingRoute);
     776         [ #  # ]:          0 :                       auto const appendResult = constellationCreator.appendIntersectionConstellation(
     777                 :            :                         intersection, egoRoute, objectRoute, *intersectionOtherRoute, egoObject, otherObject);
     778   [ #  #  #  # ]:          0 :                       result = result && appendResult;
     779                 :          0 :                       constellationAppended |= appendResult;
     780                 :            :                     }
     781                 :            :                     else
     782                 :            :                     {
     783                 :            :                       // intersection following use-case, but object route doesn not cross, strange.
     784                 :            :                       // ignore for now
     785   [ +  -  +  - ]:         39 :                       getLogger()->trace(
     786                 :            :                         "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route "
     787                 :            :                         "opposite and not crossing: ignore"
     788                 :            :                         " egoRoute({})\n objectRoute({})\n intersection({})\n {}",
     789   [ +  -  +  - ]:         13 :                         egoObject->getId(),
     790         [ +  - ]:         26 :                         otherObject->getId(),
     791                 :         13 :                         mRouteId,
     792                 :            :                         egoRoute,
     793                 :            :                         objectRoute,
     794         [ +  - ]:         13 :                         intersection->entryParaPoints(),
     795                 :            :                         connectingRoute);
     796                 :            :                     }
     797                 :            :                   }
     798                 :            :                   else
     799                 :            :                   {
     800   [ +  -  +  - ]:         62 :                     getLogger()->debug(
     801                 :            :                       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> object route "
     802                 :            :                       "crosses intersection route: "
     803                 :            :                       "intersection constellation\n"
     804                 :            :                       " egoRoute({})\n objectRoute({})\n intersectionLanesOnRoute({})\n intersection({})",
     805   [ +  -  +  - ]:         31 :                       egoObject->getId(),
     806         [ +  - ]:         62 :                       otherObject->getId(),
     807                 :         31 :                       mRouteId,
     808                 :            :                       egoRoute,
     809                 :            :                       objectRoute,
     810         [ +  - ]:         31 :                       intersection->paraPointsOnRoute(),
     811         [ +  - ]:         31 :                       intersection->entryParaPoints());
     812         [ +  - ]:         31 :                     auto const appendResult = constellationCreator.appendIntersectionConstellation(
     813                 :            :                       intersection, egoRoute, objectRoute, *intersectionOtherRoute, egoObject, otherObject);
     814   [ +  -  +  - ]:         31 :                     result = result && appendResult;
     815                 :         31 :                     constellationAppended |= appendResult;
     816                 :            :                   }
     817                 :            :                 }
     818                 :        211 :               }
     819                 :            :             }
     820                 :        103 :           }
     821                 :         95 :         }
     822                 :            :       }
     823                 :            :     }
     824         [ +  + ]:        256 :   }
     825         [ -  - ]:          0 :   catch (std::exception const &e)
     826                 :            :   {
     827   [ -  -  -  - ]:          0 :     getLogger()->error(
     828                 :            :       "RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> Failed. Catched exception: {}",
     829   [ -  -  -  - ]:          0 :       egoObject->getId(),
     830         [ -  - ]:          0 :       otherObject->getId(),
     831                 :          0 :       mRouteId,
     832                 :          0 :       e.what());
     833                 :          0 :   }
     834                 :            : 
     835         [ +  + ]:        218 :   if (!constellationAppended)
     836                 :            :   {
     837         [ +  - ]:         27 :     if (result)
     838                 :            :     {
     839         [ +  - ]:         81 :       getLogger()->debug("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> detailed analysis did not "
     840                 :            :                          "find any relevant "
     841                 :            :                          "constellation. Append non relevant constellation\n"
     842                 :            :                          " objectMatchObject({})\n egoMatchObject({})\n egoRoute({})",
     843   [ +  -  +  - ]:         27 :                          egoObject->getId(),
     844         [ +  - ]:         54 :                          otherObject->getId(),
     845                 :         27 :                          mRouteId,
     846                 :            :                          objectMatchObject,
     847                 :            :                          egoMatchObject,
     848                 :            :                          egoRouteInput);
     849                 :            :     }
     850                 :            :     else
     851                 :            :     {
     852         [ #  # ]:          0 :       getLogger()->info("RssWorldModelCreation::appendStructuredConstellations[{}->{}:{}]>> an operation failed and no "
     853                 :            :                         "constellation could have been "
     854                 :            :                         "created. Try to append non relevant constellation\n"
     855                 :            :                         " objectMatchObject({})\n egoMatchObject({})\n egoRoute({})",
     856   [ #  #  #  # ]:          0 :                         egoObject->getId(),
     857         [ #  # ]:          0 :                         otherObject->getId(),
     858                 :          0 :                         mRouteId,
     859                 :            :                         objectMatchObject,
     860                 :            :                         egoMatchObject,
     861                 :            :                         egoRouteInput);
     862                 :            :     }
     863                 :            :     auto const appendResult
     864         [ +  - ]:         27 :       = constellationCreator.appendNotRelevantConstellation(egoRouteInput, egoObject, otherObject);
     865   [ +  -  +  - ]:         27 :     result = result && appendResult;
     866                 :            :   }
     867                 :            : 
     868                 :        218 :   return result;
     869                 :            : }
     870                 :            : 
     871                 :          3 : ::ad::map::route::FullRoute shortenRoadBoundariesRouteIfRequired(::ad::map::route::FullRoute const &route,
     872                 :            :                                                                  ::ad::map::match::Object const &match_object,
     873                 :            :                                                                  physics::Distance const expectedRoutePreviewDistance)
     874                 :            : {
     875         [ +  - ]:          3 :   ::ad::map::route::FullRoute shortenedRoute = route;
     876         [ +  - ]:          3 :   auto findWaypointResult = ::ad::map::route::findCenterWaypoint(match_object, shortenedRoute);
     877         [ +  - ]:          3 :   if (findWaypointResult.isValid())
     878                 :            :   {
     879         [ +  - ]:          3 :     auto const progress_on_route = ::ad::map::route::calcLength(findWaypointResult);
     880                 :            :     // remove potential intersection prefix
     881         [ +  - ]:          3 :     ::ad::map::route::shortenRoute(progress_on_route, shortenedRoute);
     882                 :            :     // and shorten if it's too long
     883         [ +  - ]:          3 :     ::ad::map::route::shortenRouteToDistance(
     884                 :            :       shortenedRoute, expectedRoutePreviewDistance, ::ad::map::route::ShortenRouteToDistanceMode::AllowCutIntersection);
     885                 :            :   }
     886                 :          6 :   return shortenedRoute;
     887                 :          0 : }
     888                 :            : 
     889                 :         34 : bool RssWorldModelCreation::appendRoadBoundaries(RssObjectData const &egoObjectData,
     890                 :            :                                                  ::ad::map::route::FullRoute const &inputRoute,
     891                 :            :                                                  RssAppendRoadBoundariesMode const operationMode)
     892                 :            : {
     893         [ -  + ]:         34 :   if (mFinalized)
     894                 :            :   {
     895         [ #  # ]:          0 :     getLogger()->error("RssWorldModelCreation::appendRoadBoundaries[{}:{}]>> error world model already finalized.",
     896                 :          0 :                        egoObjectData.id,
     897         [ #  # ]:          0 :                        mRouteId);
     898                 :          0 :     return false;
     899                 :            :   }
     900         [ +  + ]:         34 :   if (operationMode == RssAppendRoadBoundariesMode::Off)
     901                 :            :   {
     902                 :         28 :     return true;
     903                 :            :   }
     904         [ +  + ]:          6 :   if (egoObjectData.match_object.map_matched_bounding_box.lane_occupied_regions.empty())
     905                 :            :   {
     906         [ +  - ]:          2 :     getLogger()->warn("RssWorldModelCreation::appendRoadBoundaries[{}:{}]>> ego without occupied regions skipping.",
     907                 :          1 :                       egoObjectData.id,
     908         [ +  - ]:          1 :                       mRouteId);
     909                 :          1 :     return false;
     910                 :            :   }
     911                 :            : 
     912         [ +  + ]:          5 :   if (inputRoute.road_segments.empty())
     913                 :            :   {
     914                 :          1 :     return false;
     915                 :            :   }
     916                 :          4 :   bool result = false;
     917                 :            :   try
     918                 :            :   {
     919         [ +  + ]:          4 :     auto egoObject = std::make_shared<RssObjectConversion const>(egoObjectData);
     920         [ -  + ]:          3 :     if (!bool(egoObject))
     921                 :            :     {
     922   [ #  #  #  # ]:          0 :       getLogger()->error("RssWorldModelCreation::appendRoadBoundaries[{}:{}]>> error allocating object data.",
     923                 :          0 :                          egoObjectData.id,
     924         [ #  # ]:          0 :                          mRouteId);
     925                 :          0 :       return false;
     926                 :            :     }
     927                 :            : 
     928                 :            :     // for the analysis we are only interested in the near term route
     929                 :            :     ::ad::map::route::FullRoute route = shortenRoadBoundariesRouteIfRequired(
     930         [ +  - ]:          3 :       inputRoute, *egoObject->getObjectMapMatchedPosition(), cNearTermRoadBoundariesRouteLength);
     931                 :            : 
     932   [ +  +  +  - ]:          3 :     switch (operationMode)
     933                 :            :     {
     934                 :          1 :       case RssAppendRoadBoundariesMode::RouteOnly:
     935                 :            :       {
     936         [ -  + ]:          1 :         if (route.route_creation_mode != ::ad::map::route::RouteCreationMode::SameDrivingDirection)
     937                 :            :         {
     938         [ #  # ]:          0 :           route = ::ad::map::route::getRouteExpandedToSameDrivingDirectionLanesOnly(route);
     939                 :            :         }
     940                 :          1 :         break;
     941                 :            :       }
     942                 :          1 :       case RssAppendRoadBoundariesMode::ExpandRouteToOppositeLanes:
     943                 :            :       {
     944         [ +  - ]:          1 :         if (route.route_creation_mode != ::ad::map::route::RouteCreationMode::AllRoutableLanes)
     945                 :            :         {
     946         [ +  - ]:          1 :           route = ::ad::map::route::getRouteExpandedToOppositeLanes(route);
     947                 :            :         }
     948                 :          1 :         break;
     949                 :            :       }
     950                 :          1 :       case RssAppendRoadBoundariesMode::ExpandRouteToAllNeighbors:
     951                 :            :       {
     952         [ +  - ]:          1 :         if (route.route_creation_mode != ::ad::map::route::RouteCreationMode::AllNeighborLanes)
     953                 :            :         {
     954         [ +  - ]:          1 :           route = ::ad::map::route::getRouteExpandedToAllNeighborLanes(route);
     955                 :            :         }
     956                 :          1 :         break;
     957                 :            :       }
     958                 :          0 :       default:
     959                 :          0 :         break;
     960                 :            :     }
     961                 :            : 
     962         [ +  - ]:          3 :     RssWorldModelCreator constellationCreator(*this);
     963   [ +  -  +  - ]:          6 :     getLogger()->debug("RssWorldModelCreation::appendRoadBoundaries[{}:{}]>>\n"
     964                 :            :                        " egoRoute({})\n egoObject({})",
     965                 :          3 :                        egoObjectData.id,
     966         [ +  - ]:          3 :                        mRouteId,
     967                 :            :                        route,
     968                 :            :                        egoObjectData);
     969         [ +  - ]:          3 :     result = constellationCreator.appendRoadBoundaryConstellations(route, egoObject);
     970         [ +  - ]:          3 :   }
     971         [ -  + ]:          1 :   catch (std::exception const &e)
     972                 :            :   {
     973   [ +  -  +  - ]:          2 :     getLogger()->error("RssWorldModelCreation::appendRoadBoundaries[{}:{}]>> Failed. Catched exception: {}",
     974                 :          1 :                        egoObjectData.id,
     975                 :          1 :                        mRouteId,
     976         [ +  - ]:          2 :                        e.what());
     977                 :          1 :   }
     978                 :          4 :   return result;
     979                 :            : }
     980                 :            : 
     981                 :        435 : bool RssWorldModelCreation::appendConstellationToWorldModel(world::Constellation const &constellation)
     982                 :            : {
     983         [ +  - ]:        435 :   const std::lock_guard<std::mutex> lock(mWorldModelLock);
     984         [ -  + ]:        435 :   if (mFinalized)
     985                 :            :   {
     986   [ #  #  #  # ]:          0 :     getLogger()->error(
     987         [ #  # ]:          0 :       "RssWorldModelCreation::appendConstellationToWorldModel(:{})>> error world model already finalized.", mRouteId);
     988                 :          0 :     return false;
     989                 :            :   }
     990                 :            : 
     991         [ +  - ]:        435 :   mWorldModel.constellations.push_back(constellation);
     992                 :        435 :   return true;
     993                 :        435 : }
     994                 :            : 
     995                 :            : } // namespace map
     996                 :            : } // namespace rss
     997                 :            : } // namespace ad

Generated by: LCOV version 1.14