3 #include <boost/geometry/algorithms/equals.hpp> 13 namespace bgi = boost::geometry::index;
18 #pragma GCC diagnostic push 19 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 20 template <
typename Po
int>
21 auto centerpoint(Point
p1, Point
p2) {
22 bg::add_point(p1, p2);
23 bg::multiply_value(p1, 0.5);
31 using SegmentTree = bgi::rtree<BasicSegment2d, bgi::linear<2>>;
32 using PointNode = std::pair<BasicPoint2d, ConstLineString2d::const_iterator>;
33 using PointTree = bgi::rtree<PointNode, bgi::linear<16>>;
46 const bool result = intersectsLeft(seg) || intersectsRight(seg) || crossesEntry(seg) || crossesExit(seg);
52 if (!boost::geometry::equals(it->first, seg.first)) {
61 if (!boost::geometry::equals(it->first, seg.first)) {
68 bool secondCrossesBounds(
const BasicSegment2d& seg,
bool left)
const {
70 for (
auto it = segmentTree.qbegin(bgi::intersects(seg)); it != segmentTree.qend(); ++it) {
71 using boost::geometry::equals;
72 if (!equals(it->first, seg.second) && !equals(it->second, seg.second)) {
80 if (geometry::intersects(seg,
entry_)) {
87 if (geometry::intersects(seg,
exit_)) {
93 template <
typename Func>
95 return forEachNearestPointUntilImpl(iter,
leftPts_, std::forward<Func>(f));
97 template <
typename Func>
99 return forEachNearestPointUntilImpl(iter,
rightPts_, std::forward<Func>(f));
103 template <
typename Func>
105 for (
auto qIt = tree.qbegin(boost::geometry::index::nearest(iter->basicPoint(), unsigned(tree.size())));
106 qIt != tree.qend(); ++qIt) {
107 if (f(qIt->second)) {
113 std::vector<PointNode> nodes;
114 nodes.reserve(ls.
size());
115 for (
auto it = ls.
begin(); it != ls.
end(); ++it) {
116 nodes.emplace_back(it->basicPoint(), it);
121 std::vector<BasicSegment2d> segments;
123 auto makeSegment = [](
const auto& seg) {
return BasicSegment2d(seg.first.basicPoint(), seg.second.basicPoint()); };
125 segments.push_back(makeSegment(line.
segment(i)));
134 std::pair<ConstLineString2d::const_iterator, OptDistance> findClosestNonintersectingPoint(
136 const BoundChecker& bounds,
const Point3d& lastPoint,
bool isLeft) {
144 if (candidate < currPosition) {
152 auto candidateDistance =
bg::distance(*candidate, *otherPoint) / 2;
153 if (!!distance && *distance <= candidateDistance) {
161 BasicSegment2d boundConnection(otherPoint->basicPoint(), candidate->basicPoint());
162 BasicSegment2d invBoundConnection(boundConnection.second, boundConnection.first);
163 auto centerlinePointCand = centerpoint(boundConnection.first, boundConnection.second);
165 if (!bounds.intersects(centerlineCandidate) && !bounds.secondCrossesBounds(boundConnection, isLeft) &&
166 !bounds.secondCrossesBounds(invBoundConnection, !isLeft)) {
167 distance = candidateDistance;
168 closestPosition = candidate;
173 bounds.forEachNearestPointLeftUntil(otherPoint, nonintersectingPointLoop);
175 bounds.forEachNearestPointRightUntil(otherPoint, nonintersectingPointLoop);
177 return {closestPosition, distance};
180 std::shared_ptr<ConstLineString3d> calculateCenterline(
const ConstLineString2d& leftBound,
181 const ConstLineString2d& rightBound) {
182 LineString3d centerlinePoints(
InvalId);
185 if (leftBound.empty() || rightBound.empty()) {
186 return std::make_shared<ConstLineString3d>(centerlinePoints);
192 centerlinePoints.push_back(makeCenterpoint(leftBound.front(), rightBound.front()));
194 auto leftCurrent = leftBound.begin();
195 auto rightCurrent = rightBound.begin();
197 if (*leftCurrent == *rightCurrent) {
200 while (leftCurrent != leftBound.end() || rightCurrent != rightBound.end()) {
207 std::tie(leftCandidate, leftCandidateDistance) =
208 findClosestNonintersectingPoint(std::next(leftCurrent), rightCurrent, bounds, centerlinePoints.back(),
true);
211 std::tie(rightCandidate, rightCandidateDistance) =
212 findClosestNonintersectingPoint(std::next(rightCurrent), leftCurrent, bounds, centerlinePoints.back(),
false);
214 if (leftCandidateDistance && (!rightCandidateDistance || leftCandidateDistance <= rightCandidateDistance)) {
215 assert(leftCandidate != leftBound.end());
217 const auto& leftPoint = leftBound[size_t(leftCandidate - leftBound.begin())];
218 const auto& rightPoint = rightBound[size_t(rightCurrent - rightBound.begin())];
219 centerlinePoints.push_back(makeCenterpoint(leftPoint, rightPoint));
220 leftCurrent = leftCandidate;
221 }
else if (rightCandidateDistance && (!leftCandidateDistance || leftCandidateDistance > rightCandidateDistance)) {
222 assert(rightCandidate != rightBound.end());
224 const auto& leftPoint = leftBound[size_t(leftCurrent - leftBound.begin())];
225 const auto& rightPoint = rightBound[size_t(rightCandidate - rightBound.begin())];
226 centerlinePoints.push_back(makeCenterpoint(leftPoint, rightPoint));
227 rightCurrent = rightCandidate;
235 if (!(leftCurrent == std::prev(leftBound.end()) && rightCurrent == std::prev(rightBound.end()))) {
236 centerlinePoints.push_back(makeCenterpoint(leftBound.back(), rightBound.back()));
239 return std::make_shared<ConstLineString3d>(centerlinePoints);
241 #pragma GCC diagnostic pop 249 auto centerline = std::atomic_load_explicit(¢erline_, std::memory_order_acquire);
252 std::atomic_store_explicit(¢erline_, centerline, std::memory_order_release);
258 if (bound != leftBound_) {
265 if (bound != rightBound_) {
272 centerline_ = std::make_shared<ConstLineString3d>(centerline);
276 auto centerline = std::atomic_load_explicit(¢erline_, std::memory_order_acquire);
277 return !!centerline && centerline->id() !=
InvalId;
285 if (!hasCustomCenterline()) {
286 std::atomic_store_explicit(¢erline_, std::shared_ptr<ConstLineString3d>(), std::memory_order_release);
291 stream <<
"[id: " << obj.
id();
293 stream <<
", inverted";
297 stream <<
" (inverted)";
301 stream <<
" (inverted)";
303 return stream <<
"]";
310 std::any_of(regelems.begin(), regelems.end(), [&
id](
const auto& elem) {
return elem->id() ==
id; });
Id id() const noexcept
get the unique id of this primitive
bool hasCustomCenterline() const
Returns whether the centerline has been overridden by setCenterline.
std::vector< ConstLineString3d > ConstLineStrings3d
internal::SelectLsIteratorT< const ConstPointType > const_iterator
RegulatoryElementConstPtrs regulatoryElements() const
get a list of regulatory elements that affect this lanelet
std::ostream & operator<<(std::ostream &stream, const Attribute &obj)
SegmentTree rightSegments_
const ConstPointType & back() const noexcept
returns the last point (if it exist)
const ConstPointType & front() const noexcept
returns the first point (if it exist)
const_iterator end() const noexcept
Returns an iterator to end of the points.
ConstSegmentType segment(size_t idx) const noexcept
returns the n-th segment. If n equals size() -1, the segment from back() to front() is returned...
A normal 3d linestring with immutable data.
bool has(const ConstArea &ll, Id id)
returns true if element of a regulatory element has a matching Id
size_t size() const noexcept
Return the number of points in this linestring.
void setCenterline(const LineString3d ¢erline)
Sets a new right bound. Resets all cached data of this object.
Combines multiple linestrings to one polygon in 3d.
bool inverted() const
returns if this is an inverted lanelet
CompoundPolygon2d polygon2d() const
returns the surface covered by this lanelet as 2-dimensional polygon.
A normal 3d linestring with mutable data.
CompoundPolygon3d polygon() const
Get the bounding polygon of this lanelet. Result is cached.
ConstLineString3d leftBound() const
get the left bound.
bool pointIsLeftOf(const PointT &pSeg1, const PointT &pSeg2, const PointT &p)
Optional< double > distance
ConstLineString3d rightBound() const
get the right bound.
SegmentTree leftSegments_
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > BasicPoint2d
a simple 2d-point
boost::optional< double > OptDistance
bool inverted() const noexcept
Returns whether this is an inverted linestring.
void resetCache() const
call this to indicate that the objects data has been modified.
void setLeftBound(const LineString3d &bound)
Sets a new left bound. Resets all cached data of this object.
ConstLineString3d centerline() const
Returns centerline by computing it, if necessary. Result is cached.
bgi::rtree< BasicSegment2d, bgi::linear< 4 > > SegmentTree
BoundingBox2d to2D(const BoundingBox3d &primitive)
BoundingBox3d to3D(const BoundingBox2d &primitive)
const_iterator begin() const noexcept
Returns an iterator to the start of the points.
Combines multiple linestrings to one polygon in 2d.
void setRightBound(const LineString3d &bound)
Sets a new right bound. Resets all cached data of this object.
A normal 2d linestring with immutable data.
Segment< BasicPoint2d > BasicSegment2d
size_t numSegments() const noexcept
Returns the number of (geometrically valid) segments.
constexpr Id InvalId
indicates a primitive that is not part of a map
CompoundPolygon3d polygon3d() const
returns the surface covered by this lanelet as 3-dimensional polygon.