LCOV - code coverage report
Current view: top level - src/lane - LaneOperation.cpp (source / functions) Hit Total Coverage
Test: ad_map_access Lines: 340 398 85.4 %
Date: 2022-10-04 09:48:07 Functions: 49 50 98.0 %
Branches: 302 590 51.2 %

           Branch data     Line data    Source code
       1                 :            : // ----------------- BEGIN LICENSE BLOCK ---------------------------------
       2                 :            : //
       3                 :            : // Copyright (C) 2018-2021 Intel Corporation
       4                 :            : //
       5                 :            : // SPDX-License-Identifier: MIT
       6                 :            : //
       7                 :            : // ----------------- END LICENSE BLOCK -----------------------------------
       8                 :            : 
       9                 :            : #include "ad/map/lane/LaneOperation.hpp"
      10                 :            : 
      11                 :            : #include <algorithm>
      12                 :            : #include "LaneOperationPrivate.hpp"
      13                 :            : #include "ad/map/access/Operation.hpp"
      14                 :            : #include "ad/map/lane/BorderOperation.hpp"
      15                 :            : #include "ad/map/match/AdMapMatching.hpp"
      16                 :            : #include "ad/map/match/MapMatchedOperation.hpp"
      17                 :            : #include "ad/map/point/Operation.hpp"
      18                 :            : #include "ad/map/route/LaneIntervalOperation.hpp"
      19                 :            : #include "ad/physics/RangeOperation.hpp"
      20                 :            : 
      21                 :            : namespace ad {
      22                 :            : namespace map {
      23                 :            : namespace lane {
      24                 :            : 
      25                 :     295655 : Lane::ConstPtr getLanePtr(LaneId const &id)
      26                 :            : {
      27                 :     295655 :   auto const lane = access::getStore().getLanePtr(id);
      28                 :            : 
      29         [ +  + ]:     295655 :   if (!bool(lane))
      30                 :            :   {
      31         [ +  - ]:          3 :     throw std::invalid_argument("ad::map::lane::getLane: LaneId not found in store");
      32                 :            :   }
      33                 :     295652 :   return lane;
      34                 :            : }
      35                 :            : 
      36                 :     202848 : Lane const &getLane(LaneId const &id)
      37                 :            : {
      38                 :     202848 :   return *getLanePtr(id);
      39                 :            : }
      40                 :            : 
      41                 :         19 : LaneIdList getLanes()
      42                 :            : {
      43                 :         19 :   return access::getStore().getLanes();
      44                 :            : }
      45                 :            : 
      46                 :     123907 : void interpolateHeadingParametricPoints(physics::Distance const &length,
      47                 :            :                                         physics::ParametricValue const &headingT,
      48                 :            :                                         physics::ParametricValue &longTStart,
      49                 :            :                                         physics::ParametricValue &longTEnd)
      50                 :            : {
      51                 :            :   // we target an area of +- 5cm around the point to determine the heading
      52   [ +  -  -  + ]:     123907 :   if (length < physics::Distance(0.1))
      53                 :            :   {
      54                 :          0 :     longTStart = physics::ParametricValue(0.);
      55                 :          0 :     longTEnd = physics::ParametricValue(1.);
      56                 :            :   }
      57                 :            :   else
      58                 :            :   {
      59         [ +  - ]:     123907 :     physics::ParametricValue deltaOffset(physics::Distance(0.1) / length);
      60         [ +  - ]:     123907 :     physics::ParametricValue deltaOffsetHalf = deltaOffset / 2.;
      61   [ +  -  +  -  :     123907 :     if (headingT > physics::ParametricValue(1.) - deltaOffsetHalf)
                   +  + ]
      62                 :            :     {
      63         [ +  - ]:      23803 :       longTStart = physics::ParametricValue(1.) - deltaOffset;
      64                 :      23803 :       longTEnd = physics::ParametricValue(1.);
      65                 :            :     }
      66   [ +  -  +  + ]:     100104 :     else if (headingT < deltaOffsetHalf)
      67                 :            :     {
      68                 :      20606 :       longTStart = physics::ParametricValue(0.);
      69                 :      20606 :       longTEnd = deltaOffset;
      70                 :            :     }
      71                 :            :     else
      72                 :            :     {
      73         [ +  - ]:      79498 :       longTStart = headingT - deltaOffsetHalf;
      74         [ +  - ]:      79498 :       longTEnd = headingT + deltaOffsetHalf;
      75                 :            :     }
      76                 :            :   }
      77                 :     123907 : }
      78                 :            : 
      79                 :     123907 : point::ECEFHeading getLaneECEFDirection(Lane const &lane, point::ParaPoint const &paraPoint)
      80                 :            : {
      81                 :     123907 :   physics::ParametricValue longTStart;
      82                 :     123907 :   physics::ParametricValue longTEnd;
      83         [ +  - ]:     123907 :   interpolateHeadingParametricPoints(lane.length, paraPoint.parametricOffset, longTStart, longTEnd);
      84                 :            : 
      85         [ +  - ]:     123907 :   point::ECEFPoint const laneDirStart = getParametricPoint(lane, longTStart, physics::ParametricValue(.5));
      86         [ +  - ]:     123907 :   point::ECEFPoint const laneDirEnd = getParametricPoint(lane, longTEnd, physics::ParametricValue(.5));
      87         [ +  - ]:     123907 :   point::ECEFHeading const laneDirection = point::createECEFHeading(laneDirStart, laneDirEnd);
      88                 :     247814 :   return laneDirection;
      89                 :            : }
      90                 :            : 
      91                 :     123865 : point::ECEFHeading getLaneECEFHeading(match::MapMatchedPosition const &mapMatchedPosition)
      92                 :            : {
      93                 :     123865 :   return getLaneECEFHeading(mapMatchedPosition.lanePoint.paraPoint);
      94                 :            : }
      95                 :            : 
      96                 :     123907 : point::ECEFHeading getLaneECEFHeading(point::ParaPoint const &paraPoint)
      97                 :            : {
      98   [ +  -  +  - ]:     247814 :   auto lane = getLane(paraPoint.laneId);
      99                 :            : 
     100         [ +  - ]:     123907 :   point::ECEFHeading laneDrivingDirection = getLaneECEFDirection(lane, paraPoint);
     101         [ +  + ]:     123907 :   if (!isLaneDirectionPositive(lane))
     102                 :            :   {
     103         [ +  - ]:      90602 :     laneDrivingDirection = -1. * laneDrivingDirection;
     104                 :            :   }
     105                 :     247814 :   return laneDrivingDirection;
     106                 :            : }
     107                 :            : 
     108                 :          8 : point::ENUHeading getLaneENUHeading(match::MapMatchedPosition const &mapMatchedPosition)
     109                 :            : {
     110         [ +  - ]:         16 :   return point::createENUHeading(getLaneECEFHeading(mapMatchedPosition), mapMatchedPosition.matchedPoint);
     111                 :            : }
     112                 :            : 
     113                 :         42 : point::ENUHeading getLaneENUHeading(point::ParaPoint const &paraPoint, point::GeoPoint const &gnssReference)
     114                 :            : {
     115         [ +  - ]:         84 :   return point::createENUHeading(getLaneECEFHeading(paraPoint), gnssReference);
     116                 :            : }
     117                 :            : 
     118                 :        786 : point::ParaPoint uniqueParaPoint(point::GeoPoint const &geoPoint)
     119                 :            : {
     120         [ +  - ]:       1572 :   match::AdMapMatching mapMatching;
     121                 :            :   auto mapMatchingResult
     122         [ +  - ]:        787 :     = mapMatching.getMapMatchedPositions(geoPoint, physics::Distance(0.1), physics::Probability(0.5));
     123                 :            : 
     124         [ +  + ]:        786 :   if (mapMatchingResult.size() == 0u)
     125                 :            :   {
     126         [ +  - ]:          1 :     throw std::runtime_error("uniqueLaneId: position doesn't match any lane within 0.1 meters");
     127                 :            :   }
     128         [ -  + ]:        785 :   if (mapMatchingResult.size() != 1u)
     129                 :            :   {
     130         [ #  # ]:          0 :     throw std::runtime_error("uniqueLaneId: position matches multiple lanes");
     131                 :            :   }
     132                 :            : 
     133                 :       1570 :   return mapMatchingResult[0].lanePoint.paraPoint;
     134                 :            : }
     135                 :            : 
     136                 :        786 : LaneId uniqueLaneId(point::GeoPoint const &geoPoint)
     137                 :            : {
     138                 :        786 :   return uniqueParaPoint(geoPoint).laneId;
     139                 :            : }
     140                 :            : 
     141                 :          5 : physics::Distance getWidth(Lane const &lane, physics::ParametricValue const &longitudinalOffset)
     142                 :            : {
     143                 :          5 :   physics::Distance width(0.);
     144         [ +  - ]:          5 :   point::ECEFPoint pointOnLeftEdge;
     145         [ +  - ]:          5 :   point::ECEFPoint pointOnRightEdge;
     146   [ +  -  +  - ]:          5 :   if (projectParametricPointToEdges(lane, longitudinalOffset, pointOnLeftEdge, pointOnRightEdge))
     147                 :            :   {
     148         [ +  - ]:          5 :     width = distance(pointOnLeftEdge, pointOnRightEdge);
     149                 :            :   }
     150                 :          5 :   return width;
     151                 :            : }
     152                 :            : 
     153                 :      11309 : restriction::SpeedLimitList getSpeedLimits(Lane const &lane, physics::ParametricRange const &range)
     154                 :            : {
     155                 :      11309 :   restriction::SpeedLimitList speedLimits;
     156         [ +  + ]:      22618 :   for (auto const &speedLimit : lane.speedLimits)
     157                 :            :   {
     158   [ +  -  +  - ]:      11309 :     if (doRangesOverlap(speedLimit.lanePiece, range))
     159                 :            :     {
     160         [ +  - ]:      11309 :       speedLimits.push_back(speedLimit);
     161                 :            :     }
     162                 :            :   }
     163                 :      11309 :   return speedLimits;
     164                 :            : }
     165                 :            : 
     166                 :       9917 : physics::Speed getMaxSpeed(Lane const &lane, physics::ParametricRange const &range)
     167                 :            : {
     168                 :       9917 :   physics::Speed maxSpeed(0.);
     169   [ +  -  +  + ]:      19834 :   for (auto const &speedLimit : getSpeedLimits(lane, range))
     170                 :            :   {
     171         [ +  - ]:       9917 :     maxSpeed = std::max(maxSpeed, speedLimit.speedLimit);
     172                 :            :   }
     173   [ +  -  +  + ]:       9917 :   if (maxSpeed == physics::Speed(0.))
     174                 :            :   {
     175                 :          1 :     maxSpeed = std::numeric_limits<physics::Speed>::max();
     176                 :            :   }
     177                 :       9917 :   return maxSpeed;
     178                 :            : }
     179                 :            : 
     180                 :      19880 : physics::Duration getDuration(Lane const &lane, physics::ParametricRange const &range)
     181                 :            : {
     182                 :      19880 :   physics::Duration laneMinDuration{0.};
     183                 :      19880 :   physics::Distance coveredDurationDistance{0.};
     184         [ +  + ]:      39760 :   for (auto const &speedLimit : lane.speedLimits)
     185                 :            :   {
     186         [ +  - ]:      19880 :     auto const intersectedRange = getIntersectionRange(speedLimit.lanePiece, range);
     187   [ +  -  +  - ]:      19880 :     if (isRangeValid(intersectedRange))
     188                 :            :     {
     189   [ +  -  +  - ]:      19880 :       physics::Distance const speedLimitDistance = (intersectedRange.maximum - intersectedRange.minimum) * lane.length;
     190                 :      19880 :       physics::Speed speedLimitValue = std::numeric_limits<physics::Speed>::max();
     191   [ +  -  +  - ]:      19880 :       if (speedLimit.speedLimit > physics::Speed(0.))
     192                 :            :       {
     193                 :      19880 :         speedLimitValue = speedLimit.speedLimit;
     194                 :            :       }
     195         [ +  - ]:      19880 :       physics::Duration const speedLimitDuration = speedLimitDistance / speedLimitValue;
     196         [ +  - ]:      19880 :       laneMinDuration += speedLimitDuration;
     197         [ +  - ]:      19880 :       coveredDurationDistance += speedLimitDistance;
     198                 :            :     }
     199                 :            :   }
     200   [ +  -  +  -  :      19880 :   physics::Distance const remainingDistance = (range.maximum - range.minimum) * lane.length - coveredDurationDistance;
                   +  - ]
     201   [ +  -  -  + ]:      19880 :   if (remainingDistance > physics::Distance(0.))
     202                 :            :   {
     203   [ #  #  #  # ]:          0 :     physics::Duration const speedLimitDuration = remainingDistance / getMaxSpeed(lane, range);
     204         [ #  # ]:          0 :     laneMinDuration += speedLimitDuration;
     205                 :            :   }
     206                 :      19880 :   return laneMinDuration;
     207                 :            : }
     208                 :            : 
     209                 :     141019 : ContactLaneList getContactLanes(Lane const &lane, ContactLocation const &location)
     210                 :            : {
     211         [ -  + ]:     141019 :   if (location == ContactLocation::INVALID)
     212                 :            :   {
     213                 :          0 :     std::runtime_error("LaneOperation::getContactLanes() location is INVALID");
     214                 :            :   }
     215                 :     141019 :   ContactLaneList contactLanes;
     216         [ +  + ]:    1179950 :   for (auto const &contactLane : lane.contactLanes)
     217                 :            :   {
     218         [ +  + ]:    1038930 :     if (contactLane.location == location)
     219                 :            :     {
     220         [ +  - ]:     141424 :       contactLanes.push_back(contactLane);
     221                 :            :     }
     222                 :            :   }
     223                 :     141019 :   return contactLanes;
     224                 :            : }
     225                 :            : 
     226                 :      29601 : ContactLaneList getContactLanes(Lane const &lane, ContactLocationList const &locations)
     227                 :            : {
     228                 :      29601 :   ContactLaneList contactLanes;
     229         [ +  + ]:      89403 :   for (auto const &location : locations)
     230                 :            :   {
     231         [ +  - ]:      59802 :     auto const locationContactLanes = getContactLanes(lane, location);
     232         [ +  - ]:      59802 :     contactLanes.insert(std::begin(contactLanes), std::begin(locationContactLanes), std::end(locationContactLanes));
     233                 :            :   }
     234                 :      29601 :   return contactLanes;
     235                 :            : }
     236                 :            : 
     237                 :      24376 : ContactLocation getContactLocation(Lane const &lane, LaneId const &to_lane_id)
     238                 :            : {
     239         [ +  - ]:      24376 :   if (isValid(to_lane_id))
     240                 :            :   {
     241         [ +  + ]:      61351 :     for (auto const &contact_lane : lane.contactLanes)
     242                 :            :     {
     243   [ +  -  +  + ]:      61343 :       if (contact_lane.toLane == to_lane_id)
     244                 :            :       {
     245                 :      24368 :         return contact_lane.location;
     246                 :            :       }
     247                 :            :     }
     248                 :            :   }
     249                 :          8 :   return ContactLocation::INVALID;
     250                 :            : }
     251                 :            : 
     252                 :     412569 : point::ECEFPoint getParametricPoint(Lane const &lane,
     253                 :            :                                     physics::ParametricValue const &longitudinalOffset,
     254                 :            :                                     physics::ParametricValue const &lateralOffset)
     255                 :            : {
     256         [ +  - ]:     412569 :   point::ECEFPoint const pt0 = getParametricPoint(lane.edgeLeft, longitudinalOffset);
     257   [ +  -  +  + ]:     412569 :   if (isValid(pt0))
     258                 :            :   {
     259         [ +  - ]:     412568 :     point::ECEFPoint const pt1 = getParametricPoint(lane.edgeRight, longitudinalOffset);
     260   [ +  -  +  - ]:     412568 :     if (isValid(pt1))
     261                 :            :     {
     262         [ +  - ]:     412568 :       return point::vectorInterpolate(pt0, pt1, lateralOffset);
     263                 :            :     }
     264                 :            :   }
     265         [ +  - ]:          1 :   return point::ECEFPoint();
     266                 :            : }
     267                 :            : 
     268                 :       5804 : bool projectParametricPointToEdges(Lane const &lane,
     269                 :            :                                    point::ECEFPoint const &referencePoint,
     270                 :            :                                    point::ECEFPoint &pointOnLeftEdge,
     271                 :            :                                    point::ECEFPoint &pointOnRightEdge)
     272                 :            : {
     273         [ +  - ]:       5804 :   if (isValid(referencePoint))
     274                 :            :   {
     275         [ +  - ]:       5804 :     auto const longTLeft = findNearestPointOnEdge(lane.edgeLeft, referencePoint);
     276   [ +  -  +  - ]:       5804 :     if (isRangeValid(longTLeft))
     277                 :            :     {
     278         [ +  - ]:       5804 :       auto const longTRight = findNearestPointOnEdge(lane.edgeRight, referencePoint);
     279   [ +  -  +  - ]:       5804 :       if (isRangeValid(longTRight))
     280                 :            :       {
     281         [ +  - ]:       5804 :         pointOnLeftEdge = getParametricPoint(lane.edgeLeft, longTLeft);
     282         [ +  - ]:       5804 :         pointOnRightEdge = getParametricPoint(lane.edgeRight, longTRight);
     283   [ +  -  +  -  :       5804 :         return isValid(pointOnLeftEdge) && isValid(pointOnRightEdge);
             +  -  +  - ]
     284                 :            :       }
     285                 :            :     }
     286                 :            :   }
     287                 :          0 :   return false;
     288                 :            : }
     289                 :            : 
     290                 :       5804 : bool projectParametricPointToEdges(Lane const &lane,
     291                 :            :                                    physics::ParametricValue const &longitudinalOffset,
     292                 :            :                                    point::ECEFPoint &pointOnLeftEdge,
     293                 :            :                                    point::ECEFPoint &pointOnRightEdge)
     294                 :            : {
     295         [ +  - ]:       5804 :   point::ECEFPoint const centerPoint = getParametricPoint(lane, longitudinalOffset, physics::ParametricValue(0.5));
     296         [ +  - ]:      11608 :   return projectParametricPointToEdges(lane, centerPoint, pointOnLeftEdge, pointOnRightEdge);
     297                 :            : }
     298                 :            : 
     299                 :       5797 : point::ECEFPoint getProjectedParametricPoint(Lane const &lane,
     300                 :            :                                              physics::ParametricValue const &longitudinalOffset,
     301                 :            :                                              physics::ParametricValue const &lateralOffset)
     302                 :            : {
     303         [ +  - ]:       5797 :   point::ECEFPoint pt0;
     304         [ +  - ]:       5797 :   point::ECEFPoint pt1;
     305         [ +  - ]:       5797 :   bool projectionResult = projectParametricPointToEdges(lane, longitudinalOffset, pt0, pt1);
     306         [ +  - ]:       5797 :   if (projectionResult)
     307                 :            :   {
     308         [ +  - ]:       5797 :     return point::vectorInterpolate(pt0, pt1, lateralOffset);
     309                 :            :   }
     310         [ #  # ]:          0 :   return point::ECEFPoint();
     311                 :            : }
     312                 :            : 
     313                 :          6 : bool isPyhsicalSuccessor(Lane const &lane, const Lane &other)
     314                 :            : {
     315   [ +  +  +  +  :          6 :   if (isSuccessor(lane.edgeLeft, other.edgeLeft) && isSuccessor(lane.edgeRight, other.edgeRight))
                   +  + ]
     316                 :            :   {
     317                 :          1 :     return true;
     318                 :            :   }
     319   [ +  +  +  +  :          5 :   if (isSuccessor(lane.edgeLeft, other.edgeRight) && isSuccessor(lane.edgeRight, other.edgeLeft))
                   +  + ]
     320                 :            :   {
     321                 :          1 :     return true;
     322                 :            :   }
     323   [ +  +  -  +  :          4 :   if (isVanishingLaneStart(lane) || isVanishingLaneEnd(lane))
                   +  + ]
     324                 :            :   {
     325   [ +  +  +  -  :          2 :     if (isSuccessor(lane.edgeLeft, other.edgeLeft) && isSuccessor(lane.edgeRight, other.edgeLeft))
                   +  + ]
     326                 :            :     {
     327                 :          1 :       return true;
     328                 :            :     }
     329   [ +  -  +  -  :          1 :     if (isSuccessor(lane.edgeLeft, other.edgeRight) && isSuccessor(lane.edgeRight, other.edgeRight))
                   +  - ]
     330                 :            :     {
     331                 :          1 :       return true;
     332                 :            :     }
     333                 :            :   }
     334         [ +  - ]:          2 :   if (isVanishingLaneEnd(other))
     335                 :            :   {
     336   [ +  +  -  +  :          2 :     if (isSuccessor(lane.edgeLeft, other.edgeRight) || isSuccessor(lane.edgeRight, other.edgeRight))
                   +  + ]
     337                 :            :     {
     338                 :          1 :       return true;
     339                 :            :     }
     340                 :            :   }
     341                 :          1 :   return false;
     342                 :            : }
     343                 :            : 
     344                 :          5 : bool isPhysicalPredecessor(Lane const &lane, const Lane &other)
     345                 :            : {
     346   [ +  +  +  +  :          5 :   if (isPredecessor(lane.edgeLeft, other.edgeLeft) && isPredecessor(lane.edgeRight, other.edgeRight))
                   +  + ]
     347                 :            :   {
     348                 :          1 :     return true;
     349                 :            :   }
     350   [ +  +  +  +  :          4 :   if (isPredecessor(lane.edgeLeft, other.edgeRight) && isPredecessor(lane.edgeRight, other.edgeLeft))
                   +  + ]
     351                 :            :   {
     352                 :          1 :     return true;
     353                 :            :   }
     354   [ -  +  -  -  :          3 :   if (isVanishingLaneStart(lane) || isVanishingLaneEnd(lane))
                   +  - ]
     355                 :            :   {
     356   [ +  +  +  -  :          3 :     if (isPredecessor(lane.edgeLeft, other.edgeLeft) && isPredecessor(lane.edgeRight, other.edgeLeft))
                   +  + ]
     357                 :            :     {
     358                 :          1 :       return true;
     359                 :            :     }
     360   [ +  +  +  -  :          2 :     if (isPredecessor(lane.edgeLeft, other.edgeRight) && isPredecessor(lane.edgeRight, other.edgeRight))
                   +  + ]
     361                 :            :     {
     362                 :          1 :       return true;
     363                 :            :     }
     364                 :            :   }
     365         [ +  - ]:          1 :   if (isVanishingLaneStart(other))
     366                 :            :   {
     367   [ +  -  -  +  :          1 :     if (isPredecessor(lane.edgeLeft, other.edgeRight) || isPredecessor(lane.edgeRight, other.edgeRight))
                   -  + ]
     368                 :            :     {
     369                 :          0 :       return true;
     370                 :            :     }
     371                 :            :   }
     372                 :          1 :   return false;
     373                 :            : }
     374                 :            : 
     375                 :          9 : bool isVanishingLaneStart(Lane const &lane)
     376                 :            : {
     377                 :          9 :   return haveSameStart(lane.edgeLeft, lane.edgeRight);
     378                 :            : }
     379                 :            : 
     380                 :          5 : bool isVanishingLaneEnd(Lane const &lane)
     381                 :            : {
     382                 :          5 :   return haveSameEnd(lane.edgeLeft, lane.edgeRight);
     383                 :            : }
     384                 :            : 
     385                 :          5 : bool satisfiesFilter(Lane const &lane, std::string const &typeFilter, bool isHov)
     386                 :            : {
     387         [ +  - ]:          5 :   if (isHov == (getHOV(lane) > restriction::PassengerCount(1)))
     388                 :            :   {
     389         [ +  - ]:          5 :     if (!typeFilter.empty())
     390                 :            :     {
     391         [ +  - ]:          5 :       auto const laneFullTypeString = toString(lane.type);
     392         [ +  + ]:          5 :       if (typeFilter.find(laneFullTypeString) != std::string::npos)
     393                 :            :       {
     394                 :          2 :         return true;
     395                 :            :       }
     396                 :          3 :       std::size_t found = laneFullTypeString.find_last_of(":");
     397         [ +  - ]:          3 :       auto const laneTypeWithoutPrefix = laneFullTypeString.substr(found + 1);
     398         [ +  - ]:          3 :       if (!laneTypeWithoutPrefix.empty())
     399                 :            :       {
     400         [ -  + ]:          3 :         if (typeFilter.find(laneTypeWithoutPrefix) != std::string::npos)
     401                 :            :         {
     402                 :          0 :           return true;
     403                 :            :         }
     404                 :            :       }
     405                 :            :     }
     406                 :            :     else
     407                 :            :     {
     408                 :          0 :       return true;
     409                 :            :     }
     410                 :            :   }
     411                 :          3 :   return false;
     412                 :            : }
     413                 :            : 
     414                 :      23504 : void updateLaneLengths(Lane &lane)
     415                 :            : {
     416         [ +  + ]:      23504 :   if (isValid(lane.edgeLeft))
     417                 :            :   {
     418         [ +  + ]:      23502 :     if (isValid(lane.edgeRight))
     419                 :            :     {
     420         [ +  - ]:      23501 :       lane.lengthRange.minimum = std::min(lane.edgeLeft.length, lane.edgeRight.length);
     421         [ +  - ]:      23501 :       lane.lengthRange.maximum = std::max(lane.edgeLeft.length, lane.edgeRight.length);
     422   [ +  -  +  - ]:      23501 :       lane.length = (lane.edgeLeft.length + lane.edgeRight.length) * 0.5;
     423                 :            : 
     424                 :            :       auto widthRangeResult = calculateWidthRange(
     425         [ +  - ]:      23501 :         lane.edgeLeft.ecefEdge, lane.edgeLeft.length, lane.edgeRight.ecefEdge, lane.edgeRight.length);
     426                 :      23501 :       lane.widthRange = widthRangeResult.first;
     427                 :      23501 :       lane.width = widthRangeResult.second;
     428                 :            :     }
     429                 :            :     else
     430                 :            :     {
     431                 :          1 :       lane.length = lane.edgeLeft.length;
     432                 :          1 :       lane.lengthRange.minimum = lane.length;
     433                 :          1 :       lane.lengthRange.maximum = lane.length;
     434                 :          1 :       lane.width = physics::Distance(0);
     435                 :          1 :       lane.widthRange.minimum = lane.width;
     436                 :          1 :       lane.widthRange.maximum = lane.width;
     437                 :            :     }
     438                 :            :   }
     439         [ +  + ]:          2 :   else if (isValid(lane.edgeRight))
     440                 :            :   {
     441                 :          1 :     lane.length = lane.edgeRight.length;
     442                 :          1 :     lane.lengthRange.minimum = lane.length;
     443                 :          1 :     lane.lengthRange.maximum = lane.length;
     444                 :          1 :     lane.width = physics::Distance(0);
     445                 :          1 :     lane.widthRange.minimum = lane.width;
     446                 :          1 :     lane.widthRange.maximum = lane.width;
     447                 :            :   }
     448                 :            :   else
     449                 :            :   {
     450                 :          1 :     lane.length = physics::Distance(0);
     451                 :          1 :     lane.lengthRange.minimum = lane.length;
     452                 :          1 :     lane.lengthRange.maximum = lane.length;
     453                 :          1 :     lane.width = physics::Distance(0);
     454                 :          1 :     lane.widthRange.minimum = lane.width;
     455                 :          1 :     lane.widthRange.maximum = lane.width;
     456                 :            :   }
     457                 :      23504 : }
     458                 :            : 
     459                 :         42 : point::ENUHeading getLaneENUHeading(point::ParaPoint const &position)
     460                 :            : {
     461         [ +  - ]:         42 :   const auto gnssReference = access::getENUReferencePoint();
     462         [ +  - ]:         42 :   const auto laneHeading = getLaneENUHeading(position, gnssReference);
     463                 :         42 :   return laneHeading;
     464                 :            : }
     465                 :            : 
     466                 :         23 : bool isHeadingInLaneDirection(point::ParaPoint const &position, point::ENUHeading const &heading)
     467                 :            : {
     468         [ +  - ]:         23 :   const auto laneHeading = getLaneENUHeading(position);
     469                 :            :   // enforce normalization of angle difference
     470   [ +  -  +  - ]:         23 :   const auto headingDifference = point::createENUHeading(static_cast<double>(std::fabs(heading - laneHeading)));
     471                 :            : 
     472         [ +  + ]:         23 :   if (static_cast<double>(std::fabs(headingDifference)) > M_PI / 2.)
     473                 :            :   {
     474                 :          3 :     return false;
     475                 :            :   }
     476                 :            : 
     477                 :         20 :   return true;
     478                 :            : }
     479                 :            : 
     480                 :        308 : bool isLaneDirectionPositive(LaneId const &laneId)
     481                 :            : {
     482   [ +  -  +  - ]:        616 :   auto const lane = getLane(laneId);
     483                 :        616 :   return isLaneDirectionPositive(lane);
     484                 :            : }
     485                 :            : 
     486                 :       2517 : bool isLaneDirectionNegative(LaneId const &laneId)
     487                 :            : {
     488   [ +  -  +  - ]:       5034 :   auto const lane = getLane(laneId);
     489                 :       5034 :   return isLaneDirectionNegative(lane);
     490                 :            : }
     491                 :            : 
     492                 :          1 : bool projectPositionToLaneInHeadingDirection(point::ParaPoint const &position,
     493                 :            :                                              point::ENUHeading const &heading,
     494                 :            :                                              point::ParaPoint &projectedPosition)
     495                 :            : {
     496                 :          1 :   projectedPosition = position;
     497   [ +  -  +  - ]:          1 :   if (isHeadingInLaneDirection(position, heading))
     498                 :            :   {
     499                 :          1 :     return true;
     500                 :            :   }
     501                 :            : 
     502   [ #  #  #  # ]:          0 :   const auto lane = getLane(position.laneId);
     503                 :          0 :   ContactLocationList types;
     504   [ #  #  #  # ]:          0 :   if (isLaneDirectionPositive(position.laneId))
     505                 :            :   {
     506         [ #  # ]:          0 :     types.push_back(ContactLocation::LEFT);
     507         [ #  # ]:          0 :     types.push_back(ContactLocation::RIGHT);
     508                 :            :   }
     509                 :            :   else
     510                 :            :   {
     511         [ #  # ]:          0 :     types.push_back(ContactLocation::RIGHT);
     512         [ #  # ]:          0 :     types.push_back(ContactLocation::LEFT);
     513                 :            :   }
     514         [ #  # ]:          0 :   for (auto contactType : types)
     515                 :            :   {
     516         [ #  # ]:          0 :     auto contactLanes = getContactLanes(lane, contactType);
     517         [ #  # ]:          0 :     while (contactLanes.size() > 0)
     518                 :            :     {
     519                 :            :       // check first neighbor
     520                 :          0 :       const auto neighborLaneId = contactLanes[0].toLane;
     521   [ #  #  #  # ]:          0 :       const auto neighborLane = getLane(neighborLaneId);
     522                 :            : 
     523                 :          0 :       projectedPosition.laneId = neighborLaneId;
     524                 :          0 :       projectedPosition.parametricOffset = position.parametricOffset;
     525                 :            : 
     526   [ #  #  #  #  :          0 :       if (isRouteable(neighborLane) && isHeadingInLaneDirection(projectedPosition, heading))
             #  #  #  # ]
     527                 :            :       {
     528                 :          0 :         return true;
     529                 :            :       }
     530                 :            :       else
     531                 :            :       {
     532         [ #  # ]:          0 :         contactLanes = getContactLanes(neighborLane, contactType);
     533                 :            :       }
     534                 :            :     }
     535                 :            :   }
     536                 :            : 
     537                 :          0 :   return false;
     538                 :            : }
     539                 :            : 
     540                 :     469036 : match::MapMatchedPosition calcMapMatchedPosition(Lane const &lane,
     541                 :            :                                                  physics::ParametricValue const &longTLeft,
     542                 :            :                                                  physics::ParametricValue const &longTRight,
     543                 :            :                                                  point::ECEFPoint const &pt)
     544                 :            : {
     545         [ +  - ]:     469036 :   match::MapMatchedPosition mmpos;
     546         [ +  - ]:     469036 :   point::ECEFPoint const pt_left = point::getParametricPoint(lane.edgeLeft, longTLeft);
     547         [ +  - ]:     469036 :   point::ECEFPoint const pt_right = point::getParametricPoint(lane.edgeRight, longTRight);
     548                 :            : 
     549                 :     469036 :   mmpos.lanePoint.paraPoint.laneId = lane.id;
     550         [ +  - ]:     469036 :   mmpos.lanePoint.lateralT = point::findNearestPointOnEdge(pt, pt_left, pt_right);
     551                 :     469036 :   physics::ParametricValue nearestT;
     552   [ +  -  +  + ]:     469036 :   if (mmpos.lanePoint.lateralT < physics::RatioValue(0.))
     553                 :            :   {
     554                 :     278281 :     nearestT = physics::ParametricValue(0.);
     555                 :     278281 :     mmpos.type = match::MapMatchedPositionType::LANE_LEFT;
     556                 :     278281 :     mmpos.probability = std::max(physics::Probability(0.1),
     557         [ +  - ]:     556562 :                                  physics::Probability(0.5 + static_cast<double>(mmpos.lanePoint.lateralT) / 10.));
     558                 :            :   }
     559   [ +  -  +  + ]:     190755 :   else if (mmpos.lanePoint.lateralT > physics::RatioValue(1.))
     560                 :            :   {
     561                 :     134846 :     nearestT = physics::ParametricValue(1.);
     562                 :     134846 :     mmpos.type = match::MapMatchedPositionType::LANE_RIGHT;
     563                 :            :     mmpos.probability
     564                 :     134846 :       = std::max(physics::Probability(0.1),
     565         [ +  - ]:     269692 :                  physics::Probability(0.5 - (static_cast<double>(mmpos.lanePoint.lateralT) - 1.) / 10.));
     566                 :            :   }
     567                 :            :   else
     568                 :            :   {
     569                 :      55909 :     nearestT = physics::ParametricValue(static_cast<double>(mmpos.lanePoint.lateralT));
     570                 :      55909 :     mmpos.type = match::MapMatchedPositionType::LANE_IN;
     571                 :          0 :     mmpos.probability = physics::Probability(1.)
     572                 :      55909 :       - std::min(physics::Probability(0.5),
     573   [ +  -  +  - ]:     111818 :                  physics::Probability(fabs(0.5 - static_cast<double>(mmpos.lanePoint.lateralT))));
     574                 :            :   }
     575         [ +  - ]:     469036 :   mmpos.matchedPoint = point::vectorInterpolate(pt_left, pt_right, nearestT);
     576                 :            :   mmpos.lanePoint.paraPoint.parametricOffset
     577   [ +  -  +  -  :     469036 :     = nearestT * longTLeft + (physics::ParametricValue(1.) - nearestT) * longTRight;
             +  -  +  - ]
     578                 :     469036 :   mmpos.lanePoint.laneLength = lane.length;
     579         [ +  - ]:     469036 :   mmpos.lanePoint.laneWidth = point::distance(pt_left, pt_right);
     580                 :     469036 :   mmpos.queryPoint = pt;
     581         [ +  - ]:     469036 :   mmpos.matchedPointDistance = point::distance(mmpos.matchedPoint, mmpos.queryPoint);
     582                 :     938072 :   return mmpos;
     583                 :            : }
     584                 :            : 
     585                 :     469036 : bool findNearestPointOnLane(Lane const &lane, point::ECEFPoint const &pt, match::MapMatchedPosition &mmpos)
     586                 :            : {
     587         [ +  - ]:     469036 :   auto const longTLeft = findNearestPointOnEdge(lane.edgeLeft, pt);
     588         [ +  - ]:     469036 :   if (longTLeft.isValid())
     589                 :            :   {
     590         [ +  - ]:     469036 :     auto const longTRight = findNearestPointOnEdge(lane.edgeRight, pt);
     591         [ +  - ]:     469036 :     if (longTRight.isValid())
     592                 :            :     {
     593         [ +  - ]:     469036 :       mmpos = calcMapMatchedPosition(lane, longTLeft, longTRight, pt);
     594                 :     469036 :       return true;
     595                 :            :     }
     596                 :            :   }
     597                 :          0 :   return false;
     598                 :            : }
     599                 :            : 
     600                 :          0 : bool findNearestPointOnLaneInterval(route::LaneInterval const &laneInterval,
     601                 :            :                                     point::ECEFPoint const &pt,
     602                 :            :                                     match::MapMatchedPosition &mmpos)
     603                 :            : {
     604         [ #  # ]:          0 :   auto const &lane = getLane(laneInterval.laneId);
     605         [ #  # ]:          0 :   auto const laneRange = route::toParametricRange(laneInterval);
     606         [ #  # ]:          0 :   auto longTLeft = findNearestPointOnEdge(lane.edgeLeft, pt);
     607         [ #  # ]:          0 :   if (longTLeft.isValid())
     608                 :            :   {
     609         [ #  # ]:          0 :     auto longTRight = findNearestPointOnEdge(lane.edgeRight, pt);
     610         [ #  # ]:          0 :     if (longTRight.isValid())
     611                 :            :     {
     612   [ #  #  #  # ]:          0 :       if (!physics::isWithinRange(laneRange, longTLeft))
     613                 :            :       {
     614   [ #  #  #  # ]:          0 :         if (longTLeft < laneRange.minimum)
     615                 :            :         {
     616                 :          0 :           longTLeft = laneRange.minimum;
     617                 :            :         }
     618   [ #  #  #  # ]:          0 :         else if (longTLeft > laneRange.maximum)
     619                 :            :         {
     620                 :          0 :           longTLeft = laneRange.maximum;
     621                 :            :         }
     622                 :            :       }
     623   [ #  #  #  # ]:          0 :       if (!physics::isWithinRange(laneRange, longTRight))
     624                 :            :       {
     625   [ #  #  #  # ]:          0 :         if (longTRight < laneRange.minimum)
     626                 :            :         {
     627                 :          0 :           longTRight = laneRange.minimum;
     628                 :            :         }
     629   [ #  #  #  # ]:          0 :         else if (longTRight > laneRange.maximum)
     630                 :            :         {
     631                 :          0 :           longTRight = laneRange.maximum;
     632                 :            :         }
     633                 :            :       }
     634                 :            : 
     635         [ #  # ]:          0 :       mmpos = calcMapMatchedPosition(lane, longTLeft, longTRight, pt);
     636                 :          0 :       return true;
     637                 :            :     }
     638                 :            :   }
     639                 :          0 :   return false;
     640                 :            : }
     641                 :            : 
     642                 :          2 : physics::Distance getDistanceToLane(LaneId laneId, match::Object const &object)
     643                 :            : {
     644                 :            :   // prefer fast checks first
     645         [ +  + ]:          3 :   for (auto const &occupiedLane : object.mapMatchedBoundingBox.laneOccupiedRegions)
     646                 :            :   {
     647   [ +  -  +  + ]:          2 :     if (occupiedLane.laneId == laneId)
     648                 :            :     {
     649                 :          1 :       return physics::Distance(0.);
     650                 :            :     }
     651                 :            :   }
     652                 :            :   // already map matching result available, but not within the lane
     653                 :          1 :   physics::Distance distance = std::numeric_limits<physics::Distance>::max();
     654                 :          1 :   bool mapMatchedPointFound = false;
     655                 :            :   point::ECEFPoint const objectPointECEF
     656         [ +  - ]:          1 :     = point::toECEF(object.enuPosition.centerPoint, object.enuPosition.enuReferencePoint);
     657                 :            : 
     658                 :          4 :   for (auto referencePoint : {match::ObjectReferencePoints::FrontLeft,
     659                 :            :                               match::ObjectReferencePoints::FrontRight,
     660                 :            :                               match::ObjectReferencePoints::RearLeft,
     661         [ +  + ]:          5 :                               match::ObjectReferencePoints::RearRight})
     662                 :            :   {
     663         [ +  - ]:          8 :     auto mapMatchedConfidenceList = object.mapMatchedBoundingBox.referencePointPositions[size_t(referencePoint)];
     664         [ +  + ]:         10 :     for (auto const &mapMatchedPosition : mapMatchedConfidenceList)
     665                 :            :     {
     666   [ +  -  +  + ]:          6 :       if (mapMatchedPosition.lanePoint.paraPoint.laneId == laneId)
     667                 :            :       {
     668                 :          2 :         mapMatchedPointFound = true;
     669                 :            :         // use the smallest distance if multiple have been matched
     670   [ +  -  +  - ]:          2 :         distance = std::min(distance, point::distance(mapMatchedPosition.matchedPoint, objectPointECEF));
     671                 :            :       }
     672                 :            :     }
     673                 :            :   }
     674         [ -  + ]:          1 :   if (!mapMatchedPointFound)
     675                 :            :   {
     676                 :            :     // need to perform map matching on our own
     677   [ #  #  #  # ]:          0 :     auto lane = getLane(laneId);
     678         [ #  # ]:          0 :     match::MapMatchedPosition mapMatchedPosition;
     679   [ #  #  #  # ]:          0 :     if (findNearestPointOnLane(lane, objectPointECEF, mapMatchedPosition))
     680                 :            :     {
     681         [ #  # ]:          0 :       distance = point::distance(mapMatchedPosition.matchedPoint, objectPointECEF);
     682                 :            :       distance
     683   [ #  #  #  #  :          0 :         = std::max(distance - std::max(object.enuPosition.dimension.length, object.enuPosition.dimension.width) / 2.,
                   #  # ]
     684         [ #  # ]:          0 :                    physics::Distance(0.));
     685                 :            :     }
     686                 :            :   }
     687                 :            : 
     688                 :          1 :   return distance;
     689                 :            : }
     690                 :            : 
     691                 :        155 : physics::Distance calcLength(LaneId const &laneId)
     692                 :            : {
     693         [ +  - ]:        155 :   const auto lane = getLanePtr(laneId);
     694                 :        310 :   return lane->length;
     695                 :            : }
     696                 :            : 
     697                 :          1 : physics::Distance calcLength(match::LaneOccupiedRegion const &laneOccupiedRegion)
     698                 :            : {
     699                 :            :   auto const rangeLength
     700         [ +  - ]:          1 :     = (laneOccupiedRegion.longitudinalRange.maximum - laneOccupiedRegion.longitudinalRange.minimum);
     701   [ +  -  +  - ]:          2 :   return rangeLength * calcLength(laneOccupiedRegion.laneId);
     702                 :            : }
     703                 :            : 
     704                 :          4 : physics::Distance calcWidth(point::ParaPoint const &paraPoint)
     705                 :            : {
     706                 :          4 :   return calcWidth(paraPoint.laneId, paraPoint.parametricOffset);
     707                 :            : }
     708                 :            : 
     709                 :          5 : physics::Distance calcWidth(LaneId const &laneId, physics::ParametricValue const &longOffset)
     710                 :            : {
     711         [ +  - ]:         10 :   const auto lane = getLanePtr(laneId);
     712         [ +  - ]:         10 :   return getWidth(*lane, longOffset);
     713                 :            : }
     714                 :            : 
     715                 :          2 : physics::Distance calcWidth(point::ENUPoint const &enuPoint)
     716                 :            : {
     717         [ +  - ]:          4 :   match::AdMapMatching mapMatching;
     718                 :            :   const auto mapMatchedPositions
     719         [ +  - ]:          4 :     = mapMatching.getMapMatchedPositions(enuPoint, physics::Distance(1.0), physics::Probability(0.1));
     720                 :            : 
     721         [ -  + ]:          2 :   if (mapMatchedPositions.empty())
     722                 :            :   {
     723                 :          0 :     return physics::Distance(-1.0);
     724                 :            :   }
     725         [ +  - ]:          2 :   return calcWidth(mapMatchedPositions.front().lanePoint.paraPoint);
     726                 :            : }
     727                 :            : 
     728                 :          1 : physics::Distance calcWidth(match::LaneOccupiedRegion const &laneOccupiedRegion)
     729                 :            : {
     730         [ +  - ]:          1 :   auto const rangeWidth = (laneOccupiedRegion.lateralRange.maximum - laneOccupiedRegion.lateralRange.minimum);
     731   [ +  -  +  -  :          2 :   return rangeWidth * calcWidth(match::getCenterParaPoint(laneOccupiedRegion));
                   +  - ]
     732                 :            : }
     733                 :            : 
     734                 :      19063 : ContactLocation getDirectNeighborhoodRelation(LaneId const laneId, LaneId const checkLaneId)
     735                 :            : {
     736   [ +  -  +  + ]:      19063 :   if (laneId == checkLaneId)
     737                 :            :   {
     738                 :      10724 :     return ContactLocation::OVERLAP;
     739                 :            :   }
     740   [ +  +  +  - ]:      16677 :   auto lane = getLane(laneId);
     741                 :      19434 :   for (auto contactLocation :
     742         [ +  + ]:      27772 :        {ContactLocation::LEFT, ContactLocation::RIGHT, ContactLocation::SUCCESSOR, ContactLocation::PREDECESSOR})
     743                 :            :   {
     744         [ +  - ]:      27770 :     auto contactLanes = getContactLanes(lane, contactLocation);
     745                 :            :     auto findResult
     746                 :      23602 :       = std::find_if(std::begin(contactLanes), std::end(contactLanes), [checkLaneId](ContactLane const &contactLane) {
     747                 :      23602 :           return contactLane.toLane == checkLaneId;
     748         [ +  - ]:      27770 :         });
     749         [ +  + ]:      27770 :     if (findResult != std::end(contactLanes))
     750                 :            :     {
     751                 :       8336 :       return contactLocation;
     752                 :            :     }
     753                 :            :   }
     754                 :          2 :   return ContactLocation::INVALID;
     755                 :            : }
     756                 :            : 
     757                 :          1 : bool isSuccessorOrPredecessor(LaneId const laneId, LaneId const checkLaneId)
     758                 :            : {
     759                 :          1 :   auto const neighborhood = getDirectNeighborhoodRelation(laneId, checkLaneId);
     760   [ +  -  -  + ]:          1 :   return (neighborhood == ContactLocation::SUCCESSOR) || (neighborhood == ContactLocation::PREDECESSOR);
     761                 :            : }
     762                 :            : 
     763                 :          4 : bool isSameOrDirectNeighbor(LaneId const laneId, LaneId const checkLaneId)
     764                 :            : {
     765                 :          4 :   auto const neighborhood = getDirectNeighborhoodRelation(laneId, checkLaneId);
     766         [ +  + ]:          2 :   return (neighborhood == ContactLocation::OVERLAP) || (neighborhood == ContactLocation::LEFT)
     767   [ +  +  +  - ]:          5 :     || (neighborhood == ContactLocation::RIGHT);
     768                 :            : }
     769                 :            : 
     770                 :         11 : point::ENUPoint getENULanePoint(point::ParaPoint const parametricPoint, physics::ParametricValue const &lateralOffset)
     771                 :            : {
     772                 :            :   // perform map matching
     773   [ +  -  +  - ]:         22 :   auto lane = getLane(parametricPoint.laneId);
     774         [ +  - ]:         11 :   auto ecefPoint = getParametricPoint(lane, parametricPoint.parametricOffset, lateralOffset);
     775         [ +  - ]:         11 :   auto enuPoint = point::toENU(ecefPoint);
     776                 :         22 :   return enuPoint;
     777                 :            : }
     778                 :            : 
     779                 :        564 : LaneAltitudeRange calcLaneAltitudeRange(Lane const &lane)
     780                 :            : {
     781                 :        564 :   LaneAltitudeRange altitude_range;
     782                 :        564 :   bool initialize = true;
     783         [ +  + ]:       6004 :   for (auto const &pt : lane.edgeLeft.ecefEdge)
     784                 :            :   {
     785         [ +  - ]:       5440 :     auto const pt_geo = point::toGeo(pt);
     786         [ +  + ]:       5440 :     if (initialize)
     787                 :            :     {
     788                 :        564 :       initialize = false;
     789                 :        564 :       altitude_range.minimum = pt_geo.altitude;
     790                 :        564 :       altitude_range.maximum = pt_geo.altitude;
     791                 :            :     }
     792                 :            :     else
     793                 :            :     {
     794         [ +  - ]:       4876 :       altitude_range.minimum = std::min(altitude_range.minimum, pt_geo.altitude);
     795         [ +  - ]:       4876 :       altitude_range.maximum = std::max(altitude_range.maximum, pt_geo.altitude);
     796                 :            :     }
     797                 :            :   }
     798         [ +  + ]:       6004 :   for (auto const &pt : lane.edgeRight.ecefEdge)
     799                 :            :   {
     800         [ +  - ]:       5440 :     auto const pt_geo = point::toGeo(pt);
     801         [ +  - ]:       5440 :     altitude_range.minimum = std::min(altitude_range.minimum, pt_geo.altitude);
     802         [ +  - ]:       5440 :     altitude_range.maximum = std::max(altitude_range.maximum, pt_geo.altitude);
     803                 :            :   }
     804                 :        564 :   return altitude_range;
     805                 :            : }
     806                 :            : 
     807                 :      69559 : bool isLaneRelevantForExpansion(lane::LaneId const &laneId, lane::LaneIdSet const &relevantLanes)
     808                 :            : {
     809         [ +  + ]:      69559 :   if (relevantLanes.empty())
     810                 :            :   {
     811                 :      69519 :     return true;
     812                 :            :   }
     813         [ +  - ]:         40 :   auto const findResult = relevantLanes.find(laneId);
     814         [ +  + ]:         40 :   if (findResult != relevantLanes.end())
     815                 :            :   {
     816                 :         22 :     return true;
     817                 :            :   }
     818                 :         18 :   return false;
     819                 :            : }
     820                 :            : 
     821                 :            : } // namespace lane
     822                 :            : } // namespace map
     823                 :            : } // namespace ad

Generated by: LCOV version 1.14