236 lines
7 KiB
C++
236 lines
7 KiB
C++
|
|
#include "routing/turns.hpp"
|
||
|
|
|
||
|
|
#include "geometry/angles.hpp"
|
||
|
|
|
||
|
|
#include "platform/country_file.hpp"
|
||
|
|
|
||
|
|
#include "base/internal/message.hpp"
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <array>
|
||
|
|
#include <sstream>
|
||
|
|
#include <string>
|
||
|
|
#include <utility>
|
||
|
|
|
||
|
|
namespace routing
|
||
|
|
{
|
||
|
|
using namespace routing::turns;
|
||
|
|
using namespace std;
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
array<pair<CarDirection, char const *>, static_cast<size_t>(CarDirection::Count)> const g_turnNames = {
|
||
|
|
{{CarDirection::None, "None"},
|
||
|
|
{CarDirection::GoStraight, "GoStraight"},
|
||
|
|
{CarDirection::TurnRight, "TurnRight"},
|
||
|
|
{CarDirection::TurnSharpRight, "TurnSharpRight"},
|
||
|
|
{CarDirection::TurnSlightRight, "TurnSlightRight"},
|
||
|
|
{CarDirection::TurnLeft, "TurnLeft"},
|
||
|
|
{CarDirection::TurnSharpLeft, "TurnSharpLeft"},
|
||
|
|
{CarDirection::TurnSlightLeft, "TurnSlightLeft"},
|
||
|
|
{CarDirection::UTurnLeft, "UTurnLeft"},
|
||
|
|
{CarDirection::UTurnRight, "UTurnRight"},
|
||
|
|
{CarDirection::EnterRoundAbout, "EnterRoundAbout"},
|
||
|
|
{CarDirection::LeaveRoundAbout, "LeaveRoundAbout"},
|
||
|
|
{CarDirection::StayOnRoundAbout, "StayOnRoundAbout"},
|
||
|
|
{CarDirection::StartAtEndOfStreet, "StartAtEndOfStreet"},
|
||
|
|
{CarDirection::ReachedYourDestination, "ReachedYourDestination"},
|
||
|
|
{CarDirection::ExitHighwayToLeft, "ExitHighwayToLeft"},
|
||
|
|
{CarDirection::ExitHighwayToRight, "ExitHighwayToRight"}}};
|
||
|
|
static_assert(g_turnNames.size() == static_cast<size_t>(CarDirection::Count), "Check the size of g_turnNames");
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
// SegmentRange -----------------------------------------------------------------------------------
|
||
|
|
SegmentRange::SegmentRange(FeatureID const & featureId, uint32_t startSegId, uint32_t endSegId, bool forward,
|
||
|
|
m2::PointD const & start, m2::PointD const & end)
|
||
|
|
: m_featureId(featureId)
|
||
|
|
, m_startSegId(startSegId)
|
||
|
|
, m_endSegId(endSegId)
|
||
|
|
, m_forward(forward)
|
||
|
|
, m_start(start)
|
||
|
|
, m_end(end)
|
||
|
|
{
|
||
|
|
if (m_startSegId != m_endSegId)
|
||
|
|
CHECK_EQUAL(m_forward, m_startSegId < m_endSegId, (*this));
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::operator==(SegmentRange const & rhs) const
|
||
|
|
{
|
||
|
|
return m_featureId == rhs.m_featureId && m_startSegId == rhs.m_startSegId && m_endSegId == rhs.m_endSegId &&
|
||
|
|
m_forward == rhs.m_forward && m_start == rhs.m_start && m_end == rhs.m_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::operator<(SegmentRange const & rhs) const
|
||
|
|
{
|
||
|
|
if (m_featureId != rhs.m_featureId)
|
||
|
|
return m_featureId < rhs.m_featureId;
|
||
|
|
|
||
|
|
if (m_startSegId != rhs.m_startSegId)
|
||
|
|
return m_startSegId < rhs.m_startSegId;
|
||
|
|
|
||
|
|
if (m_endSegId != rhs.m_endSegId)
|
||
|
|
return m_endSegId < rhs.m_endSegId;
|
||
|
|
|
||
|
|
if (m_forward != rhs.m_forward)
|
||
|
|
return m_forward < rhs.m_forward;
|
||
|
|
|
||
|
|
if (m_start != rhs.m_start)
|
||
|
|
return m_start < rhs.m_start;
|
||
|
|
|
||
|
|
return m_end < rhs.m_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
void SegmentRange::Clear()
|
||
|
|
{
|
||
|
|
m_featureId = FeatureID();
|
||
|
|
m_startSegId = 0;
|
||
|
|
m_endSegId = 0;
|
||
|
|
m_forward = true;
|
||
|
|
m_start = m2::PointD::Zero();
|
||
|
|
m_end = m2::PointD::Zero();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::IsEmpty() const
|
||
|
|
{
|
||
|
|
return !m_featureId.IsValid() && m_startSegId == 0 && m_endSegId == 0 && m_forward && m_start == m2::PointD::Zero() &&
|
||
|
|
m_end == m2::PointD::Zero();
|
||
|
|
}
|
||
|
|
|
||
|
|
FeatureID const & SegmentRange::GetFeature() const
|
||
|
|
{
|
||
|
|
return m_featureId;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::IsCorrect() const
|
||
|
|
{
|
||
|
|
return (m_forward && m_startSegId <= m_endSegId) || (!m_forward && m_endSegId <= m_startSegId);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::GetFirstSegment(NumMwmIds const & numMwmIds, Segment & segment) const
|
||
|
|
{
|
||
|
|
return GetSegmentBySegId(m_startSegId, numMwmIds, segment);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::GetLastSegment(NumMwmIds const & numMwmIds, Segment & segment) const
|
||
|
|
{
|
||
|
|
return GetSegmentBySegId(m_endSegId, numMwmIds, segment);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SegmentRange::GetSegmentBySegId(uint32_t segId, NumMwmIds const & numMwmIds, Segment & segment) const
|
||
|
|
{
|
||
|
|
if (!m_featureId.IsValid())
|
||
|
|
return false;
|
||
|
|
|
||
|
|
segment =
|
||
|
|
Segment(numMwmIds.GetId(platform::CountryFile(m_featureId.GetMwmName())), m_featureId.m_index, segId, m_forward);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
string DebugPrint(SegmentRange const & segmentRange)
|
||
|
|
{
|
||
|
|
stringstream out;
|
||
|
|
out << "SegmentRange "
|
||
|
|
<< "{ m_featureId = " << DebugPrint(segmentRange.m_featureId) << ", m_startSegId = " << segmentRange.m_startSegId
|
||
|
|
<< ", m_endSegId = " << segmentRange.m_endSegId << ", m_forward = " << segmentRange.m_forward
|
||
|
|
<< ", m_start = " << DebugPrint(segmentRange.m_start) << ", m_end = " << DebugPrint(segmentRange.m_end) << " }";
|
||
|
|
return out.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
namespace turns
|
||
|
|
{
|
||
|
|
string DebugPrint(TurnItem const & turnItem)
|
||
|
|
{
|
||
|
|
stringstream out;
|
||
|
|
out << "TurnItem "
|
||
|
|
<< "{ m_index = " << turnItem.m_index << ", m_turn = " << DebugPrint(turnItem.m_turn)
|
||
|
|
<< ", m_lanes = " << ::DebugPrint(turnItem.m_lanes) << ", m_exitNum = " << turnItem.m_exitNum
|
||
|
|
<< ", m_pedestrianDir = " << DebugPrint(turnItem.m_pedestrianTurn) << " }";
|
||
|
|
return out.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
string DebugPrint(TurnItemDist const & turnItemDist)
|
||
|
|
{
|
||
|
|
stringstream out;
|
||
|
|
out << "TurnItemDist "
|
||
|
|
<< "{ m_turnItem = " << DebugPrint(turnItemDist.m_turnItem) << ", m_distMeters = " << turnItemDist.m_distMeters
|
||
|
|
<< " }";
|
||
|
|
return out.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
string GetTurnString(CarDirection turn)
|
||
|
|
{
|
||
|
|
for (auto const & p : g_turnNames)
|
||
|
|
if (p.first == turn)
|
||
|
|
return p.second;
|
||
|
|
|
||
|
|
ASSERT(false, (static_cast<int>(turn)));
|
||
|
|
return "unknown CarDirection";
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsLeftTurn(CarDirection t)
|
||
|
|
{
|
||
|
|
return (t >= CarDirection::TurnLeft && t <= CarDirection::TurnSlightLeft);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsRightTurn(CarDirection t)
|
||
|
|
{
|
||
|
|
return (t >= CarDirection::TurnRight && t <= CarDirection::TurnSlightRight);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsLeftOrRightTurn(CarDirection t)
|
||
|
|
{
|
||
|
|
return IsLeftTurn(t) || IsRightTurn(t);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsTurnMadeFromLeft(CarDirection t)
|
||
|
|
{
|
||
|
|
return IsLeftTurn(t) || t == CarDirection::UTurnLeft || t == CarDirection::ExitHighwayToLeft;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsTurnMadeFromRight(CarDirection t)
|
||
|
|
{
|
||
|
|
return IsRightTurn(t) || t == CarDirection::UTurnRight || t == CarDirection::ExitHighwayToRight;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsStayOnRoad(CarDirection t)
|
||
|
|
{
|
||
|
|
return (t == CarDirection::GoStraight || t == CarDirection::StayOnRoundAbout);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool IsGoStraightOrSlightTurn(CarDirection t)
|
||
|
|
{
|
||
|
|
return (t == CarDirection::GoStraight || t == CarDirection::TurnSlightLeft || t == CarDirection::TurnSlightRight);
|
||
|
|
}
|
||
|
|
|
||
|
|
string DebugPrint(CarDirection const turn)
|
||
|
|
{
|
||
|
|
return GetTurnString(turn);
|
||
|
|
}
|
||
|
|
|
||
|
|
string DebugPrint(PedestrianDirection const l)
|
||
|
|
{
|
||
|
|
switch (l)
|
||
|
|
{
|
||
|
|
case PedestrianDirection::None: return "None";
|
||
|
|
case PedestrianDirection::GoStraight: return "GoStraight";
|
||
|
|
case PedestrianDirection::TurnRight: return "TurnRight";
|
||
|
|
case PedestrianDirection::TurnLeft: return "TurnLeft";
|
||
|
|
case PedestrianDirection::ReachedYourDestination: return "ReachedYourDestination";
|
||
|
|
case PedestrianDirection::Count:
|
||
|
|
// PedestrianDirection::Count should be never used in the code, print it as unknown value
|
||
|
|
// (it is added to cases list to suppress compiler warning).
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
ASSERT(false, (static_cast<int>(l)));
|
||
|
|
return "unknown PedestrianDirection";
|
||
|
|
}
|
||
|
|
|
||
|
|
double PiMinusTwoVectorsAngle(m2::PointD const & junctionPoint, m2::PointD const & ingoingPoint,
|
||
|
|
m2::PointD const & outgoingPoint)
|
||
|
|
{
|
||
|
|
return math::pi - ang::TwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint);
|
||
|
|
}
|
||
|
|
} // namespace turns
|
||
|
|
} // namespace routing
|