Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
230
tools/openlr/helpers.cpp
Normal file
230
tools/openlr/helpers.cpp
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
#include "openlr/helpers.hpp"
|
||||
|
||||
#include "openlr/road_info_getter.hpp"
|
||||
|
||||
#include "routing/features_road_graph.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "base/stl_iterator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace openlr;
|
||||
using namespace std;
|
||||
|
||||
openlr::FunctionalRoadClass HighwayClassToFunctionalRoadClass(ftypes::HighwayClass const & hwClass)
|
||||
{
|
||||
switch (hwClass)
|
||||
{
|
||||
case ftypes::HighwayClass::Motorway: return openlr::FunctionalRoadClass::FRC0;
|
||||
case ftypes::HighwayClass::Trunk: return openlr::FunctionalRoadClass::FRC0;
|
||||
case ftypes::HighwayClass::Primary: return openlr::FunctionalRoadClass::FRC1;
|
||||
case ftypes::HighwayClass::Secondary: return openlr::FunctionalRoadClass::FRC2;
|
||||
case ftypes::HighwayClass::Tertiary: return openlr::FunctionalRoadClass::FRC3;
|
||||
case ftypes::HighwayClass::LivingStreet: return openlr::FunctionalRoadClass::FRC4;
|
||||
case ftypes::HighwayClass::Service: return openlr::FunctionalRoadClass::FRC5;
|
||||
case ftypes::HighwayClass::ServiceMinor: return openlr::FunctionalRoadClass::FRC6;
|
||||
default: return openlr::FunctionalRoadClass::FRC7;
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns nullopt if |e| doesn't conform to |functionalRoadClass| and score otherwise.
|
||||
optional<Score> GetFrcScore(Graph::Edge const & e, FunctionalRoadClass functionalRoadClass, RoadInfoGetter & infoGetter)
|
||||
{
|
||||
CHECK(!e.IsFake(), ());
|
||||
Score constexpr kMaxScoreForFrc = 25;
|
||||
|
||||
if (functionalRoadClass == FunctionalRoadClass::NotAValue)
|
||||
return nullopt;
|
||||
|
||||
auto const hwClass = infoGetter.Get(e.GetFeatureId()).m_hwClass;
|
||||
|
||||
using ftypes::HighwayClass;
|
||||
|
||||
switch (functionalRoadClass)
|
||||
{
|
||||
case FunctionalRoadClass::FRC0:
|
||||
return hwClass == HighwayClass::Motorway || hwClass == HighwayClass::Trunk ? optional<Score>(kMaxScoreForFrc) : nullopt;
|
||||
|
||||
case FunctionalRoadClass::FRC1:
|
||||
return (hwClass == HighwayClass::Motorway || hwClass == HighwayClass::Trunk || hwClass == HighwayClass::Primary) ? optional<Score>(kMaxScoreForFrc)
|
||||
: nullopt;
|
||||
|
||||
case FunctionalRoadClass::FRC2:
|
||||
case FunctionalRoadClass::FRC3:
|
||||
if (hwClass == HighwayClass::Secondary || hwClass == HighwayClass::Tertiary)
|
||||
return optional<Score>(kMaxScoreForFrc);
|
||||
|
||||
return hwClass == HighwayClass::Primary || hwClass == HighwayClass::LivingStreet ? optional<Score>(0) : nullopt;
|
||||
|
||||
case FunctionalRoadClass::FRC4:
|
||||
if (hwClass == HighwayClass::LivingStreet || hwClass == HighwayClass::Service)
|
||||
return optional<Score>(kMaxScoreForFrc);
|
||||
|
||||
return (hwClass == HighwayClass::Tertiary || hwClass == HighwayClass::Secondary) ? optional<Score>(0) : nullopt;
|
||||
|
||||
case FunctionalRoadClass::FRC5:
|
||||
case FunctionalRoadClass::FRC6:
|
||||
case FunctionalRoadClass::FRC7:
|
||||
return (hwClass == HighwayClass::LivingStreet || hwClass == HighwayClass::Service ||
|
||||
hwClass == HighwayClass::ServiceMinor)
|
||||
? optional<Score>(kMaxScoreForFrc)
|
||||
: nullopt;
|
||||
|
||||
case FunctionalRoadClass::NotAValue: UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace openlr
|
||||
{
|
||||
// BearingPointsSelector ---------------------------------------------------------------------------
|
||||
BearingPointsSelector::BearingPointsSelector(uint32_t bearDistM, bool isLastPoint)
|
||||
: m_bearDistM(bearDistM)
|
||||
, m_isLastPoint(isLastPoint)
|
||||
{}
|
||||
|
||||
m2::PointD BearingPointsSelector::GetStartPoint(Graph::Edge const & e) const
|
||||
{
|
||||
return m_isLastPoint ? e.GetEndPoint() : e.GetStartPoint();
|
||||
}
|
||||
|
||||
m2::PointD BearingPointsSelector::GetEndPoint(Graph::Edge const & e, double distanceM) const
|
||||
{
|
||||
if (distanceM < m_bearDistM && m_bearDistM <= distanceM + EdgeLength(e))
|
||||
{
|
||||
auto const edgeLen = EdgeLength(e);
|
||||
auto const edgeBearDist = min(m_bearDistM - distanceM, edgeLen);
|
||||
CHECK_LESS_OR_EQUAL(edgeBearDist, edgeLen, ());
|
||||
return m_isLastPoint ? PointAtSegmentM(e.GetEndPoint(), e.GetStartPoint(), edgeBearDist)
|
||||
: PointAtSegmentM(e.GetStartPoint(), e.GetEndPoint(), edgeBearDist);
|
||||
}
|
||||
return m_isLastPoint ? e.GetStartPoint() : e.GetEndPoint();
|
||||
}
|
||||
|
||||
bool PointsAreClose(m2::PointD const & p1, m2::PointD const & p2)
|
||||
{
|
||||
double const kMwmRoadCrossingRadiusMeters = routing::GetRoadCrossingRadiusMeters();
|
||||
return mercator::DistanceOnEarth(p1, p2) < kMwmRoadCrossingRadiusMeters;
|
||||
}
|
||||
|
||||
double EdgeLength(Graph::Edge const & e)
|
||||
{
|
||||
return mercator::DistanceOnEarth(e.GetStartPoint(), e.GetEndPoint());
|
||||
}
|
||||
|
||||
bool EdgesAreAlmostEqual(Graph::Edge const & e1, Graph::Edge const & e2)
|
||||
{
|
||||
// TODO(mgsergio): Do I need to check fields other than points?
|
||||
return PointsAreClose(e1.GetStartPoint(), e2.GetStartPoint()) && PointsAreClose(e1.GetEndPoint(), e2.GetEndPoint());
|
||||
}
|
||||
|
||||
string LogAs2GisPath(Graph::EdgeVector const & path)
|
||||
{
|
||||
CHECK(!path.empty(), ("Paths should not be empty"));
|
||||
|
||||
ostringstream ost;
|
||||
ost << "https://2gis.ru/moscow?queryState=";
|
||||
|
||||
auto ll = mercator::ToLatLon(path.front().GetStartPoint());
|
||||
ost << "center%2F" << ll.m_lon << "%2C" << ll.m_lat << "%2F";
|
||||
ost << "zoom%2F" << 17 << "%2F";
|
||||
ost << "ruler%2Fpoints%2F";
|
||||
for (auto const & e : path)
|
||||
{
|
||||
ll = mercator::ToLatLon(e.GetStartPoint());
|
||||
ost << ll.m_lon << "%20" << ll.m_lat << "%2C";
|
||||
}
|
||||
ll = mercator::ToLatLon(path.back().GetEndPoint());
|
||||
ost << ll.m_lon << "%20" << ll.m_lat;
|
||||
|
||||
return ost.str();
|
||||
}
|
||||
|
||||
string LogAs2GisPath(Graph::Edge const & e)
|
||||
{
|
||||
return LogAs2GisPath(Graph::EdgeVector({e}));
|
||||
}
|
||||
|
||||
bool PassesRestriction(Graph::Edge const & e, FunctionalRoadClass restriction, FormOfWay formOfWay, int frcThreshold,
|
||||
RoadInfoGetter & infoGetter)
|
||||
{
|
||||
if (e.IsFake() || restriction == FunctionalRoadClass::NotAValue)
|
||||
return true;
|
||||
|
||||
auto const frc = HighwayClassToFunctionalRoadClass(infoGetter.Get(e.GetFeatureId()).m_hwClass);
|
||||
return static_cast<int>(frc) <= static_cast<int>(restriction) + frcThreshold;
|
||||
}
|
||||
|
||||
bool PassesRestrictionV3(Graph::Edge const & e, FunctionalRoadClass functionalRoadClass, FormOfWay formOfWay,
|
||||
RoadInfoGetter & infoGetter, Score & score)
|
||||
{
|
||||
CHECK(!e.IsFake(), ("Edges should not be fake:", e));
|
||||
auto const frcScore = GetFrcScore(e, functionalRoadClass, infoGetter);
|
||||
if (!frcScore)
|
||||
return false;
|
||||
|
||||
score = *frcScore;
|
||||
Score constexpr kScoreForFormOfWay = 25;
|
||||
if (formOfWay == FormOfWay::Roundabout && infoGetter.Get(e.GetFeatureId()).m_isRoundabout)
|
||||
score += kScoreForFormOfWay;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConformLfrcnp(Graph::Edge const & e, FunctionalRoadClass lowestFrcToNextPoint, int frcThreshold,
|
||||
RoadInfoGetter & infoGetter)
|
||||
{
|
||||
if (e.IsFake() || lowestFrcToNextPoint == FunctionalRoadClass::NotAValue)
|
||||
return true;
|
||||
|
||||
auto const frc = HighwayClassToFunctionalRoadClass(infoGetter.Get(e.GetFeatureId()).m_hwClass);
|
||||
return static_cast<int>(frc) <= static_cast<int>(lowestFrcToNextPoint) + frcThreshold;
|
||||
}
|
||||
|
||||
bool ConformLfrcnpV3(Graph::Edge const & e, FunctionalRoadClass lowestFrcToNextPoint, RoadInfoGetter & infoGetter)
|
||||
{
|
||||
return GetFrcScore(e, lowestFrcToNextPoint, infoGetter).has_value();
|
||||
}
|
||||
|
||||
size_t IntersectionLen(Graph::EdgeVector a, Graph::EdgeVector b)
|
||||
{
|
||||
sort(a.begin(), a.end());
|
||||
sort(b.begin(), b.end());
|
||||
return set_intersection(a.begin(), a.end(), b.begin(), b.end(), CounterIterator()).GetCount();
|
||||
}
|
||||
|
||||
bool SuffixEqualsPrefix(Graph::EdgeVector const & a, Graph::EdgeVector const & b, size_t len)
|
||||
{
|
||||
CHECK_LESS_OR_EQUAL(len, a.size(), ());
|
||||
CHECK_LESS_OR_EQUAL(len, b.size(), ());
|
||||
return equal(a.end() - len, a.end(), b.begin());
|
||||
}
|
||||
|
||||
// Returns a length of the longest suffix of |a| that matches any prefix of |b|.
|
||||
// Neither |a| nor |b| can contain several repetitions of any edge.
|
||||
// Returns -1 if |a| intersection |b| is not equal to some suffix of |a| and some prefix of |b|.
|
||||
int32_t PathOverlappingLen(Graph::EdgeVector const & a, Graph::EdgeVector const & b)
|
||||
{
|
||||
auto const len = IntersectionLen(a, b);
|
||||
if (SuffixEqualsPrefix(a, b, len))
|
||||
return base::checked_cast<int32_t>(len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
m2::PointD PointAtSegmentM(m2::PointD const & p1, m2::PointD const & p2, double const distanceM)
|
||||
{
|
||||
auto const v = p2 - p1;
|
||||
auto const l = v.Length();
|
||||
auto const L = mercator::DistanceOnEarth(p1, p2);
|
||||
auto const delta = distanceM * l / L;
|
||||
return PointAtSegment(p1, p2, delta);
|
||||
}
|
||||
} // namespace openlr
|
||||
Loading…
Add table
Add a link
Reference in a new issue