forked from organicmaps/organicmaps
Merge pull request #4854 from dobriy-eeh/compress-routing-section
Routing section compression
This commit is contained in:
commit
87771aaee4
22 changed files with 770 additions and 140 deletions
|
@ -240,7 +240,7 @@ int main(int argc, char ** argv)
|
|||
routing::BuildRoadAltitudes(datFile, FLAGS_srtm_path);
|
||||
|
||||
if (FLAGS_generate_routing)
|
||||
routing::BuildRoutingIndex(datFile);
|
||||
routing::BuildRoutingIndex(datFile, country);
|
||||
|
||||
if (FLAGS_generate_restrictions)
|
||||
{
|
||||
|
|
|
@ -1,18 +1,22 @@
|
|||
#include "generator/routing_index_generator.hpp"
|
||||
|
||||
#include "routing/bicycle_model.hpp"
|
||||
#include "routing/car_model.hpp"
|
||||
#include "routing/index_graph.hpp"
|
||||
#include "routing/routing_helpers.hpp"
|
||||
#include "routing/index_graph_serialization.hpp"
|
||||
#include "routing/pedestrian_model.hpp"
|
||||
#include "routing/vehicle_mask.hpp"
|
||||
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_processor.hpp"
|
||||
#include "indexer/point_to_int64.hpp"
|
||||
#include "indexer/routing_section.hpp"
|
||||
|
||||
#include "coding/file_container.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include "std/bind.hpp"
|
||||
#include "std/shared_ptr.hpp"
|
||||
#include "std/unordered_map.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
|
@ -25,6 +29,16 @@ namespace
|
|||
class Processor final
|
||||
{
|
||||
public:
|
||||
explicit Processor(string const & country)
|
||||
: m_pedestrianModel(PedestrianModelFactory().GetVehicleModelForCountry(country))
|
||||
, m_bicycleModel(BicycleModelFactory().GetVehicleModelForCountry(country))
|
||||
, m_carModel(CarModelFactory().GetVehicleModelForCountry(country))
|
||||
{
|
||||
CHECK(m_pedestrianModel, ());
|
||||
CHECK(m_bicycleModel, ());
|
||||
CHECK(m_carModel, ());
|
||||
}
|
||||
|
||||
void ProcessAllFeatures(string const & filename)
|
||||
{
|
||||
feature::ForEachFromDat(filename, bind(&Processor::ProcessFeature, this, _1, _2));
|
||||
|
@ -43,12 +57,16 @@ public:
|
|||
graph.Import(joints);
|
||||
}
|
||||
|
||||
unordered_map<uint32_t, VehicleMask> const & GetMasks() const { return m_masks; }
|
||||
|
||||
private:
|
||||
void ProcessFeature(FeatureType const & f, uint32_t id)
|
||||
{
|
||||
if (!IsRoad(feature::TypesHolder(f)))
|
||||
VehicleMask const mask = CalcVehicleMask(f);
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
m_masks[id] = mask;
|
||||
f.ParseGeometry(FeatureType::BEST_GEOMETRY);
|
||||
|
||||
for (size_t i = 0; i < f.GetPointsCount(); ++i)
|
||||
|
@ -58,31 +76,49 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
VehicleMask CalcVehicleMask(FeatureType const & f) const
|
||||
{
|
||||
VehicleMask mask = 0;
|
||||
if (m_pedestrianModel->IsRoad(f))
|
||||
mask |= kPedestrianMask;
|
||||
if (m_bicycleModel->IsRoad(f))
|
||||
mask |= kBicycleMask;
|
||||
if (m_carModel->IsRoad(f))
|
||||
mask |= kCarMask;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
shared_ptr<IVehicleModel> const m_pedestrianModel;
|
||||
shared_ptr<IVehicleModel> const m_bicycleModel;
|
||||
shared_ptr<IVehicleModel> const m_carModel;
|
||||
unordered_map<uint64_t, Joint> m_posToJoint;
|
||||
unordered_map<uint32_t, VehicleMask> m_masks;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
{
|
||||
bool BuildRoutingIndex(string const & filename)
|
||||
bool BuildRoutingIndex(string const & filename, string const & country)
|
||||
{
|
||||
LOG(LINFO, ("Building routing index for", filename));
|
||||
try
|
||||
{
|
||||
Processor processor;
|
||||
Processor processor(country);
|
||||
processor.ProcessAllFeatures(filename);
|
||||
|
||||
IndexGraph graph;
|
||||
processor.BuildGraph(graph);
|
||||
LOG(LINFO, ("Routing index contains", graph.GetNumRoads(), "roads,", graph.GetNumJoints(),
|
||||
"joints,", graph.GetNumPoints(), "points"));
|
||||
|
||||
FilesContainerW cont(filename, FileWriter::OP_WRITE_EXISTING);
|
||||
FileWriter writer = cont.GetWriter(ROUTING_FILE_TAG);
|
||||
|
||||
RoutingSectionHeader const routingHeader;
|
||||
routingHeader.Serialize(writer);
|
||||
graph.Serialize(writer);
|
||||
auto const startPos = writer.Pos();
|
||||
IndexGraphSerializer::Serialize(graph, processor.GetMasks(), writer);
|
||||
auto const sectionSize = writer.Pos() - startPos;
|
||||
|
||||
LOG(LINFO, ("Routing section created:", sectionSize, "bytes,", graph.GetNumRoads(), "roads,",
|
||||
graph.GetNumJoints(), "joints,", graph.GetNumPoints(), "points"));
|
||||
return true;
|
||||
}
|
||||
catch (RootException const & e)
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
namespace routing
|
||||
{
|
||||
bool BuildRoutingIndex(string const & filename);
|
||||
bool BuildRoutingIndex(string const & filename, string const & country);
|
||||
} // namespace routing
|
||||
|
|
|
@ -119,7 +119,6 @@ HEADERS += \
|
|||
point_to_int64.hpp \
|
||||
postcodes_matcher.hpp \ # it's in indexer due to editor wich is in indexer and depends on postcodes_marcher
|
||||
rank_table.hpp \
|
||||
routing_section.hpp \
|
||||
scale_index.hpp \
|
||||
scale_index_builder.hpp \
|
||||
scales.hpp \
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/write_to_sink.hpp"
|
||||
|
||||
#include "std/cstdint.hpp"
|
||||
|
||||
namespace feature
|
||||
{
|
||||
class RoutingSectionHeader final
|
||||
{
|
||||
public:
|
||||
RoutingSectionHeader() : m_version(0) {}
|
||||
|
||||
uint8_t GetVersion() const { return m_version; }
|
||||
|
||||
template <class Sink>
|
||||
void Serialize(Sink & sink) const
|
||||
{
|
||||
WriteToSink(sink, m_version);
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
void Deserialize(Source & src)
|
||||
{
|
||||
m_version = ReadPrimitiveFromSource<decltype(m_version)>(src);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t m_version;
|
||||
};
|
||||
} // namespace feature
|
|
@ -38,6 +38,8 @@ set(
|
|||
geometry.hpp
|
||||
index_graph.cpp
|
||||
index_graph.hpp
|
||||
index_graph_serialization.cpp
|
||||
index_graph_serialization.hpp
|
||||
index_graph_starter.cpp
|
||||
index_graph_starter.hpp
|
||||
joint.cpp
|
||||
|
@ -81,7 +83,7 @@ set(
|
|||
router_delegate.hpp
|
||||
routing_algorithm.cpp
|
||||
routing_algorithm.hpp
|
||||
routing_exception.hpp
|
||||
routing_exceptions.hpp
|
||||
routing_helpers.cpp
|
||||
routing_helpers.hpp
|
||||
routing_mapping.cpp
|
||||
|
@ -107,6 +109,7 @@ set(
|
|||
turns_sound_settings.hpp
|
||||
turns_tts_text.cpp
|
||||
turns_tts_text.hpp
|
||||
vehicle_mask.hpp
|
||||
vehicle_model.cpp
|
||||
vehicle_model.hpp
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "routing/geometry.hpp"
|
||||
|
||||
#include "routing/routing_exception.hpp"
|
||||
#include "routing/routing_exceptions.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
|
@ -51,14 +51,16 @@ namespace routing
|
|||
{
|
||||
// RoadGeometry ------------------------------------------------------------------------------------
|
||||
RoadGeometry::RoadGeometry(bool oneWay, double speed, Points const & points)
|
||||
: m_points(points), m_speed(speed), m_isRoad(true), m_isOneWay(oneWay)
|
||||
: m_points(points), m_speed(speed), m_isOneWay(oneWay)
|
||||
{
|
||||
ASSERT_GREATER(speed, 0.0, ());
|
||||
}
|
||||
|
||||
void RoadGeometry::Load(IVehicleModel const & vehicleModel, FeatureType const & feature)
|
||||
{
|
||||
m_isRoad = vehicleModel.IsRoad(feature);
|
||||
CHECK(vehicleModel.IsRoad(feature),
|
||||
("Feature", feature.GetID().m_index, "is not a road in the current vehicle model"));
|
||||
|
||||
m_isOneWay = vehicleModel.IsOneWay(feature);
|
||||
m_speed = vehicleModel.GetSpeed(feature);
|
||||
|
||||
|
|
|
@ -25,8 +25,6 @@ public:
|
|||
|
||||
void Load(IVehicleModel const & vehicleModel, FeatureType const & feature);
|
||||
|
||||
bool IsRoad() const { return m_isRoad; }
|
||||
|
||||
bool IsOneWay() const { return m_isOneWay; }
|
||||
|
||||
// Kilometers per hour.
|
||||
|
@ -43,7 +41,6 @@ public:
|
|||
private:
|
||||
Points m_points;
|
||||
double m_speed = 0.0;
|
||||
bool m_isRoad = false;
|
||||
bool m_isOneWay = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "base/assert.hpp"
|
||||
#include "base/exception.hpp"
|
||||
|
||||
#include "std/limits.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
IndexGraph::IndexGraph(unique_ptr<GeometryLoader> loader, shared_ptr<EdgeEstimator> estimator)
|
||||
|
@ -23,10 +25,13 @@ m2::PointD const & IndexGraph::GetPoint(Joint::Id jointId)
|
|||
return m_geometry.GetPoint(m_jointIndex.GetPoint(jointId));
|
||||
}
|
||||
|
||||
void IndexGraph::Build(uint32_t numJoints) { m_jointIndex.Build(m_roadIndex, numJoints); }
|
||||
|
||||
void IndexGraph::Import(vector<Joint> const & joints)
|
||||
{
|
||||
m_roadIndex.Import(joints);
|
||||
m_jointIndex.Build(m_roadIndex, joints.size());
|
||||
CHECK_LESS_OR_EQUAL(joints.size(), numeric_limits<uint32_t>::max(), ());
|
||||
Build(static_cast<uint32_t>(joints.size()));
|
||||
}
|
||||
|
||||
Joint::Id IndexGraph::InsertJoint(RoadPoint const & rp)
|
||||
|
@ -55,8 +60,6 @@ void IndexGraph::GetNeighboringEdges(RoadPoint const & rp, bool isOutgoing,
|
|||
vector<JointEdge> & edges)
|
||||
{
|
||||
RoadGeometry const & road = m_geometry.GetRoad(rp.GetFeatureId());
|
||||
if (!road.IsRoad())
|
||||
return;
|
||||
|
||||
bool const bidirectional = !road.IsOneWay();
|
||||
if (!isOutgoing || bidirectional)
|
||||
|
@ -66,8 +69,8 @@ void IndexGraph::GetNeighboringEdges(RoadPoint const & rp, bool isOutgoing,
|
|||
GetNeighboringEdge(road, rp, true /* forward */, edges);
|
||||
}
|
||||
|
||||
void IndexGraph::GetNeighboringEdge(RoadGeometry const & road, RoadPoint const & rp,
|
||||
bool forward, vector<JointEdge> & edges) const
|
||||
void IndexGraph::GetNeighboringEdge(RoadGeometry const & road, RoadPoint const & rp, bool forward,
|
||||
vector<JointEdge> & edges) const
|
||||
{
|
||||
pair<Joint::Id, uint32_t> const & neighbor = m_roadIndex.FindNeighbor(rp, forward);
|
||||
if (neighbor.first != Joint::kInvalidId)
|
||||
|
@ -82,8 +85,6 @@ void IndexGraph::GetDirectedEdge(uint32_t featureId, uint32_t pointFrom, uint32_
|
|||
Joint::Id target, bool forward, vector<JointEdge> & edges)
|
||||
{
|
||||
RoadGeometry const & road = m_geometry.GetRoad(featureId);
|
||||
if (!road.IsRoad())
|
||||
return;
|
||||
|
||||
if (road.IsOneWay() && forward != (pointFrom < pointTo))
|
||||
return;
|
||||
|
|
|
@ -7,9 +7,6 @@
|
|||
#include "routing/road_index.hpp"
|
||||
#include "routing/road_point.hpp"
|
||||
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/write_to_sink.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include "std/cstdint.hpp"
|
||||
|
@ -51,35 +48,34 @@ public:
|
|||
|
||||
Geometry & GetGeometry() { return m_geometry; }
|
||||
EdgeEstimator const & GetEstimator() const { return *m_estimator; }
|
||||
RoadJointIds const & GetRoad(uint32_t featureId) const { return m_roadIndex.GetRoad(featureId); }
|
||||
|
||||
uint32_t GetNumRoads() const { return m_roadIndex.GetSize(); }
|
||||
uint32_t GetNumJoints() const { return m_jointIndex.GetNumJoints(); }
|
||||
uint32_t GetNumPoints() const { return m_jointIndex.GetNumPoints(); }
|
||||
|
||||
void Build(uint32_t numJoints);
|
||||
void Import(vector<Joint> const & joints);
|
||||
Joint::Id InsertJoint(RoadPoint const & rp);
|
||||
bool JointLiesOnRoad(Joint::Id jointId, uint32_t featureId) const;
|
||||
|
||||
void PushFromSerializer(Joint::Id jointId, RoadPoint const & rp)
|
||||
{
|
||||
m_roadIndex.PushFromSerializer(jointId, rp);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEachRoad(F && f) const
|
||||
{
|
||||
m_roadIndex.ForEachRoad(forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEachPoint(Joint::Id jointId, F && f) const
|
||||
{
|
||||
m_jointIndex.ForEachPoint(jointId, forward<F>(f));
|
||||
}
|
||||
|
||||
template <class Sink>
|
||||
void Serialize(Sink & sink) const
|
||||
{
|
||||
WriteToSink(sink, static_cast<uint32_t>(GetNumJoints()));
|
||||
m_roadIndex.Serialize(sink);
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
void Deserialize(Source & src)
|
||||
{
|
||||
uint32_t const jointsSize = ReadPrimitiveFromSource<uint32_t>(src);
|
||||
m_roadIndex.Deserialize(src);
|
||||
m_jointIndex.Build(m_roadIndex, jointsSize);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetNeighboringEdge(RoadGeometry const & road, RoadPoint const & rp, bool forward,
|
||||
vector<JointEdge> & edges) const;
|
||||
|
|
123
routing/index_graph_serialization.cpp
Normal file
123
routing/index_graph_serialization.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include "routing/index_graph_serialization.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
// static
|
||||
uint8_t constexpr IndexGraphSerializer::kLastVersion;
|
||||
uint32_t constexpr IndexGraphSerializer::JointsFilter::kEmptyEntry;
|
||||
uint32_t constexpr IndexGraphSerializer::JointsFilter::kPushedEntry;
|
||||
|
||||
// IndexGraphSerializer::SectionSerializer ---------------------------------------------------------
|
||||
void IndexGraphSerializer::SectionSerializer::PreSerialize(
|
||||
IndexGraph const & graph, unordered_map<uint32_t, VehicleMask> const & masks,
|
||||
JointIdEncoder & jointEncoder)
|
||||
{
|
||||
m_buffer.clear();
|
||||
MemWriter<vector<uint8_t>> memWriter(m_buffer);
|
||||
BitWriter<MemWriter<vector<uint8_t>>> writer(memWriter);
|
||||
|
||||
// -1 for uint32_t is some confusing, but it allows process first iteration in the common way.
|
||||
// Gamma coder can't write 0, so init prevFeatureId = -1 in case of first featureId == 0.
|
||||
// It works because uint32_t is residual ring type.
|
||||
uint32_t prevFeatureId = -1;
|
||||
|
||||
for (uint32_t const featureId : m_featureIds)
|
||||
{
|
||||
RoadJointIds const & road = graph.GetRoad(featureId);
|
||||
WriteGamma(writer, featureId - prevFeatureId);
|
||||
WriteGamma(writer, ConvertJointsNumber(road.GetJointsNumber()));
|
||||
|
||||
uint32_t prevPointId = -1;
|
||||
road.ForEachJoint([&](uint32_t pointId, Joint::Id jointId) {
|
||||
WriteGamma(writer, pointId - prevPointId);
|
||||
jointEncoder.Write(jointId, writer);
|
||||
prevPointId = pointId;
|
||||
});
|
||||
|
||||
prevFeatureId = featureId;
|
||||
}
|
||||
}
|
||||
|
||||
// IndexGraphSerializer::JointsFilter --------------------------------------------------------------
|
||||
void IndexGraphSerializer::JointsFilter::Push(Joint::Id jointIdInFile, RoadPoint const & rp)
|
||||
{
|
||||
CHECK_LESS(jointIdInFile, m_entries.size(), ());
|
||||
|
||||
auto & entry = m_entries[jointIdInFile];
|
||||
switch (entry.first)
|
||||
{
|
||||
case kEmptyEntry:
|
||||
// Keep RoadPoint here until second RoadPoint with same Joint::Id comes.
|
||||
// If second point does not come, it is redundant Joint that should be filtered.
|
||||
entry.first = rp.GetFeatureId();
|
||||
entry.second.pointId = rp.GetPointId();
|
||||
break;
|
||||
case kPushedEntry: m_graph.PushFromSerializer(entry.second.jointId, rp); break;
|
||||
default:
|
||||
m_graph.PushFromSerializer(m_count,
|
||||
RoadPoint(entry.first /* featureId */, entry.second.pointId));
|
||||
m_graph.PushFromSerializer(m_count, rp);
|
||||
entry.first = kPushedEntry;
|
||||
entry.second.jointId = m_count;
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
|
||||
// IndexGraphSerializer ----------------------------------------------------------------------------
|
||||
// static
|
||||
VehicleMask IndexGraphSerializer::GetRoadMask(unordered_map<uint32_t, VehicleMask> const & masks,
|
||||
uint32_t featureId)
|
||||
{
|
||||
auto const & it = masks.find(featureId);
|
||||
CHECK(it != masks.cend(), ("Can't find vehicle mask for feature", featureId));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Gamma Coder encodes value 1 with 1 bit, value 2 with 3 bits.
|
||||
// The vast majority of roads contains 2 joints: endpoints connections.
|
||||
// Swap values 1, 2 to encode most of joints numbers with 1 bit.
|
||||
//
|
||||
// static
|
||||
uint32_t IndexGraphSerializer::ConvertJointsNumber(uint32_t jointsNumber)
|
||||
{
|
||||
switch (jointsNumber)
|
||||
{
|
||||
case 1: return 2;
|
||||
case 2: return 1;
|
||||
default: return jointsNumber;
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void IndexGraphSerializer::PrepareSectionSerializers(
|
||||
IndexGraph const & graph, unordered_map<uint32_t, VehicleMask> const & masks,
|
||||
vector<SectionSerializer> & serializers)
|
||||
{
|
||||
size_t maskToIndex[kNumVehicleMasks] = {};
|
||||
// Car routing is most used routing: put car sections first.
|
||||
// It would be a bit faster read them for car model.
|
||||
for (size_t step = 0; step < 2; ++step)
|
||||
{
|
||||
for (VehicleMask mask = 1; mask < kNumVehicleMasks; ++mask)
|
||||
{
|
||||
bool const hasCar = (mask & kCarMask) != 0;
|
||||
if ((step == 0) == hasCar)
|
||||
{
|
||||
CHECK_EQUAL(maskToIndex[mask], 0, ("Mask", mask, "already has serializer"));
|
||||
maskToIndex[mask] = serializers.size();
|
||||
serializers.emplace_back(mask /* SectionSerializer(mask) */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
graph.ForEachRoad([&](uint32_t featureId, RoadJointIds const & /* road */) {
|
||||
VehicleMask const mask = GetRoadMask(masks, featureId);
|
||||
SectionSerializer & serializer = serializers[maskToIndex[mask]];
|
||||
CHECK_EQUAL(serializer.GetMask(), mask, ());
|
||||
serializer.AddRoad(featureId);
|
||||
});
|
||||
|
||||
for (SectionSerializer & serializer : serializers)
|
||||
serializer.SortRoads();
|
||||
}
|
||||
} // namespace routing
|
413
routing/index_graph_serialization.hpp
Normal file
413
routing/index_graph_serialization.hpp
Normal file
|
@ -0,0 +1,413 @@
|
|||
#pragma once
|
||||
|
||||
#include "routing/index_graph.hpp"
|
||||
#include "routing/joint.hpp"
|
||||
#include "routing/routing_exceptions.hpp"
|
||||
#include "routing/vehicle_mask.hpp"
|
||||
|
||||
#include "coding/bit_streams.hpp"
|
||||
#include "coding/elias_coder.hpp"
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/write_to_sink.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/cstdint.hpp"
|
||||
#include "std/limits.hpp"
|
||||
#include "std/type_traits.hpp"
|
||||
#include "std/unordered_map.hpp"
|
||||
#include "std/utility.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
class IndexGraphSerializer final
|
||||
{
|
||||
public:
|
||||
IndexGraphSerializer() = delete;
|
||||
|
||||
template <class Sink>
|
||||
static void Serialize(IndexGraph const & graph,
|
||||
unordered_map<uint32_t, VehicleMask> const & masks, Sink & sink)
|
||||
{
|
||||
Header header(graph);
|
||||
JointIdEncoder jointEncoder;
|
||||
|
||||
vector<SectionSerializer> serializers;
|
||||
PrepareSectionSerializers(graph, masks, serializers);
|
||||
|
||||
for (SectionSerializer & serializer : serializers)
|
||||
{
|
||||
Joint::Id const begin = jointEncoder.GetCount();
|
||||
serializer.PreSerialize(graph, masks, jointEncoder);
|
||||
header.AddSection({
|
||||
serializer.GetBufferSize(), static_cast<uint32_t>(serializer.GetNumRoads()), begin,
|
||||
jointEncoder.GetCount(), serializer.GetMask(),
|
||||
});
|
||||
}
|
||||
|
||||
header.Serialize(sink);
|
||||
for (SectionSerializer & section : serializers)
|
||||
section.Flush(sink);
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
static void Deserialize(IndexGraph & graph, Source & src, VehicleMask requiredMask)
|
||||
{
|
||||
Header header;
|
||||
header.Deserialize(src);
|
||||
|
||||
JointsFilter jointsFilter(graph, header.GetNumJoints());
|
||||
|
||||
for (uint32_t i = 0; i < header.GetNumSections(); ++i)
|
||||
{
|
||||
Section const & section = header.GetSection(i);
|
||||
VehicleMask const mask = section.GetMask();
|
||||
|
||||
if (!(mask & requiredMask))
|
||||
{
|
||||
src.Skip(section.GetSize());
|
||||
continue;
|
||||
}
|
||||
|
||||
JointIdDecoder jointIdDecoder(section.GetBeginJointId());
|
||||
BitReader<Source> reader(src);
|
||||
uint64_t const expectedEndPos = src.Pos() + section.GetSize();
|
||||
|
||||
// -1 for uint32_t is some confusing, but it allows process first iteration in the common way.
|
||||
// Delta coder can't write 0, so init prevFeatureId = -1 in case of first featureId == 0.
|
||||
// It works because uint32_t is residual ring type.
|
||||
uint32_t featureId = -1;
|
||||
for (uint32_t i = 0; i < section.GetNumRoads(); ++i)
|
||||
{
|
||||
uint32_t const featureDelta = ReadGamma(reader);
|
||||
featureId += featureDelta;
|
||||
|
||||
uint32_t const jointsNumber = ConvertJointsNumber(ReadGamma(reader));
|
||||
|
||||
// See comment above about -1.
|
||||
uint32_t pointId = -1;
|
||||
|
||||
for (uint32_t j = 0; j < jointsNumber; ++j)
|
||||
{
|
||||
uint32_t const pointDelta = ReadGamma(reader);
|
||||
pointId += pointDelta;
|
||||
Joint::Id const jointId = jointIdDecoder.Read(reader);
|
||||
if (jointId >= section.GetEndJointId())
|
||||
{
|
||||
MYTHROW(CorruptedDataException,
|
||||
("Invalid jointId =", jointId, ", end =", section.GetEndJointId(), ", mask =",
|
||||
mask, ", pointId =", pointId, ", featureId =", featureId));
|
||||
}
|
||||
|
||||
jointsFilter.Push(jointId, RoadPoint(featureId, pointId));
|
||||
}
|
||||
}
|
||||
|
||||
if (jointIdDecoder.GetCount() != section.GetEndJointId())
|
||||
{
|
||||
MYTHROW(CorruptedDataException,
|
||||
("Invalid decoder count =", jointIdDecoder.GetCount(), ", expected =",
|
||||
section.GetEndJointId(), ", mask =", mask));
|
||||
}
|
||||
|
||||
if (src.Pos() != expectedEndPos)
|
||||
{
|
||||
MYTHROW(CorruptedDataException,
|
||||
("Wrong position", src.Pos(), "after decoding section", mask, "expected",
|
||||
expectedEndPos, "section size =", section.GetSize()));
|
||||
}
|
||||
}
|
||||
|
||||
graph.Build(jointsFilter.GetCount());
|
||||
}
|
||||
|
||||
private:
|
||||
static uint8_t constexpr kLastVersion = 0;
|
||||
static uint8_t constexpr kNewJointIdBit = 0;
|
||||
static uint8_t constexpr kRepeatJointIdBit = 1;
|
||||
|
||||
class Section final
|
||||
{
|
||||
public:
|
||||
Section() = default;
|
||||
|
||||
Section(uint64_t size, uint32_t numRoads, Joint::Id beginJointId, Joint::Id endJointId,
|
||||
VehicleMask mask)
|
||||
: m_size(size)
|
||||
, m_numRoads(numRoads)
|
||||
, m_beginJointId(beginJointId)
|
||||
, m_endJointId(endJointId)
|
||||
, m_mask(mask)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Sink>
|
||||
void Serialize(Sink & sink) const
|
||||
{
|
||||
WriteToSink(sink, m_size);
|
||||
WriteToSink(sink, m_numRoads);
|
||||
WriteToSink(sink, m_beginJointId);
|
||||
WriteToSink(sink, m_endJointId);
|
||||
WriteToSink(sink, m_mask);
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
void Deserialize(Source & src)
|
||||
{
|
||||
m_size = ReadPrimitiveFromSource<decltype(m_size)>(src);
|
||||
m_numRoads = ReadPrimitiveFromSource<decltype(m_numRoads)>(src);
|
||||
m_beginJointId = ReadPrimitiveFromSource<decltype(m_beginJointId)>(src);
|
||||
m_endJointId = ReadPrimitiveFromSource<decltype(m_endJointId)>(src);
|
||||
m_mask = ReadPrimitiveFromSource<decltype(m_mask)>(src);
|
||||
}
|
||||
|
||||
uint64_t GetSize() const { return m_size; }
|
||||
uint32_t GetNumRoads() const { return m_numRoads; }
|
||||
Joint::Id GetBeginJointId() const { return m_beginJointId; }
|
||||
Joint::Id GetEndJointId() const { return m_endJointId; }
|
||||
VehicleMask GetMask() const { return m_mask; }
|
||||
|
||||
private:
|
||||
uint64_t m_size = 0;
|
||||
uint32_t m_numRoads = 0;
|
||||
Joint::Id m_beginJointId = Joint::kInvalidId;
|
||||
Joint::Id m_endJointId = Joint::kInvalidId;
|
||||
VehicleMask m_mask = 0;
|
||||
};
|
||||
|
||||
class Header final
|
||||
{
|
||||
public:
|
||||
Header() = default;
|
||||
|
||||
explicit Header(IndexGraph const & graph)
|
||||
: m_numRoads(graph.GetNumRoads()), m_numJoints(graph.GetNumJoints())
|
||||
{
|
||||
}
|
||||
|
||||
template <class Sink>
|
||||
void Serialize(Sink & sink) const
|
||||
{
|
||||
WriteToSink(sink, m_version);
|
||||
WriteToSink(sink, m_numRoads);
|
||||
WriteToSink(sink, m_numJoints);
|
||||
|
||||
WriteToSink(sink, static_cast<uint32_t>(m_sections.size()));
|
||||
for (Section const & section : m_sections)
|
||||
section.Serialize(sink);
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
void Deserialize(Source & src)
|
||||
{
|
||||
m_version = ReadPrimitiveFromSource<decltype(m_version)>(src);
|
||||
if (m_version != kLastVersion)
|
||||
{
|
||||
MYTHROW(CorruptedDataException,
|
||||
("Unknown index graph version ", m_version, ", current version ", kLastVersion));
|
||||
}
|
||||
|
||||
m_numRoads = ReadPrimitiveFromSource<decltype(m_numRoads)>(src);
|
||||
m_numJoints = ReadPrimitiveFromSource<decltype(m_numJoints)>(src);
|
||||
|
||||
auto const sectionsSize = ReadPrimitiveFromSource<uint32_t>(src);
|
||||
m_sections.resize(sectionsSize);
|
||||
for (Section & section : m_sections)
|
||||
section.Deserialize(src);
|
||||
}
|
||||
|
||||
uint32_t GetNumRoads() const { return m_numRoads; }
|
||||
Joint::Id GetNumJoints() const { return m_numJoints; }
|
||||
uint32_t GetNumSections() const { return m_sections.size(); }
|
||||
|
||||
Section const & GetSection(size_t index) const
|
||||
{
|
||||
CHECK_LESS(index, m_sections.size(), ());
|
||||
return m_sections[index];
|
||||
}
|
||||
|
||||
void AddSection(Section const & section) { m_sections.push_back(section); }
|
||||
|
||||
private:
|
||||
uint8_t m_version = kLastVersion;
|
||||
uint32_t m_numRoads = 0;
|
||||
Joint::Id m_numJoints = 0;
|
||||
vector<Section> m_sections;
|
||||
};
|
||||
|
||||
class JointIdEncoder final
|
||||
{
|
||||
public:
|
||||
template <class Sink>
|
||||
void Write(Joint::Id originalId, BitWriter<Sink> & writer)
|
||||
{
|
||||
auto const & it = m_convertedIds.find(originalId);
|
||||
if (it != m_convertedIds.end())
|
||||
{
|
||||
Joint::Id const convertedId = it->second;
|
||||
CHECK_LESS(convertedId, m_count,
|
||||
("Duplicate joint id should be less than count, convertedId =", convertedId,
|
||||
", count =", m_count, ", originalId =", originalId));
|
||||
writer.Write(kRepeatJointIdBit, 1);
|
||||
// m_count - convertedId is less than convertedId in general.
|
||||
// So write this delta to save file space.
|
||||
WriteDelta(writer, m_count - convertedId);
|
||||
return;
|
||||
}
|
||||
|
||||
m_convertedIds[originalId] = m_count;
|
||||
writer.Write(kNewJointIdBit, 1);
|
||||
++m_count;
|
||||
}
|
||||
|
||||
Joint::Id GetCount() const { return m_count; }
|
||||
|
||||
private:
|
||||
Joint::Id m_count = 0;
|
||||
unordered_map<Joint::Id, Joint::Id> m_convertedIds;
|
||||
};
|
||||
|
||||
class JointIdDecoder final
|
||||
{
|
||||
public:
|
||||
// Joint::Id count is incrementing along entire file.
|
||||
// But deserializer skips some sections, therefore we should recover counter at each section
|
||||
// start.
|
||||
JointIdDecoder(Joint::Id startId) : m_count(startId) {}
|
||||
|
||||
template <class Source>
|
||||
Joint::Id Read(BitReader<Source> & reader)
|
||||
{
|
||||
uint8_t const bit = reader.Read(1);
|
||||
if (bit == kRepeatJointIdBit)
|
||||
{
|
||||
uint32_t const delta = ReadDelta(reader);
|
||||
if (delta > m_count)
|
||||
MYTHROW(CorruptedDataException, ("Joint id delta", delta, "> count =", m_count));
|
||||
|
||||
return m_count - delta;
|
||||
}
|
||||
|
||||
return m_count++;
|
||||
}
|
||||
|
||||
Joint::Id GetCount() const { return m_count; }
|
||||
|
||||
private:
|
||||
Joint::Id m_count;
|
||||
};
|
||||
|
||||
// JointsFilter has two goals:
|
||||
//
|
||||
// 1. Deserialization skips some sections.
|
||||
// Therefore one skips some joint ids from a continuous series of numbers [0, numJoints).
|
||||
// JointsFilter converts loaded joint ids to a new continuous series of numbers [0,
|
||||
// numLoadedJoints).
|
||||
//
|
||||
// 2. Some joints connect roads from different models.
|
||||
// E.g. 2 roads joint: all vehicles road + pedestrian road.
|
||||
// If one loads car roads only, pedestrian roads should be skipped,
|
||||
// so joint would have only point from all vehicles road.
|
||||
// JointsFilter filters such redundant joints.
|
||||
class JointsFilter final
|
||||
{
|
||||
public:
|
||||
JointsFilter(IndexGraph & graph, Joint::Id numJoints) : m_graph(graph)
|
||||
{
|
||||
m_entries.assign(numJoints, {kEmptyEntry, {0}});
|
||||
}
|
||||
|
||||
void Push(Joint::Id jointIdInFile, RoadPoint const & rp);
|
||||
Joint::Id GetCount() const { return m_count; }
|
||||
|
||||
private:
|
||||
static uint32_t constexpr kEmptyEntry = numeric_limits<uint32_t>::max();
|
||||
static uint32_t constexpr kPushedEntry = kEmptyEntry - 1;
|
||||
|
||||
// Joints number is large.
|
||||
// Therefore point id and joint id are stored in same space to save some memory.
|
||||
union Point {
|
||||
uint32_t pointId;
|
||||
Joint::Id jointId;
|
||||
};
|
||||
|
||||
static_assert(is_integral<Joint::Id>::value, "Joint::Id should be integral type");
|
||||
|
||||
IndexGraph & m_graph;
|
||||
Joint::Id m_count = 0;
|
||||
vector<pair<uint32_t, Point>> m_entries;
|
||||
};
|
||||
|
||||
class SectionSerializer final
|
||||
{
|
||||
public:
|
||||
explicit SectionSerializer(VehicleMask mask) : m_mask(mask) {}
|
||||
|
||||
size_t GetBufferSize() const { return m_buffer.size(); }
|
||||
VehicleMask GetMask() const { return m_mask; }
|
||||
size_t GetNumRoads() const { return m_featureIds.size(); }
|
||||
|
||||
void AddRoad(uint32_t featureId) { m_featureIds.push_back(featureId); }
|
||||
void SortRoads() { sort(m_featureIds.begin(), m_featureIds.end()); }
|
||||
void PreSerialize(IndexGraph const & graph, unordered_map<uint32_t, VehicleMask> const & masks,
|
||||
JointIdEncoder & jointEncoder);
|
||||
|
||||
template <class Sink>
|
||||
void Flush(Sink & sink)
|
||||
{
|
||||
sink.Write(m_buffer.data(), m_buffer.size());
|
||||
m_buffer.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
VehicleMask const m_mask;
|
||||
vector<uint32_t> m_featureIds;
|
||||
vector<uint8_t> m_buffer;
|
||||
};
|
||||
|
||||
template <typename Sink>
|
||||
static void WriteGamma(BitWriter<Sink> & writer, uint32_t value)
|
||||
{
|
||||
ASSERT_NOT_EQUAL(value, 0, ());
|
||||
|
||||
bool const success = coding::GammaCoder::Encode(writer, static_cast<uint64_t>(value));
|
||||
ASSERT(success, ());
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
static uint32_t ReadGamma(BitReader<Source> & reader)
|
||||
{
|
||||
uint64_t const decoded = coding::GammaCoder::Decode(reader);
|
||||
if (decoded > numeric_limits<uint32_t>::max())
|
||||
MYTHROW(CorruptedDataException, ("Decoded uint32_t out of limit", decoded));
|
||||
|
||||
return static_cast<uint32_t>(decoded);
|
||||
}
|
||||
|
||||
template <typename Sink>
|
||||
static void WriteDelta(BitWriter<Sink> & writer, uint32_t value)
|
||||
{
|
||||
ASSERT_NOT_EQUAL(value, 0, ());
|
||||
|
||||
bool const success = coding::DeltaCoder::Encode(writer, static_cast<uint64_t>(value));
|
||||
ASSERT(success, ());
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
static uint32_t ReadDelta(BitReader<Source> & reader)
|
||||
{
|
||||
uint64_t const decoded = coding::DeltaCoder::Decode(reader);
|
||||
if (decoded > numeric_limits<uint32_t>::max())
|
||||
MYTHROW(CorruptedDataException, ("Decoded uint32_t out of limit", decoded));
|
||||
|
||||
return static_cast<uint32_t>(decoded);
|
||||
}
|
||||
|
||||
static VehicleMask GetRoadMask(unordered_map<uint32_t, VehicleMask> const & masks,
|
||||
uint32_t featureId);
|
||||
static uint32_t ConvertJointsNumber(uint32_t jointsNumber);
|
||||
static void PrepareSectionSerializers(IndexGraph const & graph,
|
||||
unordered_map<uint32_t, VehicleMask> const & masks,
|
||||
vector<SectionSerializer> & sections);
|
||||
};
|
||||
} // namespace routing
|
|
@ -1,6 +1,6 @@
|
|||
#include "routing/index_graph_starter.hpp"
|
||||
|
||||
#include "routing/routing_exception.hpp"
|
||||
#include "routing/routing_exceptions.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
@ -141,9 +141,6 @@ void IndexGraphStarter::FindPointsWithCommonFeature(Joint::Id jointId0, Joint::I
|
|||
return;
|
||||
|
||||
RoadGeometry const & road = m_graph.GetGeometry().GetRoad(rp0.GetFeatureId());
|
||||
if (!road.IsRoad())
|
||||
return;
|
||||
|
||||
if (road.IsOneWay() && rp0.GetPointId() > rp1.GetPointId())
|
||||
return;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "routing/joint_index.hpp"
|
||||
|
||||
#include "routing/routing_exception.hpp"
|
||||
#include "routing/routing_exceptions.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "routing/road_index.hpp"
|
||||
|
||||
#include "routing/routing_exception.hpp"
|
||||
#include "routing/routing_exceptions.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
#include "routing/joint.hpp"
|
||||
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/write_to_sink.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/cstdint.hpp"
|
||||
#include "std/unordered_map.hpp"
|
||||
|
@ -16,6 +13,12 @@ namespace routing
|
|||
class RoadJointIds final
|
||||
{
|
||||
public:
|
||||
void Init(uint32_t maxPointId)
|
||||
{
|
||||
m_jointIds.clear();
|
||||
m_jointIds.reserve(maxPointId + 1);
|
||||
}
|
||||
|
||||
Joint::Id GetJointId(uint32_t pointId) const
|
||||
{
|
||||
if (pointId < m_jointIds.size())
|
||||
|
@ -26,6 +29,8 @@ public:
|
|||
|
||||
void AddJoint(uint32_t pointId, Joint::Id jointId)
|
||||
{
|
||||
ASSERT_NOT_EQUAL(jointId, Joint::kInvalidId, ());
|
||||
|
||||
if (pointId >= m_jointIds.size())
|
||||
m_jointIds.insert(m_jointIds.end(), pointId + 1 - m_jointIds.size(), Joint::kInvalidId);
|
||||
|
||||
|
@ -33,6 +38,19 @@ public:
|
|||
m_jointIds[pointId] = jointId;
|
||||
}
|
||||
|
||||
uint32_t GetJointsNumber() const
|
||||
{
|
||||
uint32_t count = 0;
|
||||
|
||||
for (Joint::Id const jointId : m_jointIds)
|
||||
{
|
||||
if (jointId != Joint::kInvalidId)
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void ForEachJoint(F && f) const
|
||||
{
|
||||
|
@ -77,27 +95,6 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
template <class Sink>
|
||||
void Serialize(Sink & sink) const
|
||||
{
|
||||
WriteToSink(sink, static_cast<Joint::Id>(m_jointIds.size()));
|
||||
for (Joint::Id jointId : m_jointIds)
|
||||
WriteToSink(sink, jointId);
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
void Deserialize(Source & src)
|
||||
{
|
||||
m_jointIds.clear();
|
||||
Joint::Id const jointsSize = ReadPrimitiveFromSource<Joint::Id>(src);
|
||||
m_jointIds.reserve(jointsSize);
|
||||
for (Joint::Id i = 0; i < jointsSize; ++i)
|
||||
{
|
||||
Joint::Id const jointId = ReadPrimitiveFromSource<Joint::Id>(src);
|
||||
m_jointIds.emplace_back(jointId);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Joint ids indexed by point id.
|
||||
// If some point id doesn't match any joint id, this vector contains Joint::kInvalidId.
|
||||
|
@ -114,35 +111,25 @@ public:
|
|||
m_roads[rp.GetFeatureId()].AddJoint(rp.GetPointId(), jointId);
|
||||
}
|
||||
|
||||
RoadJointIds const & GetRoad(uint32_t featureId) const
|
||||
{
|
||||
auto const & it = m_roads.find(featureId);
|
||||
CHECK(it != m_roads.cend(), ());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void PushFromSerializer(Joint::Id jointId, RoadPoint const & rp)
|
||||
{
|
||||
m_roads[rp.GetFeatureId()].AddJoint(rp.GetPointId(), jointId);
|
||||
}
|
||||
|
||||
// Find nearest point with normal joint id.
|
||||
// If forward == true: neighbor with larger point id (right neighbor)
|
||||
// If forward == false: neighbor with smaller point id (left neighbor)
|
||||
//
|
||||
// If there is no nearest point, return {Joint::kInvalidId, 0}
|
||||
pair<Joint::Id, uint32_t> FindNeighbor(RoadPoint const & rp, bool forward) const;
|
||||
|
||||
template <class Sink>
|
||||
void Serialize(Sink & sink) const
|
||||
{
|
||||
WriteToSink(sink, static_cast<uint32_t>(m_roads.size()));
|
||||
for (auto const & it : m_roads)
|
||||
{
|
||||
uint32_t const featureId = it.first;
|
||||
WriteToSink(sink, featureId);
|
||||
it.second.Serialize(sink);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
void Deserialize(Source & src)
|
||||
{
|
||||
m_roads.clear();
|
||||
size_t const roadsSize = static_cast<size_t>(ReadPrimitiveFromSource<uint32_t>(src));
|
||||
for (size_t i = 0; i < roadsSize; ++i)
|
||||
{
|
||||
uint32_t featureId = ReadPrimitiveFromSource<decltype(featureId)>(src);
|
||||
m_roads[featureId].Deserialize(src);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetSize() const { return m_roads.size(); }
|
||||
|
||||
Joint::Id GetJointId(RoadPoint const & rp) const
|
||||
|
|
|
@ -27,6 +27,7 @@ SOURCES += \
|
|||
features_road_graph.cpp \
|
||||
geometry.cpp \
|
||||
index_graph.cpp \
|
||||
index_graph_serialization.cpp \
|
||||
index_graph_starter.cpp \
|
||||
joint.cpp \
|
||||
joint_index.cpp \
|
||||
|
@ -77,6 +78,7 @@ HEADERS += \
|
|||
features_road_graph.hpp \
|
||||
geometry.hpp \
|
||||
index_graph.hpp \
|
||||
index_graph_serialization.hpp \
|
||||
index_graph_starter.hpp \
|
||||
joint.hpp \
|
||||
joint_index.hpp \
|
||||
|
@ -100,7 +102,7 @@ HEADERS += \
|
|||
router.hpp \
|
||||
router_delegate.hpp \
|
||||
routing_algorithm.hpp \
|
||||
routing_exception.hpp \
|
||||
routing_exceptions.hpp \
|
||||
routing_helpers.hpp \
|
||||
routing_mapping.hpp \
|
||||
routing_result_graph.hpp \
|
||||
|
@ -115,4 +117,5 @@ HEADERS += \
|
|||
turns_notification_manager.hpp \
|
||||
turns_sound_settings.hpp \
|
||||
turns_tts_text.hpp \
|
||||
vehicle_mask.hpp \
|
||||
vehicle_model.hpp \
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
|
||||
namespace routing
|
||||
{
|
||||
DECLARE_EXCEPTION(CorruptedDataException, RootException);
|
||||
DECLARE_EXCEPTION(RoutingException, RootException);
|
||||
} // namespace routing
|
|
@ -4,12 +4,17 @@
|
|||
#include "routing/car_model.hpp"
|
||||
#include "routing/edge_estimator.hpp"
|
||||
#include "routing/index_graph.hpp"
|
||||
#include "routing/index_graph_serialization.hpp"
|
||||
#include "routing/index_graph_starter.hpp"
|
||||
#include "routing/vehicle_mask.hpp"
|
||||
|
||||
#include "routing/routing_tests/index_graph_tools.hpp"
|
||||
|
||||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/writer.hpp"
|
||||
|
||||
#include "base/assert.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
|
@ -295,4 +300,64 @@ UNIT_TEST(RoadSpeed)
|
|||
vector<RoadPoint> const expectedRoute({{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}});
|
||||
TestRoute(graph, {0, 0}, {0, 4}, 5, &expectedRoute);
|
||||
}
|
||||
|
||||
//
|
||||
// Road R0 (ped) R1 (car) R2 (car)
|
||||
// 0----------1 * 0----------1 * 0----------1
|
||||
// Joints J0 J1
|
||||
//
|
||||
UNIT_TEST(SerializeSimpleGraph)
|
||||
{
|
||||
vector<uint8_t> buffer;
|
||||
{
|
||||
IndexGraph graph;
|
||||
vector<Joint> joints = {
|
||||
MakeJoint({{0, 1}, {1, 0}}), MakeJoint({{1, 1}, {2, 0}}),
|
||||
};
|
||||
graph.Import(joints);
|
||||
unordered_map<uint32_t, VehicleMask> masks;
|
||||
masks[0] = kPedestrianMask;
|
||||
masks[1] = kCarMask;
|
||||
masks[2] = kCarMask;
|
||||
|
||||
MemWriter<vector<uint8_t>> writer(buffer);
|
||||
IndexGraphSerializer::Serialize(graph, masks, writer);
|
||||
}
|
||||
|
||||
{
|
||||
IndexGraph graph;
|
||||
MemReader reader(buffer.data(), buffer.size());
|
||||
ReaderSource<MemReader> source(reader);
|
||||
IndexGraphSerializer::Deserialize(graph, source, kAllVehiclesMask);
|
||||
|
||||
TEST_EQUAL(graph.GetNumRoads(), 3, ());
|
||||
TEST_EQUAL(graph.GetNumJoints(), 2, ());
|
||||
TEST_EQUAL(graph.GetNumPoints(), 4, ());
|
||||
|
||||
TEST_EQUAL(graph.GetJointId({0, 0}), Joint::kInvalidId, ());
|
||||
TEST_EQUAL(graph.GetJointId({0, 1}), 1, ());
|
||||
TEST_EQUAL(graph.GetJointId({1, 0}), 1, ());
|
||||
TEST_EQUAL(graph.GetJointId({1, 1}), 0, ());
|
||||
TEST_EQUAL(graph.GetJointId({2, 0}), 0, ());
|
||||
TEST_EQUAL(graph.GetJointId({2, 1}), Joint::kInvalidId, ());
|
||||
}
|
||||
|
||||
{
|
||||
IndexGraph graph;
|
||||
MemReader reader(buffer.data(), buffer.size());
|
||||
ReaderSource<MemReader> source(reader);
|
||||
IndexGraphSerializer::Deserialize(graph, source, kCarMask);
|
||||
|
||||
TEST_EQUAL(graph.GetNumRoads(), 2, ());
|
||||
TEST_EQUAL(graph.GetNumJoints(), 1, ());
|
||||
TEST_EQUAL(graph.GetNumPoints(), 2, ());
|
||||
|
||||
TEST_EQUAL(graph.GetJointId({0, 0}), Joint::kInvalidId, ());
|
||||
TEST_EQUAL(graph.GetJointId({0, 1}), Joint::kInvalidId, ());
|
||||
TEST_EQUAL(graph.GetJointId({1, 0}), Joint::kInvalidId, ());
|
||||
TEST_EQUAL(graph.GetJointId({1, 1}), 0, ());
|
||||
TEST_EQUAL(graph.GetJointId({2, 0}), 0, ());
|
||||
TEST_EQUAL(graph.GetJointId({2, 1}), Joint::kInvalidId, ());
|
||||
}
|
||||
}
|
||||
} // namespace routing_test
|
||||
|
|
|
@ -6,14 +6,15 @@
|
|||
#include "routing/bicycle_model.hpp"
|
||||
#include "routing/car_model.hpp"
|
||||
#include "routing/index_graph.hpp"
|
||||
#include "routing/index_graph_serialization.hpp"
|
||||
#include "routing/index_graph_starter.hpp"
|
||||
#include "routing/pedestrian_model.hpp"
|
||||
#include "routing/route.hpp"
|
||||
#include "routing/routing_helpers.hpp"
|
||||
#include "routing/turns_generator.hpp"
|
||||
#include "routing/vehicle_mask.hpp"
|
||||
|
||||
#include "indexer/feature_altitude.hpp"
|
||||
#include "indexer/routing_section.hpp"
|
||||
|
||||
#include "geometry/distance.hpp"
|
||||
#include "geometry/mercator.hpp"
|
||||
|
@ -196,9 +197,7 @@ bool SingleMwmRouter::LoadIndex(MwmSet::MwmId const & mwmId, string const & coun
|
|||
my::Timer timer;
|
||||
FilesContainerR::TReader reader(mwmValue->m_cont.GetReader(ROUTING_FILE_TAG));
|
||||
ReaderSource<FilesContainerR::TReader> src(reader);
|
||||
feature::RoutingSectionHeader header;
|
||||
header.Deserialize(src);
|
||||
graph.Deserialize(src);
|
||||
IndexGraphSerializer::Deserialize(graph, src, kCarMask);
|
||||
LOG(LINFO,
|
||||
(ROUTING_FILE_TAG, "section for", country, "loaded in", timer.ElapsedSeconds(), "seconds"));
|
||||
return true;
|
||||
|
|
28
routing/vehicle_mask.hpp
Normal file
28
routing/vehicle_mask.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "std/cstdint.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
enum class VehicleType
|
||||
{
|
||||
Pedestrian = 0,
|
||||
Bicycle = 1,
|
||||
Car = 2,
|
||||
Count = 3
|
||||
};
|
||||
|
||||
using VehicleMask = uint32_t;
|
||||
|
||||
inline constexpr VehicleMask GetVehicleMask(VehicleType vehicleType)
|
||||
{
|
||||
return static_cast<VehicleMask>(1) << static_cast<uint32_t>(vehicleType);
|
||||
}
|
||||
|
||||
VehicleMask constexpr kNumVehicleMasks = GetVehicleMask(VehicleType::Count);
|
||||
VehicleMask constexpr kAllVehiclesMask = kNumVehicleMasks - 1;
|
||||
|
||||
VehicleMask constexpr kPedestrianMask = GetVehicleMask(VehicleType::Pedestrian);
|
||||
VehicleMask constexpr kBicycleMask = GetVehicleMask(VehicleType::Bicycle);
|
||||
VehicleMask constexpr kCarMask = GetVehicleMask(VehicleType::Car);
|
||||
} // namespace routing
|
|
@ -7,11 +7,14 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0C08AA341DF83223004195DD /* index_graph_serialization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C08AA321DF83223004195DD /* index_graph_serialization.cpp */; };
|
||||
0C08AA351DF83223004195DD /* index_graph_serialization.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C08AA331DF83223004195DD /* index_graph_serialization.hpp */; };
|
||||
0C08AA371DF8324D004195DD /* vehicle_mask.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C08AA361DF8324D004195DD /* vehicle_mask.hpp */; };
|
||||
0C08AA391DF8329B004195DD /* routing_exceptions.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C08AA381DF8329B004195DD /* routing_exceptions.hpp */; };
|
||||
0C0DF9211DE898B70055A22F /* index_graph_starter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C0DF91F1DE898B70055A22F /* index_graph_starter.cpp */; };
|
||||
0C0DF9221DE898B70055A22F /* index_graph_starter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C0DF9201DE898B70055A22F /* index_graph_starter.hpp */; };
|
||||
0C0DF9251DE898CF0055A22F /* single_mwm_router.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C0DF9231DE898CF0055A22F /* single_mwm_router.cpp */; };
|
||||
0C0DF9261DE898CF0055A22F /* single_mwm_router.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C0DF9241DE898CF0055A22F /* single_mwm_router.hpp */; };
|
||||
0C0DF9291DE898FF0055A22F /* routing_exception.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C0DF9271DE898FF0055A22F /* routing_exception.hpp */; };
|
||||
0C0DF92A1DE898FF0055A22F /* routing_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C0DF9281DE898FF0055A22F /* routing_helpers.cpp */; };
|
||||
0C5FEC541DDE191E0017688C /* edge_estimator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC521DDE191E0017688C /* edge_estimator.cpp */; };
|
||||
0C5FEC551DDE191E0017688C /* edge_estimator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC531DDE191E0017688C /* edge_estimator.hpp */; };
|
||||
|
@ -239,11 +242,14 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0C08AA321DF83223004195DD /* index_graph_serialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_graph_serialization.cpp; sourceTree = "<group>"; };
|
||||
0C08AA331DF83223004195DD /* index_graph_serialization.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = index_graph_serialization.hpp; sourceTree = "<group>"; };
|
||||
0C08AA361DF8324D004195DD /* vehicle_mask.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = vehicle_mask.hpp; sourceTree = "<group>"; };
|
||||
0C08AA381DF8329B004195DD /* routing_exceptions.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_exceptions.hpp; sourceTree = "<group>"; };
|
||||
0C0DF91F1DE898B70055A22F /* index_graph_starter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_graph_starter.cpp; sourceTree = "<group>"; };
|
||||
0C0DF9201DE898B70055A22F /* index_graph_starter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = index_graph_starter.hpp; sourceTree = "<group>"; };
|
||||
0C0DF9231DE898CF0055A22F /* single_mwm_router.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = single_mwm_router.cpp; sourceTree = "<group>"; };
|
||||
0C0DF9241DE898CF0055A22F /* single_mwm_router.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = single_mwm_router.hpp; sourceTree = "<group>"; };
|
||||
0C0DF9271DE898FF0055A22F /* routing_exception.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_exception.hpp; sourceTree = "<group>"; };
|
||||
0C0DF9281DE898FF0055A22F /* routing_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = routing_helpers.cpp; sourceTree = "<group>"; };
|
||||
0C5FEC521DDE191E0017688C /* edge_estimator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = edge_estimator.cpp; sourceTree = "<group>"; };
|
||||
0C5FEC531DDE191E0017688C /* edge_estimator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = edge_estimator.hpp; sourceTree = "<group>"; };
|
||||
|
@ -673,6 +679,8 @@
|
|||
0C5FEC591DDE192A0017688C /* index_graph.hpp */,
|
||||
0C5FEC5A1DDE192A0017688C /* joint_index.cpp */,
|
||||
0C5FEC5B1DDE192A0017688C /* joint_index.hpp */,
|
||||
0C08AA321DF83223004195DD /* index_graph_serialization.cpp */,
|
||||
0C08AA331DF83223004195DD /* index_graph_serialization.hpp */,
|
||||
0C0DF91F1DE898B70055A22F /* index_graph_starter.cpp */,
|
||||
0C0DF9201DE898B70055A22F /* index_graph_starter.hpp */,
|
||||
0C5FEC5C1DDE192A0017688C /* joint.cpp */,
|
||||
|
@ -693,7 +701,7 @@
|
|||
0C5FEC661DDE193F0017688C /* road_index.cpp */,
|
||||
0C5FEC671DDE193F0017688C /* road_index.hpp */,
|
||||
0C5FEC681DDE193F0017688C /* road_point.hpp */,
|
||||
0C0DF9271DE898FF0055A22F /* routing_exception.hpp */,
|
||||
0C08AA381DF8329B004195DD /* routing_exceptions.hpp */,
|
||||
0C0DF9281DE898FF0055A22F /* routing_helpers.cpp */,
|
||||
0C0DF9231DE898CF0055A22F /* single_mwm_router.cpp */,
|
||||
0C0DF9241DE898CF0055A22F /* single_mwm_router.hpp */,
|
||||
|
@ -755,6 +763,7 @@
|
|||
6753440F1A3F644F00A0A8C3 /* router.hpp */,
|
||||
675344101A3F644F00A0A8C3 /* turns.cpp */,
|
||||
675344111A3F644F00A0A8C3 /* turns.hpp */,
|
||||
0C08AA361DF8324D004195DD /* vehicle_mask.hpp */,
|
||||
675344121A3F644F00A0A8C3 /* vehicle_model.cpp */,
|
||||
675344131A3F644F00A0A8C3 /* vehicle_model.hpp */,
|
||||
);
|
||||
|
@ -787,6 +796,7 @@
|
|||
0C5FEC631DDE192A0017688C /* joint_index.hpp in Headers */,
|
||||
67AB92E51B7B3E6E00AB5194 /* routing_mapping.hpp in Headers */,
|
||||
674F9BCB1B0A580E00704FFA /* async_router.hpp in Headers */,
|
||||
0C08AA391DF8329B004195DD /* routing_exceptions.hpp in Headers */,
|
||||
674F9BD11B0A580E00704FFA /* online_cross_fetcher.hpp in Headers */,
|
||||
A120B3531B4A7C1C002F3808 /* astar_algorithm.hpp in Headers */,
|
||||
0C5FEC5F1DDE192A0017688C /* geometry.hpp in Headers */,
|
||||
|
@ -805,7 +815,6 @@
|
|||
A120B3461B4A7BE5002F3808 /* cross_mwm_road_graph.hpp in Headers */,
|
||||
6753441C1A3F644F00A0A8C3 /* route.hpp in Headers */,
|
||||
A1616E2C1B6B60AB003F078E /* router_delegate.hpp in Headers */,
|
||||
0C0DF9291DE898FF0055A22F /* routing_exception.hpp in Headers */,
|
||||
A17B42991BCFBD0E00A1EAE4 /* osrm_helpers.hpp in Headers */,
|
||||
67C7D42E1B4EB48F00FE41AA /* turns_sound_settings.hpp in Headers */,
|
||||
56099E341CC9247E00A7772A /* bicycle_directions.hpp in Headers */,
|
||||
|
@ -817,6 +826,7 @@
|
|||
0C5FEC6A1DDE193F0017688C /* road_index.hpp in Headers */,
|
||||
674F9BCD1B0A580E00704FFA /* features_road_graph.hpp in Headers */,
|
||||
670EE5741B664796001E8064 /* pedestrian_directions.hpp in Headers */,
|
||||
0C08AA371DF8324D004195DD /* vehicle_mask.hpp in Headers */,
|
||||
6753441D1A3F644F00A0A8C3 /* router.hpp in Headers */,
|
||||
A1616E2E1B6B60B3003F078E /* astar_progress.hpp in Headers */,
|
||||
670EE5721B664796001E8064 /* directions_engine.hpp in Headers */,
|
||||
|
@ -825,6 +835,7 @@
|
|||
0C0DF9221DE898B70055A22F /* index_graph_starter.hpp in Headers */,
|
||||
56099E2F1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp in Headers */,
|
||||
67C7D42A1B4EB48F00FE41AA /* car_model.hpp in Headers */,
|
||||
0C08AA351DF83223004195DD /* index_graph_serialization.hpp in Headers */,
|
||||
670D049F1B0B4A970013A7AC /* nearest_edge_finder.hpp in Headers */,
|
||||
A120B34F1B4A7C0A002F3808 /* online_absent_fetcher.hpp in Headers */,
|
||||
674F9BD51B0A580E00704FFA /* road_graph.hpp in Headers */,
|
||||
|
@ -1081,6 +1092,7 @@
|
|||
67C7D4291B4EB48F00FE41AA /* car_model.cpp in Sources */,
|
||||
56099E331CC9247E00A7772A /* bicycle_directions.cpp in Sources */,
|
||||
674A28B11B1605D2001A525C /* osrm_engine.cpp in Sources */,
|
||||
0C08AA341DF83223004195DD /* index_graph_serialization.cpp in Sources */,
|
||||
674F9BD41B0A580E00704FFA /* road_graph.cpp in Sources */,
|
||||
0C0DF92A1DE898FF0055A22F /* routing_helpers.cpp in Sources */,
|
||||
67AB92E61B7B3E6E00AB5194 /* turns_tts_text.cpp in Sources */,
|
||||
|
|
Loading…
Add table
Reference in a new issue