Merge pull request #79 from mgsergio/fix-turn-bug

Fix turn bug
This commit is contained in:
Lev Dragunov 2015-09-30 19:12:37 +03:00
commit 6299e3bcc1
12 changed files with 210 additions and 121 deletions

View file

@ -132,7 +132,7 @@ private:
class Uint32ValueList
{
public:
using BufferT = vector<uint32_t>;
using TBuffer = vector<uint32_t>;
void Append(uint32_t value)
{
@ -146,11 +146,11 @@ public:
template <typename TSink>
void Dump(TSink & sink) const
{
sink.Write(m_values.data(), m_values.size() * sizeof(BufferT::value_type));
sink.Write(m_values.data(), m_values.size() * sizeof(TBuffer::value_type));
}
private:
BufferT m_values;
TBuffer m_values;
};
} // unnamed namespace

View file

@ -17,7 +17,7 @@ using namespace feature;
// FeatureBase implementation
///////////////////////////////////////////////////////////////////////////////////////////////////
void FeatureBase::Deserialize(feature::LoaderBase * pLoader, BufferT buffer)
void FeatureBase::Deserialize(feature::LoaderBase * pLoader, TBuffer buffer)
{
m_pLoader = pLoader;
m_pLoader->Init(buffer);
@ -76,7 +76,7 @@ string FeatureBase::DebugString() const
// FeatureType implementation
///////////////////////////////////////////////////////////////////////////////////////////////////
void FeatureType::Deserialize(feature::LoaderBase * pLoader, BufferT buffer)
void FeatureType::Deserialize(feature::LoaderBase * pLoader, TBuffer buffer)
{
base_type::Deserialize(pLoader, buffer);

View file

@ -29,9 +29,9 @@ class FeatureBase
public:
typedef char const * BufferT;
using TBuffer = char const *;
void Deserialize(feature::LoaderBase * pLoader, BufferT buffer);
void Deserialize(feature::LoaderBase * pLoader, TBuffer buffer);
/// @name Parse functions. Do simple dispatching to m_pLoader.
//@{
@ -151,7 +151,7 @@ class FeatureType : public FeatureBase
FeatureID m_id;
public:
void Deserialize(feature::LoaderBase * pLoader, BufferT buffer);
void Deserialize(feature::LoaderBase * pLoader, TBuffer buffer);
inline void SetID(FeatureID const & id) { m_id = id; }
inline FeatureID GetID() const { return m_id; }

View file

@ -71,7 +71,7 @@ LoaderBase::LoaderBase(SharedLoadInfo const & info)
{
}
void LoaderBase::Init(BufferT data)
void LoaderBase::Init(TBuffer data)
{
m_Data = data;
m_pF = 0;

View file

@ -58,11 +58,11 @@ namespace feature
virtual ~LoaderBase() {}
// It seems like no need to store a copy of buffer (see FeaturesVector).
typedef char const * BufferT;
typedef char const * TBuffer;
/// @name Initialize functions.
//@{
void Init(BufferT data);
void Init(TBuffer data);
inline void InitFeature(FeatureType * p) { m_pF = p; }
void ResetGeometry();
@ -99,7 +99,7 @@ namespace feature
SharedLoadInfo const & m_Info;
FeatureType * m_pF;
BufferT m_Data;
TBuffer m_Data;
static uint32_t const m_TypesOffset = 1;
uint32_t m_CommonOffset, m_Header2Offset;

View file

@ -135,20 +135,20 @@ namespace serial
};
}
void TrianglesChainSaver::operator() (PointT arr[3], vector<EdgeT> edges)
void TrianglesChainSaver::operator() (TPoint arr[3], vector<TEdge> edges)
{
m_buffers.push_back(BufferT());
MemWriter<BufferT> writer(m_buffers.back());
m_buffers.push_back(TBuffer());
MemWriter<TBuffer> writer(m_buffers.back());
WriteVarUint(writer, EncodeDelta(arr[0], m_base));
WriteVarUint(writer, EncodeDelta(arr[1], arr[0]));
EdgeT curr = edges.front();
TEdge curr = edges.front();
curr.m_delta = EncodeDelta(arr[2], arr[1]);
sort(edges.begin(), edges.end(), edge_less_p0());
stack<EdgeT> st;
stack<TEdge> st;
while (true)
{
CHECK_EQUAL ( curr.m_delta >> 62, 0, () );
@ -156,7 +156,7 @@ namespace serial
// find next edges
int const nextNode = curr.m_p[1];
vector<EdgeT>::iterator i = lower_bound(edges.begin(), edges.end(), nextNode, edge_less_p0());
auto i = lower_bound(edges.begin(), edges.end(), nextNode, edge_less_p0());
bool const found = (i != edges.end() && i->m_p[0] == nextNode);
if (found)
{
@ -168,7 +168,7 @@ namespace serial
// first child
delta |= (one << i->m_side);
vector<EdgeT>::iterator j = i+1;
vector<TEdge>::iterator j = i+1;
if (j != edges.end() && j->m_p[0] == nextNode)
{
// second child

View file

@ -159,27 +159,28 @@ namespace serial
class TrianglesChainSaver
{
typedef m2::PointU PointT;
typedef tesselator::Edge EdgeT;
typedef vector<char> BufferT;
using TPoint = m2::PointU;
using TEdge = tesselator::Edge;
using TBuffer = vector<char>;
PointT m_base, m_max;
TPoint m_base;
TPoint m_max;
list<BufferT> m_buffers;
list<TBuffer> m_buffers;
public:
explicit TrianglesChainSaver(CodingParams const & params);
PointT GetBasePoint() const { return m_base; }
PointT GetMaxPoint() const { return m_max; }
TPoint GetBasePoint() const { return m_base; }
TPoint GetMaxPoint() const { return m_max; }
void operator() (PointT arr[3], vector<EdgeT> edges);
void operator() (TPoint arr[3], vector<TEdge> edges);
size_t GetBufferSize() const
{
size_t sz = 0;
for (list<BufferT>::const_iterator i = m_buffers.begin(); i != m_buffers.end(); ++i)
sz += i->size();
for (auto const & i : m_buffers)
sz += i.size();
return sz;
}

View file

@ -11,8 +11,9 @@ using namespace routing::turns;
UNIT_TEST(RussiaMoscowLenigradskiy39UturnTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.537544383032568, 67.536216737893028}, {0., 0.},
{37.538908531885973, 67.54544090660923});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.79693, 37.53754), {0., 0.},
MercatorBounds::FromLatLon(55.80212, 37.5389));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -34,8 +35,9 @@ UNIT_TEST(RussiaMoscowLenigradskiy39UturnTurnTest)
UNIT_TEST(RussiaMoscowSalameiNerisUturnTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.395332276656617, 67.633925439079519}, {0., 0.},
{37.392503720352721, 67.61975260731343});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.85182, 37.39533), {0., 0.},
MercatorBounds::FromLatLon(55.84386, 37.39250));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -43,19 +45,19 @@ UNIT_TEST(RussiaMoscowSalameiNerisUturnTurnTest)
integration::TestTurnCount(route, 4);
integration::GetNthTurn(route, 0)
.TestValid()
.TestPoint({37.388482521388539, 67.633382734905041}, 20.)
.TestPoint({37.38848, 67.63338}, 20.)
.TestDirection(TurnDirection::TurnSlightRight);
integration::GetNthTurn(route, 1)
.TestValid()
.TestPoint({37.387117276989784, 67.633369323859881}, 20.)
.TestPoint({37.38711, 67.63336}, 20.)
.TestDirection(TurnDirection::TurnLeft);
integration::GetNthTurn(route, 2)
.TestValid()
.TestPoint({37.387380133475205, 67.632781920081243}, 20.)
.TestPoint({37.38738, 67.63278}, 20.)
.TestDirection(TurnDirection::TurnLeft);
integration::GetNthTurn(route, 3)
.TestValid()
.TestPoint({37.390526364673121, 67.633106467374461}, 20.)
.TestPoint({37.39052, 67.63310}, 20.)
.TestDirection(TurnDirection::TurnRight);
integration::TestRouteLength(route, 1637.);
@ -63,9 +65,10 @@ UNIT_TEST(RussiaMoscowSalameiNerisUturnTurnTest)
UNIT_TEST(RussiaMoscowTrikotagniAndPohodniRoundaboutTurnTest)
{
TRouteResult const routeResult =
integration::CalculateRoute(integration::GetOsrmComponents(), {37.405153751040686, 67.5971698246356},
{0., 0.}, {37.40521071657038, 67.601903779043795});
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.83118, 37.40515), {0., 0.},
MercatorBounds::FromLatLon(55.83384, 37.40521));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -84,8 +87,10 @@ UNIT_TEST(RussiaMoscowTrikotagniAndPohodniRoundaboutTurnTest)
UNIT_TEST(RussiaMoscowPlanetnaiTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.546683164991776, 67.545511147376089}, {0., 0.},
{37.549153861529007, 67.54467404790482});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.80216, 37.54668), {0., 0.},
MercatorBounds::FromLatLon(55.80169, 37.54915));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -99,8 +104,10 @@ UNIT_TEST(RussiaMoscowPlanetnaiTurnTest)
UNIT_TEST(RussiaMoscowNoTurnsOnMKADTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.391635636579785, 67.62455792789649}, {0., 0.},
{37.692547253527685, 67.127684414191762});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.84656, 37.39163), {0., 0.},
MercatorBounds::FromLatLon(55.56661, 37.69254));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -108,7 +115,7 @@ UNIT_TEST(RussiaMoscowNoTurnsOnMKADTurnTest)
integration::TestTurnCount(route, 1);
integration::GetNthTurn(route, 0)
.TestValid()
.TestPoint({37.682761085650043, 67.140620702062705})
.TestPoint({37.68276, 67.14062})
.TestOneOfDirections({TurnDirection::TurnSlightRight, TurnDirection::TurnRight});
integration::TestRouteLength(route, 43233.7);
@ -117,8 +124,10 @@ UNIT_TEST(RussiaMoscowNoTurnsOnMKADTurnTest)
UNIT_TEST(RussiaMoscowTTKKashirskoeShosseOutTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.606320023648998, 67.36682695403141}, {0., 0.},
{37.621220025471168, 67.352441627022912});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.70160, 37.60632), {0., 0.},
MercatorBounds::FromLatLon(55.69349, 37.62122));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -132,8 +141,10 @@ UNIT_TEST(RussiaMoscowTTKKashirskoeShosseOutTurnTest)
UNIT_TEST(RussiaMoscowPankratevskiPerBolshaySuharedskazPloschadTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.635563528539393, 67.491460725721268}, {0., 0.},
{37.637054339197832, 67.491929797067371});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.77177, 37.63556), {0., 0.},
MercatorBounds::FromLatLon(55.77203, 37.63705));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -145,8 +156,10 @@ UNIT_TEST(RussiaMoscowPankratevskiPerBolshaySuharedskazPloschadTurnTest)
UNIT_TEST(RussiaMoscowMKADPutilkovskeShosseTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.394141645624103, 67.63612831787222}, {0., 0.},
{37.391050708989461, 67.632454269643091});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.85305, 37.39414), {0., 0.},
MercatorBounds::FromLatLon(55.85099, 37.39105));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -159,8 +172,10 @@ UNIT_TEST(RussiaMoscowMKADPutilkovskeShosseTurnTest)
UNIT_TEST(RussiaMoscowPetushkovaShodniaReverTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.405917692164508, 67.614731601278493}, {0., 0.},
{37.408550782937482, 67.61160397953185});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.84104, 37.40591), {0., 0.},
MercatorBounds::FromLatLon(55.83929, 37.40855));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -171,8 +186,10 @@ UNIT_TEST(RussiaMoscowPetushkovaShodniaReverTurnTest)
UNIT_TEST(RussiaHugeRoundaboutTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.325810690728495, 67.544175542376436}, {0., 0.},
{37.325360456262153, 67.543013703414516});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.80141, 37.32581), {0., 0.},
MercatorBounds::FromLatLon(55.80075, 37.32536));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -191,8 +208,10 @@ UNIT_TEST(RussiaHugeRoundaboutTurnTest)
UNIT_TEST(BelarusMiskProspNezavisimostiMKADTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {27.658572046123947, 64.302533720228126}, {0., 0.},
{27.670461944729382, 64.307480201489582});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(53.93642, 27.65857), {0., 0.},
MercatorBounds::FromLatLon(53.93933, 27.67046));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -207,7 +226,10 @@ UNIT_TEST(BelarusMiskProspNezavisimostiMKADTurnTest)
UNIT_TEST(RussiaMoscowPetushkovaPetushkovaTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {37.40555, 67.60640}, {0., 0.}, {37.40489, 67.60766});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.83636, 37.40555), {0., 0.},
MercatorBounds::FromLatLon(55.83707, 37.40489));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -223,6 +245,7 @@ UNIT_TEST(RussiaMoscowMKADLeningradkaTest)
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), MercatorBounds::FromLatLon(55.87992, 37.43940),
{0., 0.}, MercatorBounds::FromLatLon(55.87854, 37.44865));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -233,7 +256,10 @@ UNIT_TEST(RussiaMoscowMKADLeningradkaTest)
UNIT_TEST(BelarusMKADShosseinai)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {29.43123, 66.68486}, {0., 0.}, {29.42626, 66.68687});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(55.31541, 29.43123), {0., 0.},
MercatorBounds::FromLatLon(55.31656, 29.42626));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -248,7 +274,10 @@ UNIT_TEST(BelarusMKADShosseinai)
UNIT_TEST(ThailandPhuketNearPrabarameeRoad)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), {98.36937, 7.94330}, {0., 0.}, {98.36785, 7.93247});
integration::GetOsrmComponents(),
MercatorBounds::FromLatLon(7.91797, 98.36937), {0., 0.},
MercatorBounds::FromLatLon(7.90724, 98.36785));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
@ -273,3 +302,49 @@ UNIT_TEST(RussiaMoscowVarshavskoeShosseMKAD)
integration::GetNthTurn(route, 0).TestValid().TestOneOfDirections(
{TurnDirection::TurnSlightRight, TurnDirection::TurnRight});
}
// Test case: a route goes in Moscow from Tverskaya street (towards city center)
// to Mokhovaya street. A turn instruction (turn left) shell be generated.
UNIT_TEST(RussiaMoscowTverskajaOkhotnyRyadTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), MercatorBounds::FromLatLon(55.75765, 37.61355), {0., 0.},
MercatorBounds::FromLatLon(55.75737, 37.61601));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
TEST_EQUAL(result, IRouter::NoError, ());
integration::TestTurnCount(route, 1);
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
}
UNIT_TEST(RussiaMoscowBolshoyKislovskiyPerBolshayaNikitinskayaUlTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), MercatorBounds::FromLatLon(55.75574, 37.60702), {0., 0.},
MercatorBounds::FromLatLon(55.75586, 37.60819));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
TEST_EQUAL(result, IRouter::NoError, ());
integration::TestTurnCount(route, 1);
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnRight);
}
// Test case: a route goes in Moscow along Leningradskiy Prpt (towards city center)
// and makes u-turn. A only one turn instruction (turn left) shell be generated.
UNIT_TEST(RussiaMoscowLeningradskiyPrptToTheCenterUTurnTest)
{
TRouteResult const routeResult = integration::CalculateRoute(
integration::GetOsrmComponents(), MercatorBounds::FromLatLon(55.79231, 37.54951), {0., 0.},
MercatorBounds::FromLatLon(55.79280, 37.55028));
Route const & route = *routeResult.first;
IRouter::ResultCode const result = routeResult.second;
TEST_EQUAL(result, IRouter::NoError, ());
integration::TestTurnCount(route, 2);
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
}

View file

@ -497,7 +497,7 @@ OsrmRouter::ResultCode OsrmRouter::MakeRouteFromCrossesPath(TCheckedPath const &
vector<m2::PointD> mwmPoints;
MakeTurnAnnotation(routingResult, mwmMapping, delegate, mwmPoints, mwmTurnsDir, mwmTimes);
// Connect annotated route.
const uint32_t pSize = static_cast<uint32_t>(Points.size());
auto const pSize = static_cast<uint32_t>(Points.size());
for (auto turn : mwmTurnsDir)
{
if (turn.m_index == 0)
@ -699,51 +699,51 @@ OsrmRouter::ResultCode OsrmRouter::MakeTurnAnnotation(
size_t lastIdx = 0;
#endif
for (auto const & segment : routingResult.unpackedPathSegments)
for (auto const & pathSegments : routingResult.unpackedPathSegments)
{
INTERRUPT_WHEN_CANCELLED(delegate);
// Get all the coordinates for the computed route
size_t const n = segment.size();
for (size_t j = 0; j < n; ++j)
// Get all computed route coordinates.
size_t const numSegments = pathSegments.size();
for (size_t segmentIndex = 0; segmentIndex < numSegments; ++segmentIndex)
{
RawPathData const & path_data = segment[j];
RawPathData const & pathData = pathSegments[segmentIndex];
if (j > 0 && !points.empty())
if (segmentIndex > 0 && !points.empty())
{
turns::TurnItem t;
t.m_index = static_cast<uint32_t>(points.size() - 1);
turns::TurnItem turnItem;
turnItem.m_index = static_cast<uint32_t>(points.size() - 1);
turns::TurnInfo turnInfo(*mapping, segment[j - 1].node, segment[j].node);
turns::GetTurnDirection(*m_pIndex, turnInfo, t);
turns::TurnInfo turnInfo(*mapping, pathSegments[segmentIndex - 1].node, pathSegments[segmentIndex].node);
turns::GetTurnDirection(*m_pIndex, turnInfo, turnItem);
// ETA information.
// Osrm multiples seconds to 10, so we need to divide it back.
double const nodeTimeSeconds = path_data.segmentWeight / 10.0;
double const nodeTimeSeconds = pathData.segmentWeight / 10.0;
#ifdef DEBUG
double distMeters = 0.0;
for (size_t k = lastIdx + 1; k < points.size(); ++k)
distMeters += MercatorBounds::DistanceOnEarth(points[k - 1], points[k]);
LOG(LDEBUG, ("Speed:", 3.6 * distMeters / nodeTimeSeconds, "kmph; Dist:", distMeters, "Time:",
nodeTimeSeconds, "s", lastIdx, "e", points.size(), "source:", t.m_sourceName,
"target:", t.m_targetName));
nodeTimeSeconds, "s", lastIdx, "e", points.size(), "source:", turnItem.m_sourceName,
"target:", turnItem.m_targetName));
lastIdx = points.size();
#endif
estimatedTime += nodeTimeSeconds;
times.push_back(Route::TTimeItem(points.size(), estimatedTime));
// Lane information.
if (t.m_turn != turns::TurnDirection::NoTurn)
if (turnItem.m_turn != turns::TurnDirection::NoTurn)
{
t.m_lanes = turns::GetLanesInfo(segment[j - 1].node,
turnItem.m_lanes = turns::GetLanesInfo(pathSegments[segmentIndex - 1].node,
*mapping, turns::GetLastSegmentPointIndex, *m_pIndex);
turnsDir.push_back(move(t));
turnsDir.push_back(move(turnItem));
}
}
buffer_vector<TSeg, 8> buffer;
mapping->m_segMapping.ForEachFtSeg(path_data.node, MakeBackInsertFunctor(buffer));
mapping->m_segMapping.ForEachFtSeg(pathData.node, MakeBackInsertFunctor(buffer));
auto FindIntersectingSeg = [&buffer] (TSeg const & seg) -> size_t
{
@ -761,15 +761,15 @@ OsrmRouter::ResultCode OsrmRouter::MakeTurnAnnotation(
//Do not put out node geometry (we do not have it)!
size_t startK = 0, endK = buffer.size();
if (j == 0)
if (segmentIndex == 0)
{
if (!segBegin.IsValid())
continue;
startK = FindIntersectingSeg(segBegin);
}
if (j == n - 1)
if (segmentIndex + 1 == numSegments)
{
if (!segEnd.IsValid())
if (!segEnd.IsValid())
continue;
endK = FindIntersectingSeg(segEnd) + 1;
}
@ -785,11 +785,11 @@ OsrmRouter::ResultCode OsrmRouter::MakeTurnAnnotation(
auto startIdx = seg.m_pointStart;
auto endIdx = seg.m_pointEnd;
bool const needTime = (j == 0) || (j == n - 1);
bool const needTime = (segmentIndex == 0) || (segmentIndex == numSegments - 1);
if (j == 0 && k == startK && segBegin.IsValid())
if (segmentIndex == 0 && k == startK && segBegin.IsValid())
startIdx = (seg.m_pointEnd > seg.m_pointStart) ? segBegin.m_pointStart : segBegin.m_pointEnd;
if (j == n - 1 && k == endK - 1 && segEnd.IsValid())
if (segmentIndex == numSegments - 1 && k == endK - 1 && segEnd.IsValid())
endIdx = (seg.m_pointEnd > seg.m_pointStart) ? segEnd.m_pointEnd : segEnd.m_pointStart;
if (seg.m_pointEnd > seg.m_pointStart)
@ -826,8 +826,8 @@ OsrmRouter::ResultCode OsrmRouter::MakeTurnAnnotation(
times.push_back(Route::TTimeItem(points.size() - 1, estimatedTime));
if (routingResult.targetEdge.segment.IsValid())
{
turnsDir.push_back(
turns::TurnItem(static_cast<uint32_t>(points.size() - 1), turns::TurnDirection::ReachedYourDestination));
turnsDir.emplace_back(
turns::TurnItem(static_cast<uint32_t>(points.size()) - 1, turns::TurnDirection::ReachedYourDestination));
}
turns::FixupTurns(points, turnsDir);

View file

@ -17,7 +17,7 @@ using TCountryFileFn = function<string(m2::PointD const &)>;
class Route;
/// Routing engine type.
enum RouterType
enum class RouterType
{
Vehicle = 0, /// For OSRM vehicle routing
Pedestrian /// For A star pedestrian routing
@ -31,7 +31,7 @@ public:
/// Routing possible statuses enumeration.
/// \warning this enum has JNI mirror!
/// \see android/src/com/mapswithme/maps/data/RoutingResultCodesProcessor.java
enum ResultCode
enum ResultCode // TODO(mgsergio) enum class
{
NoError = 0,
Cancelled = 1,

View file

@ -22,6 +22,10 @@ using namespace routing::turns;
namespace
{
double const kFeaturesNearTurnMeters = 3.0;
size_t constexpr kMaxPointsCount = 7;
double constexpr kMinDistMeters = 300.;
size_t constexpr kNotSoCloseMaxPointsCount = 3;
double constexpr kNotSoCloseMinDistMeters = 30.;
typedef vector<double> TGeomTurnCandidate;
@ -49,7 +53,7 @@ struct TurnCandidate
TurnCandidate(double a, NodeID n) : angle(a), node(n) {}
};
typedef vector<TurnCandidate> TTurnCandidates;
using TTurnCandidates = vector<TurnCandidate>;
/*!
* \brief The Point2Geometry class is responsable for looking for all adjacent to junctionPoint
@ -251,8 +255,10 @@ bool KeepTurnByIngoingEdges(m2::PointD const & junctionPoint,
m2::PointD const & outgoingPoint, bool hasMultiTurns,
RoutingMapping const & routingMapping, Index const & index)
{
bool const isGoStraightOrSlightTurn = IsGoStraightOrSlightTurn(IntermediateDirection(
my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPointOneSegment, outgoingPoint))));
double const turnAngle =
my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPointOneSegment, outgoingPoint));
bool const isGoStraightOrSlightTurn = IsGoStraightOrSlightTurn(IntermediateDirection(turnAngle));
// The code below is resposible for cases when there is only one way to leave the junction.
// Such junction has to be kept as a turn when it's not a slight turn and it has ingoing edges
// (one or more);
@ -324,26 +330,25 @@ TurnDirection FindDirectionByAngle(vector<pair<double, TurnDirection>> const & l
* \param segment is a ingoing or outgoing feature segment.
* \param ft is a ingoing or outgoing feature.
* \param junctionPoint is a junction point.
* \param maxPointsCount returned poit could't be more than maxPointsCount poins away from junctionPoint
* \param minDistMeters returned point should be minDistMeters away from junctionPoint if ft is long and consists of short segments
* \param GetPointIndex is a function for getting points by index.
* It defines a direction of following along a feature. So it differs for ingoing and outgoing cases.
* It has following parameters:
* - start is an index of the start point of a feature segment. For example, FtSeg::m_pointStart.
* - end is an index of the end point of a feature segment. For example, FtSeg::m_pointEnd.
* - shift is a number of points which shall be added to end or start index. After that
* the sum reflects an index of a point of a feature segment which will be used for turn calculation.
* the sum reflects an index of a feature segment point which will be used for a turn calculation.
* The sum shall belongs to a range [min(start, end), max(start, end)].
* shift belongs to a range [0, abs(end - start)].
* \return an ingoing or outgoing point for turn calculation.
* \return an ingoing or outgoing point for a turn calculation.
*/
m2::PointD GetPointForTurn(OsrmMappingTypes::FtSeg const & segment, FeatureType const & ft,
m2::PointD const & junctionPoint,
size_t const maxPointsCount,
double const minDistMeters,
size_t (*GetPointIndex)(const size_t start, const size_t end, const size_t shift))
{
// An ingoing and outgoing point could be farther then kMaxPointsCount points from the junctionPoint
size_t const kMaxPointsCount = 7;
// If ft feature is long enough and consist of short segments
// the point for turn generation is taken as the next point the route after kMinDistMeters.
double const kMinDistMeters = 300.;
double curDistanceMeters = 0.;
m2::PointD point = junctionPoint;
m2::PointD nextPoint;
@ -351,16 +356,17 @@ m2::PointD GetPointForTurn(OsrmMappingTypes::FtSeg const & segment, FeatureType
size_t const numSegPoints = abs(segment.m_pointEnd - segment.m_pointStart);
ASSERT_GREATER(numSegPoints, 0, ());
ASSERT_LESS(numSegPoints, ft.GetPointsCount(), ());
size_t const usedFtPntNum = min(kMaxPointsCount, numSegPoints);
size_t const usedFtPntNum = min(maxPointsCount, numSegPoints);
for (size_t i = 1; i <= usedFtPntNum; ++i)
{
nextPoint = ft.GetPoint(GetPointIndex(segment.m_pointStart, segment.m_pointEnd, i));
curDistanceMeters += MercatorBounds::DistanceOnEarth(point, nextPoint);
if (curDistanceMeters > kMinDistMeters)
if (curDistanceMeters > minDistMeters)
return nextPoint;
point = nextPoint;
}
return nextPoint;
}
@ -438,6 +444,16 @@ void GetPossibleTurns(Index const & index, NodeID node, m2::PointD const & ingoi
return t1.angle < t2.angle;
});
}
size_t GetIngoingPointIndex(const size_t start, const size_t end, const size_t i)
{
return end > start ? end - i : end + i;
}
size_t GetOutgoingPointIndex(const size_t start, const size_t end, const size_t i)
{
return end > start ? start + i : start - i;
}
} // namespace
namespace routing
@ -726,20 +742,13 @@ void GetTurnDirection(Index const & index, TurnInfo & turnInfo, TurnItem & turn)
kFeaturesNearTurnMeters, ());
m2::PointD const junctionPoint = ingoingFeature.GetPoint(turnInfo.m_ingoingSegment.m_pointEnd);
m2::PointD const ingoingPoint =
GetPointForTurn(turnInfo.m_ingoingSegment, ingoingFeature, junctionPoint,
[](const size_t start, const size_t end, const size_t i)
{
return end > start ? end - i : end + i;
});
m2::PointD const outgoingPoint =
GetPointForTurn(turnInfo.m_outgoingSegment, outgoingFeature, junctionPoint,
[](const size_t start, const size_t end, const size_t i)
{
return end > start ? start + i : start - i;
});
double const a = my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint));
TurnDirection const intermediateDirection = IntermediateDirection(a);
m2::PointD const ingoingPoint = GetPointForTurn(turnInfo.m_ingoingSegment, ingoingFeature,
junctionPoint, kMaxPointsCount, kMinDistMeters, GetIngoingPointIndex);
m2::PointD const outgoingPoint = GetPointForTurn(turnInfo.m_outgoingSegment, outgoingFeature,
junctionPoint, kMaxPointsCount, kMinDistMeters, GetOutgoingPointIndex);
double const turnAngle = my::RadToDeg(PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint));
TurnDirection const intermediateDirection = IntermediateDirection(turnAngle);
// Getting all the information about ingoing and outgoing edges.
turnInfo.m_isIngoingEdgeRoundabout = ftypes::IsRoundAboutChecker::Instance()(ingoingFeature);
@ -767,10 +776,10 @@ void GetTurnDirection(Index const & index, TurnInfo & turnInfo, TurnItem & turn)
GetPossibleTurns(index, turnInfo.m_ingoingNodeID, ingoingPointOneSegment, junctionPoint,
turnInfo.m_routeMapping, nodes);
size_t const nodesSize = nodes.size();
bool const hasMultiTurns = (nodesSize >= 2);
size_t const numNodes = nodes.size();
bool const hasMultiTurns = numNodes > 1;
if (nodesSize == 0)
if (numNodes == 0)
return;
if (!hasMultiTurns)
@ -780,9 +789,9 @@ void GetTurnDirection(Index const & index, TurnInfo & turnInfo, TurnItem & turn)
else
{
if (nodes.front().node == turnInfo.m_outgoingNodeID)
turn.m_turn = LeftmostDirection(a);
turn.m_turn = LeftmostDirection(turnAngle);
else if (nodes.back().node == turnInfo.m_outgoingNodeID)
turn.m_turn = RightmostDirection(a);
turn.m_turn = RightmostDirection(turnAngle);
else
turn.m_turn = intermediateDirection;
}
@ -802,7 +811,10 @@ void GetTurnDirection(Index const & index, TurnInfo & turnInfo, TurnItem & turn)
return;
}
if (!KeepTurnByIngoingEdges(junctionPoint, ingoingPointOneSegment, outgoingPoint, hasMultiTurns,
auto const notSoCloseToTheTurnPoint = GetPointForTurn(turnInfo.m_ingoingSegment, ingoingFeature, junctionPoint,
kNotSoCloseMaxPointsCount, kNotSoCloseMinDistMeters, GetIngoingPointIndex);
if (!KeepTurnByIngoingEdges(junctionPoint, notSoCloseToTheTurnPoint, outgoingPoint, hasMultiTurns,
turnInfo.m_routeMapping, index))
{
turn.m_turn = TurnDirection::NoTurn;

View file

@ -26,7 +26,7 @@ namespace turns
/*!
* \brief Returns a segment index by STL-like range [s, e) of segments indices for the passed node.
*/
typedef function<size_t(pair<size_t, size_t>)> TGetIndexFunction;
using TGetIndexFunction = function<size_t(pair<size_t, size_t>)>;
/*!
* \brief The TurnInfo struct is an accumulator for all junction information.
@ -116,6 +116,7 @@ bool CheckRoundaboutExit(bool isIngoingEdgeRoundabout, bool isOutgoingEdgeRounda
*/
TurnDirection GetRoundaboutDirection(bool isIngoingEdgeRoundabout, bool isOutgoingEdgeRoundabout,
bool isMultiTurnJunction, bool keepTurnByHighwayClass);
/*!
* \brief GetTurnDirection makes a primary decision about turns on the route.
* \param turnInfo is used for cashing some information while turn calculation.