// Copyright (c) 2020 Computer Vision Center (CVC) at the Universitat Autonoma // de Barcelona (UAB). // // This work is licensed under the terms of the MIT license. // For a copy, see . #include "carla/road/Map.h" #include "carla/Exception.h" #include "carla/geom/Math.h" #include "carla/geom/Vector3D.h" #include "carla/road/MeshFactory.h" #include "carla/road/Deformation.h" #include "carla/road/element/LaneCrossingCalculator.h" #include "carla/road/element/RoadInfoCrosswalk.h" #include "carla/road/element/RoadInfoElevation.h" #include "carla/road/element/RoadInfoGeometry.h" #include "carla/road/element/RoadInfoLaneOffset.h" #include "carla/road/element/RoadInfoLaneWidth.h" #include "carla/road/element/RoadInfoMarkRecord.h" #include "carla/road/element/RoadInfoSpeed.h" #include "carla/road/element/RoadInfoSignal.h" #include "marchingcube/MeshReconstruction.h" #include #include #include #include #include #include #include namespace carla { namespace road { using namespace carla::road::element; /// We use this epsilon to shift the waypoints away from the edges of the lane /// sections to avoid floating point precision errors. static constexpr double EPSILON = 10.0 * std::numeric_limits::epsilon(); // =========================================================================== // -- Static local methods --------------------------------------------------- // =========================================================================== template static std::vector ConcatVectors(std::vector dst, std::vector src) { if (src.size() > dst.size()) { return ConcatVectors(src, dst); } dst.insert( dst.end(), std::make_move_iterator(src.begin()), std::make_move_iterator(src.end())); return dst; } static double GetDistanceAtStartOfLane(const Lane &lane) { if (lane.GetId() <= 0) { return lane.GetDistance() + 10.0 * EPSILON; } else { return lane.GetDistance() + lane.GetLength() - 10.0 * EPSILON; } } static double GetDistanceAtEndOfLane(const Lane &lane) { if (lane.GetId() > 0) { return lane.GetDistance() + 10.0 * EPSILON; } else { return lane.GetDistance() + lane.GetLength() - 10.0 * EPSILON; } } /// Return a waypoint for each drivable lane on @a lane_section. template static void ForEachDrivableLaneImpl( RoadId road_id, const LaneSection &lane_section, double distance, FuncT &&func) { for (const auto &pair : lane_section.GetLanes()) { const auto &lane = pair.second; if (lane.GetId() == 0) { continue; } if ((static_cast(lane.GetType()) & static_cast(Lane::LaneType::Driving)) > 0) { std::forward(func)(Waypoint{ road_id, lane_section.GetId(), lane.GetId(), distance < 0.0 ? GetDistanceAtStartOfLane(lane) : distance}); } } } template static void ForEachLaneImpl( RoadId road_id, const LaneSection &lane_section, double distance, Lane::LaneType lane_type, FuncT &&func) { for (const auto &pair : lane_section.GetLanes()) { const auto &lane = pair.second; if (lane.GetId() == 0) { continue; } if ((static_cast(lane.GetType()) & static_cast(lane_type)) > 0) { std::forward(func)(Waypoint{ road_id, lane_section.GetId(), lane.GetId(), distance < 0.0 ? GetDistanceAtStartOfLane(lane) : distance}); } } } /// Return a waypoint for each drivable lane on each lane section of @a road. template static void ForEachDrivableLane(const Road &road, FuncT &&func) { for (const auto &lane_section : road.GetLaneSections()) { ForEachDrivableLaneImpl( road.GetId(), lane_section, -1.0, // At start of the lane std::forward(func)); } } /// Return a waypoint for each lane of the specified type on each lane section of @a road. template static void ForEachLane(const Road &road, Lane::LaneType lane_type, FuncT &&func) { for (const auto &lane_section : road.GetLaneSections()) { ForEachLaneImpl( road.GetId(), lane_section, -1.0, // At start of the lane lane_type, std::forward(func)); } } /// Return a waypoint for each drivable lane at @a distance on @a road. template static void ForEachDrivableLaneAt(const Road &road, double distance, FuncT &&func) { for (const auto &lane_section : road.GetLaneSectionsAt(distance)) { ForEachDrivableLaneImpl( road.GetId(), lane_section, distance, std::forward(func)); } } /// Assumes road_id and section_id are valid. static bool IsLanePresent(const MapData &data, Waypoint waypoint) { const auto §ion = data.GetRoad(waypoint.road_id).GetLaneSectionById(waypoint.section_id); return section.ContainsLane(waypoint.lane_id); } // =========================================================================== // -- Map: Geometry ---------------------------------------------------------- // =========================================================================== boost::optional Map::GetClosestWaypointOnRoad( const geom::Location &pos, int32_t lane_type) const { std::vector query_result = _rtree.GetNearestNeighboursWithFilter(Rtree::BPoint(pos.x, pos.y, pos.z), [&](Rtree::TreeElement const &element) { const Lane &lane = GetLane(element.second.first); return (lane_type & static_cast(lane.GetType())) > 0; }); if (query_result.size() == 0) { return boost::optional{}; } Rtree::BSegment segment = query_result.front().first; Rtree::BPoint s1 = segment.first; Rtree::BPoint s2 = segment.second; auto distance_to_segment = geom::Math::DistanceSegmentToPoint(pos, geom::Vector3D(s1.get<0>(), s1.get<1>(), s1.get<2>()), geom::Vector3D(s2.get<0>(), s2.get<1>(), s2.get<2>())); Waypoint result_start = query_result.front().second.first; Waypoint result_end = query_result.front().second.second; if (result_start.lane_id < 0) { double delta_s = distance_to_segment.first; double final_s = result_start.s + delta_s; if (final_s >= result_end.s) { return result_end; } else if (delta_s <= 0) { return result_start; } else { return GetNext(result_start, delta_s).front(); } } else { double delta_s = distance_to_segment.first; double final_s = result_start.s - delta_s; if (final_s <= result_end.s) { return result_end; } else if (delta_s <= 0) { return result_start; } else { return GetNext(result_start, delta_s).front(); } } } boost::optional Map::GetWaypoint( const geom::Location &pos, int32_t lane_type) const { boost::optional w = GetClosestWaypointOnRoad(pos, lane_type); if (!w.has_value()) { return w; } const auto dist = geom::Math::Distance2D(ComputeTransform(*w).location, pos); const auto lane_width_info = GetLane(*w).GetInfo(w->s); const auto half_lane_width = lane_width_info->GetPolynomial().Evaluate(w->s) * 0.5; if (dist < half_lane_width) { return w; } return boost::optional{}; } boost::optional Map::GetWaypoint( RoadId road_id, LaneId lane_id, float s) const { // define the waypoint with the known parameters Waypoint waypoint; waypoint.road_id = road_id; waypoint.lane_id = lane_id; waypoint.s = s; // check the road if (!_data.ContainsRoad(waypoint.road_id)) { return boost::optional{}; } const Road &road = _data.GetRoad(waypoint.road_id); // check the 's' distance if (s < 0.0f || s >= road.GetLength()) { return boost::optional{}; } // check the section bool lane_found = false; for (auto §ion : road.GetLaneSectionsAt(s)) { if (section.ContainsLane(lane_id)) { waypoint.section_id = section.GetId(); lane_found = true; break; } } // check the lane id if (!lane_found) { return boost::optional{}; } return waypoint; } geom::Transform Map::ComputeTransform(Waypoint waypoint) const { return GetLane(waypoint).ComputeTransform(waypoint.s); } // =========================================================================== // -- Map: Road information -------------------------------------------------- // =========================================================================== Lane::LaneType Map::GetLaneType(const Waypoint waypoint) const { return GetLane(waypoint).GetType(); } double Map::GetLaneWidth(const Waypoint waypoint) const { const auto s = waypoint.s; const auto &lane = GetLane(waypoint); RELEASE_ASSERT(lane.GetRoad() != nullptr); RELEASE_ASSERT(s <= lane.GetRoad()->GetLength()); const auto lane_width_info = lane.GetInfo(s); RELEASE_ASSERT(lane_width_info != nullptr); return lane_width_info->GetPolynomial().Evaluate(s); } JuncId Map::GetJunctionId(RoadId road_id) const { return _data.GetRoad(road_id).GetJunctionId(); } bool Map::IsJunction(RoadId road_id) const { return _data.GetRoad(road_id).IsJunction(); } std::pair Map::GetMarkRecord(const Waypoint waypoint) const { // if lane Id is 0, just return a pair of nulls if (waypoint.lane_id == 0) return std::make_pair(nullptr, nullptr); const auto s = waypoint.s; const auto ¤t_lane = GetLane(waypoint); RELEASE_ASSERT(current_lane.GetRoad() != nullptr); RELEASE_ASSERT(s <= current_lane.GetRoad()->GetLength()); const auto inner_lane_id = waypoint.lane_id < 0 ? waypoint.lane_id + 1 : waypoint.lane_id - 1; const auto &inner_lane = current_lane.GetRoad()->GetLaneById(waypoint.section_id, inner_lane_id); auto current_lane_info = current_lane.GetInfo(s); auto inner_lane_info = inner_lane.GetInfo(s); return std::make_pair(current_lane_info, inner_lane_info); } std::vector Map::GetSignalsInDistance( Waypoint waypoint, double distance, bool stop_at_junction) const { const auto &lane = GetLane(waypoint); const bool forward = (waypoint.lane_id <= 0); const double signed_distance = forward ? distance : -distance; const double relative_s = waypoint.s - lane.GetDistance(); const double remaining_lane_length = forward ? lane.GetLength() - relative_s : relative_s; DEBUG_ASSERT(remaining_lane_length >= 0.0); auto &road =_data.GetRoad(waypoint.road_id); std::vector result; // If after subtracting the distance we are still in the same lane, return // same waypoint with the extra distance. if (distance <= remaining_lane_length) { auto signals = road.GetInfosInRange( waypoint.s, waypoint.s + signed_distance); for(auto* signal : signals){ double distance_to_signal = 0; if (waypoint.lane_id < 0){ distance_to_signal = signal->GetDistance() - waypoint.s; } else { distance_to_signal = waypoint.s - signal->GetDistance(); } // check that the signal affects the waypoint bool is_valid = false; for (auto &validity : signal->GetValidities()) { if (waypoint.lane_id >= validity._from_lane && waypoint.lane_id <= validity._to_lane) { is_valid = true; break; } } if(!is_valid){ continue; } if (distance_to_signal == 0) { result.emplace_back(SignalSearchData {signal, waypoint, distance_to_signal}); } else { result.emplace_back(SignalSearchData {signal, GetNext(waypoint, distance_to_signal).front(), distance_to_signal}); } } return result; } const double signed_remaining_length = forward ? remaining_lane_length : -remaining_lane_length; //result = road.GetInfosInRange(waypoint.s, waypoint.s + signed_remaining_length); auto signals = road.GetInfosInRange( waypoint.s, waypoint.s + signed_remaining_length); for(auto* signal : signals){ double distance_to_signal = 0; if (waypoint.lane_id < 0){ distance_to_signal = signal->GetDistance() - waypoint.s; } else { distance_to_signal = waypoint.s - signal->GetDistance(); } // check that the signal affects the waypoint bool is_valid = false; for (auto &validity : signal->GetValidities()) { if (waypoint.lane_id >= validity._from_lane && waypoint.lane_id <= validity._to_lane) { is_valid = true; break; } } if(!is_valid){ continue; } if (distance_to_signal == 0) { result.emplace_back(SignalSearchData {signal, waypoint, distance_to_signal}); } else { result.emplace_back(SignalSearchData {signal, GetNext(waypoint, distance_to_signal).front(), distance_to_signal}); } } // If we run out of remaining_lane_length we have to go to the successors. for (auto &successor : GetSuccessors(waypoint)) { if(_data.GetRoad(successor.road_id).IsJunction() && stop_at_junction){ continue; } auto& sucessor_lane = _data.GetRoad(successor.road_id). GetLaneByDistance(successor.s, successor.lane_id); if (successor.lane_id < 0) { successor.s = sucessor_lane.GetDistance(); } else { successor.s = sucessor_lane.GetDistance() + sucessor_lane.GetLength(); } auto sucessor_signals = GetSignalsInDistance( successor, distance - remaining_lane_length, stop_at_junction); for(auto& signal : sucessor_signals){ signal.accumulated_s += remaining_lane_length; } result = ConcatVectors(result, sucessor_signals); } return result; } std::vector Map::GetAllSignalReferences() const { std::vector result; for (const auto& road_pair : _data.GetRoads()) { const auto &road = road_pair.second; auto road_infos = road.GetInfos(); for(const auto* road_info : road_infos) { result.push_back(road_info); } } return result; } std::vector Map::CalculateCrossedLanes( const geom::Location &origin, const geom::Location &destination) const { return LaneCrossingCalculator::Calculate(*this, origin, destination); } std::vector Map::GetAllCrosswalkZones() const { std::vector result; for (const auto &pair : _data.GetRoads()) { const auto &road = pair.second; std::vector crosswalks = road.GetInfos(); if (crosswalks.size() > 0) { for (auto crosswalk : crosswalks) { // waypoint only at start position std::vector points; Waypoint waypoint; geom::Transform base; for (const auto §ion : road.GetLaneSectionsAt(crosswalk->GetS())) { // get the section with the center lane for (const auto &lane : section.GetLanes()) { // is the center line if (lane.first == 0) { // get the center point waypoint.road_id = pair.first; waypoint.section_id = section.GetId(); waypoint.lane_id = 0; waypoint.s = crosswalk->GetS(); base = ComputeTransform(waypoint); } } } // move perpendicular ('t') geom::Transform pivot = base; pivot.rotation.yaw -= geom::Math::ToDegrees(static_cast(crosswalk->GetHeading())); pivot.rotation.yaw -= 90; // move perpendicular to 's' for the lateral offset geom::Vector3D v(static_cast(crosswalk->GetT()), 0.0f, 0.0f); pivot.TransformPoint(v); // restore pivot position and orientation pivot = base; pivot.location = v; pivot.rotation.yaw -= geom::Math::ToDegrees(static_cast(crosswalk->GetHeading())); // calculate all the corners for (auto corner : crosswalk->GetPoints()) { geom::Vector3D v2( static_cast(corner.u), static_cast(corner.v), static_cast(corner.z)); // set the width larger to contact with the sidewalk (in case they have gutter area) if (corner.u < 0) { v2.x -= 1.0f; } else { v2.x += 1.0f; } pivot.TransformPoint(v2); result.push_back(v2); } } } } return result; } // =========================================================================== // -- Map: Waypoint generation ----------------------------------------------- // =========================================================================== std::vector Map::GetSuccessors(const Waypoint waypoint) const { const auto &next_lanes = GetLane(waypoint).GetNextLanes(); std::vector result; result.reserve(next_lanes.size()); for (auto *next_lane : next_lanes) { RELEASE_ASSERT(next_lane != nullptr); const auto lane_id = next_lane->GetId(); RELEASE_ASSERT(lane_id != 0); const auto *section = next_lane->GetLaneSection(); RELEASE_ASSERT(section != nullptr); const auto *road = next_lane->GetRoad(); RELEASE_ASSERT(road != nullptr); const auto distance = GetDistanceAtStartOfLane(*next_lane); result.emplace_back(Waypoint{road->GetId(), section->GetId(), lane_id, distance}); } return result; } std::vector Map::GetPredecessors(const Waypoint waypoint) const { const auto &prev_lanes = GetLane(waypoint).GetPreviousLanes(); std::vector result; result.reserve(prev_lanes.size()); for (auto *next_lane : prev_lanes) { RELEASE_ASSERT(next_lane != nullptr); const auto lane_id = next_lane->GetId(); RELEASE_ASSERT(lane_id != 0); const auto *section = next_lane->GetLaneSection(); RELEASE_ASSERT(section != nullptr); const auto *road = next_lane->GetRoad(); RELEASE_ASSERT(road != nullptr); const auto distance = GetDistanceAtEndOfLane(*next_lane); result.emplace_back(Waypoint{road->GetId(), section->GetId(), lane_id, distance}); } return result; } std::vector Map::GetNext( const Waypoint waypoint, const double distance) const { RELEASE_ASSERT(distance > 0.0); if (distance <= EPSILON) { return {waypoint}; } const auto &lane = GetLane(waypoint); const bool forward = (waypoint.lane_id <= 0); const double signed_distance = forward ? distance : -distance; const double relative_s = waypoint.s - lane.GetDistance(); const double remaining_lane_length = forward ? lane.GetLength() - relative_s : relative_s; DEBUG_ASSERT(remaining_lane_length >= 0.0); // If after subtracting the distance we are still in the same lane, return // same waypoint with the extra distance. if (distance <= remaining_lane_length) { Waypoint result = waypoint; result.s += signed_distance; result.s += forward ? -EPSILON : EPSILON; RELEASE_ASSERT(result.s > 0.0); return { result }; } // If we run out of remaining_lane_length we have to go to the successors. std::vector result; for (const auto &successor : GetSuccessors(waypoint)) { DEBUG_ASSERT( successor.road_id != waypoint.road_id || successor.section_id != waypoint.section_id || successor.lane_id != waypoint.lane_id); result = ConcatVectors(result, GetNext(successor, distance - remaining_lane_length)); } return result; } std::vector Map::GetPrevious( const Waypoint waypoint, const double distance) const { RELEASE_ASSERT(distance > 0.0); if (distance <= EPSILON) { return {waypoint}; } const auto &lane = GetLane(waypoint); const bool forward = !(waypoint.lane_id <= 0); const double signed_distance = forward ? distance : -distance; const double relative_s = waypoint.s - lane.GetDistance(); const double remaining_lane_length = forward ? lane.GetLength() - relative_s : relative_s; DEBUG_ASSERT(remaining_lane_length >= 0.0); // If after subtracting the distance we are still in the same lane, return // same waypoint with the extra distance. if (distance <= remaining_lane_length) { Waypoint result = waypoint; result.s += signed_distance; result.s += forward ? -EPSILON : EPSILON; RELEASE_ASSERT(result.s > 0.0); return { result }; } // If we run out of remaining_lane_length we have to go to the successors. std::vector result; for (const auto &successor : GetPredecessors(waypoint)) { DEBUG_ASSERT( successor.road_id != waypoint.road_id || successor.section_id != waypoint.section_id || successor.lane_id != waypoint.lane_id); result = ConcatVectors(result, GetPrevious(successor, distance - remaining_lane_length)); } return result; } boost::optional Map::GetRight(Waypoint waypoint) const { RELEASE_ASSERT(waypoint.lane_id != 0); if (waypoint.lane_id > 0) { ++waypoint.lane_id; } else { --waypoint.lane_id; } return IsLanePresent(_data, waypoint) ? waypoint : boost::optional{}; } boost::optional Map::GetLeft(Waypoint waypoint) const { RELEASE_ASSERT(waypoint.lane_id != 0); if (std::abs(waypoint.lane_id) == 1) { waypoint.lane_id *= -1; } else if (waypoint.lane_id > 0) { --waypoint.lane_id; } else { ++waypoint.lane_id; } return IsLanePresent(_data, waypoint) ? waypoint : boost::optional{}; } std::vector Map::GenerateWaypoints(const double distance) const { RELEASE_ASSERT(distance > 0.0); std::vector result; for (const auto &pair : _data.GetRoads()) { const auto &road = pair.second; for (double s = EPSILON; s < (road.GetLength() - EPSILON); s += distance) { ForEachDrivableLaneAt(road, s, [&](auto &&waypoint) { result.emplace_back(waypoint); }); } } return result; } std::vector Map::GenerateWaypointsOnRoadEntries(Lane::LaneType lane_type) const { std::vector result; for (const auto &pair : _data.GetRoads()) { const auto &road = pair.second; // right lanes start at s 0 for (const auto &lane_section : road.GetLaneSectionsAt(0.0)) { for (const auto &lane : lane_section.GetLanes()) { // add only the right (negative) lanes if (lane.first < 0 && static_cast(lane.second.GetType()) & static_cast(lane_type)) { result.emplace_back(Waypoint{ road.GetId(), lane_section.GetId(), lane.second.GetId(), 0.0 }); } } } // left lanes start at s max const auto road_len = road.GetLength(); for (const auto &lane_section : road.GetLaneSectionsAt(road_len)) { for (const auto &lane : lane_section.GetLanes()) { // add only the left (positive) lanes if (lane.first > 0 && static_cast(lane.second.GetType()) & static_cast(lane_type)) { result.emplace_back( Waypoint{ road.GetId(), lane_section.GetId(), lane.second.GetId(), road_len }); } } } } return result; } std::vector Map::GenerateWaypointsInRoad( RoadId road_id, Lane::LaneType lane_type) const { std::vector result; if(_data.GetRoads().count(road_id)) { const auto &road = _data.GetRoads().at(road_id); // right lanes start at s 0 for (const auto &lane_section : road.GetLaneSectionsAt(0.0)) { for (const auto &lane : lane_section.GetLanes()) { // add only the right (negative) lanes if (lane.first < 0 && static_cast(lane.second.GetType()) & static_cast(lane_type)) { result.emplace_back(Waypoint{ road.GetId(), lane_section.GetId(), lane.second.GetId(), 0.0 }); } } } // left lanes start at s max const auto road_len = road.GetLength(); for (const auto &lane_section : road.GetLaneSectionsAt(road_len)) { for (const auto &lane : lane_section.GetLanes()) { // add only the left (positive) lanes if (lane.first > 0 && static_cast(lane.second.GetType()) & static_cast(lane_type)) { result.emplace_back( Waypoint{ road.GetId(), lane_section.GetId(), lane.second.GetId(), road_len }); } } } } return result; } std::vector> Map::GenerateTopology() const { std::vector> result; for (const auto &pair : _data.GetRoads()) { const auto &road = pair.second; ForEachDrivableLane(road, [&](auto &&waypoint) { auto successors = GetSuccessors(waypoint); if (successors.size() == 0){ auto distance = static_cast(GetDistanceAtEndOfLane(GetLane(waypoint))); auto last_waypoint = GetWaypoint(waypoint.road_id, waypoint.lane_id, distance); if (last_waypoint.has_value()){ result.push_back({waypoint, *last_waypoint}); } } else{ for (auto &&successor : GetSuccessors(waypoint)) { result.push_back({waypoint, successor}); } } }); } return result; } std::vector> Map::GetJunctionWaypoints(JuncId id, Lane::LaneType lane_type) const { std::vector> result; const Junction * junction = GetJunction(id); for(auto &connections : junction->GetConnections()) { const Road &road = _data.GetRoad(connections.second.connecting_road); ForEachLane(road, lane_type, [&](auto &&waypoint) { const auto& lane = GetLane(waypoint); const double final_s = GetDistanceAtEndOfLane(lane); Waypoint lane_end(waypoint); lane_end.s = final_s; result.push_back({waypoint, lane_end}); }); } return result; } std::unordered_map> Map::ComputeJunctionConflicts(JuncId id) const { const float epsilon = 0.0001f; // small delta in the road (set to 0.1 // millimeters to prevent numeric errors) const Junction *junction = GetJunction(id); std::unordered_map> conflicts; // 2d typedefs typedef boost::geometry::model::point Point2d; typedef boost::geometry::model::segment Segment2d; typedef boost::geometry::model::box Box; // box range auto bbox_pos = junction->GetBoundingBox().location; auto bbox_ext = junction->GetBoundingBox().extent; auto min_corner = geom::Vector3D( bbox_pos.x - bbox_ext.x, bbox_pos.y - bbox_ext.y, bbox_pos.z - bbox_ext.z - epsilon); auto max_corner = geom::Vector3D( bbox_pos.x + bbox_ext.x, bbox_pos.y + bbox_ext.y, bbox_pos.z + bbox_ext.z + epsilon); Box box({min_corner.x, min_corner.y, min_corner.z}, {max_corner.x, max_corner.y, max_corner.z}); auto segments = _rtree.GetIntersections(box); for (size_t i = 0; i < segments.size(); ++i){ auto &segment1 = segments[i]; auto waypoint1 = segment1.second.first; JuncId junc_id1 = _data.GetRoad(waypoint1.road_id).GetJunctionId(); // only segments in the junction if(junc_id1 != id){ continue; } Segment2d seg1{{segment1.first.first.get<0>(), segment1.first.first.get<1>()}, {segment1.first.second.get<0>(), segment1.first.second.get<1>()}}; for (size_t j = i + 1; j < segments.size(); ++j){ auto &segment2 = segments[j]; auto waypoint2 = segment2.second.first; JuncId junc_id2 = _data.GetRoad(waypoint2.road_id).GetJunctionId(); // only segments in the junction if(junc_id2 != id){ continue; } // discard same road if(waypoint1.road_id == waypoint2.road_id){ continue; } Segment2d seg2{{segment2.first.first.get<0>(), segment2.first.first.get<1>()}, {segment2.first.second.get<0>(), segment2.first.second.get<1>()}}; double distance = boost::geometry::distance(seg1, seg2); // better to set distance to lanewidth if(distance > 2.0){ continue; } if(conflicts[waypoint1.road_id].count(waypoint2.road_id) == 0){ conflicts[waypoint1.road_id].insert(waypoint2.road_id); } if(conflicts[waypoint2.road_id].count(waypoint1.road_id) == 0){ conflicts[waypoint2.road_id].insert(waypoint1.road_id); } } } return conflicts; } const Lane &Map::GetLane(Waypoint waypoint) const { return _data.GetRoad(waypoint.road_id).GetLaneById(waypoint.section_id, waypoint.lane_id); } // =========================================================================== // -- Map: Private functions ------------------------------------------------- // =========================================================================== // Adds a new element to the rtree element list using the position of the // waypoints both ends of the segment void Map::AddElementToRtree( std::vector &rtree_elements, geom::Transform ¤t_transform, geom::Transform &next_transform, Waypoint ¤t_waypoint, Waypoint &next_waypoint) { Rtree::BPoint init = Rtree::BPoint( current_transform.location.x, current_transform.location.y, current_transform.location.z); Rtree::BPoint end = Rtree::BPoint( next_transform.location.x, next_transform.location.y, next_transform.location.z); rtree_elements.emplace_back(std::make_pair(Rtree::BSegment(init, end), std::make_pair(current_waypoint, next_waypoint))); } // Adds a new element to the rtree element list using the position of the // waypoints, both ends of the segment void Map::AddElementToRtreeAndUpdateTransforms( std::vector &rtree_elements, geom::Transform ¤t_transform, Waypoint ¤t_waypoint, Waypoint &next_waypoint) { geom::Transform next_transform = ComputeTransform(next_waypoint); AddElementToRtree(rtree_elements, current_transform, next_transform, current_waypoint, next_waypoint); current_waypoint = next_waypoint; current_transform = next_transform; } // returns the remaining length of the geometry depending on the lane // direction double GetRemainingLength(const Lane &lane, double current_s) { if (lane.GetId() < 0) { return (lane.GetDistance() + lane.GetLength() - current_s); } else { return (current_s - lane.GetDistance()); } } void Map::CreateRtree() { const double epsilon = 0.000001; // small delta in the road (set to 1 // micrometer to prevent numeric errors) const double min_delta_s = 1; // segments of minimum 1m through the road // 1.8 degrees, maximum angle in a curve to place a segment constexpr double angle_threshold = geom::Math::Pi() / 100.0; // maximum distance of a segment constexpr double max_segment_length = 100.0; // Generate waypoints at start of every lane std::vector topology; for (const auto &pair : _data.GetRoads()) { const auto &road = pair.second; ForEachLane(road, Lane::LaneType::Any, [&](auto &&waypoint) { if(waypoint.lane_id != 0) { topology.push_back(waypoint); } }); } // Container of segments and waypoints std::vector rtree_elements; // Loop through all lanes for (auto &waypoint : topology) { auto &lane_start_waypoint = waypoint; auto current_waypoint = lane_start_waypoint; const Lane &lane = GetLane(current_waypoint); geom::Transform current_transform = ComputeTransform(current_waypoint); // Save computation time in straight lines if (lane.IsStraight()) { double delta_s = min_delta_s; double remaining_length = GetRemainingLength(lane, current_waypoint.s); remaining_length -= epsilon; delta_s = remaining_length; if (delta_s < epsilon) { continue; } auto next = GetNext(current_waypoint, delta_s); RELEASE_ASSERT(next.size() == 1); RELEASE_ASSERT(next.front().road_id == current_waypoint.road_id); auto next_waypoint = next.front(); AddElementToRtreeAndUpdateTransforms( rtree_elements, current_transform, current_waypoint, next_waypoint); // end of lane } else { auto next_waypoint = current_waypoint; // Loop until the end of the lane // Advance in small s-increments while (true) { double delta_s = min_delta_s; double remaining_length = GetRemainingLength(lane, next_waypoint.s); remaining_length -= epsilon; delta_s = std::min(delta_s, remaining_length); if (delta_s < epsilon) { AddElementToRtreeAndUpdateTransforms( rtree_elements, current_transform, current_waypoint, next_waypoint); break; } auto next = GetNext(next_waypoint, delta_s); if (next.size() != 1 || current_waypoint.section_id != next.front().section_id) { AddElementToRtreeAndUpdateTransforms( rtree_elements, current_transform, current_waypoint, next_waypoint); break; } next_waypoint = next.front(); geom::Transform next_transform = ComputeTransform(next_waypoint); double angle = geom::Math::GetVectorAngle( current_transform.GetForwardVector(), next_transform.GetForwardVector()); if (std::abs(angle) > angle_threshold || std::abs(current_waypoint.s - next_waypoint.s) > max_segment_length) { AddElementToRtree( rtree_elements, current_transform, next_transform, current_waypoint, next_waypoint); current_waypoint = next_waypoint; current_transform = next_transform; } } } } // Add segments to Rtree _rtree.InsertElements(rtree_elements); } Junction* Map::GetJunction(JuncId id) { return _data.GetJunction(id); } const Junction* Map::GetJunction(JuncId id) const { return _data.GetJunction(id); } geom::Mesh Map::GenerateMesh( const double distance, const float extra_width, const bool smooth_junctions) const { RELEASE_ASSERT(distance > 0.0); geom::MeshFactory mesh_factory; geom::Mesh out_mesh; mesh_factory.road_param.resolution = static_cast(distance); mesh_factory.road_param.extra_lane_width = extra_width; // Generate roads outside junctions for (auto &&pair : _data.GetRoads()) { const auto &road = pair.second; if (road.IsJunction()) { continue; } out_mesh += *mesh_factory.Generate(road); } // Generate roads within junctions and smooth them for (const auto &junc_pair : _data.GetJunctions()) { const auto &junction = junc_pair.second; std::vector> lane_meshes; for(const auto &connection_pair : junction.GetConnections()) { const auto &connection = connection_pair.second; const auto &road = _data.GetRoads().at(connection.connecting_road); for (auto &&lane_section : road.GetLaneSections()) { for (auto &&lane_pair : lane_section.GetLanes()) { lane_meshes.push_back(mesh_factory.Generate(lane_pair.second)); } } } if(smooth_junctions) { out_mesh += *mesh_factory.MergeAndSmooth(lane_meshes); } else { geom::Mesh junction_mesh; for(auto& lane : lane_meshes) { junction_mesh += *lane; } out_mesh += junction_mesh; } } return out_mesh; } std::vector> Map::GenerateChunkedMesh( const rpc::OpendriveGenerationParameters& params) const { geom::MeshFactory mesh_factory(params); std::vector> out_mesh_list; std::unordered_map junction_map; for (auto &&pair : _data.GetRoads()) { const auto &road = pair.second; if (!road.IsJunction()) { std::vector> road_mesh_list = mesh_factory.GenerateAllWithMaxLen(road); out_mesh_list.insert( out_mesh_list.end(), std::make_move_iterator(road_mesh_list.begin()), std::make_move_iterator(road_mesh_list.end())); } } // Generate roads within junctions and smooth them for (const auto &junc_pair : _data.GetJunctions()) { const auto &junction = junc_pair.second; std::vector> lane_meshes; std::vector> sidewalk_lane_meshes; for(const auto &connection_pair : junction.GetConnections()) { const auto &connection = connection_pair.second; const auto &road = _data.GetRoads().at(connection.connecting_road); for (auto &&lane_section : road.GetLaneSections()) { for (auto &&lane_pair : lane_section.GetLanes()) { const auto &lane = lane_pair.second; if (lane.GetType() != road::Lane::LaneType::Sidewalk) { lane_meshes.push_back(mesh_factory.Generate(lane)); } else { sidewalk_lane_meshes.push_back(mesh_factory.Generate(lane)); } } } } if(params.smooth_junctions) { auto merged_mesh = mesh_factory.MergeAndSmooth(lane_meshes); for(auto& lane : sidewalk_lane_meshes) { *merged_mesh += *lane; } out_mesh_list.push_back(std::move(merged_mesh)); } else { std::unique_ptr junction_mesh = std::make_unique(); for(auto& lane : lane_meshes) { *junction_mesh += *lane; } for(auto& lane : sidewalk_lane_meshes) { *junction_mesh += *lane; } out_mesh_list.push_back(std::move(junction_mesh)); } } auto min_pos = geom::Vector2D( out_mesh_list.front()->GetVertices().front().x, out_mesh_list.front()->GetVertices().front().y); auto max_pos = min_pos; for (auto & mesh : out_mesh_list) { auto vertex = mesh->GetVertices().front(); min_pos.x = std::min(min_pos.x, vertex.x); min_pos.y = std::min(min_pos.y, vertex.y); max_pos.x = std::max(max_pos.x, vertex.x); max_pos.y = std::max(max_pos.y, vertex.y); } size_t mesh_amount_x = static_cast((max_pos.x - min_pos.x)/params.max_road_length) + 1; size_t mesh_amount_y = static_cast((max_pos.y - min_pos.y)/params.max_road_length) + 1; std::vector> result; result.reserve(mesh_amount_x*mesh_amount_y); for (size_t i = 0; i < mesh_amount_x*mesh_amount_y; ++i) { result.emplace_back(std::make_unique()); } for (auto & mesh : out_mesh_list) { auto vertex = mesh->GetVertices().front(); size_t x_pos = static_cast((vertex.x - min_pos.x) / params.max_road_length); size_t y_pos = static_cast((vertex.y - min_pos.y) / params.max_road_length); *(result[x_pos + mesh_amount_x*y_pos]) += *mesh; } return result; } std::map>> Map::GenerateOrderedChunkedMeshInLocations( const rpc::OpendriveGenerationParameters& params, const geom::Vector3D& minpos, const geom::Vector3D& maxpos) const { geom::MeshFactory mesh_factory(params); std::map>> road_out_mesh_list; std::map>> junction_out_mesh_list; std::thread juntction_thread( &Map::GenerateJunctions, this, mesh_factory, params, minpos, maxpos, &junction_out_mesh_list); const std::vector RoadsIDToGenerate = FilterRoadsByPosition(minpos, maxpos); size_t num_roads = RoadsIDToGenerate.size(); size_t num_roads_per_thread = 30; size_t num_threads = (num_roads / num_roads_per_thread) + 1; num_threads = num_threads > 1 ? num_threads : 1; std::vector workers; std::mutex write_mutex; std::cout << "Generating " << std::to_string(num_roads) << " roads" << std::endl; for ( size_t i = 0; i < num_threads; ++i ) { std::thread neworker( [this, &write_mutex, &mesh_factory, &RoadsIDToGenerate, &road_out_mesh_list, i, num_roads_per_thread]() { std::map>> Current = std::move(GenerateRoadsMultithreaded(mesh_factory, RoadsIDToGenerate,i, num_roads_per_thread )); std::lock_guard guard(write_mutex); for ( auto&& pair : Current ) { if (road_out_mesh_list.find(pair.first) != road_out_mesh_list.end()) { road_out_mesh_list[pair.first].insert(road_out_mesh_list[pair.first].end(), std::make_move_iterator(pair.second.begin()), std::make_move_iterator(pair.second.end())); } else { road_out_mesh_list[pair.first] = std::move(pair.second); } } }); workers.push_back(std::move(neworker)); } for (size_t i = 0; i < workers.size(); ++i) { workers[i].join(); } workers.clear(); for (size_t i = 0; i < workers.size(); ++i) { if (workers[i].joinable()) { workers[i].join(); } } juntction_thread.join(); for (auto&& pair : junction_out_mesh_list) { if (road_out_mesh_list.find(pair.first) != road_out_mesh_list.end()) { road_out_mesh_list[pair.first].insert(road_out_mesh_list[pair.first].end(), std::make_move_iterator(pair.second.begin()), std::make_move_iterator(pair.second.end())); } else { road_out_mesh_list[pair.first] = std::move(pair.second); } } std::cout << "Generated " << std::to_string(num_roads) << " roads" << std::endl; return road_out_mesh_list; } std::vector> Map::GetTreesTransform( const geom::Vector3D& minpos, const geom::Vector3D& maxpos, float distancebetweentrees, float distancefromdrivinglineborder, float s_offset) const { std::vector> transforms; const std::vector RoadsIDToGenerate = FilterRoadsByPosition(minpos, maxpos); for ( RoadId id : RoadsIDToGenerate ) { const auto& road = _data.GetRoads().at(id); if (!road.IsJunction()) { for (auto &&lane_section : road.GetLaneSections()) { LaneId min_lane = 0; for (auto &pairlane : lane_section.GetLanes()) { if (min_lane > pairlane.first && pairlane.second.GetType() == Lane::LaneType::Driving) { min_lane = pairlane.first; } } const road::Lane* lane = lane_section.GetLane(min_lane); if( lane ) { double s_current = lane_section.GetDistance() + s_offset; const double s_end = lane_section.GetDistance() + lane_section.GetLength(); while(s_current < s_end){ if(lane->GetWidth(s_current) != 0.0f){ const auto edges = lane->GetCornerPositions(s_current, 0); geom::Vector3D director = edges.second - edges.first; geom::Vector3D treeposition = edges.first - director.MakeUnitVector() * distancefromdrivinglineborder; geom::Transform lanetransform = lane->ComputeTransform(s_current); geom::Transform treeTransform(treeposition, lanetransform.rotation); const carla::road::element::RoadInfoSpeed* roadinfo = lane->GetInfo(s_current); transforms.push_back(std::make_pair(treeTransform,roadinfo->GetType())); } s_current += distancebetweentrees; } } } } } return transforms; } geom::Mesh Map::GetAllCrosswalkMesh() const { geom::Mesh out_mesh; // Get the crosswalk vertices for the current map const std::vector crosswalk_vertex = GetAllCrosswalkZones(); if (crosswalk_vertex.empty()) { return out_mesh; } // Create a a list of triangle fans with material "crosswalk" out_mesh.AddMaterial("crosswalk"); size_t start_vertex_index = 0; size_t i = 0; std::vector vertices; // Iterate the vertices until a repeated one is found, this indicates // the triangle fan is done and another one must start do { // Except for the first iteration && triangle fan done if (i != 0 && crosswalk_vertex[start_vertex_index] == crosswalk_vertex[i]) { // Create the actual fan out_mesh.AddTriangleFan(vertices); vertices.clear(); // End the loop if i reached the end of the vertex list if (i >= crosswalk_vertex.size() - 1) { break; } start_vertex_index = ++i; } // Append a new Vector3D that will be added to the triangle fan vertices.push_back(crosswalk_vertex[i++]); } while (i < crosswalk_vertex.size()); out_mesh.EndMaterial(); return out_mesh; } /// Buids a list of meshes related with LineMarkings std::vector> Map::GenerateLineMarkings( const rpc::OpendriveGenerationParameters& params, const geom::Vector3D& minpos, const geom::Vector3D& maxpos, std::vector& outinfo ) const { std::vector> LineMarks; geom::MeshFactory mesh_factory(params); const std::vector RoadsIDToGenerate = FilterRoadsByPosition(minpos, maxpos); for ( RoadId id : RoadsIDToGenerate ) { const auto& road = _data.GetRoads().at(id); if (!road.IsJunction()) { mesh_factory.GenerateLaneMarkForRoad(road, LineMarks, outinfo); } } return std::move(LineMarks); } std::vector Map::GetJunctionsBoundingBoxes() const { std::vector returning; for ( const auto& junc_pair : _data.GetJunctions() ) { const auto& junction = junc_pair.second; float box_extraextension_factor = 1.5f; carla::geom::BoundingBox bb = junction.GetBoundingBox(); bb.extent *= box_extraextension_factor; returning.push_back(bb); } return returning; } inline float Map::GetZPosInDeformation(float posx, float posy) const { return geom::deformation::GetZPosInDeformation(posx, posy) + geom::deformation::GetBumpDeformation(posx,posy); } std::map>> Map::GenerateRoadsMultithreaded( const carla::geom::MeshFactory& mesh_factory, const std::vector& RoadsId, const size_t index, const size_t number_of_roads_per_thread) const { std::map>> out; size_t start = index * number_of_roads_per_thread; size_t endoffset = (index+1) * number_of_roads_per_thread; size_t end = RoadsId.size(); for (int i = start; i < endoffset && i < end; ++i) { const auto& road = _data.GetRoads().at(RoadsId[i]); if (!road.IsJunction()) { mesh_factory.GenerateAllOrderedWithMaxLen(road, out); } } std::cout << "Generated roads from " + std::to_string(index * number_of_roads_per_thread) + " to " + std::to_string((index+1) * number_of_roads_per_thread ) << std::endl; return out; } void Map::GenerateJunctions(const carla::geom::MeshFactory& mesh_factory, const rpc::OpendriveGenerationParameters& params, const geom::Vector3D& minpos, const geom::Vector3D& maxpos, std::map>>* junction_out_mesh_list) const { std::vector JunctionsToGenerate = FilterJunctionsByPosition(minpos, maxpos); size_t num_junctions = JunctionsToGenerate.size(); std::cout << "Generating " << std::to_string(num_junctions) << " junctions" << std::endl; size_t junctionindex = 0; size_t num_junctions_per_thread = 5; size_t num_threads = (num_junctions / num_junctions_per_thread) + 1; num_threads = num_threads > 1 ? num_threads : 1; std::vector workers; std::mutex write_mutex; for ( size_t i = 0; i < num_threads; ++i ) { std::thread neworker( [this, &write_mutex, &mesh_factory, &junction_out_mesh_list, JunctionsToGenerate, i, num_junctions_per_thread, num_junctions]() { std::map>> junctionsofthisthread; size_t minimum = 0; if( (i + 1) * num_junctions_per_thread < num_junctions ){ minimum = (i + 1) * num_junctions_per_thread; }else{ minimum = num_junctions; } std::cout << "Generating Junctions between " << std::to_string(i * num_junctions_per_thread) << " and " << std::to_string(minimum) << std::endl; for ( size_t junctionindex = i * num_junctions_per_thread; junctionindex < minimum; ++junctionindex ) { GenerateSingleJunction(mesh_factory, JunctionsToGenerate[junctionindex], &junctionsofthisthread); } std::cout << "Generated Junctions between " << std::to_string(i * num_junctions_per_thread) << " and " << std::to_string(minimum) << std::endl; std::lock_guard guard(write_mutex); for ( auto&& pair : junctionsofthisthread ) { if ((*junction_out_mesh_list).find(pair.first) != (*junction_out_mesh_list).end()) { (*junction_out_mesh_list)[pair.first].insert((*junction_out_mesh_list)[pair.first].end(), std::make_move_iterator(pair.second.begin()), std::make_move_iterator(pair.second.end())); } else { (*junction_out_mesh_list)[pair.first] = std::move(pair.second); } } }); workers.push_back(std::move(neworker)); } for (size_t i = 0; i < workers.size(); ++i) { workers[i].join(); } workers.clear(); for (size_t i = 0; i < workers.size(); ++i) { if (workers[i].joinable()) { workers[i].join(); } } } std::vector Map::FilterJunctionsByPosition( const geom::Vector3D& minpos, const geom::Vector3D& maxpos ) const { std::cout << "Filtered from " + std::to_string(_data.GetJunctions().size() ) + " junctions " << std::endl; std::vector ToReturn; for( auto& junction : _data.GetJunctions() ){ geom::Location junctionLocation = junction.second.GetBoundingBox().location; if( minpos.x < junctionLocation.x && junctionLocation.x < maxpos.x && minpos.y > junctionLocation.y && junctionLocation.y > maxpos.y ) { ToReturn.push_back(junction.first); } } std::cout << "To " + std::to_string(ToReturn.size() ) + " junctions " << std::endl; return ToReturn; } std::vector Map::FilterRoadsByPosition( const geom::Vector3D& minpos, const geom::Vector3D& maxpos ) const { std::vector ToReturn; std::cout << "Filtered from " + std::to_string(_data.GetRoads().size() ) + " roads " << std::endl; for( auto& road : _data.GetRoads() ){ auto &&lane_section = (*road.second.GetLaneSections().begin()); const road::Lane* lane = lane_section.GetLane(-1); if( lane ) { const double s_check = lane_section.GetDistance() + lane_section.GetLength() * 0.5; geom::Location roadLocation = lane->ComputeTransform(s_check).location; if( minpos.x < roadLocation.x && roadLocation.x < maxpos.x && minpos.y > roadLocation.y && roadLocation.y > maxpos.y ) { ToReturn.push_back(road.first); } } } std::cout << "To " + std::to_string(ToReturn.size() ) + " roads " << std::endl; return ToReturn; } std::unique_ptr Map::SDFToMesh(const road::Junction& jinput, const std::vector& sdfinput, int grid_cells_per_dim) const { int junctionid = jinput.GetId(); float box_extraextension_factor = 1.2f; const double CubeSize = 0.5; carla::geom::BoundingBox bb = jinput.GetBoundingBox(); carla::geom::Vector3D MinOffset = bb.location - geom::Location(bb.extent * box_extraextension_factor); carla::geom::Vector3D MaxOffset = bb.location + geom::Location(bb.extent * box_extraextension_factor); carla::geom::Vector3D OffsetPerCell = ( bb.extent * box_extraextension_factor * 2 ) / grid_cells_per_dim; auto junctionsdf = [this, OffsetPerCell, CubeSize, MinOffset, junctionid](MeshReconstruction::Vec3 const& pos) { geom::Vector3D worldloc(pos.x, pos.y, pos.z); boost::optional CheckingWaypoint = GetWaypoint(geom::Location(worldloc), 0x1 << 1); if (CheckingWaypoint) { if ( pos.z < 0.2) { return 0.0; } else { return -abs(pos.z); } } boost::optional InRoadWaypoint = GetClosestWaypointOnRoad(geom::Location(worldloc), 0x1 << 1); geom::Transform InRoadWPTransform = ComputeTransform(*InRoadWaypoint); geom::Vector3D director = geom::Location(worldloc) - (InRoadWPTransform.location); geom::Vector3D laneborder = InRoadWPTransform.location + geom::Location(director.MakeUnitVector() * GetLaneWidth(*InRoadWaypoint) * 0.5f); geom::Vector3D Distance = laneborder - worldloc; if (Distance.Length2D() < CubeSize * 1.1 && pos.z < 0.2) { return 0.0; } return Distance.Length() * -1.0; }; double gridsizeindouble = grid_cells_per_dim; MeshReconstruction::Rect3 domain; domain.min = { MinOffset.x, MinOffset.y, MinOffset.z }; domain.size = { bb.extent.x * box_extraextension_factor * 2, bb.extent.y * box_extraextension_factor * 2, 0.4 }; MeshReconstruction::Vec3 cubeSize{ CubeSize, CubeSize, 0.2 }; auto mesh = MeshReconstruction::MarchCube(junctionsdf, domain, cubeSize ); carla::geom::Rotation inverse = bb.rotation; carla::geom::Vector3D trasltation = bb.location; geom::Mesh out_mesh; for (auto& cv : mesh.vertices) { geom::Vector3D newvertex; newvertex.x = cv.x; newvertex.y = cv.y; newvertex.z = cv.z; out_mesh.AddVertex(newvertex); } auto finalvertices = out_mesh.GetVertices(); for (auto ct : mesh.triangles) { out_mesh.AddIndex(ct[1] + 1); out_mesh.AddIndex(ct[0] + 1); out_mesh.AddIndex(ct[2] + 1); } for (auto& cv : out_mesh.GetVertices() ) { boost::optional CheckingWaypoint = GetWaypoint(geom::Location(cv), 0x1 << 1); if (!CheckingWaypoint) { boost::optional InRoadWaypoint = GetClosestWaypointOnRoad(geom::Location(cv), 0x1 << 1); geom::Transform InRoadWPTransform = ComputeTransform(*InRoadWaypoint); geom::Vector3D director = geom::Location(cv) - (InRoadWPTransform.location); geom::Vector3D laneborder = InRoadWPTransform.location + geom::Location(director.MakeUnitVector() * GetLaneWidth(*InRoadWaypoint) * 0.5f); cv = laneborder; } } return std::make_unique(out_mesh); } void Map::GenerateSingleJunction(const carla::geom::MeshFactory& mesh_factory, const JuncId Id, std::map>>* junction_out_mesh_list) const { const auto& junction = _data.GetJunctions().at(Id); if (junction.GetConnections().size() > 2) { std::vector> lane_meshes; std::vector> sidewalk_lane_meshes; std::vector perimeterpoints; auto pmesh = SDFToMesh(junction, perimeterpoints, 75); (*junction_out_mesh_list)[road::Lane::LaneType::Driving].push_back(std::move(pmesh)); for (const auto& connection_pair : junction.GetConnections()) { const auto& connection = connection_pair.second; const auto& road = _data.GetRoads().at(connection.connecting_road); for (auto&& lane_section : road.GetLaneSections()) { for (auto&& lane_pair : lane_section.GetLanes()) { const auto& lane = lane_pair.second; if ( lane.GetType() == road::Lane::LaneType::Sidewalk ) { boost::optional sw = GetWaypoint(road.GetId(), lane_pair.first, lane.GetDistance() + (lane.GetLength() * 0.5f)); if( GetWaypoint(ComputeTransform(*sw).location).get_ptr () == nullptr ){ sidewalk_lane_meshes.push_back(mesh_factory.GenerateSidewalk(lane)); } } } } } std::unique_ptr sidewalk_mesh = std::make_unique(); for (auto& lane : sidewalk_lane_meshes) { *sidewalk_mesh += *lane; } (*junction_out_mesh_list)[road::Lane::LaneType::Sidewalk].push_back(std::move(sidewalk_mesh)); } else { std::vector> lane_meshes; std::vector> sidewalk_lane_meshes; for (const auto& connection_pair : junction.GetConnections()) { const auto& connection = connection_pair.second; const auto& road = _data.GetRoads().at(connection.connecting_road); for (auto&& lane_section : road.GetLaneSections()) { for (auto&& lane_pair : lane_section.GetLanes()) { const auto& lane = lane_pair.second; if (lane.GetType() != road::Lane::LaneType::Sidewalk) { lane_meshes.push_back(mesh_factory.GenerateTesselated(lane)); } else { sidewalk_lane_meshes.push_back(mesh_factory.GenerateSidewalk(lane)); } } } } std::unique_ptr merged_mesh = std::make_unique(); for (auto& lane : lane_meshes) { *merged_mesh += *lane; } std::unique_ptr sidewalk_mesh = std::make_unique(); for (auto& lane : sidewalk_lane_meshes) { *sidewalk_mesh += *lane; } (*junction_out_mesh_list)[road::Lane::LaneType::Driving].push_back(std::move(merged_mesh)); (*junction_out_mesh_list)[road::Lane::LaneType::Sidewalk].push_back(std::move(sidewalk_mesh)); } } } // namespace road } // namespace carla