Merge pull request #4854 from dobriy-eeh/compress-routing-section

Routing section compression
This commit is contained in:
Vladimir Byko-Ianko 2016-12-07 18:43:24 +03:00 committed by GitHub
commit 87771aaee4
22 changed files with 770 additions and 140 deletions

View file

@ -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)
{

View file

@ -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)

View file

@ -4,5 +4,5 @@
namespace routing
{
bool BuildRoutingIndex(string const & filename);
bool BuildRoutingIndex(string const & filename, string const & country);
} // namespace routing

View file

@ -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 \

View file

@ -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

View file

@ -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
)

View file

@ -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);

View file

@ -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;
};

View file

@ -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;

View file

@ -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;

View 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

View 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

View file

@ -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;

View file

@ -1,6 +1,6 @@
#include "routing/joint_index.hpp"
#include "routing/routing_exception.hpp"
#include "routing/routing_exceptions.hpp"
namespace routing
{

View file

@ -1,6 +1,6 @@
#include "routing/road_index.hpp"
#include "routing/routing_exception.hpp"
#include "routing/routing_exceptions.hpp"
namespace routing
{

View file

@ -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

View file

@ -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 \

View file

@ -4,5 +4,6 @@
namespace routing
{
DECLARE_EXCEPTION(CorruptedDataException, RootException);
DECLARE_EXCEPTION(RoutingException, RootException);
} // namespace routing

View file

@ -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

View file

@ -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
View 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

View file

@ -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 */,