2016-05-13 13:18:00 -04:00
|
|
|
#include "extractor/guidance/turn_lane_data.hpp"
|
|
|
|
#include "util/guidance/turn_lanes.hpp"
|
|
|
|
|
|
|
|
#include <boost/numeric/conversion/cast.hpp>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace extractor
|
|
|
|
{
|
|
|
|
namespace guidance
|
|
|
|
{
|
|
|
|
namespace lanes
|
|
|
|
{
|
|
|
|
|
|
|
|
bool TurnLaneData::operator<(const TurnLaneData &other) const
|
|
|
|
{
|
|
|
|
if (from < other.from)
|
|
|
|
return true;
|
|
|
|
if (from > other.from)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (to < other.to)
|
|
|
|
return true;
|
|
|
|
if (to > other.to)
|
|
|
|
return false;
|
|
|
|
|
2016-06-21 04:41:08 -04:00
|
|
|
const constexpr TurnLaneType::Mask tag_by_modifier[] = {TurnLaneType::sharp_right,
|
|
|
|
TurnLaneType::right,
|
|
|
|
TurnLaneType::slight_right,
|
|
|
|
TurnLaneType::straight,
|
|
|
|
TurnLaneType::slight_left,
|
|
|
|
TurnLaneType::left,
|
|
|
|
TurnLaneType::sharp_left,
|
|
|
|
TurnLaneType::uturn};
|
2016-08-08 09:44:58 -04:00
|
|
|
// U-Turns are supposed to be on the outside. So if the first lane is 0 and we are looking at a
|
|
|
|
// u-turn, it has to be on the very left. If it is equal to the number of lanes, it has to be on
|
|
|
|
// the right. These sorting function assume reverse to be on the outside always. Might need to
|
|
|
|
// be reconsidered if there are situations that offer a reverse from some middle lane (seems
|
|
|
|
// improbable)
|
|
|
|
|
|
|
|
if (tag == TurnLaneType::uturn)
|
|
|
|
{
|
|
|
|
if (from == 0)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (other.tag == TurnLaneType::uturn)
|
|
|
|
{
|
|
|
|
if (other.from == 0)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-05-13 13:18:00 -04:00
|
|
|
return std::find(tag_by_modifier, tag_by_modifier + 8, this->tag) <
|
|
|
|
std::find(tag_by_modifier, tag_by_modifier + 8, other.tag);
|
|
|
|
}
|
|
|
|
|
2016-06-21 04:41:08 -04:00
|
|
|
LaneDataVector laneDataFromDescription(const TurnLaneDescription &turn_lane_description)
|
2016-05-13 13:18:00 -04:00
|
|
|
{
|
2016-06-21 04:41:08 -04:00
|
|
|
typedef std::unordered_map<TurnLaneType::Mask, std::pair<LaneID, LaneID>> LaneMap;
|
|
|
|
const auto num_lanes = boost::numeric_cast<LaneID>(turn_lane_description.size());
|
|
|
|
const auto setLaneData = [&](
|
|
|
|
LaneMap &map, TurnLaneType::Mask full_mask, const LaneID current_lane) {
|
|
|
|
const auto isSet = [&](const TurnLaneType::Mask test_mask) -> bool {
|
|
|
|
return (test_mask & full_mask) == test_mask;
|
|
|
|
};
|
|
|
|
|
|
|
|
for (std::size_t shift = 0; shift < TurnLaneType::detail::num_supported_lane_types; ++shift)
|
2016-05-13 13:18:00 -04:00
|
|
|
{
|
2016-06-21 04:41:08 -04:00
|
|
|
TurnLaneType::Mask mask = 1 << shift;
|
|
|
|
if (isSet(mask))
|
2016-05-13 13:18:00 -04:00
|
|
|
{
|
2016-06-21 04:41:08 -04:00
|
|
|
auto map_iterator = map.find(mask);
|
|
|
|
if (map_iterator == map.end())
|
|
|
|
map[mask] = std::make_pair(current_lane, current_lane);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
map_iterator->second.first = current_lane;
|
|
|
|
}
|
2016-05-13 13:18:00 -04:00
|
|
|
}
|
2016-06-21 04:41:08 -04:00
|
|
|
}
|
2016-05-13 13:18:00 -04:00
|
|
|
};
|
|
|
|
|
2016-06-21 04:41:08 -04:00
|
|
|
LaneMap lane_map;
|
|
|
|
LaneID lane_nr = num_lanes - 1;
|
|
|
|
if (turn_lane_description.empty())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
for (auto full_mask : turn_lane_description)
|
|
|
|
{
|
|
|
|
setLaneData(lane_map, full_mask, lane_nr);
|
|
|
|
--lane_nr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// transform the map into the lane data vector
|
|
|
|
LaneDataVector lane_data;
|
|
|
|
for (const auto tag : lane_map)
|
|
|
|
{
|
|
|
|
lane_data.push_back({tag.first, tag.second.first, tag.second.second});
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort(lane_data.begin(), lane_data.end());
|
|
|
|
|
2016-05-13 13:18:00 -04:00
|
|
|
// check whether a given turn lane string resulted in valid lane data
|
|
|
|
const auto hasValidOverlaps = [](const LaneDataVector &lane_data) {
|
|
|
|
// Allow an overlap of at most one. Larger overlaps would result in crossing another turn,
|
|
|
|
// which is invalid
|
|
|
|
for (std::size_t index = 1; index < lane_data.size(); ++index)
|
|
|
|
{
|
|
|
|
if (lane_data[index - 1].to > lane_data[index].from)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!hasValidOverlaps(lane_data))
|
|
|
|
lane_data.clear();
|
|
|
|
|
|
|
|
return lane_data;
|
|
|
|
}
|
|
|
|
|
2016-06-21 04:41:08 -04:00
|
|
|
LaneDataVector::iterator findTag(const TurnLaneType::Mask tag, LaneDataVector &data)
|
2016-05-13 13:18:00 -04:00
|
|
|
{
|
|
|
|
return std::find_if(data.begin(), data.end(), [&](const TurnLaneData &lane_data) {
|
2016-06-21 04:41:08 -04:00
|
|
|
return (tag & lane_data.tag) != TurnLaneType::empty;
|
2016-05-13 13:18:00 -04:00
|
|
|
});
|
|
|
|
}
|
2016-06-21 04:41:08 -04:00
|
|
|
LaneDataVector::const_iterator findTag(const TurnLaneType::Mask tag, const LaneDataVector &data)
|
2016-05-13 13:18:00 -04:00
|
|
|
{
|
|
|
|
return std::find_if(data.cbegin(), data.cend(), [&](const TurnLaneData &lane_data) {
|
2016-06-21 04:41:08 -04:00
|
|
|
return (tag & lane_data.tag) != TurnLaneType::empty;
|
2016-05-13 13:18:00 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-21 04:41:08 -04:00
|
|
|
bool hasTag(const TurnLaneType::Mask tag, const LaneDataVector &data)
|
2016-06-15 08:38:24 -04:00
|
|
|
{
|
|
|
|
return findTag(tag, data) != data.cend();
|
2016-05-13 13:18:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace lanes
|
|
|
|
} // namespace guidance
|
|
|
|
} // namespace extractor
|
|
|
|
} // namespace osrm
|