[routing] Extended navigation info about next turn street/road #2658

Merged
AntonM030481 merged 15 commits from navigation into master 2022-06-07 12:20:22 +00:00
22 changed files with 229 additions and 84 deletions

View file

@ -55,7 +55,8 @@ public class Metadata implements Parcelable
FMD_CONTACT_VK(35),
FMD_CONTACT_LINE(36),
FMD_DESTINATION(37),
FMD_DESTINATION_REF(38);
FMD_DESTINATION_REF(38),
FMD_JUNCTION_REF(39);
private final int mMetaType;
MetadataType(int metadataType)

View file

@ -42,3 +42,15 @@ UNIT_TEST(ValidateAndFormat_building_levels)
TEST_EQUAL(tp.ValidateAndFormat_building_levels("2.51"), "2.5", ());
TEST_EQUAL(tp.ValidateAndFormat_building_levels("250"), "", ("Too many levels."));
}
UNIT_TEST(ValidateAndFormat_destination)
{
FeatureBuilderParams params;
MetadataTagProcessorImpl tp(params);
TEST_EQUAL(tp.ValidateAndFormat_destination("a1 a2"), "a1 a2", ());
TEST_EQUAL(tp.ValidateAndFormat_destination("b1-b2"), "b1-b2", ());
TEST_EQUAL(tp.ValidateAndFormat_destination(" c,d ;"), "c; d", ());
TEST_EQUAL(tp.ValidateAndFormat_destination("e,;f; g;"), "e; f; g", ());
TEST_EQUAL(tp.ValidateAndFormat_destination(""), "", ());
TEST_EQUAL(tp.ValidateAndFormat_destination("a1 a2;b1-b2; c,d ;e,;f; ;g"), "a1 a2; b1-b2; c; d; e; f; g", ());
}

View file

@ -148,7 +148,18 @@ string MetadataTagProcessorImpl::ValidateAndFormat_ele(string const & v) const
string MetadataTagProcessorImpl::ValidateAndFormat_destination(string const & v) const
{
return v;
// Normalization. "a1 a2;b1-b2; c,d ;e,;f; ;g" -> "a1 a2; b1-b2; c; d; e; f; g"
string r;
strings::Tokenize(v, ";,", [&](std::string_view d)
{
strings::Trim(d);
if (d.empty())
return;
if (!r.empty())
r += "; ";
r.append(d);
});
return r;
}
string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const & v) const
@ -156,6 +167,11 @@ string MetadataTagProcessorImpl::ValidateAndFormat_destination_ref(string const
return v;
}
string MetadataTagProcessorImpl::ValidateAndFormat_junction_ref(string const & v) const
{
return v;
}
string MetadataTagProcessorImpl::ValidateAndFormat_turn_lanes(string const & v) const
{
return v;
@ -458,6 +474,7 @@ void MetadataTagProcessor::operator()(std::string const & k, std::string const &
case Metadata::FMD_ELE: valid = ValidateAndFormat_ele(v); break;
case Metadata::FMD_DESTINATION: valid = ValidateAndFormat_destination(v); break;
case Metadata::FMD_DESTINATION_REF: valid = ValidateAndFormat_destination_ref(v); break;
case Metadata::FMD_JUNCTION_REF: valid = ValidateAndFormat_junction_ref(v); break;
case Metadata::FMD_TURN_LANES: valid = ValidateAndFormat_turn_lanes(v); break;
case Metadata::FMD_TURN_LANES_FORWARD: valid = ValidateAndFormat_turn_lanes_forward(v); break;
case Metadata::FMD_TURN_LANES_BACKWARD: valid = ValidateAndFormat_turn_lanes_backward(v); break;

View file

@ -18,6 +18,7 @@ struct MetadataTagProcessorImpl
std::string ValidateAndFormat_ele(std::string const & v) const;
std::string ValidateAndFormat_destination(std::string const & v) const;
std::string ValidateAndFormat_destination_ref(std::string const & v) const;
std::string ValidateAndFormat_junction_ref(std::string const & v) const;
std::string ValidateAndFormat_turn_lanes(std::string const & v) const;
std::string ValidateAndFormat_turn_lanes_forward(std::string const & v) const;
std::string ValidateAndFormat_turn_lanes_backward(std::string const & v) const;

View file

@ -76,6 +76,8 @@ bool Metadata::TypeFromString(string const & k, Metadata::EType & outType)
outType = Metadata::FMD_DESTINATION;
else if (k == "destination:ref")
outType = Metadata::FMD_DESTINATION_REF;
else if (k == "junction:ref")
outType = Metadata::FMD_JUNCTION_REF;
vng commented 2022-06-02 09:29:02 +00:00 (Migrated from github.com)
Review

Is there any difference in junction:ref and ref tag?
For highway=motorway_junction we already should take refs into (like) name. Can we make the same with junction:ref.

I suspect that we can merge ref and junction:ref

Is there any difference in junction:ref and ref tag? For highway=motorway_junction we already should take refs into (like) name. Can we make the same with junction:ref. I suspect that we can _merge_ ref and junction:ref
AntonM030481 commented 2022-06-02 09:48:50 +00:00 (Migrated from github.com)
Review

The reason why do we have all these tags separately to have an ability to handle incomplete data.
E.g. only JUNCTION_REF exists for link, but we can find calculate DESTINATION_REF from main road (by it's REF).

The reason why do we have all these tags separately to have an ability to handle incomplete data. E.g. only JUNCTION_REF exists for link, but we can find calculate DESTINATION_REF from main road (by it's REF).
vng commented 2022-06-02 09:51:16 +00:00 (Migrated from github.com)
Review

I agree with destination:*, but I suspect that ref and junction:ref are the same and should be processed identically, e.g. transfer into name and draw on the map.

I agree with destination:*, but I suspect that ref and junction:ref are the same and should be processed identically, e.g. transfer into name and draw on the map.
vng commented 2022-06-02 09:58:05 +00:00 (Migrated from github.com)
Review

Ah, I understood. junction:ref is used for outgoing highway way, not in motorway_junction ..

Ah, I understood. junction:ref is used for _outgoing highway way_, not in motorway_junction ..
AntonM030481 commented 2022-06-02 10:21:17 +00:00 (Migrated from github.com)
Review

tags for exit:
junction:ref is number of the junction (exit).
destination:ref - ref of next main road. Normally should match it's ref.

Added comment at RoadNameInfo definition definition.

tags for exit: junction:ref is number of the junction (exit). destination:ref - ref of next main road. Normally should match it's ref. Added comment at RoadNameInfo definition definition.
AntonM030481 commented 2022-06-02 11:09:21 +00:00 (Migrated from github.com)
Review

Right, currently I don't care about motorway_junction.
But of course it would be better to get it, and use it's tag ref instead of tag junction:ref of link it last tag does not exist.
But I don't know how to do it properly.

Right, currently I don't care about `motorway_junction`. But of course it would be better to get it, and use it's tag `ref` instead of tag `junction:ref` of link it last tag does not exist. But I don't know how to do it properly.
AntonM030481 commented 2022-06-02 12:42:05 +00:00 (Migrated from github.com)
Review

@vng maybe you can guide me how to merge it in proper way? Or just change the code if it's easier than to explain 😄

@vng maybe you can guide me how to merge it in proper way? Or just change the code if it's easier than to explain 😄
vng commented 2022-06-02 13:25:52 +00:00 (Migrated from github.com)
Review

No need to merge. Yes, this tags are used for highway ways, so everything is fine.

No need to merge. Yes, this tags are used for highway ways, so everything is fine.
AntonM030481 commented 2022-06-03 03:43:10 +00:00 (Migrated from github.com)
Review

I just want to clarify.
Some links have junction:ref tag, and some have not.
So we can fill missed data by finding appropriate junction point (motorway_junction) in the beginning of link, and using it's ref tag.

I just want to clarify. Some links have `junction:ref` tag, and some have not. So we can fill missed data by finding appropriate junction point (`motorway_junction`) in the beginning of link, and using it's `ref` tag.
AntonM030481 commented 2022-06-03 11:30:21 +00:00 (Migrated from github.com)
Review

We can do it in the next iteration.

We can do it in the next iteration.
else if (k == "turn:lanes")
outType = Metadata::FMD_TURN_LANES;
else if (k == "turn:lanes:forward")
@ -173,8 +175,9 @@ string ToString(Metadata::EType type)
case Metadata::FMD_CONTACT_LINE: return "contact:line";
case Metadata::FMD_INTERNET: return "internet_access";
case Metadata::FMD_ELE: return "ele";
case Metadata::FMD_DESTINATION: return "desination";
case Metadata::FMD_DESTINATION_REF: return "desination:ref";
case Metadata::FMD_DESTINATION: return "destination";
case Metadata::FMD_DESTINATION_REF: return "destination:ref";
case Metadata::FMD_JUNCTION_REF: return "junction:ref";
case Metadata::FMD_TURN_LANES: return "turn:lanes";
case Metadata::FMD_TURN_LANES_FORWARD: return "turn:lanes:forward";
case Metadata::FMD_TURN_LANES_BACKWARD: return "turn:lanes:backward";

View file

@ -155,6 +155,7 @@ public:
FMD_CONTACT_LINE = 36,
FMD_DESTINATION = 37,
FMD_DESTINATION_REF = 38,
FMD_JUNCTION_REF = 39,
FMD_COUNT
};

View file

@ -181,6 +181,7 @@ std::vector<Props> MetadataToProps(std::vector<T> const & metadata)
case Metadata::FMD_DESTINATION:
case Metadata::FMD_DESTINATION_REF:
case Metadata::FMD_JUNCTION_REF:
case Metadata::FMD_TURN_LANES:
case Metadata::FMD_TURN_LANES_FORWARD:
case Metadata::FMD_TURN_LANES_BACKWARD:

View file

@ -101,6 +101,13 @@ size_t CarDirectionsEngine::GetTurnDirection(IRoutingResult const & result, size
NumMwmIds const & numMwmIds,
RoutingSettings const & vehicleSettings, TurnItem & turnItem)
{
// This is for jump from initial point to start of the route. No direction is given.
/// @todo Sometimes results of GetPossibleTurns are empty, sometimes are invalid.
biodranik commented 2022-06-05 05:04:32 +00:00 (Migrated from github.com)
Review

What should be done to fix it?

What should be done to fix it?
AntonM030481 commented 2022-06-05 13:48:41 +00:00 (Migrated from github.com)
Review

The best will be to fix GetPossibleTurns(). It should return valid results with proper angles.

The best will be to fix GetPossibleTurns(). It should return valid results with proper angles.
AntonM030481 commented 2022-06-05 14:02:26 +00:00 (Migrated from github.com)
Review

Comment added.

Comment added.
/// The best will be to fix GetPossibleTurns(). It will allow us to use following approach.
/// E.g. Google Maps until you reach the destination will guide you to go to the left or to the right of the first road.
if (turnItem.m_index == 2)
return 0;
size_t skipTurnSegments = CheckUTurnOnRoute(result, outgoingSegmentIndex, numMwmIds, vehicleSettings, turnItem);
if (turnItem.m_turn == CarDirection::None)
@ -418,8 +425,8 @@ void GetTurnDirectionBasic(IRoutingResult const & result, size_t const outgoingS
if (!GetTurnInfo(result, outgoingSegmentIndex, vehicleSettings, turnInfo))
return;
turn.m_sourceName = turnInfo.m_ingoing->m_name;
turn.m_targetName = turnInfo.m_outgoing->m_name;
turn.m_sourceName = turnInfo.m_ingoing->m_roadNameInfo.m_name;
turn.m_targetName = turnInfo.m_outgoing->m_roadNameInfo.m_name;
turn.m_turn = CarDirection::None;
ASSERT_GREATER(turnInfo.m_ingoing->m_path.size(), 1, ());
@ -531,7 +538,7 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg
if (checkedSegment.m_path.size() < 2)
return 0;
if (checkedSegment.m_name == masterSegment.m_name &&
if (checkedSegment.m_roadNameInfo.m_name == masterSegment.m_roadNameInfo.m_name &&
checkedSegment.m_highwayClass == masterSegment.m_highwayClass &&
checkedSegment.m_isLink == masterSegment.m_isLink && !checkedSegment.m_onRoundabout)
{
@ -555,7 +562,7 @@ size_t CheckUTurnOnRoute(IRoutingResult const & result, size_t const outgoingSeg
}
// Avoid the UTurn on unnamed roads inside the rectangle based distinct.
if (checkedSegment.m_name.empty())
if (checkedSegment.m_roadNameInfo.m_name.empty())
return 0;
// Avoid returning to the same edge after uturn somewere else.

View file

@ -66,18 +66,12 @@ void DirectionsEngine::LoadPathAttributes(FeatureID const & featureId,
pathSegment.m_onRoundabout = ftypes::IsRoundAboutChecker::Instance()(*ft);
pathSegment.m_isOneWay = ftypes::IsOneWayChecker::Instance()(*ft);
if (pathSegment.m_isLink)
{
if (auto const & dst_number = ft->GetMetadata(feature::Metadata::FMD_DESTINATION_REF); !dst_number.empty())
pathSegment.m_name = "[" + string(dst_number) + "] ";
pathSegment.m_name += ft->GetMetadata(feature::Metadata::FMD_DESTINATION);
}
else
{
if (auto const & road_number = ft->GetRoadNumber(); !road_number.empty())
pathSegment.m_name = "[" + road_number + "] ";
pathSegment.m_name += ft->GetName(StringUtf8Multilang::kDefaultCode);
}
pathSegment.m_roadNameInfo.m_isLink = pathSegment.m_isLink;
pathSegment.m_roadNameInfo.m_junction_ref = ft->GetMetadata(feature::Metadata::FMD_JUNCTION_REF);
pathSegment.m_roadNameInfo.m_destination_ref = ft->GetMetadata(feature::Metadata::FMD_DESTINATION_REF);
pathSegment.m_roadNameInfo.m_destination = ft->GetMetadata(feature::Metadata::FMD_DESTINATION);
pathSegment.m_roadNameInfo.m_ref = ft->GetRoadNumber();
pathSegment.m_roadNameInfo.m_name = ft->GetName(StringUtf8Multilang::kDefaultCode);
}
void DirectionsEngine::GetSegmentRangeAndAdjacentEdges(IRoadGraph::EdgeListT const & outgoingEdges,
@ -355,7 +349,7 @@ RouterResultCode DirectionsEngine::MakeTurnAnnotation(IndexRoadGraph::EdgeVector
// Street names contain empty names too for avoiding of freezing of old street name while
// moving along unnamed street.
streets.emplace_back(max(junctions.size(), static_cast<size_t>(1)) - 1, loadedSegmentIt->m_name);
streets.emplace_back(max(junctions.size(), static_cast<size_t>(1)) - 1, loadedSegmentIt->m_roadNameInfo);
// Turns information.
if (!junctions.empty() && skipTurnSegments == 0)

View file

@ -3,6 +3,7 @@
#include "routing/road_point.hpp"
#include "routing/turns.hpp"
#include "routing/segment.hpp"
#include "routing/route.hpp"
#include "indexer/ftypes_matcher.hpp"
@ -22,7 +23,7 @@ struct LoadedPathSegment
{
std::vector<geometry::PointWithAltitude> m_path;
std::vector<turns::SingleLaneInfo> m_lanes;
std::string m_name;
RouteSegment::RoadNameInfo m_roadNameInfo;
double m_weight = 0.0; /*!< Time in seconds to pass the segment. */
SegmentRange m_segmentRange;
std::vector<Segment> m_segments; /*!< Traffic segments for |m_path|. */

View file

@ -30,8 +30,8 @@ size_t PedestrianDirectionsEngine::GetTurnDirection(IRoutingResult const & resul
double const turnAngle = CalcTurnAngle(result, outgoingSegmentIndex, numMwmIds, vehicleSettings);
turn.m_sourceName = turnInfo.m_ingoing->m_name;
turn.m_targetName = turnInfo.m_outgoing->m_name;
turn.m_sourceName = turnInfo.m_ingoing->m_roadNameInfo.m_name;
turn.m_targetName = turnInfo.m_outgoing->m_roadNameInfo.m_name;
turn.m_pedestrianTurn = PedestrianDirection::None;
ASSERT_GREATER(turnInfo.m_ingoing->m_path.size(), 1, ());

View file

@ -117,36 +117,77 @@ double Route::GetCurrentTimeToEndSec() const
m_poly.GetDistFromCurPointToRoutePointMeters() / curSegSpeedMPerS);
}
void Route::GetCurrentStreetName(string & name) const
void Route::GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const
{
GetStreetNameAfterIdx(static_cast<uint32_t>(m_poly.GetCurrentIter().m_ind), name);
GetStreetNameAfterIdx(static_cast<uint32_t>(m_poly.GetCurrentIter().m_ind), roadNameInfo);
}
void Route::GetStreetNameAfterIdx(uint32_t idx, string & name) const
void Route::GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const
{
double distance;
TurnItem turn;
GetCurrentTurn(distance, turn);
GetStreetNameAfterIdx(turn.m_index, roadNameInfo);
}
// If exit is false, returns ref and name.
// If exit is true, returns m_junction_ref, m_destination_ref, m_destination, m_name.
// Handling of incomplete data or non-standard data:
// - We go trough 400m to find first segment with existing data.
// But for link we go through all segments till we reach non-link segment,
// This is for really long links (e.g. 1km+ in USA) which have no tags.
// - Normally for link both destination and destination:ref tags exist together.
// But sometimes only |destination| tag exists for link. And |destination:ref| can be calculated
// by checking next segments of route until link will end and normal road will start.
// Hopefully it will have |ref| tag. So we can use it instead of |destination:ref|.
// Also we can use info about it's |name|. It can be useful if no |destination| tag.
// - Sometimes exit is not tagged as link (e.g. if new road starts here).
// At the same time they can have all useful tags just like link.
// Usually |destination:ref| = |ref| in such cases, or only 1st part of |destination:ref| can match.
void Route::GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const
{
name.clear();
auto const iterIdx = m_poly.GetIterToIndex(idx);
if (!IsValid() || !iterIdx.IsValid())
return;
size_t i = idx;
for (; i < m_poly.GetPolyline().GetSize(); ++i)
// Info about 1st segment with existing basic (non-link) info after link.
RouteSegment::RoadNameInfo roadNameInfoNext;
for (size_t i = idx; i < m_poly.GetPolyline().GetSize(); ++i)
{
// Note. curIter.m_ind == 0 means route iter at zero point. No corresponding route segments at
// |m_routeSegments| in this case. |name| should be cleared.
if (i == 0)
continue;
string const street = m_routeSegments[ConvertPointIdxToSegmentIdx(i)].GetStreet();
if (!street.empty())
auto const & r = m_routeSegments[ConvertPointIdxToSegmentIdx(i)].GetRoadNameInfo();
if (r.HasBasicTextInfo())
{
name = street;
return;
if (roadNameInfo.HasExitInfo())
roadNameInfoNext = r;
else
roadNameInfo = r;
break;
}
else if (r.HasExitInfo() && !roadNameInfo.HasExitInfo())
roadNameInfo = r;
// For exit wait for non-exit.
else if (roadNameInfo.HasExitInfo() && !r.m_isLink)
continue;
// For non-exits check only during first |kSteetNameLinkMeters|.
auto const furtherIter = m_poly.GetIterToIndex(i);
CHECK(furtherIter.IsValid(), ());
if (m_poly.GetDistanceM(iterIdx, furtherIter) > kSteetNameLinkMeters)
return;
break;
}
if (roadNameInfo.HasExitInfo())
{
// Use basic info from |roadNameInfoNext| to update |roadNameInfo|.
if (roadNameInfo.m_destination_ref.empty())
roadNameInfo.m_destination_ref = roadNameInfoNext.m_ref;
roadNameInfo.m_name = roadNameInfoNext.m_name;
}
}

View file

@ -64,15 +64,29 @@ public:
uint8_t m_maxSpeedKmPH = 0;
};
struct RoadNameInfo
{
// This is for street/road. |m_ref| |m_name|.
std::string m_name; // E.g "Johnson Ave.".
std::string m_ref; // Number of street/road e.g. "CA 85".
// This is for 1st segment of link after junction. Exit |junction_ref| to |m_destination_ref| for |m_destination|.
std::string m_junction_ref; // Number of junction e.g. "398B".
std::string m_destination_ref; // Number of next road, e.g. "CA 85", Sometimes "CA 85 South". Usually match |m_ref| of next main road.
std::string m_destination; // E.g. "Cupertino".
bool m_isLink = false;
bool HasBasicTextInfo() const { return !m_ref.empty() || !m_name.empty(); }
bool HasExitInfo() const { return m_isLink || !m_junction_ref.empty() || !m_destination_ref.empty() || !m_destination.empty(); }
};
RouteSegment(Segment const & segment, turns::TurnItem const & turn,
geometry::PointWithAltitude const & junction, std::string const & street,
geometry::PointWithAltitude const & junction, RoadNameInfo const & roadNameInfo,
double distFromBeginningMeters, double distFromBeginningMerc,
double timeFromBeginningS, traffic::SpeedGroup traffic,
std::unique_ptr<TransitInfo> transitInfo)
: m_segment(segment)
, m_turn(turn)
, m_junction(junction)
, m_street(street)
, m_roadNameInfo(roadNameInfo)
, m_distFromBeginningMeters(distFromBeginningMeters)
, m_distFromBeginningMerc(distFromBeginningMerc)
, m_timeFromBeginningS(timeFromBeginningS)
@ -89,7 +103,7 @@ public:
Segment const & GetSegment() const { return m_segment; }
Segment & GetSegment() { return m_segment; }
geometry::PointWithAltitude const & GetJunction() const { return m_junction; }
std::string const & GetStreet() const { return m_street; }
RoadNameInfo const & GetRoadNameInfo() const { return m_roadNameInfo; }
traffic::SpeedGroup GetTraffic() const { return m_traffic; }
turns::TurnItem const & GetTurn() const { return m_turn; }
@ -116,8 +130,8 @@ private:
/// The furthest point of the segment from the beginning of the route along the route.
geometry::PointWithAltitude m_junction;
/// Street name of |m_segment| if any. Otherwise |m_street| is empty.
std::string m_street;
/// RoadNameInfo of |m_segment| if any. Otherwise |m_roadInfo| is empty.
RoadNameInfo m_roadNameInfo;
/// Distance from the route (not the subroute) beginning to the farthest end of |m_segment| in meters.
double m_distFromBeginningMeters = 0.0;
@ -147,7 +161,7 @@ public:
using TTurns = std::vector<turns::TurnItem>;
using TTimeItem = std::pair<uint32_t, double>;
using TTimes = std::vector<TTimeItem>;
using TStreetItem = std::pair<uint32_t, std::string>;
using TStreetItem = std::pair<uint32_t, RouteSegment::RoadNameInfo>;
using TStreets = std::vector<TStreetItem>;
class SubrouteAttrs final
@ -299,11 +313,14 @@ public:
/// set with MoveIterator() method. If it's not possible returns nullopt.
std::optional<turns::TurnItem> GetCurrentIteratorTurn() const;
/// \brief Returns a name of a street where the user rides at this moment.
void GetCurrentStreetName(std::string & name) const;
/// \brief Returns a name info of a street next to idx point of the path.
void GetStreetNameAfterIdx(uint32_t idx, RouteSegment::RoadNameInfo & roadNameInfo) const;
/// \brief Returns a name of a street next to idx point of the path. Function avoids short unnamed links.
void GetStreetNameAfterIdx(uint32_t idx, std::string & name) const;
/// \brief Returns name info of a street where the user rides at this moment.
void GetCurrentStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const;
/// \brief Return name info of a street according to next turn.
void GetNextTurnStreetName(RouteSegment::RoadNameInfo & roadNameInfo) const;
/// \brief Gets turn information after the turn next to the nearest one.
/// \param distanceToTurnMeters is a distance from current position to the second turn.

View file

@ -4,6 +4,7 @@
#include "routing/fake_feature_ids.hpp"
#include "routing/index_graph_starter.hpp"
#include "routing/road_point.hpp"
#include "routing/route.hpp"
#include "routing/segment.hpp"
#include "routing/traffic_stash.hpp"
#include "routing/world_graph.hpp"
@ -68,7 +69,7 @@ void FillSegmentInfo(vector<Segment> const & segments,
++turnIdx;
}
string curStreet;
RouteSegment::RoadNameInfo curStreet;
if (!streets.empty())
{
CHECK_LESS_OR_EQUAL(streetIdx, streets.size(), ());

View file

@ -422,7 +422,7 @@ using namespace std;
for (auto const & routeSegment : routeSegments)
{
TEST(routeSegment.GetSpeedCams().empty(),
(routeSegment.GetSegment(), routeSegment.GetStreet()));
(routeSegment.GetSegment(), routeSegment.GetRoadNameInfo().m_name));
}
}

View file

@ -183,19 +183,16 @@ void TestTurnCount(routing::Route const & route, uint32_t expectedTurnCount)
void TestCurrentStreetName(routing::Route const & route, string const & expectedStreetName)
{
string streetName;
route.GetCurrentStreetName(streetName);
TEST_EQUAL(streetName, expectedStreetName, ());
RouteSegment::RoadNameInfo roadNameInfo;
route.GetCurrentStreetName(roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, expectedStreetName, ());
}
void TestNextStreetName(routing::Route const & route, string const & expectedStreetName)
{
string streetName;
double distance;
turns::TurnItem turn;
route.GetCurrentTurn(distance, turn);
route.GetStreetNameAfterIdx(turn.m_index, streetName);
TEST_EQUAL(streetName, expectedStreetName, ());
RouteSegment::RoadNameInfo roadNameInfo;
route.GetNextTurnStreetName(roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, expectedStreetName, ());
}
void TestRouteLength(Route const & route, double expectedRouteMeters, double relativeError)

View file

@ -52,8 +52,9 @@ UNIT_TEST(RussiaTulskayaToPaveletskayaStreetNamesTest)
MoveRoute(route, ms::LatLon(55.73034, 37.63099));
// No more extra last turn, so TestNextStreetName returns "".
integration::TestCurrentStreetName(route, "Валовая улица");
integration::TestNextStreetName(route, "улица Зацепский Вал");
//integration::TestNextStreetName(route, "улица Зацепский Вал");
MoveRoute(route, ms::LatLon(55.730912, 37.636191));

View file

@ -10,6 +10,8 @@
#include "geometry/angles.hpp"
#include "geometry/mercator.hpp"
#include "indexer/road_shields_parser.hpp"
#include <utility>
using namespace location;
@ -339,6 +341,41 @@ SessionState RoutingSession::OnLocationPositionChanged(GpsInfo const & info)
return m_state;
}
// For next street returns "[ref] name" .
// For highway exits (or main roads with exit info) returns "[junction:ref]: [target:ref] > target".
// If no |target| - it will be replaced by |name| of next street.
// If no |target:ref| - it will be replaced by |ref| of next road.
// So if link has no info at all, "[ref] name" of next will be returned (as for next street).
void GetFullRoadName(RouteSegment::RoadNameInfo & road, string & name)
{
if (auto const & sh = ftypes::GetRoadShields(road.m_ref); !sh.empty())
road.m_ref = sh[0].m_name;
if (auto const & sh = ftypes::GetRoadShields(road.m_destination_ref); !sh.empty())
road.m_destination_ref = sh[0].m_name;
name.clear();
if (road.HasExitInfo())
{
if (!road.m_junction_ref.empty())
name = "[" + road.m_junction_ref + "]";
if (!road.m_destination_ref.empty())
name += string(name.empty() ? "" : ": ") + "[" + road.m_destination_ref + "]";
if (!road.m_destination.empty())
name += string(name.empty() ? "" : " ") + "> " + road.m_destination;
else if (!road.m_name.empty())
name += (road.m_destination_ref.empty() ? string(name.empty() ? "" : " ") : ": ") + road.m_name;
}
else
{
if (!road.m_ref.empty())
name = "[" + road.m_ref + "]";
if (!road.m_name.empty())
name += (name.empty() ? "" : " ") + road.m_name;
}
}
void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const
{
CHECK_THREAD_CHECKER(m_threadChecker, ());
@ -376,8 +413,12 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const
info.m_exitNum = turn.m_exitNum;
info.m_time = static_cast<int>(max(kMinimumETASec, m_route->GetCurrentTimeToEndSec()));
m_route->GetCurrentStreetName(info.m_sourceName);
m_route->GetStreetNameAfterIdx(turn.m_index, info.m_targetName);
RouteSegment::RoadNameInfo sourceRoadNameInfo, targetRoadNameInfo;
m_route->GetCurrentStreetName(sourceRoadNameInfo);
GetFullRoadName(sourceRoadNameInfo, info.m_sourceName);
m_route->GetNextTurnStreetName(targetRoadNameInfo);
GetFullRoadName(targetRoadNameInfo, info.m_targetName);
info.m_completionPercent = GetCompletionPercent();
// Lane information and next street name.

View file

@ -29,7 +29,9 @@ static Route::TTurns const kTestTurns(
{turns::TurnItem(1, turns::CarDirection::TurnLeft),
turns::TurnItem(2, turns::CarDirection::TurnRight),
turns::TurnItem(4, turns::CarDirection::ReachedYourDestination)});
static Route::TStreets const kTestNames({{0, "Street1"}, {1, "Street2"}, {4, "Street3"}});
static Route::TStreets const kTestNames({{0, {"Street1", "", "", "", "", false}},
{1, {"Street2", "", "", "", "", false}},
{4, {"Street3", "", "", "", "", false}}});
static Route::TTimes const kTestTimes({Route::TTimeItem(1, 5), Route::TTimeItem(3, 10),
Route::TTimeItem(4, 15)});
@ -39,11 +41,15 @@ static Route::TTurns const kTestTurns2(
turns::TurnItem(2, turns::CarDirection::TurnRight),
turns::TurnItem(3, turns::CarDirection::None),
turns::TurnItem(4, turns::CarDirection::ReachedYourDestination)});
static vector<string> const kTestNames2 = {"Street0", "Street1", "Street2", "", "Street3"};
static vector<RouteSegment::RoadNameInfo> const kTestNames2 = {{"Street0", "", "", "", "", false},
{"Street1", "", "", "", "", false},
{"Street2", "", "", "", "", false},
{"", "", "", "", "", false},
{"Street3", "", "", "", "", false}};
static vector<double> const kTestTimes2 = {0.0, 5.0, 6.0, 10.0, 15.0};
void GetTestRouteSegments(vector<m2::PointD> const & routePoints, Route::TTurns const & turns,
vector<string> const & streets, vector<double> const & times,
vector<RouteSegment::RoadNameInfo> const & streets, vector<double> const & times,
vector<RouteSegment> & routeSegments)
{
CHECK_EQUAL(routePoints.size(), turns.size(), ());
@ -290,7 +296,7 @@ UNIT_TEST(SelfIntersectedRouteMatchingTest)
Route route("TestRouter", 0 /* route id */);
route.SetGeometry(kRouteGeometry.begin(), kRouteGeometry.end());
vector<RouteSegment> routeSegments;
GetTestRouteSegments(kRouteGeometry, kTestTurns2, kTestNames2, kTestTimes2, routeSegments);
route.SetRouteSegments(move(routeSegments));
@ -346,30 +352,30 @@ UNIT_TEST(RouteNameTest)
GetTestRouteSegments(kTestGeometry, kTestTurns2, kTestNames2, kTestTimes2, routeSegments);
route.SetRouteSegments(move(routeSegments));
string name;
route.GetCurrentStreetName(name);
TEST_EQUAL(name, "Street1", ());
RouteSegment::RoadNameInfo roadNameInfo;
route.GetCurrentStreetName(roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name));
route.GetStreetNameAfterIdx(0, name);
TEST_EQUAL(name, "Street1", ());
route.GetStreetNameAfterIdx(0, roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name));
route.GetStreetNameAfterIdx(1, name);
TEST_EQUAL(name, "Street1", ());
route.GetStreetNameAfterIdx(1, roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street1", (roadNameInfo.m_name));
route.GetStreetNameAfterIdx(2, name);
TEST_EQUAL(name, "Street2", ());
route.GetStreetNameAfterIdx(2, roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street2", (roadNameInfo.m_name));
route.GetStreetNameAfterIdx(3, name);
TEST_EQUAL(name, "Street3", ());
route.GetStreetNameAfterIdx(3, roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street3", (roadNameInfo.m_name));
route.GetStreetNameAfterIdx(4, name);
TEST_EQUAL(name, "Street3", ());
route.GetStreetNameAfterIdx(4, roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street3", (roadNameInfo.m_name));
location::GpsInfo info;
info.m_longitude = 1.0;
info.m_latitude = 2.0;
route.MoveIterator(info);
route.GetCurrentStreetName(name);
TEST_EQUAL(name, "Street2", ());
route.GetCurrentStreetName(roadNameInfo);
TEST_EQUAL(roadNameInfo.m_name, "Street2", (roadNameInfo.m_name));
}
} // namespace route_tests

View file

@ -37,7 +37,7 @@ UNIT_TEST(FillSegmentInfoSmokeTest)
TEST_EQUAL(segmentInfo.size(), 1, ());
TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::ReachedYourDestination, ());
TEST(segmentInfo[0].GetStreet().empty(), ());
TEST(segmentInfo[0].GetRoadNameInfo().m_name.empty(), ());
}
UNIT_TEST(FillSegmentInfoTest)
@ -50,7 +50,9 @@ UNIT_TEST(FillSegmentInfoTest)
{m2::PointD(0.2 /* x */, 0.0 /* y */), geometry::kInvalidAltitude}};
Route::TTurns const & turnDirs = {{1 /* point index */, CarDirection::TurnRight},
{2 /* point index */, CarDirection::ReachedYourDestination}};
Route::TStreets const streets = {{0 /* point index */, "zero"}, {1, "first"}, {2, "second"}};
Route::TStreets const streets = {{0 /* point index */, {"zero", "", "", "", "", false}},
{1 /* point index */, {"first", "", "", "", "", false}},
{2 /* point index */, {"second", "", "", "", "", false}}};
Route::TTimes const times = {
{0 /* point index */, 0.0 /* time in seconds */}, {1, 1.0}, {2, 2.0}};
@ -59,11 +61,11 @@ UNIT_TEST(FillSegmentInfoTest)
TEST_EQUAL(segmentInfo.size(), 2, ());
TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::TurnRight, ());
TEST_EQUAL(segmentInfo[0].GetStreet(), string("first"), ());
TEST_EQUAL(segmentInfo[0].GetRoadNameInfo().m_name, string("first"), ());
TEST_EQUAL(segmentInfo[0].GetSegment(), segments[0], ());
TEST_EQUAL(segmentInfo[1].GetTurn().m_turn, CarDirection::ReachedYourDestination, ());
TEST_EQUAL(segmentInfo[1].GetStreet(), string("second"), ());
TEST_EQUAL(segmentInfo[1].GetRoadNameInfo().m_name, string("second"), ());
TEST_EQUAL(segmentInfo[1].GetSegment(), segments[1], ());
}

View file

@ -339,7 +339,7 @@ UNIT_TEST(TestIntermediateDirection)
UNIT_TEST(TestCheckUTurnOnRoute)
{
TUnpackedPathSegments pathSegments(4, LoadedPathSegment());
pathSegments[0].m_name = "A road";
pathSegments[0].m_roadNameInfo = {"A road", "", "", "", "", false};
pathSegments[0].m_weight = 1;
pathSegments[0].m_highwayClass = ftypes::HighwayClass::Trunk;
pathSegments[0].m_onRoundabout = false;

View file

@ -292,7 +292,8 @@ void CorrectCandidatesSegmentByOutgoing(TurnInfo const & turnInfo, Segment const
it->m_segment = firstOutgoingSeg;
}
else if (nodes.isCandidatesAngleValid)
ASSERT(false, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true."));
// Typically all candidates are from one mwm, and missed one (firstOutgoingSegment) from another.
LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment but isCandidatesAngleValid == true."));
else
{
LOG(LWARNING, ("Can't match any candidate with firstOutgoingSegment and isCandidatesAngleValid == false"));