ad_map_access
EdgeOperation.hpp
Go to the documentation of this file.
1 // ----------------- BEGIN LICENSE BLOCK ---------------------------------
2 //
3 // Copyright (C) 2018-2021 Intel Corporation
4 //
5 // SPDX-License-Identifier: MIT
6 //
7 // ----------------- END LICENSE BLOCK -----------------------------------
12 #pragma once
13 
14 #include <utility>
15 #include <vector>
17 #include "ad/physics/MetricRange.hpp"
18 #include "ad/physics/Operation.hpp"
19 #include "ad/physics/ParametricRange.hpp"
20 #include "ad/physics/ParametricValueValidInputRange.hpp"
21 #include "ad/physics/RangeOperation.hpp"
22 
24 namespace ad {
26 namespace map {
28 namespace point {
29 
33 physics::Distance const cEdgePointBorderDistance{0.1};
34 
43 template <typename PointType>
44 physics::RatioValue findNearestPointOnEdge(PointType const &a, const PointType &pt0, const PointType &pt1)
45 {
46  PointType line = pt1 - pt0;
47  PointType pt02a = a - pt0;
48  auto const divisor = vectorDotProduct(line, line);
49  if (physics::Distance(divisor) > physics::Distance(0))
50  {
51  auto const dividend = vectorDotProduct(pt02a, line);
52  auto result = dividend / divisor;
53  return physics::RatioValue(result);
54  }
55  else
56  {
57  return physics::RatioValue(0.5);
58  }
59 }
60 
70 template <typename PointType>
71 physics::ParametricValue findNearestPointOnSegment(PointType const &a, const PointType &pt0, const PointType &pt1)
72 {
73  auto const t = findNearestPointOnEdge(a, pt0, pt1);
74  if (t < physics::RatioValue(0.))
75  {
76  return physics::ParametricValue(0.);
77  }
78  else if (t > physics::RatioValue(1.))
79  {
80  return physics::ParametricValue(1.);
81  }
82  else
83  {
84  return physics::ParametricValue(static_cast<double>(t));
85  }
86 }
87 
93 template <typename PointType> physics::Distance calculateEdgeLength(std::vector<PointType> const &edge)
94 {
95  physics::Distance length(0.);
96  for (auto i = 1u; i < edge.size(); ++i)
97  {
98  length += distance(edge[i - 1u], edge[i]);
99  }
100  return length;
101 }
102 
108 template <typename PointType>
109 std::vector<physics::ParametricValue> getParametricEdgePoints(std::vector<PointType> const &edge)
110 {
111  std::vector<physics::ParametricValue> resultPoints;
112  resultPoints.reserve(edge.size());
113  resultPoints.push_back(physics::ParametricValue(0.));
114  physics::Distance length(0.);
115  for (auto i = 1u; i < edge.size(); ++i)
116  {
117  length += distance(edge[i - 1u], edge[i]);
118  resultPoints.push_back(physics::ParametricValue(static_cast<double>(length)));
119  }
120 
121  for (auto i = 1u; i < edge.size(); ++i)
122  {
123  if (length > physics::Distance(0.))
124  {
125  resultPoints[i] = resultPoints[i] / static_cast<double>(length);
126  }
127  }
128  return resultPoints;
129 }
130 
137 template <typename PointType>
138 PointType getParametricPoint(std::vector<PointType> const &edge,
139  physics::Distance const &edgeLength,
140  const physics::ParametricValue &t)
141 {
142  if (!edge.empty())
143  {
144  physics::Distance length(0);
145  physics::Distance length_t = edgeLength * t;
146  for (size_t i = 0; i < edge.size() - 1; i++)
147  {
148  const auto &pt0 = edge[i];
149  const auto &pt1 = edge[i + 1];
150  auto d = distance(pt0, pt1);
151  if (d != physics::Distance(0.))
152  {
153  auto length_1 = length + d;
154  if (length_1 >= length_t)
155  {
156  auto d_t = length_t - length;
157  physics::ParametricValue tt(d_t / d);
158  return vectorInterpolate(pt0, pt1, tt);
159  }
160  else
161  {
162  length = length_1;
163  }
164  }
165  }
166  return edge.back();
167  }
168  else
169  {
170  return PointType();
171  }
172 }
173 
180 template <typename PointType>
181 PointType getParametricPoint(std::vector<PointType> const &edge, const physics::ParametricValue &t)
182 {
183  return getParametricPoint(edge, calculateEdgeLength(edge), t);
184 }
185 
192 template <typename PointType>
193 std::vector<PointType> getParametricRange(std::vector<PointType> const &edge,
194  physics::Distance const &edgeLength,
195  const physics::ParametricRange &trange)
196 {
197  typedef std::vector<PointType> EdgeType;
198  if (!edge.empty())
199  {
200  EdgeType pts;
201  physics::Distance length(0);
202  physics::Distance length_t_start = edgeLength * trange.minimum;
203  size_t i = 0;
204  for (; i < edge.size() - 1 && pts.empty(); i++)
205  {
206  const PointType &pt0 = edge[i];
207  const PointType &pt1 = edge[i + 1];
208  physics::Distance d = distance(pt0, pt1);
209  physics::Distance length_1 = length + d;
210  if (length_1 >= length_t_start)
211  {
212  if (d != physics::Distance(0))
213  {
214  physics::Distance d_t = length_t_start - length;
215  physics::ParametricValue tt(d_t / d);
216  PointType pt_start = vectorInterpolate(pt0, pt1, tt);
217  pts.push_back(pt_start);
218  }
219  else
220  {
221  pts.push_back(pt1);
222  }
223  break;
224  }
225  else
226  {
227  length = length_1;
228  }
229  }
230  if (!pts.empty())
231  {
232  physics::Distance length_t_end = edgeLength * trange.maximum;
233  for (; i < edge.size() - 1; i++)
234  {
235  const PointType &pt0 = edge[i];
236  const PointType &pt1 = edge[i + 1];
237  physics::Distance d = distance(pt0, pt1);
238  physics::Distance length_1 = length + d;
239  if (length_1 >= length_t_end)
240  {
241  if (d != physics::Distance(0))
242  {
243  physics::Distance d_t = length_t_end - length;
244  physics::ParametricValue tt(d_t / d);
245  PointType pt_end = vectorInterpolate(pt0, pt1, tt);
246  pts.push_back(pt_end);
247  }
248  else
249  {
250  pts.push_back(pt1);
251  }
252  return pts;
253  }
254  else
255  {
256  pts.push_back(pt1);
257  length = length_1;
258  }
259  }
260  pts.push_back(edge.back());
261  return pts;
262  }
263  }
264  return EdgeType();
265 }
266 
273 template <typename PointType>
274 std::vector<PointType> getParametricRange(std::vector<PointType> const &edge, const physics::ParametricRange &trange)
275 {
276  return getParametricRange(edge, calculateEdgeLength(edge), trange);
277 }
278 
285 template <typename PointType>
286 physics::ParametricValue
287 findNearestPointOnEdge(std::vector<PointType> const &edge, physics::Distance const &edgeLength, const PointType &pt)
288 {
289  if (isValid(pt))
290  {
291  if (edge.size() == 0)
292  {
293  return physics::ParametricValue();
294  }
295  else if ((edge.size() == 1) || (edgeLength == physics::Distance(0.)))
296  {
297  return physics::ParametricValue(0);
298  }
299  else
300  {
301  physics::ParametricValue t_one = findNearestPointOnSegment(pt, edge[0], edge[1]);
302  PointType pt_nearest = vectorInterpolate(edge[0], edge[1], t_one);
303  physics::Distance d_nearest = distance(pt, pt_nearest);
304  physics::Distance offset_nearest = distance(pt_nearest, edge[0]);
305  physics::Distance running_offset = physics::Distance(0);
306  for (size_t i = 1; i + 1 < edge.size(); i++)
307  {
308  physics::ParametricValue t = findNearestPointOnSegment(pt, edge[i], edge[i + 1]);
309  PointType pt_candidate = vectorInterpolate(edge[i], edge[i + 1], t);
310  physics::Distance d = distance(pt_candidate, pt);
311  running_offset += distance(edge[i - 1], edge[i]);
312  if (d < d_nearest)
313  {
314  pt_nearest = pt_candidate;
315  d_nearest = d;
316  offset_nearest = running_offset + distance(pt_nearest, edge[i]);
317  }
318  }
319  return physics::ParametricValue(offset_nearest / edgeLength);
320  }
321  }
322  else
323  {
324  return physics::ParametricValue();
325  }
326 }
327 
335 template <typename PointType>
336 physics::ParametricValue findNearestPointOnEdge(std::vector<PointType> const &edge, const PointType &pt)
337 {
338  return findNearestPointOnEdge(edge, calculateEdgeLength(edge), pt);
339 }
340 
353 template <typename PointType>
354 std::pair<physics::MetricRange, physics::Distance> calculateWidthRange(std::vector<PointType> const &edgeLeft,
355  physics::Distance const &edgeLeftLength,
356  std::vector<PointType> const &edgeRight,
357  physics::Distance const &edgeRightLength)
358 {
359  physics::MetricRange widthRange;
360  widthRange.minimum = std::numeric_limits<physics::Distance>::max();
361  widthRange.maximum = physics::Distance(0.);
362  physics::Distance widthSum(0.);
363  size_t widthSumCount(0u);
364  physics::ParametricValue parametricStepsize(0.5);
365  auto length = (edgeLeftLength + edgeRightLength) * 0.5;
366  if (length > physics::Distance(1.))
367  {
368  parametricStepsize
369  = std::max(physics::ParametricValue(0.01), physics::ParametricValue(1. / static_cast<double>(length)));
370  }
371  physics::ParametricValue longitudinalOffset(0.);
372  bool endReached = false;
373  do
374  {
375  auto const pt0 = getParametricPoint(edgeLeft, edgeLeftLength, longitudinalOffset);
376  auto const pt1 = getParametricPoint(edgeRight, edgeRightLength, longitudinalOffset);
377  if (!isValid(pt1) || !isValid(pt1))
378  {
379  return std::make_pair(physics::MetricRange(), physics::Distance());
380  }
381  auto const centerPoint = point::vectorInterpolate(pt0, pt1, physics::ParametricValue(0.5));
382  if (!isValid(centerPoint))
383  {
384  return std::make_pair(physics::MetricRange(), physics::Distance());
385  }
386  auto const longTLeft = findNearestPointOnEdge(edgeLeft, edgeLeftLength, centerPoint);
387  auto const longTRight = findNearestPointOnEdge(edgeRight, edgeRightLength, centerPoint);
388  if (!isRangeValid(longTLeft) || !isRangeValid(longTRight))
389  {
390  return std::make_pair(physics::MetricRange(), physics::Distance());
391  }
392  auto const pointOnLeftEdge = getParametricPoint(edgeLeft, edgeLeftLength, longTLeft);
393  auto const pointOnRightEdge = getParametricPoint(edgeRight, edgeRightLength, longTRight);
394  if (!isValid(pointOnLeftEdge) || !isValid(pointOnRightEdge))
395  {
396  return std::make_pair(physics::MetricRange(), physics::Distance());
397  }
398  physics::Distance const width = distance(pointOnLeftEdge, pointOnRightEdge);
399  unionRangeWith(widthRange, width);
400  widthSum += width;
401  widthSumCount++;
402  if (longitudinalOffset < physics::ParametricValue(1.))
403  {
404  longitudinalOffset += parametricStepsize;
405  if (longitudinalOffset > physics::ParametricValue(1.))
406  {
407  longitudinalOffset = physics::ParametricValue(1.);
408  }
409  }
410  else
411  {
412  endReached = true;
413  }
414  } while (!endReached);
415 
416  auto averageWidth = (widthSum / static_cast<double>(widthSumCount));
417 
418  return std::make_pair(widthRange, averageWidth);
419 }
420 
439 template <typename PointType>
440 std::vector<PointType> getLateralAlignmentEdge(std::vector<PointType> const &leftEdge,
441  physics::Distance const &leftEdgeLength,
442  std::vector<PointType> const &rightEdge,
443  physics::Distance const &rightEdgeLength,
444  physics::ParametricValue const lateralAlignment)
445 {
446  typedef std::vector<PointType> EdgeType;
447 
448  if (!withinValidInputRange(lateralAlignment))
449  {
450  throw std::invalid_argument("ad::map::point::getLateralAlignmentEdge()"
451  " the given lateralAlignment is out of range");
452  }
453 
454  EdgeType const *primary;
455  EdgeType const *secondary;
456  physics::Distance primaryLength;
457  physics::Distance secondaryLength;
458  physics::ParametricValue lateralOffset = lateralAlignment;
459  if (leftEdge.size() > rightEdge.size())
460  {
461  primary = &leftEdge;
462  primaryLength = leftEdgeLength;
463  secondary = &rightEdge;
464  secondaryLength = rightEdgeLength;
465  lateralOffset = physics::ParametricValue(1.) - lateralAlignment;
466  }
467  else
468  {
469  primary = &rightEdge;
470  primaryLength = rightEdgeLength;
471  secondary = &leftEdge;
472  secondaryLength = leftEdgeLength;
473  }
474 
475  std::vector<physics::ParametricValue> const primaryParametric = getParametricEdgePoints(*primary);
476  EdgeType alignmentEdge;
477  alignmentEdge.reserve(primaryParametric.size());
478  for (size_t i = 0; i < primaryParametric.size(); i++)
479  {
480  PointType const &pri = primary->at(i);
481  PointType const sec = getParametricPoint(*secondary, secondaryLength, primaryParametric[i]);
482  PointType const alignmentPoint = vectorInterpolate(pri, sec, lateralOffset);
483  alignmentEdge.push_back(alignmentPoint);
484  }
485  return alignmentEdge;
486 }
487 
506 template <typename PointType>
507 std::vector<PointType> getLateralAlignmentEdge(std::vector<PointType> const &leftEdge,
508  std::vector<PointType> const &rightEdge,
509  physics::ParametricValue const lateralAlignment)
510 {
512  leftEdge, calculateEdgeLength(leftEdge), rightEdge, calculateEdgeLength(rightEdge), lateralAlignment);
513 }
514 
522 template <typename PointType> PointType getEdgeStartDirectionalVector(std::vector<PointType> const edge)
523 {
524  if (edge.size() <= 1u)
525  {
526  return PointType();
527  }
528 
529  auto edgeStartVec = edge[1u] - edge[0u];
530  // in case the end points are too near to each other we take another point into account if possible
531  if ((vectorLength(edgeStartVec) < cEdgePointBorderDistance) && (edge.size() > 2u))
532  {
533  edgeStartVec = edge[2u] - edge[0u];
534  }
535  return vectorNorm(edgeStartVec);
536 }
537 
545 template <typename PointType> PointType getEdgeEndDirectionalVector(std::vector<PointType> const edge)
546 {
547  if (edge.size() <= 1u)
548  {
549  return PointType();
550  }
551 
552  auto edgeEndVec = edge[edge.size() - 1u] - edge[edge.size() - 2u];
553  // in case the end points are too near to each other we take another point into account if possible
554  if ((vectorLength(edgeEndVec) < cEdgePointBorderDistance) && (edge.size() > 2u))
555  {
556  edgeEndVec = edge[edge.size() - 1u] - edge[edge.size() - 3u];
557  }
558  return vectorNorm(edgeEndVec);
559 }
560 
561 } // namespace point
562 } // namespace map
563 } // namespace ad
ad::map::point::getParametricEdgePoints
std::vector< physics::ParametricValue > getParametricEdgePoints(std::vector< PointType > const &edge)
Get the parametric edge points.
Definition: EdgeOperation.hpp:109
ad
namespace ad
Definition: GeometryStoreItem.hpp:28
PointOperation.hpp
ad::map::point::calculateEdgeLength
physics::Distance calculateEdgeLength(std::vector< PointType > const &edge)
Calculate the length of an edge.
Definition: EdgeOperation.hpp:93
ad::map::point::findNearestPointOnSegment
physics::ParametricValue findNearestPointOnSegment(PointType const &a, const PointType &pt0, const PointType &pt1)
Find point nearest to the segment formed by two points.
Definition: EdgeOperation.hpp:71
ad::map::point::vectorDotProduct
double vectorDotProduct(PointType const &a, PointType const &b)
calculate the dot product of two vectors
Definition: PointOperation.hpp:54
withinValidInputRange
bool withinValidInputRange(::ad::map::access::MapMetaData const &input, bool const logErrors=true)
check if the given MapMetaData is within valid input range
Definition: MapMetaDataValidInputRange.hpp:37
ad::map::point::getLateralAlignmentEdge
std::vector< PointType > getLateralAlignmentEdge(std::vector< PointType > const &leftEdge, physics::Distance const &leftEdgeLength, std::vector< PointType > const &rightEdge, physics::Distance const &rightEdgeLength, physics::ParametricValue const lateralAlignment)
Get an edge between the two given border edges with corresponding lateralAlignment.
Definition: EdgeOperation.hpp:440
ad::map::point::distance
physics::Distance distance(BoundingSphere const &left, BoundingSphere const &right)
Computes distance between BoundingSpheres.
Definition: BoundingSphereOperation.hpp:29
ad::map::point::getParametricPoint
PointType getParametricPoint(std::vector< PointType > const &edge, physics::Distance const &edgeLength, const physics::ParametricValue &t)
Calculates parametric point on the edge.
Definition: EdgeOperation.hpp:138
ad::map::point::vectorInterpolate
PointType vectorInterpolate(PointType const &a, PointType const &b, physics::ParametricValue const &tparam)
Interpolates point between two points.
Definition: PointOperation.hpp:164
ad::map::point::isValid
bool isValid(ECEFPoint const &point, bool const logErrors=true)
checks if the given ECEFPoint is valid
Definition: ECEFOperation.hpp:27
ad::map::point::calculateWidthRange
std::pair< physics::MetricRange, physics::Distance > calculateWidthRange(std::vector< PointType > const &edgeLeft, physics::Distance const &edgeLeftLength, std::vector< PointType > const &edgeRight, physics::Distance const &edgeRightLength)
Calculate the width range and the average width of a pair of edges.
Definition: EdgeOperation.hpp:354
ad::map::point::getParametricRange
std::vector< PointType > getParametricRange(std::vector< PointType > const &edge, physics::Distance const &edgeLength, const physics::ParametricRange &trange)
Generates sub-edge for given range.
Definition: EdgeOperation.hpp:193
ad::map::point::getEdgeStartDirectionalVector
PointType getEdgeStartDirectionalVector(std::vector< PointType > const edge)
get a normalized vector representing the edge direction at edge start
Definition: EdgeOperation.hpp:522
ad::map::point::getEdgeEndDirectionalVector
PointType getEdgeEndDirectionalVector(std::vector< PointType > const edge)
get a normalized vector representing the edge direction at edge end
Definition: EdgeOperation.hpp:545
ad::map::point::cEdgePointBorderDistance
const physics::Distance cEdgePointBorderDistance
The edge point border distance.
Definition: EdgeOperation.hpp:33
ad::map::point::vectorLength
physics::Distance vectorLength(PointType const &a)
calculate the length of a vector
Definition: PointOperation.hpp:91
ad::map::point::findNearestPointOnEdge
physics::RatioValue findNearestPointOnEdge(PointType const &a, const PointType &pt0, const PointType &pt1)
Find point nearest to the line formed by two points.
Definition: EdgeOperation.hpp:44
ad::map::point::vectorNorm
PointType vectorNorm(PointType const &a)
normalizes a vector
Definition: PointOperation.hpp:104