LCOV - code coverage report
Current view: top level - src/lane - BorderOperation.cpp (source / functions) Hit Total Coverage
Test: ad_map_access Lines: 182 279 65.2 %
Date: 2022-10-04 09:48:07 Functions: 15 20 75.0 %
Branches: 177 470 37.7 %

           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/BorderOperation.hpp"
      10                 :            : #include <algorithm>
      11                 :            : #include "LaneOperationPrivate.hpp"
      12                 :            : #include "ad/map/access/Logging.hpp"
      13                 :            : #include "ad/map/point/Operation.hpp"
      14                 :            : 
      15                 :            : namespace ad {
      16                 :            : namespace map {
      17                 :            : namespace lane {
      18                 :            : 
      19                 :          1 : physics::Distance calcLength(ENUBorderList const &borderList)
      20                 :            : {
      21                 :          1 :   physics::Distance total(0.);
      22         [ +  + ]:          4 :   for (auto const &value : borderList)
      23                 :            :   {
      24   [ +  -  +  - ]:          3 :     total = total + calcLength(value);
      25                 :            :   }
      26                 :          1 :   return total;
      27                 :            : }
      28                 :            : 
      29                 :          0 : physics::Distance calcLength(ECEFBorderList const &borderList)
      30                 :            : {
      31                 :          0 :   physics::Distance total(0.);
      32         [ #  # ]:          0 :   for (auto const &value : borderList)
      33                 :            :   {
      34   [ #  #  #  # ]:          0 :     total = total + calcLength(value);
      35                 :            :   }
      36                 :          0 :   return total;
      37                 :            : }
      38                 :            : 
      39                 :          0 : physics::Distance calcLength(GeoBorderList const &borderList)
      40                 :            : {
      41                 :          0 :   physics::Distance total(0.);
      42         [ #  # ]:          0 :   for (auto const &value : borderList)
      43                 :            :   {
      44   [ #  #  #  # ]:          0 :     total = total + calcLength(value);
      45                 :            :   }
      46                 :          0 :   return total;
      47                 :            : }
      48                 :            : 
      49                 :          6 : void removeDegeneratedEdgePoints(point::ENUEdge &edge, point::ENUEdge const *previousEdge = nullptr)
      50                 :            : {
      51         [ -  + ]:          6 :   if (edge.size() < 2u)
      52                 :            :   {
      53                 :          0 :     return;
      54                 :            :   }
      55                 :            : 
      56         [ +  - ]:          6 :   point::ENUPoint previousEdgeDir;
      57         [ +  + ]:          6 :   if (previousEdge != nullptr)
      58                 :            :   {
      59         [ -  + ]:          2 :     if (previousEdge->size() < 2u)
      60                 :            :     {
      61                 :          0 :       return;
      62                 :            :     }
      63                 :            :     // decide if edge start point has to be adapted
      64   [ +  -  +  -  :          2 :     previousEdgeDir = previousEdge->at(previousEdge->size() - 1u) - previousEdge->at(previousEdge->size() - 2u);
                   +  - ]
      65   [ +  -  +  - ]:          2 :     auto nextEdgeDir = edge[0] - previousEdge->at(previousEdge->size() - 1u);
      66                 :            : 
      67                 :            :     // if the two edges are near to each other or the direction is dramatically different,
      68                 :            :     // the start point is overwritten by the end of the previous edge
      69   [ +  -  +  - ]:          2 :     if ((point::vectorLength(nextEdgeDir) > point::cEdgePointBorderDistance)
      70   [ -  +  -  -  :          2 :         || (point::vectorDotProduct(previousEdgeDir, nextEdgeDir) < 0.))
                   +  - ]
      71                 :            :     {
      72         [ +  - ]:          2 :       edge[0] = previousEdge->at(previousEdge->size() - 1u);
      73                 :            :     }
      74                 :            :     else
      75                 :            :     {
      76                 :          0 :       previousEdgeDir = nextEdgeDir;
      77                 :            :     }
      78                 :            :   }
      79                 :            :   else
      80                 :            :   {
      81         [ +  - ]:          4 :     previousEdgeDir = edge[1] - edge[0];
      82                 :            :   }
      83                 :            : 
      84                 :          6 :   std::size_t pointsToDrop = 0u;
      85         [ +  + ]:         14 :   for (std::size_t i = 1u; i < edge.size(); ++i)
      86                 :            :   {
      87                 :            :     // i-pointsToDrop > 0
      88         [ -  + ]:          8 :     if (pointsToDrop > 0u)
      89                 :            :     {
      90                 :          0 :       edge[i - pointsToDrop] = edge[i];
      91                 :            :     }
      92         [ +  - ]:          8 :     auto nextEdgeDir = edge[i - pointsToDrop] - edge[i - pointsToDrop - 1];
      93                 :          8 :     auto dotProduct = point::vectorDotProduct(previousEdgeDir, nextEdgeDir);
      94         [ -  + ]:          8 :     if (dotProduct < 0.)
      95                 :            :     {
      96                 :          0 :       pointsToDrop++;
      97                 :            :     }
      98                 :            :     else
      99                 :            :     {
     100                 :          8 :       previousEdgeDir = nextEdgeDir;
     101                 :            :     }
     102                 :            :   }
     103         [ -  + ]:          6 :   if (pointsToDrop > 0u)
     104                 :            :   {
     105                 :          0 :     std::size_t const newEdgeSize = std::max(std::size_t(2u), edge.size() - pointsToDrop);
     106         [ #  # ]:          0 :     edge.resize(newEdgeSize);
     107                 :            :   }
     108                 :            : }
     109                 :            : 
     110                 :            : std::vector<std::size_t>
     111                 :          3 : calcSmallerEdgeIndexPairs(std::vector<physics::ParametricValue> const &biggerEdgeParametricPoints,
     112                 :            :                           std::vector<physics::ParametricValue> const &smallerEdgeParametricPoints)
     113                 :            : {
     114                 :          3 :   std::vector<std::size_t> indexPairs;
     115         [ +  - ]:          3 :   indexPairs.reserve(biggerEdgeParametricPoints.size());
     116         [ +  - ]:          3 :   indexPairs.push_back(0u);
     117                 :          3 :   std::size_t matchingSmallerIndex = 0u;
     118         [ +  + ]:          9 :   for (std::size_t biggerIndex = 1u; biggerIndex < biggerEdgeParametricPoints.size(); biggerIndex++)
     119                 :            :   {
     120                 :          6 :     physics::ParametricValue minParametricDistance(1.);
     121                 :          6 :     bool matchingIndexFound = false;
     122                 :            :     // since both lists are sorted in ascending, it's ok to start search at last found index
     123                 :         15 :     for (std::size_t smallerIndex = matchingSmallerIndex;
     124   [ +  -  +  +  :         15 :          (!matchingIndexFound) && (smallerIndex < smallerEdgeParametricPoints.size());
                   +  + ]
     125                 :            :          smallerIndex++)
     126                 :            :     {
     127                 :            :       auto const parametricDistance
     128         [ +  - ]:          9 :         = std::fabs(smallerEdgeParametricPoints[smallerIndex] - biggerEdgeParametricPoints[biggerIndex]);
     129   [ +  -  -  + ]:          9 :       if (parametricDistance > minParametricDistance)
     130                 :            :       {
     131                 :            :         // the best matching edge point is the one we have seen last
     132                 :          0 :         matchingSmallerIndex = smallerIndex - 1u;
     133                 :          0 :         matchingIndexFound = true;
     134         [ #  # ]:          0 :         indexPairs.push_back(matchingSmallerIndex);
     135                 :            :       }
     136                 :            :       else
     137                 :            :       {
     138                 :          9 :         minParametricDistance = parametricDistance;
     139                 :            :       }
     140                 :            :     }
     141         [ +  - ]:          6 :     if (!matchingIndexFound)
     142                 :            :     {
     143                 :            :       // if not yet found, the last is the best matching one
     144                 :          6 :       matchingSmallerIndex = smallerEdgeParametricPoints.size() - 1u;
     145         [ +  - ]:          6 :       indexPairs.push_back(matchingSmallerIndex);
     146                 :            :     }
     147                 :            :   }
     148                 :          6 :   return indexPairs;
     149                 :            : }
     150                 :            : 
     151                 :         14 : point::ENUPoint interpolatePoint(point::ENUPoint const &pointBefore,
     152                 :            :                                  point::ENUPoint const &pointAfter,
     153                 :            :                                  physics::ParametricValue const pointBeforeParametricEdgeOffset,
     154                 :            :                                  physics::ParametricValue const pointInterpolatedParametricEdgeOffset,
     155                 :            :                                  physics::ParametricValue const pointAfterParametricEdgeOffset)
     156                 :            : {
     157                 :            :   physics::ParametricValue const parametricOffset(
     158         [ +  - ]:         14 :     (pointInterpolatedParametricEdgeOffset - pointBeforeParametricEdgeOffset)
     159   [ +  -  +  - ]:         28 :     / (pointAfterParametricEdgeOffset - pointBeforeParametricEdgeOffset));
     160         [ +  - ]:         28 :   return point::vectorInterpolate(pointBefore, pointAfter, parametricOffset);
     161                 :            : }
     162                 :            : 
     163                 :          2 : void fillSmallerEdge(point::ENUEdge const &biggerEdge, point::ENUEdge &smallerEdge)
     164                 :            : {
     165         [ +  - ]:          4 :   auto const biggerEdgeParametricPoints = getParametricEdgePoints(biggerEdge);
     166         [ +  - ]:          4 :   auto const smallerEdgeParametricPoints = getParametricEdgePoints(smallerEdge);
     167                 :            : 
     168         [ +  - ]:          4 :   auto const smallerEdgeIndices = calcSmallerEdgeIndexPairs(biggerEdgeParametricPoints, smallerEdgeParametricPoints);
     169                 :            : 
     170                 :          4 :   point::ENUEdge newSmallerEdge;
     171         [ +  - ]:          2 :   newSmallerEdge.reserve(biggerEdge.size());
     172         [ +  - ]:          2 :   newSmallerEdge.push_back(smallerEdge.front());
     173                 :          2 :   std::size_t lastWrittenSmallerEdgeIndex = 0u;
     174         [ +  + ]:          4 :   for (std::size_t i = 1u; i < smallerEdgeIndices.size() - 1u; ++i)
     175                 :            :   {
     176                 :            :     // i-1, i, i+1 indices are valid for smallerEdgeIndices and biggerEdgeParametricPoints
     177                 :            : 
     178                 :          2 :     if ( // smaller point already processed, insert an interpolated
     179                 :          2 :       (smallerEdgeIndices[i] == lastWrittenSmallerEdgeIndex)
     180                 :            :       // the point before the last point of the smaller edge is already written, so we have to interpolate till the end
     181   [ +  -  +  -  :          2 :       || (lastWrittenSmallerEdgeIndex == (smallerEdge.size() - 2u)))
                   +  - ]
     182                 :            :     {
     183                 :          2 :       auto interpolatedPoint = interpolatePoint(smallerEdge[lastWrittenSmallerEdgeIndex],
     184                 :          2 :                                                 smallerEdge[lastWrittenSmallerEdgeIndex + 1u],
     185                 :          2 :                                                 biggerEdgeParametricPoints[i - 1],
     186                 :          2 :                                                 biggerEdgeParametricPoints[i],
     187         [ +  - ]:          4 :                                                 biggerEdgeParametricPoints[i + 1]);
     188         [ +  - ]:          2 :       newSmallerEdge.push_back(interpolatedPoint);
     189                 :            :     }
     190                 :            :     else
     191                 :            :     {
     192                 :          0 :       lastWrittenSmallerEdgeIndex = smallerEdgeIndices[i];
     193         [ #  # ]:          0 :       newSmallerEdge.push_back(smallerEdge[lastWrittenSmallerEdgeIndex]);
     194                 :            :     }
     195                 :            :   }
     196         [ +  - ]:          2 :   newSmallerEdge.push_back(smallerEdge.back());
     197                 :          2 :   smallerEdge.swap(newSmallerEdge);
     198                 :          2 : }
     199                 :            : 
     200                 :          3 : void normalizeBorder(ENUBorder &border, ENUBorder const *previousBorder)
     201                 :            : {
     202   [ +  -  -  +  :          3 :   if ((border.left.size() < 2u) || (border.right.size() < 2u))
                   -  + ]
     203                 :            :   {
     204                 :          1 :     return;
     205                 :            :   }
     206   [ +  -  +  +  :          3 :   if ((previousBorder != nullptr) && (previousBorder->left.size() >= 2u) && (previousBorder->right.size() >= 2u))
             +  -  +  + ]
     207                 :            :   {
     208         [ +  - ]:          1 :     removeDegeneratedEdgePoints(border.left, &previousBorder->left);
     209         [ +  - ]:          1 :     removeDegeneratedEdgePoints(border.right, &previousBorder->right);
     210                 :            :   }
     211                 :            :   else
     212                 :            :   {
     213         [ +  - ]:          2 :     removeDegeneratedEdgePoints(border.left);
     214         [ +  - ]:          2 :     removeDegeneratedEdgePoints(border.right);
     215                 :            :   }
     216         [ +  + ]:          3 :   if (border.left.size() == border.right.size())
     217                 :            :   {
     218                 :          1 :     return;
     219                 :            :   }
     220                 :            : 
     221                 :          4 :   std::vector<std::size_t> smallerEdgeIndices;
     222         [ +  - ]:          2 :   if (border.left.size() > border.right.size())
     223                 :            :   {
     224         [ +  - ]:          2 :     fillSmallerEdge(border.left, border.right);
     225                 :            :   }
     226                 :            :   else
     227                 :            :   {
     228         [ #  # ]:          0 :     fillSmallerEdge(border.right, border.left);
     229                 :            :   }
     230                 :            : }
     231                 :            : 
     232                 :          2 : IndexPairs getIndexPairs(point::ENUEdge const &leftEdge, point::ENUEdge const &rightEdge)
     233                 :            : {
     234                 :          2 :   std::size_t const maxSize = std::max(leftEdge.size(), rightEdge.size());
     235                 :          4 :   std::vector<std::size_t> equalIndices;
     236         [ +  - ]:          2 :   equalIndices.reserve(maxSize);
     237         [ +  + ]:          7 :   for (size_t i = 0u; i < maxSize; ++i)
     238                 :            :   {
     239         [ +  - ]:          5 :     equalIndices.push_back(i);
     240                 :            :   }
     241                 :            : 
     242                 :          2 :   IndexPairs indexPairs;
     243         [ +  + ]:          2 :   if (leftEdge.size() == rightEdge.size())
     244                 :            :   {
     245         [ +  - ]:          1 :     indexPairs.leftEdgeIndices = equalIndices;
     246                 :          1 :     indexPairs.rightEdgeIndices.swap(equalIndices);
     247                 :            :   }
     248         [ +  - ]:          1 :   else if (leftEdge.size() > rightEdge.size())
     249                 :            :   {
     250                 :          1 :     indexPairs.leftEdgeIndices.swap(equalIndices);
     251                 :            :     indexPairs.rightEdgeIndices
     252   [ +  -  +  -  :          1 :       = calcSmallerEdgeIndexPairs(getParametricEdgePoints(leftEdge), getParametricEdgePoints(rightEdge));
                   +  - ]
     253                 :            :   }
     254                 :            :   else
     255                 :            :   {
     256                 :            :     indexPairs.leftEdgeIndices
     257   [ #  #  #  #  :          0 :       = calcSmallerEdgeIndexPairs(getParametricEdgePoints(rightEdge), getParametricEdgePoints(leftEdge));
                   #  # ]
     258                 :          0 :     indexPairs.rightEdgeIndices.swap(equalIndices);
     259                 :            :   }
     260                 :          4 :   return indexPairs;
     261                 :            : }
     262                 :            : 
     263                 :          1 : point::ENUEdge getLateralAlignmentEdge(ENUBorder const &border, physics::ParametricValue const lateralAlignment)
     264                 :            : {
     265                 :          1 :   return point::getLateralAlignmentEdge(border.left, border.right, lateralAlignment);
     266                 :            : }
     267                 :            : 
     268                 :          0 : inline bool isPointWithinBorderPoints(point::ENUPoint const &ptLeft,
     269                 :            :                                       point::ENUPoint const &ptRight,
     270                 :            :                                       point::ENUPoint const &enuPoint)
     271                 :            : {
     272                 :            :   // check if the point is actually located in between the border points
     273         [ #  # ]:          0 :   auto const towardsLeft = ptLeft - enuPoint;
     274         [ #  # ]:          0 :   auto const towardsRight = ptRight - enuPoint;
     275                 :          0 :   auto const dotProduct = point::vectorDotProduct(towardsLeft, towardsRight);
     276   [ #  #  #  #  :          0 :   auto const withinBorders = (dotProduct < 0.) || (point::vectorLength(towardsLeft) < physics::Distance(0.01))
                   #  # ]
     277   [ #  #  #  #  :          0 :     || (point::vectorLength(towardsRight) < physics::Distance(0.01));
             #  #  #  # ]
     278                 :          0 :   return withinBorders;
     279                 :            : }
     280                 :            : 
     281                 :          0 : inline point::ENUHeading createHeadingFromBorderPoints(point::ENUPoint const &ptLeft, point::ENUPoint const &ptRight)
     282                 :            : {
     283         [ #  # ]:          0 :   auto const headingLeftToRight = point::createENUHeading(ptLeft, ptRight);
     284         [ #  # ]:          0 :   auto const resultHeading = point::createENUHeading(static_cast<double>(headingLeftToRight) + M_PI_2);
     285                 :          0 :   return resultHeading;
     286                 :            : }
     287                 :            : 
     288                 :          0 : point::ENUHeading getENUHeading(ENUBorderList const &borderList, point::ENUPoint const &enuPoint)
     289                 :            : {
     290                 :          0 :   point::ENUHeading resultHeading(2. * M_PI);
     291                 :            : 
     292                 :          0 :   auto firstBeforeBorderDetected = borderList.end();
     293                 :          0 :   auto lastAfterBorderDetected = borderList.end();
     294         [ #  # ]:          0 :   for (auto borderIter = borderList.begin(); borderIter != borderList.end(); borderIter++)
     295                 :            :   {
     296         [ #  # ]:          0 :     auto const edgeLeftLength = calcLength(borderIter->left);
     297         [ #  # ]:          0 :     auto const edgeRightLength = calcLength(borderIter->right);
     298                 :            : 
     299                 :            :     // first of all we have to handle degenerated borders
     300   [ #  #  #  #  :          0 :     if ((edgeLeftLength == physics::Distance(0.)) || (edgeRightLength == physics::Distance(0.)))
          #  #  #  #  #  
                      # ]
     301                 :            :     {
     302   [ #  #  #  #  :          0 :       if ((borderIter->left.size() == 0u) || (borderIter->right.size() == 0u))
                   #  # ]
     303                 :            :       {
     304   [ #  #  #  # ]:          0 :         access::getLogger()->error(
     305                 :            :           "ad::map::lane::getENUHeading: invalid enu border of size border-left:{} border-rigth:{} query-point:{}!",
     306                 :          0 :           borderIter->left,
     307                 :          0 :           borderIter->right,
     308                 :            :           enuPoint);
     309                 :          0 :         return resultHeading;
     310                 :            :       }
     311                 :            : 
     312                 :            :       // the question here is: are we actually before or after the border
     313         [ #  # ]:          0 :       auto const headingLeftToRight = point::createENUHeading(borderIter->left[0], borderIter->right[0]);
     314         [ #  # ]:          0 :       auto const headingLeftToPoint = point::createENUHeading(borderIter->left[0], enuPoint);
     315   [ #  #  #  # ]:          0 :       auto const headingDiff = point::createENUHeading(static_cast<double>(headingLeftToPoint - headingLeftToRight));
     316   [ #  #  #  # ]:          0 :       if (headingDiff < point::ENUHeading(0.))
     317                 :            :       {
     318         [ #  # ]:          0 :         if (firstBeforeBorderDetected == borderList.end())
     319                 :            :         {
     320                 :          0 :           firstBeforeBorderDetected = borderIter;
     321                 :            :         }
     322                 :            :       }
     323                 :            :       else
     324                 :            :       {
     325                 :          0 :         lastAfterBorderDetected = borderIter;
     326                 :            :       }
     327                 :            :     }
     328                 :            :     else
     329                 :            :     {
     330         [ #  # ]:          0 :       auto parametricOffsetLeft = point::findNearestPointOnEdge(borderIter->left, edgeLeftLength, enuPoint);
     331         [ #  # ]:          0 :       auto parametricOffsetRight = point::findNearestPointOnEdge(borderIter->right, edgeRightLength, enuPoint);
     332                 :            : 
     333                 :            :       // catch errors
     334   [ #  #  #  #  :          0 :       if ((!parametricOffsetLeft.isValid()) || (!parametricOffsetRight.isValid()))
                   #  # ]
     335                 :            :       {
     336   [ #  #  #  # ]:          0 :         access::getLogger()->error(
     337                 :            :           "ad::map::lane::getENUHeading: invalid input data border-left:{} border-rigth:{} query-point:{}",
     338                 :          0 :           borderIter->left,
     339                 :          0 :           borderIter->right,
     340                 :            :           enuPoint);
     341                 :          0 :         return resultHeading;
     342                 :            :       }
     343                 :            : 
     344         [ #  # ]:          0 :       if ((parametricOffsetLeft == physics::ParametricValue(0.))
     345   [ #  #  #  #  :          0 :           || (parametricOffsetRight == physics::ParametricValue(0.)))
             #  #  #  # ]
     346                 :            :       {
     347         [ #  # ]:          0 :         if (firstBeforeBorderDetected == borderList.end())
     348                 :            :         {
     349                 :          0 :           firstBeforeBorderDetected = borderIter;
     350                 :            :         }
     351                 :            :       }
     352         [ #  # ]:          0 :       else if ((parametricOffsetLeft == physics::ParametricValue(1.))
     353   [ #  #  #  #  :          0 :                || (parametricOffsetRight == physics::ParametricValue(1.)))
             #  #  #  # ]
     354                 :            :       {
     355                 :          0 :         lastAfterBorderDetected = borderIter;
     356                 :            :       }
     357                 :            :       else
     358                 :            :       {
     359                 :            :         // looks as we have found a potential segment
     360         [ #  # ]:          0 :         auto const ptLeft = point::getParametricPoint(borderIter->left, parametricOffsetLeft);
     361         [ #  # ]:          0 :         auto const ptRight = point::getParametricPoint(borderIter->right, parametricOffsetRight);
     362         [ #  # ]:          0 :         bool const withinBorder = isPointWithinBorderPoints(ptLeft, ptRight, enuPoint);
     363                 :            : 
     364         [ #  # ]:          0 :         if (withinBorder)
     365                 :            :         {
     366         [ #  # ]:          0 :           return createHeadingFromBorderPoints(ptLeft, ptRight);
     367                 :            :         }
     368                 :            :       }
     369                 :            :     }
     370                 :            :   }
     371                 :            : 
     372                 :            :   // if we didn't find any actual match in between so far, use either the first before or the last after to create the
     373                 :            :   // heading
     374         [ #  # ]:          0 :   if (firstBeforeBorderDetected != borderList.end())
     375                 :            :   {
     376                 :          0 :     auto const ptLeft = firstBeforeBorderDetected->left.front();
     377                 :          0 :     auto const ptRight = firstBeforeBorderDetected->right.front();
     378         [ #  # ]:          0 :     bool const withinBorder = isPointWithinBorderPoints(ptLeft, ptRight, enuPoint);
     379         [ #  # ]:          0 :     if (withinBorder)
     380                 :            :     {
     381         [ #  # ]:          0 :       return createHeadingFromBorderPoints(ptLeft, ptRight);
     382                 :            :     }
     383                 :            :   }
     384         [ #  # ]:          0 :   if (lastAfterBorderDetected != borderList.end())
     385                 :            :   {
     386                 :          0 :     auto const ptLeft = lastAfterBorderDetected->left.back();
     387                 :          0 :     auto const ptRight = lastAfterBorderDetected->right.back();
     388         [ #  # ]:          0 :     bool const withinBorder = isPointWithinBorderPoints(ptLeft, ptRight, enuPoint);
     389         [ #  # ]:          0 :     if (withinBorder)
     390                 :            :     {
     391         [ #  # ]:          0 :       return createHeadingFromBorderPoints(ptLeft, ptRight);
     392                 :            :     }
     393                 :            :   }
     394                 :            : 
     395                 :          0 :   return resultHeading;
     396                 :            : }
     397                 :            : 
     398                 :          1 : physics::Distance getDistanceEnuPointToLateralAlignmentEdge(point::ENUPoint const &enuPoint,
     399                 :            :                                                             point::ENUEdge const &lateralAlignmentEdge)
     400                 :            : {
     401         [ +  - ]:          1 :   auto const edgeLength = calcLength(lateralAlignmentEdge);
     402         [ +  - ]:          1 :   auto const parametricOffset = point::findNearestPointOnEdge(lateralAlignmentEdge, edgeLength, enuPoint);
     403         [ +  - ]:          1 :   auto const projectedPoint = point::getParametricPoint(lateralAlignmentEdge, edgeLength, parametricOffset);
     404         [ +  - ]:          1 :   auto const distance = point::distance(projectedPoint, enuPoint);
     405                 :          1 :   return distance;
     406                 :            : }
     407                 :            : 
     408                 :         12 : bool areEdgesContinuous(point::ENUEdge const &first, point::ENUEdge const &second)
     409                 :            : {
     410   [ +  -  -  +  :         12 :   if ((first.size() < 2u) || (second.size() < 2u))
                   -  + ]
     411                 :            :   {
     412                 :          0 :     return true;
     413                 :            :   }
     414                 :            : 
     415         [ +  - ]:         12 :   auto const firstToSecondDistance = point::distance(second.front(), first.back());
     416   [ +  -  -  + ]:         12 :   if (firstToSecondDistance < point::cEdgePointBorderDistance)
     417                 :            :   {
     418                 :          0 :     return true;
     419                 :            :   }
     420                 :         12 :   return false;
     421                 :            : }
     422                 :            : 
     423                 :          8 : void performMakeTransitionToSecondEdgeContinuous(point::ENUEdge const &first,
     424                 :            :                                                  point::ENUEdge &second,
     425                 :            :                                                  point::ENUEdge *secondOtherLane = nullptr)
     426                 :            : {
     427   [ +  -  -  + ]:          8 :   if (areEdgesContinuous(first, second))
     428                 :            :   {
     429                 :          0 :     return;
     430                 :            :   }
     431         [ +  - ]:          8 :   auto const firstToSecondVec = second.front() - first.back();
     432         [ +  - ]:          8 :   auto const firstToSecondDistance = point::vectorLength(firstToSecondVec);
     433         [ +  - ]:          8 :   auto const firstToSecondDir = point::vectorNorm(firstToSecondVec);
     434   [ +  -  +  - ]:          8 :   auto const firstEndDir = getEdgeEndDirectionalVector(first);
     435   [ +  -  +  - ]:          8 :   auto const secondStartDir = getEdgeStartDirectionalVector(second);
     436   [ +  -  +  - ]:          8 :   auto const averageEdgeDir = 0.5 * (firstEndDir + secondStartDir);
     437                 :            :   double const sinAngle
     438   [ +  -  +  - ]:          8 :     = static_cast<double>(point::vectorLength(point::vectorCrossProduct(averageEdgeDir, firstToSecondDir)));
     439                 :            :   // the distance of our interpolation changes depend on the offset of the two edges ends and the lateral offset
     440                 :            :   // (given by the sine of the angle between the general edge direction and the offset direction)
     441                 :            :   // e.g. if the offset is 3m and orthogonal we get a 6m interpolating distance
     442         [ +  - ]:          8 :   auto const interpolatingDistance = sinAngle * 2.0 * firstToSecondDistance;
     443                 :            : 
     444         [ +  - ]:          8 :   auto const secondLength = calcLength(second);
     445                 :            : 
     446         [ +  - ]:          8 :   physics::ParametricValue const parametricInterpolatingDistance(std::min(.95, interpolatingDistance / secondLength));
     447                 :            : 
     448         [ +  - ]:         16 :   auto const secondParametricEdgePoints = getParametricEdgePoints(second);
     449                 :            : 
     450                 :          8 :   std::size_t const newSecondSize = second.size() + 1u;
     451                 :         16 :   point::ENUEdge newSecond;
     452         [ +  - ]:          8 :   newSecond.reserve(newSecondSize);
     453                 :         16 :   point::ENUEdge newOtherSecond;
     454   [ +  +  +  -  :          8 :   if ((secondOtherLane != nullptr) && (secondOtherLane->size() == second.size()))
                   +  + ]
     455                 :            :   {
     456         [ +  - ]:          4 :     newOtherSecond.resize(newSecondSize);
     457                 :            :   }
     458         [ +  + ]:         18 :   for (std::size_t i = 1u; i < secondParametricEdgePoints.size(); ++i)
     459                 :            :   {
     460   [ +  -  +  - ]:         10 :     if (secondParametricEdgePoints[i] >= parametricInterpolatingDistance)
     461                 :            :     {
     462         [ +  + ]:         10 :       if (newSecond.empty())
     463                 :            :       {
     464                 :            :         // first point found
     465                 :            : 
     466                 :            :         // take the last point of the first edge
     467         [ +  - ]:          8 :         newSecond.push_back(first.back());
     468                 :            : 
     469                 :            :         // calculate the interpolated point
     470                 :          8 :         point::ENUPoint interpolatedPoint = interpolatePoint(second[i - 1],
     471                 :          8 :                                                              second[i],
     472                 :          8 :                                                              secondParametricEdgePoints[i - 1],
     473                 :            :                                                              parametricInterpolatingDistance,
     474         [ +  - ]:         16 :                                                              secondParametricEdgePoints[i]);
     475                 :            : 
     476                 :            :         //@todo: one potential issue is not considered in here yet:
     477                 :            :         // if second curvature is extreme, the newly created linear edge segment by the above two points could
     478                 :            :         // potentially intersect with the old second border and by that enlarging a driving area beyond the
     479                 :            :         // allowed borders. To prevent from this one would have to implement 'point::vectorIntersects':
     480                 :            :         //
     481                 :            :         // auto const newEdgeSegment = interpolatedPoint-newSecond[0];
     482                 :            :         // for (std::size_t j=1u; j<i; j++ )
     483                 :            :         // {
     484                 :            :         //     auto const checkSegment = second[j] - second[j-1u];
     485                 :            :         //     if ( point::vectorIntersects(checkSegment, newEdgeSegment) )
     486                 :            :         //     {
     487                 :            :         //        i = j;
     488                 :            :         //        std::size_t const newSecondSize = secondParametricEdgePoints.size()-i + 1u;
     489                 :            :         //        newSecond.reserve(newSecondSize);
     490                 :            :         //        interpolatedPoint = secondParametricEdgePoints[i-1];
     491                 :            :         //        break;
     492                 :            :         //     }
     493                 :            :         // }
     494                 :            : 
     495                 :            :         // before adding the interpolated point we have to add also some interpolated points on the vector
     496                 :            :         // newSecond[0] -> interpolatedPoint if there have been others skipped
     497         [ -  + ]:          8 :         for (std::size_t j = 1u; j < i; ++j)
     498                 :            :         {
     499                 :          0 :           auto innerInterpolatedPoint = interpolatePoint(newSecond[0],
     500                 :            :                                                          interpolatedPoint,
     501                 :            :                                                          physics::ParametricValue(0.),
     502                 :          0 :                                                          secondParametricEdgePoints[j],
     503         [ #  # ]:          0 :                                                          parametricInterpolatingDistance);
     504         [ #  # ]:          0 :           newSecond.push_back(innerInterpolatedPoint);
     505                 :            :         }
     506                 :            : 
     507                 :            :         // then we add the interpolated point
     508         [ +  - ]:          8 :         newSecond.push_back(interpolatedPoint);
     509                 :            : 
     510                 :            :         // fill the newOtherSecond lane if available
     511         [ +  + ]:          8 :         if (newOtherSecond.size() > 0u)
     512                 :            :         {
     513                 :          4 :           std::size_t j = 0u;
     514   [ +  +  +  -  :          8 :           for (; (j < i) && (j < newOtherSecond.size()) && (j < secondOtherLane->size()); ++j)
             +  -  +  + ]
     515                 :            :           {
     516         [ +  - ]:          4 :             newOtherSecond[j] = secondOtherLane->at(j);
     517                 :            :           }
     518   [ +  -  +  -  :          4 :           if ((j < newOtherSecond.size()) && (j < secondOtherLane->size()))
                   +  - ]
     519                 :            :           {
     520                 :            :             // same parametric range than the interpolated point
     521                 :          4 :             newOtherSecond[j] = interpolatePoint(secondOtherLane->at(j - 1u),
     522   [ +  -  +  - ]:          4 :                                                  secondOtherLane->at(j),
     523                 :          4 :                                                  secondParametricEdgePoints[i - 1],
     524                 :            :                                                  parametricInterpolatingDistance,
     525         [ +  - ]:          8 :                                                  secondParametricEdgePoints[i]);
     526                 :            :           }
     527   [ +  +  +  -  :         10 :           for (; ((j + 1u) < newOtherSecond.size()) && (j < secondOtherLane->size()); j++)
                   +  + ]
     528                 :            :           {
     529         [ +  - ]:          6 :             newOtherSecond[j + 1u] = secondOtherLane->at(j);
     530                 :            :           }
     531                 :            :         }
     532                 :            :       }
     533                 :            :       // add this one
     534         [ +  - ]:         10 :       newSecond.push_back(second[i]);
     535                 :            :     }
     536                 :            :   }
     537                 :          8 :   second.swap(newSecond);
     538         [ +  + ]:          8 :   if (secondOtherLane != nullptr)
     539                 :            :   {
     540                 :          4 :     secondOtherLane->swap(newOtherSecond);
     541                 :            :   }
     542                 :            : }
     543                 :            : 
     544                 :          2 : void makeTransitionToSecondEdgeContinuous(point::ENUEdge const &first, point::ENUEdge &second)
     545                 :            : {
     546                 :          2 :   performMakeTransitionToSecondEdgeContinuous(first, second);
     547                 :          2 : }
     548                 :            : 
     549                 :          2 : void makeTransitionFromFirstEdgeContinuous(point::ENUEdge &first, point::ENUEdge const &second)
     550                 :            : {
     551   [ +  -  -  + ]:          2 :   if (areEdgesContinuous(first, second))
     552                 :            :   {
     553                 :          0 :     return;
     554                 :            :   }
     555                 :            :   // if actually something has to be calculated, we reverse the edge and let the other function do the job
     556         [ +  - ]:          4 :   point::ENUEdge invertedFirstEdge = first;
     557         [ +  - ]:          2 :   std::reverse(invertedFirstEdge.begin(), invertedFirstEdge.end());
     558         [ +  - ]:          4 :   point::ENUEdge invertedSecondEdge = second;
     559         [ +  - ]:          2 :   std::reverse(invertedSecondEdge.begin(), invertedSecondEdge.end());
     560         [ +  - ]:          2 :   performMakeTransitionToSecondEdgeContinuous(invertedSecondEdge, invertedFirstEdge);
     561         [ +  - ]:          2 :   first = invertedFirstEdge;
     562         [ +  - ]:          2 :   std::reverse(first.begin(), first.end());
     563                 :            : }
     564                 :            : 
     565                 :          2 : void makeTransitionToSecondBorderContinuous(ENUBorder const &first, ENUBorder &second)
     566                 :            : {
     567                 :          2 :   performMakeTransitionToSecondEdgeContinuous(first.left, second.left, &second.right);
     568                 :          2 :   performMakeTransitionToSecondEdgeContinuous(first.right, second.right, &second.left);
     569                 :          2 : }
     570                 :            : 
     571                 :          2 : void makeTransitionFromFirstBorderContinuous(ENUBorder &first, ENUBorder const &second)
     572                 :            : {
     573   [ +  -  -  +  :          2 :   if (areEdgesContinuous(first.left, second.left) && areEdgesContinuous(first.right, second.right))
          -  -  -  -  -  
                      + ]
     574                 :            :   {
     575                 :          0 :     return;
     576                 :            :   }
     577                 :            :   // if actually something has to be calculated, we reverse the borders and let the other function do the job
     578                 :          4 :   ENUBorder invertedFirstBorder;
     579         [ +  - ]:          2 :   invertedFirstBorder.left = first.left;
     580         [ +  - ]:          2 :   invertedFirstBorder.right = first.right;
     581         [ +  - ]:          2 :   std::reverse(invertedFirstBorder.left.begin(), invertedFirstBorder.left.end());
     582         [ +  - ]:          2 :   std::reverse(invertedFirstBorder.right.begin(), invertedFirstBorder.right.end());
     583                 :          4 :   ENUBorder invertedSecondBorder;
     584         [ +  - ]:          2 :   invertedSecondBorder.left = second.left;
     585         [ +  - ]:          2 :   invertedSecondBorder.right = second.right;
     586         [ +  - ]:          2 :   std::reverse(invertedSecondBorder.left.begin(), invertedSecondBorder.left.end());
     587         [ +  - ]:          2 :   std::reverse(invertedSecondBorder.right.begin(), invertedSecondBorder.right.end());
     588         [ +  - ]:          2 :   makeTransitionToSecondBorderContinuous(invertedSecondBorder, invertedFirstBorder);
     589         [ +  - ]:          2 :   first = invertedFirstBorder;
     590         [ +  - ]:          2 :   std::reverse(first.left.begin(), first.left.end());
     591         [ +  - ]:          2 :   std::reverse(first.right.begin(), first.right.end());
     592                 :            : }
     593                 :            : 
     594                 :            : } // namespace lane
     595                 :            : } // namespace map
     596                 :            : } // namespace ad

Generated by: LCOV version 1.14