Merge pull request #352 from gardster/cross_routing_speedup

Tree index for a mwm cross point finding.
This commit is contained in:
Viktor Govako 2015-10-30 18:02:19 +03:00
commit df79233a66
18 changed files with 398 additions and 288 deletions

View file

@ -91,7 +91,7 @@ void FindCrossNodes(osrm::NodeDataVectorT const & nodeData, gen::OsmID2FeatureID
});
});
for (WritedNodeID nodeId = 0; nodeId < nodeData.size(); ++nodeId)
for (TWrittenNodeId nodeId = 0; nodeId < nodeData.size(); ++nodeId)
{
auto const & data = nodeData[nodeId];
@ -128,9 +128,9 @@ void FindCrossNodes(osrm::NodeDataVectorT const & nodeData, gen::OsmID2FeatureID
continue;
}
// for old format compatibility
intersection = m2::PointD(MercatorBounds::XToLon(intersection.x), MercatorBounds::YToLat(intersection.y));
ms::LatLon wgsIntersection = MercatorBounds::ToLatLon(intersection);
if (!outStart && outEnd)
crossContext.AddIngoingNode(nodeId, intersection);
crossContext.AddIngoingNode(nodeId, wgsIntersection);
else if (outStart && !outEnd)
{
string mwmName;
@ -147,7 +147,7 @@ void FindCrossNodes(osrm::NodeDataVectorT const & nodeData, gen::OsmID2FeatureID
});
});
if (!mwmName.empty())
crossContext.AddOutgoingNode(nodeId, mwmName, intersection);
crossContext.AddOutgoingNode(nodeId, mwmName, wgsIntersection);
else
LOG(LINFO, ("Unknowing outgoing edge", endSeg.lat2, endSeg.lon2, startSeg.lat1, startSeg.lon1));
}
@ -173,10 +173,10 @@ void CalculateCrossAdjacency(string const & mwmRoutingPath, routing::CrossRoutin
// Fill sources and targets with start node task for ingoing (true) and target node task
// (false) for outgoing nodes
for (auto i = in.first; i != in.second; ++i)
sources.emplace_back(i->m_nodeId, true /* isStartNode */, mwmRoutingPath);
sources.emplace_back(i->m_nodeId, true /* isStartNode */, Index::MwmId());
for (auto i = out.first; i != out.second; ++i)
targets.emplace_back(i->m_nodeId, false /* isStartNode */, mwmRoutingPath);
targets.emplace_back(i->m_nodeId, false /* isStartNode */, Index::MwmId());
LOG(LINFO, ("Cross section has", sources.size(), "incomes and ", targets.size(), "outcomes."));
vector<EdgeWeight> costs;
@ -259,7 +259,7 @@ void BuildRoutingIndex(string const & baseDir, string const & countryName, strin
uint32_t found = 0, all = 0, multiple = 0, equal = 0, moreThan1Seg = 0, stored = 0;
for (WritedNodeID nodeId = 0; nodeId < nodeData.size(); ++nodeId)
for (TWrittenNodeId nodeId = 0; nodeId < nodeData.size(); ++nodeId)
{
auto const & data = nodeData[nodeId];

View file

@ -13,4 +13,13 @@ string DebugPrint(LatLon const & t)
return out.str();
}
bool LatLon::operator == (ms::LatLon const & p) const
{
return lat == p.lat && lon == p.lon;
}
bool LatLon::EqualDxDy(LatLon const & p, double eps) const
{
return (my::AlmostEqualAbs(lat, p.lat, eps) && my::AlmostEqualAbs(lon, p.lon, eps));
}
} // namespace ms

View file

@ -1,5 +1,7 @@
#pragma once
#include "base/math.hpp"
#include "std/string.hpp"
namespace ms
@ -9,8 +11,23 @@ namespace ms
class LatLon
{
public:
LatLon(double lat, double lon) : lat(lat), lon(lon) {}
double lat, lon;
LatLon(double lat, double lon) : lat(lat), lon(lon) {}
static LatLon Zero() { return LatLon(0., 0.); }
bool operator == (ms::LatLon const & p) const;
bool EqualDxDy(LatLon const & p, double eps) const;
struct Hash
{
size_t operator()(ms::LatLon const & p) const
{
return my::Hash(p.lat, p.lon);
}
};
};
string DebugPrint(LatLon const & t);

View file

@ -6,24 +6,30 @@
namespace
{
inline bool IsValidEdgeWeight(EdgeWeight const & w) { return w != INVALID_EDGE_WEIGHT; }
double constexpr kMwmCrossingNodeEqualityRadiusMeters = 5.0;
}
namespace routing
{
IRouter::ResultCode CrossMwmGraph::SetStartNode(CrossNode const & startNode)
{
ASSERT(!startNode.mwmName.empty(), ());
ASSERT(startNode.mwmId.IsAlive(), ());
// TODO (ldragunov) make cancellation if necessary
TRoutingMappingPtr startMapping = m_indexManager.GetMappingByName(startNode.mwmName);
TRoutingMappingPtr startMapping = m_indexManager.GetMappingById(startNode.mwmId);
if (!startMapping->IsValid())
return IRouter::ResultCode::StartPointNotFound;
MappingGuard startMappingGuard(startMapping);
UNUSED_VALUE(startMappingGuard);
startMapping->LoadCrossContext();
// Load source data.
auto const mwmOutsIter = startMapping->m_crossContext.GetOutgoingIterators();
size_t const outSize = distance(mwmOutsIter.first, mwmOutsIter.second);
vector<OutgoingCrossNode> outgoingNodes;
startMapping->m_crossContext.ForEachOutgoingNode([&outgoingNodes](OutgoingCrossNode const & node)
{
outgoingNodes.push_back(node);
});
size_t const outSize = outgoingNodes.size();
// Can't find the route if there are no routes outside source map.
if (!outSize)
return IRouter::RouteNotFound;
@ -31,10 +37,13 @@ IRouter::ResultCode CrossMwmGraph::SetStartNode(CrossNode const & startNode)
// Generate routing task from one source to several targets.
TRoutingNodes sources(1), targets;
targets.reserve(outSize);
for (auto j = mwmOutsIter.first; j < mwmOutsIter.second; ++j)
targets.emplace_back(j->m_nodeId, false /* isStartNode */, startNode.mwmName);
for (auto const & node : outgoingNodes)
{
targets.emplace_back(node.m_nodeId, false /* isStartNode */, startNode.mwmId);
targets.back().segmentPoint = MercatorBounds::FromLatLon(node.m_point);
}
sources[0] = FeatureGraphNode(startNode.node, startNode.reverseNode, true /* isStartNode */,
startNode.mwmName);
startNode.mwmId);
vector<EdgeWeight> weights;
FindWeightsMatrix(sources, targets, startMapping->m_dataFacade, weights);
@ -45,7 +54,7 @@ IRouter::ResultCode CrossMwmGraph::SetStartNode(CrossNode const & startNode)
{
if (IsValidEdgeWeight(weights[i]))
{
BorderCross nextNode = FindNextMwmNode(*(mwmOutsIter.first + i), startMapping);
BorderCross nextNode = FindNextMwmNode(outgoingNodes[i], startMapping);
if (nextNode.toNode.IsValid())
dummyEdges.emplace_back(nextNode, weights[i]);
}
@ -58,8 +67,7 @@ IRouter::ResultCode CrossMwmGraph::SetStartNode(CrossNode const & startNode)
void CrossMwmGraph::AddVirtualEdge(IngoingCrossNode const & node, CrossNode const & finalNode,
EdgeWeight weight)
{
CrossNode start(node.m_nodeId, finalNode.mwmName,
MercatorBounds::FromLatLon(node.m_point.y, node.m_point.x));
CrossNode start(node.m_nodeId, finalNode.mwmId, node.m_point);
vector<CrossWeightedEdge> dummyEdges;
dummyEdges.emplace_back(BorderCross(finalNode, finalNode), weight);
m_virtualEdges.insert(make_pair(start, dummyEdges));
@ -67,37 +75,44 @@ void CrossMwmGraph::AddVirtualEdge(IngoingCrossNode const & node, CrossNode cons
IRouter::ResultCode CrossMwmGraph::SetFinalNode(CrossNode const & finalNode)
{
ASSERT(finalNode.mwmName.length(), ());
TRoutingMappingPtr finalMapping = m_indexManager.GetMappingByName(finalNode.mwmName);
ASSERT(finalNode.mwmId.IsAlive(), ());
TRoutingMappingPtr finalMapping = m_indexManager.GetMappingById(finalNode.mwmId);
if (!finalMapping->IsValid())
return IRouter::ResultCode::EndPointNotFound;
MappingGuard finalMappingGuard(finalMapping);
UNUSED_VALUE(finalMappingGuard);
finalMapping->LoadCrossContext();
// Load source data.
auto const mwmIngoingIter = finalMapping->m_crossContext.GetIngoingIterators();
// Generate routing task from one source to several targets.
TRoutingNodes sources, targets(1);
size_t const ingoingSize = distance(mwmIngoingIter.first, mwmIngoingIter.second);
sources.reserve(ingoingSize);
vector<IngoingCrossNode> ingoingNodes;
finalMapping->m_crossContext.ForEachIngoingNode([&ingoingNodes](IngoingCrossNode const & node)
{
ingoingNodes.push_back(node);
});
size_t const ingoingSize = ingoingNodes.size();
// If there is no routes inside target map.
if (!ingoingSize)
if (ingoingSize == 0)
return IRouter::RouteNotFound;
for (auto j = mwmIngoingIter.first; j != mwmIngoingIter.second; ++j)
// Generate routing task from one source to several targets.
TRoutingNodes sources, targets(1);
sources.reserve(ingoingSize);
for (auto const & node : ingoingNodes)
{
// Case with a target node at the income mwm node.
if (j->m_nodeId == finalNode.node)
if (node.m_nodeId == finalNode.node)
{
AddVirtualEdge(*j, finalNode, 0 /* no weight */);
AddVirtualEdge(node, finalNode, 0 /* no weight */);
return IRouter::NoError;
}
sources.emplace_back(j->m_nodeId, true /* isStartNode */, finalNode.mwmName);
sources.emplace_back(node.m_nodeId, true /* isStartNode */, finalNode.mwmId);
sources.back().segmentPoint = MercatorBounds::FromLatLon(node.m_point);
}
vector<EdgeWeight> weights;
targets[0] = FeatureGraphNode(finalNode.node, finalNode.reverseNode, false /* isStartNode */,
finalNode.mwmName);
finalNode.mwmId);
FindWeightsMatrix(sources, targets, finalMapping->m_dataFacade, weights);
if (find_if(weights.begin(), weights.end(), &IsValidEdgeWeight) == weights.end())
return IRouter::EndPointNotFound;
@ -105,7 +120,7 @@ IRouter::ResultCode CrossMwmGraph::SetFinalNode(CrossNode const & finalNode)
{
if (IsValidEdgeWeight(weights[i]))
{
AddVirtualEdge(*(mwmIngoingIter.first + i), finalNode, weights[i]);
AddVirtualEdge(ingoingNodes[i], finalNode, weights[i]);
}
}
return IRouter::NoError;
@ -114,7 +129,7 @@ IRouter::ResultCode CrossMwmGraph::SetFinalNode(CrossNode const & finalNode)
BorderCross CrossMwmGraph::FindNextMwmNode(OutgoingCrossNode const & startNode,
TRoutingMappingPtr const & currentMapping) const
{
m2::PointD const & startPoint = startNode.m_point;
ms::LatLon const & startPoint = startNode.m_point;
// Check cached crosses.
auto const it = m_cachedNextNodes.find(startPoint);
@ -131,22 +146,17 @@ BorderCross CrossMwmGraph::FindNextMwmNode(OutgoingCrossNode const & startNode,
return BorderCross();
nextMapping->LoadCrossContext();
auto incomeIters = nextMapping->m_crossContext.GetIngoingIterators();
for (auto i = incomeIters.first; i < incomeIters.second; ++i)
IngoingCrossNode ingoingNode;
if (nextMapping->m_crossContext.FindIngoingNodeByPoint(startPoint, ingoingNode))
{
m2::PointD const & targetPoint = i->m_point;
if (ms::DistanceOnEarth(startPoint.y, startPoint.x, targetPoint.y, targetPoint.x) <
kMwmCrossingNodeEqualityRadiusMeters)
{
BorderCross const cross(
CrossNode(startNode.m_nodeId, currentMapping->GetCountryName(),
MercatorBounds::FromLatLon(targetPoint.y, targetPoint.x)),
CrossNode(i->m_nodeId, nextMwm,
MercatorBounds::FromLatLon(targetPoint.y, targetPoint.x)));
m_cachedNextNodes.insert(make_pair(startPoint, cross));
return cross;
}
auto const & targetPoint = ingoingNode.m_point;
BorderCross const cross(
CrossNode(startNode.m_nodeId, currentMapping->GetMwmId(), targetPoint),
CrossNode(ingoingNode.m_nodeId, nextMapping->GetMwmId(), targetPoint));
m_cachedNextNodes.insert(make_pair(startPoint, cross));
return cross;
}
return BorderCross();
}
@ -163,35 +173,37 @@ void CrossMwmGraph::GetOutgoingEdgesList(BorderCross const & v,
}
// Loading cross routing section.
TRoutingMappingPtr currentMapping = m_indexManager.GetMappingByName(v.toNode.mwmName);
TRoutingMappingPtr currentMapping = m_indexManager.GetMappingById(v.toNode.mwmId);
ASSERT(currentMapping->IsValid(), ());
currentMapping->LoadCrossContext();
currentMapping->FreeFileIfPossible();
CrossRoutingContextReader const & currentContext = currentMapping->m_crossContext;
auto inRange = currentContext.GetIngoingIterators();
auto outRange = currentContext.GetOutgoingIterators();
// Find income node.
auto inIt = inRange.first;
while (inIt != inRange.second)
IngoingCrossNode ingoingNode;
CHECK(currentContext.FindIngoingNodeByPoint(v.toNode.point, ingoingNode), ());
if (ingoingNode.m_nodeId != v.toNode.node)
{
if (inIt->m_nodeId == v.toNode.node)
break;
++inIt;
LOG(LDEBUG, ("Several nodes stores in one border point.", v.toNode.point));
currentContext.ForEachIngoingNode([&ingoingNode, &v](IngoingCrossNode const & node)
{
if (node.m_nodeId == v.toNode.node)
ingoingNode = node;
});
}
CHECK(inIt != inRange.second, ());
// Find outs. Generate adjacency list.
for (auto outIt = outRange.first; outIt != outRange.second; ++outIt)
{
EdgeWeight const outWeight = currentContext.GetAdjacencyCost(inIt, outIt);
if (outWeight != INVALID_CONTEXT_EDGE_WEIGHT && outWeight != 0)
{
BorderCross target = FindNextMwmNode(*outIt, currentMapping);
if (target.toNode.IsValid())
adj.emplace_back(target, outWeight);
}
}
currentContext.ForEachOutgoingNode([&, this](OutgoingCrossNode const & node)
{
EdgeWeight const outWeight = currentContext.GetAdjacencyCost(ingoingNode, node);
if (outWeight != kInvalidContextEdgeWeight && outWeight != 0)
{
BorderCross target = FindNextMwmNode(node, currentMapping);
if (target.toNode.IsValid())
adj.emplace_back(target, outWeight);
}
});
}
double CrossMwmGraph::HeuristicCostEstimate(BorderCross const & v, BorderCross const & w) const
@ -208,9 +220,12 @@ void ConvertToSingleRouterTasks(vector<BorderCross> const & graphCrosses,
route.clear();
for (size_t i = 0; i + 1 < graphCrosses.size(); ++i)
{
ASSERT_EQUAL(graphCrosses[i].toNode.mwmName, graphCrosses[i + 1].fromNode.mwmName, ());
route.emplace_back(graphCrosses[i].toNode.node, graphCrosses[i + 1].fromNode.node,
graphCrosses[i].toNode.mwmName);
ASSERT_EQUAL(graphCrosses[i].toNode.mwmId, graphCrosses[i + 1].fromNode.mwmId, ());
route.emplace_back(graphCrosses[i].toNode.node,
MercatorBounds::FromLatLon(graphCrosses[i].toNode.point),
graphCrosses[i + 1].fromNode.node,
MercatorBounds::FromLatLon(graphCrosses[i + 1].fromNode.point),
graphCrosses[i].toNode.mwmId);
}
if (route.empty())
@ -218,8 +233,8 @@ void ConvertToSingleRouterTasks(vector<BorderCross> const & graphCrosses,
route.front().startNode = startGraphNode;
route.back().finalNode = finalGraphNode;
ASSERT_EQUAL(route.front().startNode.mwmName, route.front().finalNode.mwmName, ());
ASSERT_EQUAL(route.back().startNode.mwmName, route.back().finalNode.mwmName, ());
ASSERT_EQUAL(route.front().startNode.mwmId, route.front().finalNode.mwmId, ());
ASSERT_EQUAL(route.back().startNode.mwmId, route.back().finalNode.mwmId, ());
}
} // namespace routing

View file

@ -6,6 +6,7 @@
#include "indexer/index.hpp"
#include "geometry/latlon.hpp"
#include "geometry/point2d.hpp"
#include "base/macros.hpp"
@ -19,27 +20,27 @@ struct CrossNode
{
NodeID node;
NodeID reverseNode;
string mwmName;
m2::PointD point;
Index::MwmId mwmId;
ms::LatLon point;
bool isVirtual;
CrossNode(NodeID node, NodeID reverse, string const & mwmName, m2::PointD const & point)
: node(node), reverseNode(reverse), mwmName(mwmName), point(point), isVirtual(false)
CrossNode(NodeID node, NodeID reverse, Index::MwmId const & id, ms::LatLon const & point)
: node(node), reverseNode(reverse), mwmId(id), point(point), isVirtual(false)
{
}
CrossNode(NodeID node, string const & mwmName, m2::PointD const & point)
: node(node), reverseNode(INVALID_NODE_ID), mwmName(mwmName), point(point), isVirtual(false)
CrossNode(NodeID node, Index::MwmId const & id, ms::LatLon const & point)
: node(node), reverseNode(INVALID_NODE_ID), mwmId(id), point(point), isVirtual(false)
{
}
CrossNode() : node(INVALID_NODE_ID), reverseNode(INVALID_NODE_ID), point(m2::PointD::Zero()) {}
CrossNode() : node(INVALID_NODE_ID), reverseNode(INVALID_NODE_ID), point(ms::LatLon::Zero()) {}
inline bool IsValid() const { return node != INVALID_NODE_ID; }
inline bool operator==(CrossNode const & a) const
{
return node == a.node && mwmName == a.mwmName && isVirtual == a.isVirtual;
return node == a.node && mwmId == a.mwmId && isVirtual == a.isVirtual;
}
inline bool operator<(CrossNode const & a) const
@ -50,14 +51,14 @@ struct CrossNode
if (isVirtual != a.isVirtual)
return isVirtual < a.isVirtual;
return mwmName < a.mwmName;
return mwmId < a.mwmId;
}
};
inline string DebugPrint(CrossNode const & t)
{
ostringstream out;
out << "CrossNode [ node: " << t.node << ", map: " << t.mwmName << " ]";
out << "CrossNode [ node: " << t.node << ", map: " << t.mwmId.GetInfo()->GetCountryName()<< " ]";
return out.str();
}
@ -130,7 +131,7 @@ private:
map<CrossNode, vector<CrossWeightedEdge> > m_virtualEdges;
mutable RoutingIndexManager m_indexManager;
mutable unordered_map<m2::PointD, BorderCross, m2::PointD::Hash> m_cachedNextNodes;
mutable unordered_map<ms::LatLon, BorderCross, ms::LatLon::Hash> m_cachedNextNodes;
};
//--------------------------------------------------------------------------------------------------

View file

@ -18,7 +18,7 @@ IRouter::ResultCode CalculateRoute(BorderCross const & startPos, BorderCross con
TAlgorithm::TOnVisitedVertexCallback onVisitedVertex =
[&delegate](BorderCross const & cross, BorderCross const & /* target */)
{
delegate.OnPointCheck(cross.fromNode.point);
delegate.OnPointCheck(MercatorBounds::FromLatLon(cross.fromNode.point));
};
my::HighResTimer timer(true);
@ -53,8 +53,8 @@ IRouter::ResultCode CalculateCrossMwmPath(TRoutingNodes const & startGraphNodes,
IRouter::ResultCode code = IRouter::StartPointNotFound;
for (FeatureGraphNode const & start : startGraphNodes)
{
startNode = CrossNode(start.node.forward_node_id, start.node.reverse_node_id, start.mwmName,
start.segmentPoint);
startNode = CrossNode(start.node.forward_node_id, start.node.reverse_node_id, start.mwmId,
MercatorBounds::ToLatLon(start.segmentPoint));
code = roadGraph.SetStartNode(startNode);
if (code == IRouter::NoError)
{
@ -71,8 +71,8 @@ IRouter::ResultCode CalculateCrossMwmPath(TRoutingNodes const & startGraphNodes,
code = IRouter::EndPointNotFound;
for (FeatureGraphNode const & final : finalGraphNodes)
{
finalNode = CrossNode(final.node.reverse_node_id, final.node.forward_node_id, final.mwmName,
final.segmentPoint);
finalNode = CrossNode(final.node.reverse_node_id, final.node.forward_node_id, final.mwmId,
MercatorBounds::ToLatLon(final.segmentPoint));
finalNode.isVirtual = true;
code = roadGraph.SetFinalNode(finalNode);
if (code == IRouter::NoError)

View file

@ -17,10 +17,12 @@ struct RoutePathCross
FeatureGraphNode startNode; /**< start graph node representation */
FeatureGraphNode finalNode; /**< end graph node representation */
RoutePathCross(NodeID const startNode, NodeID const finalNode, string const & name)
: startNode(startNode, true /* isStartNode */, name),
finalNode(finalNode, false /* isStartNode*/, name)
RoutePathCross(NodeID const startNodeId, m2::PointD const & startPoint, NodeID const finalNodeId, m2::PointD const & finalPoint, Index::MwmId const & id)
: startNode(startNodeId, true /* isStartNode */, id),
finalNode(finalNodeId, false /* isStartNode*/, id)
{
startNode.segmentPoint = startPoint;
finalNode.segmentPoint = finalPoint;
}
};

View file

@ -1,81 +1,85 @@
#include "routing/cross_routing_context.hpp"
#include "indexer/mercator.hpp"
#include "indexer/point_to_int64.hpp"
namespace
{
uint32_t constexpr kCoordBits = POINT_COORD_BITS;
double constexpr kMwmCrossingNodeEqualityRadiusDegrees = 0.001;
} // namespace
namespace routing
{
static uint32_t const g_coordBits = POINT_COORD_BITS;
void OutgoingCrossNode::Save(Writer &w) const
void OutgoingCrossNode::Save(Writer & w) const
{
uint64_t point = PointToInt64(m_point, g_coordBits);
uint64_t point = PointToInt64(m2::PointD(m_point.lon, m_point.lat), kCoordBits);
char buff[sizeof(m_nodeId) + sizeof(point) + sizeof(m_outgoingIndex)];
*reinterpret_cast<decltype(m_nodeId) *>(&buff[0]) = m_nodeId;
*reinterpret_cast<decltype(point) *>(&(buff[sizeof(m_nodeId)])) = point;
*reinterpret_cast<decltype(m_outgoingIndex) *>(&(buff[sizeof(m_nodeId) + sizeof(point)])) = m_outgoingIndex;
w.Write(buff, sizeof(buff));
}
size_t OutgoingCrossNode::Load(const Reader &r, size_t pos)
size_t OutgoingCrossNode::Load(const Reader & r, size_t pos, size_t adjacencyIndex)
{
char buff[sizeof(m_nodeId) + sizeof(uint64_t) + sizeof(m_outgoingIndex)];
r.Read(pos, buff, sizeof(buff));
m_nodeId = *reinterpret_cast<decltype(m_nodeId) *>(&buff[0]);
m_point = Int64ToPoint(*reinterpret_cast<uint64_t *>(&(buff[sizeof(m_nodeId)])), g_coordBits);
m2::PointD bufferPoint = Int64ToPoint(*reinterpret_cast<uint64_t *>(&(buff[sizeof(m_nodeId)])), kCoordBits);
m_point = ms::LatLon(bufferPoint.y, bufferPoint.x);
m_outgoingIndex = *reinterpret_cast<decltype(m_outgoingIndex) *>(&(buff[sizeof(m_nodeId) + sizeof(uint64_t)]));
m_adjacencyIndex = adjacencyIndex;
return pos + sizeof(buff);
}
void IngoingCrossNode::Save(Writer &w) const
void IngoingCrossNode::Save(Writer & w) const
{
uint64_t point = PointToInt64(m_point, g_coordBits);
uint64_t point = PointToInt64(m2::PointD(m_point.lon, m_point.lat), kCoordBits);
char buff[sizeof(m_nodeId) + sizeof(point)];
*reinterpret_cast<decltype(m_nodeId) *>(&buff[0]) = m_nodeId;
*reinterpret_cast<decltype(point) *>(&(buff[sizeof(m_nodeId)])) = point;
w.Write(buff, sizeof(buff));
}
size_t IngoingCrossNode::Load(const Reader &r, size_t pos)
size_t IngoingCrossNode::Load(const Reader & r, size_t pos, size_t adjacencyIndex)
{
char buff[sizeof(m_nodeId) + sizeof(uint64_t)];
r.Read(pos, buff, sizeof(buff));
m_nodeId = *reinterpret_cast<decltype(m_nodeId) *>(&buff[0]);
m_point = Int64ToPoint(*reinterpret_cast<uint64_t *>(&(buff[sizeof(m_nodeId)])), g_coordBits);
m2::PointD bufferPoint = Int64ToPoint(*reinterpret_cast<uint64_t *>(&(buff[sizeof(m_nodeId)])), kCoordBits);
m_point = ms::LatLon(bufferPoint.y, bufferPoint.x);
m_adjacencyIndex = adjacencyIndex;
return pos + sizeof(buff);
}
size_t CrossRoutingContextReader::GetIndexInAdjMatrix(IngoingEdgeIteratorT ingoing, OutgoingEdgeIteratorT outgoing) const
{
size_t ingoing_index = distance(m_ingoingNodes.cbegin(), ingoing);
size_t outgoing_index = distance(m_outgoingNodes.cbegin(), outgoing);
ASSERT_LESS(ingoing_index, m_ingoingNodes.size(), ("ingoing index out of range"));
ASSERT_LESS(outgoing_index, m_outgoingNodes.size(), ("outgoing index out of range"));
return m_outgoingNodes.size() * ingoing_index + outgoing_index;
}
void CrossRoutingContextReader::Load(Reader const & r)
{
size_t pos = 0;
uint32_t size;
r.Read(pos, &size, sizeof(size));
pos += sizeof(size);
m_ingoingNodes.resize(size);
uint32_t size, ingoingSize;
r.Read(pos, &ingoingSize, sizeof(ingoingSize));
pos += sizeof(ingoingSize);
for (auto & node : m_ingoingNodes)
pos = node.Load(r, pos);
for (size_t i = 0; i < ingoingSize; ++i)
{
IngoingCrossNode node;
pos = node.Load(r, pos, i);
m_ingoingIndex.Add(node);
}
r.Read(pos, &size, sizeof(size));
pos += sizeof(size);
m_outgoingNodes.resize(size);
for (auto & node : m_outgoingNodes)
pos = node.Load(r, pos);
for (size_t i = 0; i < size; ++i)
pos = m_outgoingNodes[i].Load(r, pos, i);
size_t const adjMatrixSize = sizeof(WritedEdgeWeightT) * m_ingoingNodes.size() * m_outgoingNodes.size();
mp_reader = unique_ptr<Reader>(r.CreateSubReader(pos, adjMatrixSize));
size_t adjacencySize = ingoingSize * m_outgoingNodes.size();
size_t const adjMatrixSize = sizeof(TWrittenEdgeWeight) * adjacencySize;
m_adjacencyMatrix.resize(adjacencySize);
r.Read(pos, &m_adjacencyMatrix[0], adjMatrixSize);
pos += adjMatrixSize;
uint32_t strsize;
@ -92,6 +96,22 @@ void CrossRoutingContextReader::Load(Reader const & r)
}
}
bool CrossRoutingContextReader::FindIngoingNodeByPoint(ms::LatLon const & point,
IngoingCrossNode & node) const
{
bool found = false;
m_ingoingIndex.ForEachInRect(m2::RectD(point.lat - kMwmCrossingNodeEqualityRadiusDegrees,
point.lon - kMwmCrossingNodeEqualityRadiusDegrees,
point.lat + kMwmCrossingNodeEqualityRadiusDegrees,
point.lon + kMwmCrossingNodeEqualityRadiusDegrees),
[&found, &node](IngoingCrossNode const & nd)
{
node = nd;
found = true;
});
return found;
}
const string & CrossRoutingContextReader::GetOutgoingMwmName(
OutgoingCrossNode const & outgoingNode) const
{
@ -101,33 +121,15 @@ const string & CrossRoutingContextReader::GetOutgoingMwmName(
return m_neighborMwmList[outgoingNode.m_outgoingIndex];
}
pair<IngoingEdgeIteratorT, IngoingEdgeIteratorT> CrossRoutingContextReader::GetIngoingIterators() const
TWrittenEdgeWeight CrossRoutingContextReader::GetAdjacencyCost(IngoingCrossNode const & ingoing,
OutgoingCrossNode const & outgoing) const
{
return make_pair(m_ingoingNodes.cbegin(), m_ingoingNodes.cend());
}
if (ingoing.m_adjacencyIndex == kInvalidAdjacencyIndex ||
outgoing.m_adjacencyIndex == kInvalidAdjacencyIndex)
return kInvalidContextEdgeWeight;
pair<OutgoingEdgeIteratorT, OutgoingEdgeIteratorT> CrossRoutingContextReader::GetOutgoingIterators() const
{
return make_pair(m_outgoingNodes.cbegin(), m_outgoingNodes.cend());
}
WritedEdgeWeightT CrossRoutingContextReader::GetAdjacencyCost(IngoingEdgeIteratorT ingoing,
OutgoingEdgeIteratorT outgoing) const
{
if (!mp_reader)
return INVALID_CONTEXT_EDGE_WEIGHT;
WritedEdgeWeightT result;
mp_reader->Read(GetIndexInAdjMatrix(ingoing, outgoing) * sizeof(WritedEdgeWeightT), &result, sizeof(WritedEdgeWeightT));
return result;
}
size_t CrossRoutingContextWriter::GetIndexInAdjMatrix(IngoingEdgeIteratorT ingoing, OutgoingEdgeIteratorT outgoing) const
{
size_t ingoing_index = distance(m_ingoingNodes.cbegin(), ingoing);
size_t outgoing_index = distance(m_outgoingNodes.cbegin(), outgoing);
ASSERT_LESS(ingoing_index, m_ingoingNodes.size(), ("ingoing index out of range"));
ASSERT_LESS(outgoing_index, m_outgoingNodes.size(), ("outgoing index out of range"));
return m_outgoingNodes.size() * ingoing_index + outgoing_index;
size_t cost_index = m_outgoingNodes.size() * ingoing.m_adjacencyIndex + outgoing.m_adjacencyIndex;
return cost_index < m_adjacencyMatrix.size() ? m_adjacencyMatrix[cost_index] : kInvalidContextEdgeWeight;
}
void CrossRoutingContextWriter::Save(Writer & w) const
@ -143,12 +145,12 @@ void CrossRoutingContextWriter::Save(Writer & w) const
for (auto const & node : m_outgoingNodes)
node.Save(w);
CHECK(m_adjacencyMatrix.size() == m_outgoingNodes.size()*m_ingoingNodes.size(), ());
CHECK(m_adjacencyMatrix.size() == m_outgoingNodes.size() * m_ingoingNodes.size(), ());
w.Write(&m_adjacencyMatrix[0], sizeof(m_adjacencyMatrix[0]) * m_adjacencyMatrix.size());
size = static_cast<uint32_t>(m_neighborMwmList.size());
w.Write(&size, sizeof(size));
for (string const & neighbor: m_neighborMwmList)
for (string const & neighbor : m_neighborMwmList)
{
size = static_cast<uint32_t>(neighbor.size());
w.Write(&size, sizeof(size));
@ -156,38 +158,45 @@ void CrossRoutingContextWriter::Save(Writer & w) const
}
}
void CrossRoutingContextWriter::AddIngoingNode(WritedNodeID const nodeId, m2::PointD const & point)
void CrossRoutingContextWriter::AddIngoingNode(TWrittenNodeId const nodeId, ms::LatLon const & point)
{
m_ingoingNodes.push_back(IngoingCrossNode(nodeId, point));
size_t const adjIndex = m_ingoingNodes.size();
m_ingoingNodes.emplace_back(nodeId, point, adjIndex);
}
void CrossRoutingContextWriter::AddOutgoingNode(WritedNodeID const nodeId, string const & targetMwm,
m2::PointD const & point)
void CrossRoutingContextWriter::AddOutgoingNode(TWrittenNodeId const nodeId, string const & targetMwm,
ms::LatLon const & point)
{
size_t const adjIndex = m_outgoingNodes.size();
auto it = find(m_neighborMwmList.begin(), m_neighborMwmList.end(), targetMwm);
if (it == m_neighborMwmList.end())
it = m_neighborMwmList.insert(m_neighborMwmList.end(), targetMwm);
m_outgoingNodes.push_back(OutgoingCrossNode(nodeId, distance(m_neighborMwmList.begin(), it), point));
m_outgoingNodes.emplace_back(nodeId, distance(m_neighborMwmList.begin(), it), point, adjIndex);
}
void CrossRoutingContextWriter::ReserveAdjacencyMatrix()
{
m_adjacencyMatrix.resize(m_ingoingNodes.size() * m_outgoingNodes.size(), INVALID_CONTEXT_EDGE_WEIGHT);
m_adjacencyMatrix.resize(m_ingoingNodes.size() * m_outgoingNodes.size(),
kInvalidContextEdgeWeight);
}
void CrossRoutingContextWriter::SetAdjacencyCost(IngoingEdgeIteratorT ingoing,
OutgoingEdgeIteratorT outgoin,
WritedEdgeWeightT value)
OutgoingEdgeIteratorT outgoing,
TWrittenEdgeWeight value)
{
m_adjacencyMatrix[GetIndexInAdjMatrix(ingoing, outgoin)] = value;
size_t const index = m_outgoingNodes.size() * ingoing->m_adjacencyIndex + outgoing->m_adjacencyIndex;
ASSERT_LESS(index, m_adjacencyMatrix.size(), ());
m_adjacencyMatrix[index] = value;
}
pair<IngoingEdgeIteratorT, IngoingEdgeIteratorT> CrossRoutingContextWriter::GetIngoingIterators() const
pair<IngoingEdgeIteratorT, IngoingEdgeIteratorT> CrossRoutingContextWriter::GetIngoingIterators()
const
{
return make_pair(m_ingoingNodes.cbegin(), m_ingoingNodes.cend());
}
pair<OutgoingEdgeIteratorT, OutgoingEdgeIteratorT> CrossRoutingContextWriter::GetOutgoingIterators() const
pair<OutgoingEdgeIteratorT, OutgoingEdgeIteratorT> CrossRoutingContextWriter::GetOutgoingIterators()
const
{
return make_pair(m_outgoingNodes.cbegin(), m_outgoingNodes.cend());
}

View file

@ -2,45 +2,73 @@
#include "coding/file_container.hpp"
#include "geometry/latlon.hpp"
#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
#include "geometry/tree4d.hpp"
#include "std/string.hpp"
#include "std/vector.hpp"
namespace routing
{
using WritedNodeID = uint32_t;
using WritedEdgeWeightT = uint32_t;
static WritedEdgeWeightT const INVALID_CONTEXT_EDGE_WEIGHT = std::numeric_limits<WritedEdgeWeightT>::max();
static WritedEdgeWeightT const INVALID_CONTEXT_EDGE_NODE_ID = std::numeric_limits<uint32_t>::max();
using TWrittenNodeId = uint32_t;
using TWrittenEdgeWeight = uint32_t;
TWrittenEdgeWeight constexpr kInvalidContextEdgeNodeId = std::numeric_limits<uint32_t>::max();
TWrittenEdgeWeight constexpr kInvalidContextEdgeWeight = std::numeric_limits<TWrittenEdgeWeight>::max();
size_t constexpr kInvalidAdjacencyIndex = numeric_limits<size_t>::max();
struct IngoingCrossNode
{
m2::PointD m_point;
WritedNodeID m_nodeId;
ms::LatLon m_point;
TWrittenNodeId m_nodeId;
size_t m_adjacencyIndex;
IngoingCrossNode() : m_point(m2::PointD::Zero()), m_nodeId(INVALID_CONTEXT_EDGE_NODE_ID) {}
IngoingCrossNode(WritedNodeID nodeId, m2::PointD const & point) :m_point(point), m_nodeId(nodeId) {}
IngoingCrossNode()
: m_point(ms::LatLon::Zero())
, m_nodeId(kInvalidContextEdgeNodeId)
, m_adjacencyIndex(kInvalidAdjacencyIndex)
{
}
IngoingCrossNode(TWrittenNodeId nodeId, ms::LatLon const & point, size_t const adjacencyIndex)
: m_point(point), m_nodeId(nodeId), m_adjacencyIndex(adjacencyIndex)
{
}
void Save(Writer & w) const;
size_t Load(Reader const & r, size_t pos);
size_t Load(Reader const & r, size_t pos, size_t adjacencyIndex);
m2::RectD const GetLimitRect() const { return m2::RectD(m_point.lat, m_point.lon, m_point.lat, m_point.lon); }
};
struct OutgoingCrossNode
{
m2::PointD m_point;
WritedNodeID m_nodeId;
ms::LatLon m_point;
TWrittenNodeId m_nodeId;
unsigned char m_outgoingIndex;
size_t m_adjacencyIndex;
OutgoingCrossNode() : m_point(m2::PointD::Zero()), m_nodeId(INVALID_CONTEXT_EDGE_NODE_ID), m_outgoingIndex(0) {}
OutgoingCrossNode(WritedNodeID nodeId, size_t const index, m2::PointD const & point) : m_point(point),
m_nodeId(nodeId),
m_outgoingIndex(static_cast<unsigned char>(index)){}
OutgoingCrossNode()
: m_point(ms::LatLon::Zero())
, m_nodeId(kInvalidContextEdgeNodeId)
, m_outgoingIndex(0)
, m_adjacencyIndex(kInvalidAdjacencyIndex)
{
}
OutgoingCrossNode(TWrittenNodeId nodeId, size_t const index, ms::LatLon const & point,
size_t const adjacencyIndex)
: m_point(point)
, m_nodeId(nodeId)
, m_outgoingIndex(static_cast<unsigned char>(index))
, m_adjacencyIndex(adjacencyIndex)
{
}
void Save(Writer & w) const;
size_t Load(Reader const & r, size_t pos);
size_t Load(Reader const & r, size_t pos, size_t adjacencyIndex);
};
using IngoingEdgeIteratorT = vector<IngoingCrossNode>::const_iterator;
@ -49,24 +77,32 @@ using OutgoingEdgeIteratorT = vector<OutgoingCrossNode>::const_iterator;
/// Reader class from cross context section in mwm.routing file
class CrossRoutingContextReader
{
vector<IngoingCrossNode> m_ingoingNodes;
vector<OutgoingCrossNode> m_outgoingNodes;
vector<string> m_neighborMwmList;
unique_ptr<Reader> mp_reader = nullptr;
vector<TWrittenEdgeWeight> m_adjacencyMatrix;
m4::Tree<IngoingCrossNode> m_ingoingIndex;
size_t GetIndexInAdjMatrix(IngoingEdgeIteratorT ingoing, OutgoingEdgeIteratorT outgoing) const;
public:
public:
void Load(Reader const & r);
const string & GetOutgoingMwmName(OutgoingCrossNode const & mwmIndex) const;
pair<IngoingEdgeIteratorT, IngoingEdgeIteratorT> GetIngoingIterators() const;
bool FindIngoingNodeByPoint(ms::LatLon const & point, IngoingCrossNode & node) const;
pair<OutgoingEdgeIteratorT, OutgoingEdgeIteratorT> GetOutgoingIterators() const;
TWrittenEdgeWeight GetAdjacencyCost(IngoingCrossNode const & ingoing,
OutgoingCrossNode const & outgoing) const;
WritedEdgeWeightT GetAdjacencyCost(IngoingEdgeIteratorT ingoing,
OutgoingEdgeIteratorT outgoing) const;
template <class TFunctor>
void ForEachIngoingNode(TFunctor f) const
{
m_ingoingIndex.ForEach(f);
}
template <class TFunctor>
void ForEachOutgoingNode(TFunctor f) const
{
for_each(m_outgoingNodes.cbegin(), m_outgoingNodes.cend(), f);
}
};
/// Helper class to generate cross context section in mwm.routing file
@ -74,7 +110,7 @@ class CrossRoutingContextWriter
{
vector<IngoingCrossNode> m_ingoingNodes;
vector<OutgoingCrossNode> m_outgoingNodes;
vector<WritedEdgeWeightT> m_adjacencyMatrix;
vector<TWrittenEdgeWeight> m_adjacencyMatrix;
vector<string> m_neighborMwmList;
size_t GetIndexInAdjMatrix(IngoingEdgeIteratorT ingoing, OutgoingEdgeIteratorT outgoing) const;
@ -82,14 +118,15 @@ class CrossRoutingContextWriter
public:
void Save(Writer & w) const;
void AddIngoingNode(WritedNodeID const nodeId, m2::PointD const & point);
void AddIngoingNode(TWrittenNodeId const nodeId, ms::LatLon const & point);
void AddOutgoingNode(WritedNodeID const nodeId, string const & targetMwm, m2::PointD const & point);
void AddOutgoingNode(TWrittenNodeId const nodeId, string const & targetMwm,
ms::LatLon const & point);
void ReserveAdjacencyMatrix();
void SetAdjacencyCost(IngoingEdgeIteratorT ingoing, OutgoingEdgeIteratorT outgoin,
WritedEdgeWeightT value);
TWrittenEdgeWeight value);
pair<IngoingEdgeIteratorT, IngoingEdgeIteratorT> GetIngoingIterators() const;

View file

@ -91,8 +91,8 @@ bool FindSingleRoute(FeatureGraphNode const & source, FeatureGraphNode const & t
}
FeatureGraphNode::FeatureGraphNode(NodeID const nodeId, bool const isStartNode,
string const & mwmName)
: segmentPoint(m2::PointD::Zero()), mwmName(mwmName)
Index::MwmId const & id)
: segmentPoint(m2::PointD::Zero()), mwmId(id)
{
node.forward_node_id = isStartNode ? nodeId : INVALID_NODE_ID;
node.reverse_node_id = isStartNode ? INVALID_NODE_ID : nodeId;
@ -105,8 +105,8 @@ FeatureGraphNode::FeatureGraphNode(NodeID const nodeId, bool const isStartNode,
}
FeatureGraphNode::FeatureGraphNode(NodeID const nodeId, NodeID const reverseNodeId,
bool const isStartNode, string const & mwmName)
: segmentPoint(m2::PointD::Zero()), mwmName(mwmName)
bool const isStartNode, Index::MwmId const & id)
: segmentPoint(m2::PointD::Zero()), mwmId(id)
{
node.forward_node_id = isStartNode ? nodeId : reverseNodeId;
node.reverse_node_id = isStartNode ? reverseNodeId : nodeId;

View file

@ -3,6 +3,8 @@
#include "routing/osrm2feature_map.hpp"
#include "routing/osrm_data_facade.hpp"
#include "indexer/index.hpp"
#include "geometry/point2d.hpp"
#include "std/vector.hpp"
@ -17,7 +19,7 @@ struct FeatureGraphNode
PhantomNode node;
OsrmMappingTypes::FtSeg segment;
m2::PointD segmentPoint;
string mwmName;
Index::MwmId mwmId;
/*!
* \brief fill FeatureGraphNode with values.
@ -25,10 +27,10 @@ struct FeatureGraphNode
* \param isStartNode true if this node will first in the path.
* \param mwmName @nodeId refers node on the graph of this map.
*/
FeatureGraphNode(NodeID const nodeId, bool const isStartNode, string const & mwmName);
FeatureGraphNode(NodeID const nodeId, bool const isStartNode, Index::MwmId const & id);
FeatureGraphNode(NodeID const nodeId, NodeID const reverseNodeId, bool const isStartNode,
string const & mwmName);
Index::MwmId const & id);
/// \brief Invalid graph node constructor
FeatureGraphNode();

View file

@ -189,8 +189,7 @@ EdgeWeight Point2PhantomNode::GetMinNodeWeight(NodeID node, m2::PointD const & p
return minWeight;
}
void Point2PhantomNode::MakeResult(vector<FeatureGraphNode> & res, size_t maxCount,
string const & mwmName)
void Point2PhantomNode::MakeResult(vector<FeatureGraphNode> & res, size_t maxCount)
{
vector<OsrmMappingTypes::FtSeg> segments;
@ -258,14 +257,14 @@ void Point2PhantomNode::MakeResult(vector<FeatureGraphNode> & res, size_t maxCou
node.segment = segments[j];
node.segmentPoint = m_candidates[j].m_point;
node.mwmName = mwmName;
node.mwmId = m_routingMapping.GetMwmId();
CalculateWeights(node);
}
res.erase(remove_if(res.begin(), res.end(),
[](FeatureGraphNode const & f)
{
return f.mwmName.empty();
return !f.mwmId.IsAlive();
}),
res.end());
}

View file

@ -49,7 +49,7 @@ public:
void operator()(FeatureType const & ft);
/// Makes OSRM tasks result vector.
void MakeResult(vector<FeatureGraphNode> & res, size_t maxCount, string const & mwmName);
void MakeResult(vector<FeatureGraphNode> & res, size_t maxCount);
private:
// Calculates distance in meters on the feature from startPoint to endPoint.

View file

@ -149,38 +149,7 @@ void CalculatePhantomNodeForCross(TRoutingMappingPtr & mapping, FeatureGraphNode
CHECK_NOT_EQUAL(nodeId, INVALID_NODE_ID, ());
mapping->LoadCrossContext();
MappingGuard guard(mapping);
UNUSED_VALUE(guard);
m2::PointD point = m2::PointD::Zero();
if (forward)
{
auto inIters = mapping->m_crossContext.GetIngoingIterators();
for (auto iter = inIters.first; iter != inIters.second; ++iter)
{
if (iter->m_nodeId != nodeId)
continue;
point = iter->m_point;
break;
}
}
else
{
auto outIters = mapping->m_crossContext.GetOutgoingIterators();
for (auto iter = outIters.first; iter != outIters.second; ++iter)
{
if (iter->m_nodeId != nodeId)
continue;
point = iter->m_point;
break;
}
}
CHECK(!point.IsAlmostZero(), ());
FindGraphNodeOffsets(nodeId, MercatorBounds::FromLatLon(point.y, point.x),
pIndex, mapping, graphNode);
FindGraphNodeOffsets(nodeId, graphNode.segmentPoint, pIndex, mapping, graphNode);
}
// TODO (ldragunov) move this function to cross mwm router
@ -194,9 +163,9 @@ OsrmRouter::ResultCode OsrmRouter::MakeRouteFromCrossesPath(TCheckedPath const &
vector<m2::PointD> Points;
for (RoutePathCross cross : path)
{
ASSERT_EQUAL(cross.startNode.mwmName, cross.finalNode.mwmName, ());
ASSERT_EQUAL(cross.startNode.mwmId, cross.finalNode.mwmId, ());
RawRoutingResult routingResult;
TRoutingMappingPtr mwmMapping = m_indexManager.GetMappingByName(cross.startNode.mwmName);
TRoutingMappingPtr mwmMapping = m_indexManager.GetMappingById(cross.startNode.mwmId);
ASSERT(mwmMapping->IsValid(), ());
MappingGuard mwmMappingGuard(mwmMapping);
UNUSED_VALUE(mwmMappingGuard);
@ -390,7 +359,7 @@ IRouter::ResultCode OsrmRouter::FindPhantomNodes(m2::PointD const & point,
if (!getter.HasCandidates())
return RouteNotFound;
getter.MakeResult(res, maxCount, mapping->GetCountryName());
getter.MakeResult(res, maxCount);
return NoError;
}

View file

@ -17,7 +17,6 @@ namespace
UNIT_TEST(CheckCrossSections)
{
static double constexpr kPointEquality = 0.01;
static m2::PointD const kZeroPoint = m2::PointD(0., 0.);
vector<platform::LocalCountryFile> localFiles;
platform::FindAllLocalMaps(localFiles);
@ -38,24 +37,24 @@ UNIT_TEST(CheckCrossSections)
}
FilesMappingContainer container(file.GetPath(MapOptions::CarRouting));
crossReader.Load(container.GetReader(ROUTING_CROSS_CONTEXT_TAG));
auto ingoing = crossReader.GetIngoingIterators();
for (auto i = ingoing.first; i != ingoing.second; ++i)
{
if (i->m_point.EqualDxDy(kZeroPoint, kPointEquality))
{
ingoingErrors++;
break;
}
}
auto outgoing = crossReader.GetOutgoingIterators();
for (auto i = outgoing.first; i != outgoing.second; ++i)
{
if (i->m_point.EqualDxDy(kZeroPoint, kPointEquality))
{
outgoingErrors++;
break;
}
}
bool error = false;
crossReader.ForEachIngoingNode([&error](IngoingCrossNode const & node)
{
if (node.m_point.EqualDxDy(ms::LatLon::Zero(), kPointEquality))
error = true;
});
if (error)
ingoingErrors++;
error = false;
crossReader.ForEachOutgoingNode([&error](OutgoingCrossNode const & node)
{
if (node.m_point.EqualDxDy(ms::LatLon::Zero(), kPointEquality))
error = true;
});
if (error)
outgoingErrors++;
}
TEST_EQUAL(ingoingErrors, 0, ("Some countries have zero point incomes."));
TEST_EQUAL(outgoingErrors, 0, ("Some countries have zero point exits."));

View file

@ -196,4 +196,11 @@ TRoutingMappingPtr RoutingIndexManager::GetMappingByName(string const & mapName)
return newMapping;
}
TRoutingMappingPtr RoutingIndexManager::GetMappingById(Index::MwmId const & id)
{
if (!id.IsAlive())
return TRoutingMappingPtr(new RoutingMapping());
return GetMappingByName(id.GetInfo()->GetCountryName());
}
} // namespace routing

View file

@ -106,6 +106,8 @@ public:
TRoutingMappingPtr GetMappingByName(string const & mapName);
TRoutingMappingPtr GetMappingById(Index::MwmId const & id);
template <class TFunctor>
void ForEachMapping(TFunctor toDo)
{
@ -116,6 +118,7 @@ public:
private:
TCountryFileFn m_countryFileFn;
// TODO (ldragunov) Rewrite to mwmId.
unordered_map<string, TRoutingMappingPtr> m_mapping;
MwmSet & m_index;
};

View file

@ -14,23 +14,22 @@ namespace
// Graph to convertions.
UNIT_TEST(TestCrossRouteConverter)
{
Index::MwmId aMap, bMap;
vector<BorderCross> graphCrosses;
CrossNode const a(1, "aMap", {0, 0}), b(2, "aMap", {2, 2});
CrossNode const c(3, "bMap", {3, 3}), d(3, "bMap", {4, 4});
CrossNode const a(1, aMap, {0, 0}), b(2, aMap, {2, 2});
CrossNode const c(3, bMap, {3, 3}), d(3, bMap, {4, 4});
graphCrosses.emplace_back(a, b);
graphCrosses.emplace_back(b, c);
graphCrosses.emplace_back(c, d);
FeatureGraphNode startGraphNode;
startGraphNode.node.forward_node_id = 5;
startGraphNode.mwmName = "aMap";
startGraphNode.mwmId = aMap;
FeatureGraphNode finalGraphNode;
finalGraphNode.node.reverse_node_id = 6;
finalGraphNode.mwmName = "bMap";
finalGraphNode.mwmId = bMap;
TCheckedPath route;
ConvertToSingleRouterTasks(graphCrosses, startGraphNode, finalGraphNode, route);
TEST_EQUAL(route.size(), 2, ("We have 2 maps aMap and bMap."));
for (auto const & r : route)
TEST_EQUAL(r.startNode.mwmName, r.finalNode.mwmName, ());
TEST_EQUAL(route.front().startNode.node, startGraphNode.node,
("Start node must be replaced by origin."));
TEST_EQUAL(route.back().finalNode.node, finalGraphNode.node,
@ -43,10 +42,10 @@ UNIT_TEST(TestContextSerialization)
routing::CrossRoutingContextWriter context;
routing::CrossRoutingContextReader newContext;
context.AddIngoingNode(1, m2::PointD::Zero());
context.AddIngoingNode(2, m2::PointD::Zero());
context.AddOutgoingNode(3, "foo", m2::PointD::Zero());
context.AddOutgoingNode(4, "bar", m2::PointD::Zero());
context.AddIngoingNode(1, ms::LatLon::Zero());
context.AddIngoingNode(2, ms::LatLon::Zero());
context.AddOutgoingNode(3, "foo", ms::LatLon::Zero());
context.AddOutgoingNode(4, "bar", ms::LatLon::Zero());
context.ReserveAdjacencyMatrix();
vector<char> buffer;
@ -56,18 +55,25 @@ UNIT_TEST(TestContextSerialization)
MemReader reader(buffer.data(), buffer.size());
newContext.Load(reader);
auto ins = newContext.GetIngoingIterators();
TEST_EQUAL(distance(ins.first,ins.second), 2, ());
TEST_EQUAL(ins.first->m_nodeId, 1, ());
TEST_EQUAL((++ins.first)->m_nodeId, 2, ());
vector<IngoingCrossNode> ingoingNodes;
newContext.ForEachIngoingNode([&ingoingNodes](IngoingCrossNode const & node)
{
ingoingNodes.push_back(node);
});
TEST_EQUAL(ingoingNodes.size(), 2, ());
TEST_EQUAL(ingoingNodes[0].m_nodeId, 1, ());
TEST_EQUAL(ingoingNodes[1].m_nodeId, 2, ());
auto outs = newContext.GetOutgoingIterators();
TEST_EQUAL(distance(outs.first,outs.second), 2, ());
TEST_EQUAL(outs.first->m_nodeId, 3, ());
TEST_EQUAL(newContext.GetOutgoingMwmName(*outs.first), string("foo"), ());
++outs.first;
TEST_EQUAL(outs.first->m_nodeId, 4, ());
TEST_EQUAL(newContext.GetOutgoingMwmName(*outs.first), string("bar"), ());
vector<OutgoingCrossNode> outgoingNodes;
newContext.ForEachOutgoingNode([&outgoingNodes](OutgoingCrossNode const & node)
{
outgoingNodes.push_back(node);
});
TEST_EQUAL(outgoingNodes.size(), 2, ());
TEST_EQUAL(outgoingNodes[0].m_nodeId, 3, ());
TEST_EQUAL(newContext.GetOutgoingMwmName(outgoingNodes[0]), string("foo"), ());
TEST_EQUAL(outgoingNodes[1].m_nodeId, 4, ());
TEST_EQUAL(newContext.GetOutgoingMwmName(outgoingNodes[1]), string("bar"), ());
}
UNIT_TEST(TestAdjacencyMatrix)
@ -75,10 +81,10 @@ UNIT_TEST(TestAdjacencyMatrix)
routing::CrossRoutingContextWriter context;
routing::CrossRoutingContextReader newContext;
context.AddIngoingNode(1, m2::PointD::Zero());
context.AddIngoingNode(2, m2::PointD::Zero());
context.AddIngoingNode(3, m2::PointD::Zero());
context.AddOutgoingNode(4, "foo", m2::PointD::Zero());
context.AddIngoingNode(1, ms::LatLon::Zero());
context.AddIngoingNode(2, ms::LatLon::Zero());
context.AddIngoingNode(3, ms::LatLon::Zero());
context.AddOutgoingNode(4, "foo", ms::LatLon::Zero());
context.ReserveAdjacencyMatrix();
{
auto ins = context.GetIngoingIterators();
@ -94,12 +100,47 @@ UNIT_TEST(TestAdjacencyMatrix)
MemReader reader(buffer.data(), buffer.size());
newContext.Load(reader);
auto ins = newContext.GetIngoingIterators();
auto outs = newContext.GetOutgoingIterators();
TEST_EQUAL(newContext.GetAdjacencyCost(ins.first, outs.first), 5, ());
TEST_EQUAL(newContext.GetAdjacencyCost(ins.first + 1, outs.first), 9, ());
TEST_EQUAL(newContext.GetAdjacencyCost(ins.first + 2, outs.first),
routing::INVALID_CONTEXT_EDGE_WEIGHT, ("Default cost"));
vector<IngoingCrossNode> ingoingNodes;
newContext.ForEachIngoingNode([&ingoingNodes](IngoingCrossNode const & node)
{
ingoingNodes.push_back(node);
});
vector<OutgoingCrossNode> outgoingNodes;
newContext.ForEachOutgoingNode([&outgoingNodes](OutgoingCrossNode const & node)
{
outgoingNodes.push_back(node);
});
TEST_EQUAL(newContext.GetAdjacencyCost(ingoingNodes[0], outgoingNodes[0]), 5, ());
TEST_EQUAL(newContext.GetAdjacencyCost(ingoingNodes[1], outgoingNodes[0]), 9, ());
TEST_EQUAL(newContext.GetAdjacencyCost(ingoingNodes[2], outgoingNodes[0]),
routing::kInvalidContextEdgeWeight, ("Default cost"));
}
UNIT_TEST(TestFindingByPoint)
{
routing::CrossRoutingContextWriter context;
routing::CrossRoutingContextReader newContext;
ms::LatLon p1(1., 1.), p2(5., 5.), p3(10.,1.);
context.AddIngoingNode(1, ms::LatLon::Zero());
context.AddIngoingNode(2, p1);
context.AddIngoingNode(3, p2);
context.AddOutgoingNode(4, "foo", ms::LatLon::Zero());
context.ReserveAdjacencyMatrix();
vector<char> buffer;
MemWriter<vector<char> > writer(buffer);
context.Save(writer);
TEST_GREATER(buffer.size(), 5, ("Context serializer make some data"));
MemReader reader(buffer.data(), buffer.size());
newContext.Load(reader);
IngoingCrossNode node;
TEST(newContext.FindIngoingNodeByPoint(p1, node), ());
TEST_EQUAL(node.m_nodeId, 2, ());
TEST(newContext.FindIngoingNodeByPoint(p2, node), ());
TEST_EQUAL(node.m_nodeId, 3, ());
TEST(!newContext.FindIngoingNodeByPoint(p3, node), ());
}
} // namespace