Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--android/src/com/mapswithme/maps/routing/NavigationController.java9
-rw-r--r--coding/file_name_utils.hpp13
-rw-r--r--data/countries_meta.txt3
-rw-r--r--defines.hpp1
-rw-r--r--generator/generator_tool/generator_tool.cpp8
-rw-r--r--generator/routing_index_generator.cpp171
-rw-r--r--generator/routing_index_generator.hpp1
-rw-r--r--map/framework.cpp5
-rw-r--r--map/framework.hpp5
-rw-r--r--routing/CMakeLists.txt4
-rw-r--r--routing/cross_mwm_connector.cpp136
-rw-r--r--routing/cross_mwm_connector.hpp139
-rw-r--r--routing/cross_mwm_connector_serialization.cpp30
-rw-r--r--routing/cross_mwm_connector_serialization.hpp353
-rw-r--r--routing/edge_estimator.cpp23
-rw-r--r--routing/routing.pro4
-rw-r--r--routing/routing_tests/CMakeLists.txt1
-rw-r--r--routing/routing_tests/cross_mwm_connector_test.cpp239
-rw-r--r--routing/routing_tests/routing_tests.pro1
-rw-r--r--routing/segment.hpp12
-rw-r--r--search/nearby_points_sweeper.hpp1
-rw-r--r--search/search_quality/assessment_tool/CMakeLists.txt10
-rw-r--r--search/search_quality/assessment_tool/assessment_tool.cpp (renamed from search/search_quality/assessment_tool/assessment_tool.cc)6
-rw-r--r--search/search_quality/assessment_tool/helpers.cpp13
-rw-r--r--search/search_quality/assessment_tool/helpers.hpp22
-rw-r--r--search/search_quality/assessment_tool/languages_list.cpp21
-rw-r--r--search/search_quality/assessment_tool/languages_list.hpp15
-rw-r--r--search/search_quality/assessment_tool/main_model.cpp45
-rw-r--r--search/search_quality/assessment_tool/main_model.hpp17
-rw-r--r--search/search_quality/assessment_tool/main_view.cpp99
-rw-r--r--search/search_quality/assessment_tool/main_view.hpp24
-rw-r--r--search/search_quality/assessment_tool/sample_view.cpp106
-rw-r--r--search/search_quality/assessment_tool/sample_view.hpp28
-rw-r--r--search/search_quality/assessment_tool/samples_view.cpp29
-rw-r--r--search/search_quality/assessment_tool/samples_view.hpp20
-rw-r--r--search/search_quality/assessment_tool/view.hpp2
-rw-r--r--xcode/routing/routing.xcodeproj/project.pbxproj20
37 files changed, 1530 insertions, 106 deletions
diff --git a/android/src/com/mapswithme/maps/routing/NavigationController.java b/android/src/com/mapswithme/maps/routing/NavigationController.java
index dc42b35ef2..4e43bf7b98 100644
--- a/android/src/com/mapswithme/maps/routing/NavigationController.java
+++ b/android/src/com/mapswithme/maps/routing/NavigationController.java
@@ -30,7 +30,9 @@ import com.mapswithme.util.statistics.AlohaHelper;
import com.mapswithme.util.statistics.Statistics;
import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.Locale;
import java.util.concurrent.TimeUnit;
public class NavigationController implements TrafficManager.TrafficCallback
@@ -281,8 +283,11 @@ public class NavigationController implements TrafficManager.TrafficCallback
{
final Calendar currentTime = Calendar.getInstance();
currentTime.add(Calendar.SECOND, seconds);
- UiUtils.setTextAndShow(mTimeMinuteValue, DateFormat.getTimeInstance(DateFormat.SHORT)
- .format(currentTime.getTime()));
+ final DateFormat timeFormat12 = new SimpleDateFormat("h:mm aa", Locale.getDefault());
+ final DateFormat timeFormat24 = new SimpleDateFormat("HH:mm", Locale.getDefault());
+ boolean is24Format = android.text.format.DateFormat.is24HourFormat(mTimeMinuteValue.getContext());
+ UiUtils.setTextAndShow(mTimeMinuteValue, is24Format ? timeFormat24.format(currentTime.getTime())
+ : timeFormat12.format(currentTime.getTime()));
UiUtils.hide(mTimeHourUnits, mTimeHourValue, mTimeMinuteUnits);
}
diff --git a/coding/file_name_utils.hpp b/coding/file_name_utils.hpp
index 1e3ffe83d1..4bcb32f616 100644
--- a/coding/file_name_utils.hpp
+++ b/coding/file_name_utils.hpp
@@ -3,6 +3,8 @@
#include "std/initializer_list.hpp"
#include "std/string.hpp"
+#include <utility>
+
namespace my
{
/// Remove extension from file name.
@@ -22,10 +24,19 @@ namespace my
/// Get folder separator for specific platform
string GetNativeSeparator();
- /// Create full path from some folder using native folders separator
+ /// @deprecated use JoinPath instead.
string JoinFoldersToPath(const string & folder, const string & file);
string JoinFoldersToPath(initializer_list<string> const & folders, const string & file);
/// Add the terminating slash to the folder path string if it's not already there.
string AddSlashIfNeeded(string const & path);
+
+ inline std::string JoinPath(std::string const & file) { return file; }
+
+ /// Create full path from some folder using native folders separator.
+ template<typename... Args>
+ std::string JoinPath(std::string const & folder, Args&&... args)
+ {
+ return AddSlashIfNeeded(folder) + JoinPath(std::forward<Args>(args)...);
+ }
}
diff --git a/data/countries_meta.txt b/data/countries_meta.txt
index d3020f5e9c..fa88d2ec00 100644
--- a/data/countries_meta.txt
+++ b/data/countries_meta.txt
@@ -546,6 +546,9 @@
"Taiwan": {
"languages": ["zh"]
},
+"Panama": {
+ "languages": ["es"]
+},
"Peru": {
"languages": ["es"]
},
diff --git a/defines.hpp b/defines.hpp
index ea9796a2b4..c8d87a2e8f 100644
--- a/defines.hpp
+++ b/defines.hpp
@@ -29,6 +29,7 @@
#define ALTITUDES_FILE_TAG "altitudes"
#define RESTRICTIONS_FILE_TAG "restrictions"
#define ROUTING_FILE_TAG "routing"
+#define CROSS_MWM_FILE_TAG "cross_mwm"
#define FEATURE_OFFSETS_FILE_TAG "offs"
#define RANKS_FILE_TAG "ranks"
#define REGION_INFO_FILE_TAG "rgninfo"
diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp
index 151b9d5655..3cbcd60940 100644
--- a/generator/generator_tool/generator_tool.cpp
+++ b/generator/generator_tool/generator_tool.cpp
@@ -69,8 +69,9 @@ DEFINE_bool(split_by_polygons, false,
// Routing.
DEFINE_string(osrm_file_name, "", "Input osrm file to generate routing info.");
DEFINE_bool(make_routing, false, "Make routing info based on osrm file.");
-DEFINE_bool(make_cross_section, false, "Make cross section in routing file for cross mwm routing.");
+DEFINE_bool(make_cross_section, false, "Make cross section in routing file for cross mwm routing (for OSRM routing).");
DEFINE_bool(make_routing_index, false, "Make sections with the routing information.");
+DEFINE_bool(make_cross_mwm, false, "Make section for cross mwm routing (for dynamic indexed routing).");
DEFINE_string(srtm_path, "",
"Path to srtm directory. If set, generates a section with altitude information "
"about roads.");
@@ -161,7 +162,7 @@ int main(int argc, char ** argv)
FLAGS_generate_index || FLAGS_generate_search_index || FLAGS_calc_statistics ||
FLAGS_type_statistics || FLAGS_dump_types || FLAGS_dump_prefixes ||
FLAGS_dump_feature_names != "" || FLAGS_check_mwm || FLAGS_srtm_path != "" ||
- FLAGS_make_routing_index || FLAGS_generate_traffic_keys)
+ FLAGS_make_routing_index || FLAGS_make_cross_mwm || FLAGS_generate_traffic_keys)
{
classificator::Load();
classif().SortClassificator();
@@ -256,6 +257,9 @@ int main(int argc, char ** argv)
routing::BuildRoutingIndex(datFile, country);
}
+ if (FLAGS_make_cross_mwm)
+ routing::BuildCrossMwmSection(path, datFile, country);
+
if (FLAGS_generate_traffic_keys)
{
if (!traffic::GenerateTrafficKeysFromDataFile(datFile))
diff --git a/generator/routing_index_generator.cpp b/generator/routing_index_generator.cpp
index 6db5e03755..e141dee0f8 100644
--- a/generator/routing_index_generator.cpp
+++ b/generator/routing_index_generator.cpp
@@ -1,5 +1,10 @@
#include "generator/routing_index_generator.hpp"
+#include "generator/borders_generator.hpp"
+#include "generator/borders_loader.hpp"
+
+#include "routing/cross_mwm_connector.hpp"
+#include "routing/cross_mwm_connector_serialization.hpp"
#include "routing/index_graph.hpp"
#include "routing/index_graph_serialization.hpp"
#include "routing/vehicle_mask.hpp"
@@ -8,19 +13,22 @@
#include "routing_common/car_model.hpp"
#include "routing_common/pedestrian_model.hpp"
+#include "indexer/coding_params.hpp"
+#include "indexer/data_header.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_processor.hpp"
#include "indexer/point_to_int64.hpp"
#include "coding/file_container.hpp"
+#include "coding/file_name_utils.hpp"
#include "base/checked_cast.hpp"
#include "base/logging.hpp"
-#include "std/bind.hpp"
-#include "std/shared_ptr.hpp"
-#include "std/unordered_map.hpp"
-#include "std/vector.hpp"
+#include <functional>
+#include <memory>
+#include <unordered_map>
+#include <vector>
using namespace feature;
using namespace platform;
@@ -28,10 +36,10 @@ using namespace routing;
namespace
{
-class Processor final
+class VehicleMaskBuilder final
{
public:
- explicit Processor(string const & country)
+ explicit VehicleMaskBuilder(string const & country)
: m_pedestrianModel(PedestrianModelFactory().GetVehicleModelForCountry(country))
, m_bicycleModel(BicycleModelFactory().GetVehicleModelForCountry(country))
, m_carModel(CarModelFactory().GetVehicleModelForCountry(country))
@@ -41,6 +49,42 @@ public:
CHECK(m_carModel, ());
}
+ VehicleMask CalcRoadMask(FeatureType const & f) const
+ {
+ return CalcMask(
+ f, [&](IVehicleModel const & model, FeatureType const & f) { return model.IsRoad(f); });
+ }
+
+ VehicleMask CalcOneWayMask(FeatureType const & f) const
+ {
+ return CalcMask(
+ f, [&](IVehicleModel const & model, FeatureType const & f) { return model.IsOneWay(f); });
+ }
+
+private:
+ template <class Fn>
+ VehicleMask CalcMask(FeatureType const & f, Fn && fn) const
+ {
+ VehicleMask mask = 0;
+ if (fn(*m_pedestrianModel, f))
+ mask |= kPedestrianMask;
+ if (fn(*m_bicycleModel, f))
+ mask |= kBicycleMask;
+ if (fn(*m_carModel, f))
+ mask |= kCarMask;
+
+ return mask;
+ }
+
+ shared_ptr<IVehicleModel> const m_pedestrianModel;
+ shared_ptr<IVehicleModel> const m_bicycleModel;
+ shared_ptr<IVehicleModel> const m_carModel;
+};
+
+class Processor final
+{
+public:
+ explicit Processor(string const & country) : m_maskBuilder(country) {}
void ProcessAllFeatures(string const & filename)
{
feature::ForEachFromDat(filename, bind(&Processor::ProcessFeature, this, _1, _2));
@@ -60,11 +104,10 @@ public:
}
unordered_map<uint32_t, VehicleMask> const & GetMasks() const { return m_masks; }
-
private:
void ProcessFeature(FeatureType const & f, uint32_t id)
{
- VehicleMask const mask = CalcVehicleMask(f);
+ VehicleMask const mask = m_maskBuilder.CalcRoadMask(f);
if (mask == 0)
return;
@@ -78,25 +121,79 @@ 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;
+ VehicleMaskBuilder const m_maskBuilder;
unordered_map<uint64_t, Joint> m_posToJoint;
unordered_map<uint32_t, VehicleMask> m_masks;
};
+
+bool RegionsContain(vector<m2::RegionD> const & regions, m2::PointD const & point)
+{
+ for (auto const & region : regions)
+ {
+ if (region.Contains(point))
+ return true;
+ }
+
+ return false;
+}
+
+void CalcCrossMwmTransitions(string const & path, string const & mwmFile, string const & country,
+ vector<CrossMwmConnectorSerializer::Transition> & transitions,
+ CrossMwmConnectorPerVehicleType & connectors)
+{
+ string const polyFile = my::JoinPath(path, BORDERS_DIR, country + BORDERS_EXTENSION);
+ vector<m2::RegionD> borders;
+ osm::LoadBorders(polyFile, borders);
+
+ VehicleMaskBuilder const maskMaker(country);
+
+ feature::ForEachFromDat(mwmFile, [&](FeatureType const & f, uint32_t featureId) {
+ VehicleMask const roadMask = maskMaker.CalcRoadMask(f);
+ if (roadMask == 0)
+ return;
+
+ f.ParseGeometry(FeatureType::BEST_GEOMETRY);
+ size_t const pointsCount = f.GetPointsCount();
+ if (pointsCount == 0)
+ return;
+
+ bool prevPointIn = RegionsContain(borders, f.GetPoint(0));
+
+ for (size_t i = 1; i < pointsCount; ++i)
+ {
+ bool const currPointIn = RegionsContain(borders, f.GetPoint(i));
+ if (currPointIn == prevPointIn)
+ continue;
+
+ uint32_t const segmentIdx = base::asserted_cast<uint32_t>(i - 1);
+ VehicleMask const oneWayMask = maskMaker.CalcOneWayMask(f);
+
+ transitions.emplace_back(featureId, segmentIdx, roadMask, oneWayMask, currPointIn,
+ f.GetPoint(i - 1), f.GetPoint(i));
+
+ for (size_t j = 0; j < connectors.size(); ++j)
+ {
+ VehicleMask const mask = GetVehicleMask(static_cast<VehicleType>(j));
+ CrossMwmConnectorSerializer::AddTransition(transitions.back(), mask, connectors[j]);
+ }
+
+ prevPointIn = currPointIn;
+ }
+ });
+}
+
+void FillWeights(string const & path, string const & country, CrossMwmConnector & connector)
+{
+ shared_ptr<IVehicleModel> vehicleModel = CarModelFactory().GetVehicleModelForCountry(country);
+ shared_ptr<EdgeEstimator> estimator =
+ EdgeEstimator::CreateForCar(nullptr /* trafficStash */, vehicleModel->GetMaxSpeed());
+
+ connector.FillWeights([&](Segment const & enter, Segment const & exit) {
+ // TODO replace fake weights with weights calculated by routing.
+ return estimator->CalcHeuristic(connector.GetPoint(enter, true /* front */),
+ connector.GetPoint(exit, true /* front */));
+ });
+}
} // namespace
namespace routing
@@ -129,4 +226,30 @@ bool BuildRoutingIndex(string const & filename, string const & country)
return false;
}
}
+
+void BuildCrossMwmSection(string const & path, string const & mwmFile, string const & country)
+{
+ LOG(LINFO, ("Building cross mwm section for", country));
+ my::Timer timer;
+
+ CrossMwmConnectorPerVehicleType connectors;
+
+ vector<CrossMwmConnectorSerializer::Transition> transitions;
+ CalcCrossMwmTransitions(path, mwmFile, country, transitions, connectors);
+
+ FillWeights(path, country, connectors[static_cast<size_t>(VehicleType::Car)]);
+
+ FilesContainerW cont(mwmFile, FileWriter::OP_WRITE_EXISTING);
+ FileWriter writer = cont.GetWriter(CROSS_MWM_FILE_TAG);
+
+ DataHeader const dataHeader(mwmFile);
+ serial::CodingParams const & codingParams = dataHeader.GetDefCodingParams();
+
+ auto const startPos = writer.Pos();
+ CrossMwmConnectorSerializer::Serialize(transitions, connectors, codingParams, writer);
+ auto const sectionSize = writer.Pos() - startPos;
+
+ LOG(LINFO, ("Cross mwm section for", country, "generated in", timer.ElapsedSeconds(),
+ "seconds, section size:", sectionSize, "bytes, transitions:", transitions.size()));
+}
} // namespace routing
diff --git a/generator/routing_index_generator.hpp b/generator/routing_index_generator.hpp
index f5158c904d..6d70078618 100644
--- a/generator/routing_index_generator.hpp
+++ b/generator/routing_index_generator.hpp
@@ -5,4 +5,5 @@
namespace routing
{
bool BuildRoutingIndex(string const & filename, string const & country);
+void BuildCrossMwmSection(string const & path, string const & mwmFile, string const & country);
} // namespace routing
diff --git a/map/framework.cpp b/map/framework.cpp
index 6094a12a64..1656ca4631 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -1089,9 +1089,10 @@ void Framework::SetVisibleViewport(m2::RectD const & rect)
m_drapeEngine->SetVisibleViewport(rect);
}
-void Framework::ShowRect(m2::RectD const & rect, int maxScale)
+void Framework::ShowRect(m2::RectD const & rect, int maxScale, bool animation)
{
- CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewRect, _1, rect, true, maxScale, true));
+ CallDrapeFunction(bind(&df::DrapeEngine::SetModelViewRect, _1, rect, true /* applyRotation */,
+ maxScale /* zoom */, animation));
}
void Framework::ShowRect(m2::AnyRectD const & rect)
diff --git a/map/framework.hpp b/map/framework.hpp
index 3c380674ae..5a85619b38 100644
--- a/map/framework.hpp
+++ b/map/framework.hpp
@@ -275,6 +275,9 @@ public:
Index const & GetIndex() const { return m_model.GetIndex(); }
+ search::Engine & GetSearchEngine() { return *m_searchEngine; }
+ search::Engine const & GetSearchEngine() const { return *m_searchEngine; }
+
/// @name Bookmarks, Tracks and other UserMarks
//@{
/// Scans and loads all kml files with bookmarks in WritableDir.
@@ -571,7 +574,7 @@ public:
void SetVisibleViewport(m2::RectD const & rect);
/// - Check minimal visible scale according to downloaded countries.
- void ShowRect(m2::RectD const & rect, int maxScale = -1);
+ void ShowRect(m2::RectD const & rect, int maxScale = -1, bool animation = true);
void ShowRect(m2::AnyRectD const & rect);
void GetTouchRect(m2::PointD const & center, uint32_t pxRadius, m2::AnyRectD & rect);
diff --git a/routing/CMakeLists.txt b/routing/CMakeLists.txt
index be86001356..16b4374e17 100644
--- a/routing/CMakeLists.txt
+++ b/routing/CMakeLists.txt
@@ -18,6 +18,10 @@ set(
bicycle_directions.hpp
car_router.cpp
car_router.hpp
+ cross_mwm_connector.cpp
+ cross_mwm_connector.hpp
+ cross_mwm_connector_serialization.cpp
+ cross_mwm_connector_serialization.hpp
cross_mwm_index_graph.cpp
cross_mwm_index_graph.hpp
cross_mwm_road_graph.cpp
diff --git a/routing/cross_mwm_connector.cpp b/routing/cross_mwm_connector.cpp
new file mode 100644
index 0000000000..cf6d62469f
--- /dev/null
+++ b/routing/cross_mwm_connector.cpp
@@ -0,0 +1,136 @@
+#include "routing/cross_mwm_connector.hpp"
+
+namespace
+{
+uint32_t constexpr kFakeId = std::numeric_limits<uint32_t>::max();
+} // namespace
+
+namespace routing
+{
+// static
+CrossMwmConnector::Weight constexpr CrossMwmConnector::kNoRoute;
+
+void CrossMwmConnector::AddTransition(uint32_t featureId, uint32_t segmentIdx, bool oneWay,
+ bool forwardIsEnter, m2::PointD const & backPoint,
+ m2::PointD const & frontPoint)
+{
+ Transition transition(kFakeId, kFakeId, oneWay, forwardIsEnter, backPoint, frontPoint);
+
+ if (forwardIsEnter)
+ {
+ transition.m_enterIdx = base::asserted_cast<uint32_t>(m_enters.size());
+ m_enters.emplace_back(m_mwmId, featureId, segmentIdx, true /* forward */);
+ }
+ else
+ {
+ transition.m_exitIdx = base::asserted_cast<uint32_t>(m_exits.size());
+ m_exits.emplace_back(m_mwmId, featureId, segmentIdx, true /* forward */);
+ }
+
+ if (!oneWay)
+ {
+ if (forwardIsEnter)
+ {
+ transition.m_exitIdx = base::asserted_cast<uint32_t>(m_exits.size());
+ m_exits.emplace_back(m_mwmId, featureId, segmentIdx, false /* forward */);
+ }
+ else
+ {
+ transition.m_enterIdx = base::asserted_cast<uint32_t>(m_enters.size());
+ m_enters.emplace_back(m_mwmId, featureId, segmentIdx, false /* forward */);
+ }
+ }
+
+ m_transitions[Key(featureId, segmentIdx)] = transition;
+}
+
+bool CrossMwmConnector::IsTransition(Segment const & segment, bool isOutgoing) const
+{
+ auto it = m_transitions.find(Key(segment.GetFeatureId(), segment.GetSegmentIdx()));
+ if (it == m_transitions.cend())
+ return false;
+
+ Transition const & transition = it->second;
+ if (transition.m_oneWay && !segment.IsForward())
+ return false;
+
+ return (segment.IsForward() == transition.m_forwardIsEnter) == isOutgoing;
+}
+
+m2::PointD const & CrossMwmConnector::GetPoint(Segment const & segment, bool front) const
+{
+ Transition const & transition = GetTransition(segment);
+ return segment.IsForward() == front ? transition.m_frontPoint : transition.m_backPoint;
+}
+
+void CrossMwmConnector::GetEdgeList(Segment const & segment, bool isOutgoing,
+ std::vector<SegmentEdge> & edges) const
+{
+ Transition const & transition = GetTransition(segment);
+ if (isOutgoing)
+ {
+ ASSERT_NOT_EQUAL(transition.m_enterIdx, kFakeId, ());
+ for (size_t exitIdx = 0; exitIdx < m_exits.size(); ++exitIdx)
+ {
+ Weight const weight = GetWeight(base::asserted_cast<size_t>(transition.m_enterIdx), exitIdx);
+ AddEdge(m_exits[exitIdx], weight, edges);
+ }
+ }
+ else
+ {
+ ASSERT_NOT_EQUAL(transition.m_exitIdx, kFakeId, ());
+ for (size_t enterIdx = 0; enterIdx < m_enters.size(); ++enterIdx)
+ {
+ Weight const weight = GetWeight(enterIdx, base::asserted_cast<size_t>(transition.m_exitIdx));
+ AddEdge(m_enters[enterIdx], weight, edges);
+ }
+ }
+}
+
+bool CrossMwmConnector::WeightsWereLoaded() const
+{
+ switch (m_weightsLoadState)
+ {
+ case WeightsLoadState::Unknown:
+ case WeightsLoadState::ReadyToLoad: return false;
+ case WeightsLoadState::NotExists:
+ case WeightsLoadState::Loaded: return true;
+ }
+}
+
+std::string DebugPrint(CrossMwmConnector::WeightsLoadState state)
+{
+ switch (state)
+ {
+ case CrossMwmConnector::WeightsLoadState::Unknown: return "Unknown";
+ case CrossMwmConnector::WeightsLoadState::ReadyToLoad: return "ReadyToLoad";
+ case CrossMwmConnector::WeightsLoadState::NotExists: return "NotExists";
+ case CrossMwmConnector::WeightsLoadState::Loaded: return "Loaded";
+ }
+}
+
+void CrossMwmConnector::AddEdge(Segment const & segment, Weight weight,
+ std::vector<SegmentEdge> & edges) const
+{
+ if (weight != kNoRoute)
+ edges.emplace_back(segment, static_cast<double>(weight));
+}
+
+CrossMwmConnector::Transition const & CrossMwmConnector::GetTransition(
+ Segment const & segment) const
+{
+ auto it = m_transitions.find(Key(segment.GetFeatureId(), segment.GetSegmentIdx()));
+ CHECK(it != m_transitions.cend(), ("Not a transition segment:", segment));
+ return it->second;
+}
+
+CrossMwmConnector::Weight CrossMwmConnector::GetWeight(size_t enterIdx, size_t exitIdx) const
+{
+ ASSERT_LESS(enterIdx, m_enters.size(), ());
+ ASSERT_LESS(exitIdx, m_exits.size(), ());
+
+ size_t const i = enterIdx * m_exits.size() + exitIdx;
+ ASSERT_LESS(i, m_weights.size(), ());
+ return m_weights[i];
+}
+} // namespace routing
diff --git a/routing/cross_mwm_connector.hpp b/routing/cross_mwm_connector.hpp
new file mode 100644
index 0000000000..22ef84de61
--- /dev/null
+++ b/routing/cross_mwm_connector.hpp
@@ -0,0 +1,139 @@
+#pragma once
+
+#include "routing/segment.hpp"
+
+#include "geometry/point2d.hpp"
+
+#include "base/assert.hpp"
+
+#include <cmath>
+#include <limits>
+#include <unordered_map>
+#include <vector>
+
+namespace routing
+{
+class CrossMwmConnector final
+{
+public:
+ CrossMwmConnector() : m_mwmId(kFakeNumMwmId) {}
+ explicit CrossMwmConnector(NumMwmId mwmId) : m_mwmId(mwmId) {}
+
+ void AddTransition(uint32_t featureId, uint32_t segmentIdx, bool oneWay, bool forwardIsEnter,
+ m2::PointD const & backPoint, m2::PointD const & frontPoint);
+
+ bool IsTransition(Segment const & segment, bool isOutgoing) const;
+ m2::PointD const & GetPoint(Segment const & segment, bool front) const;
+ void GetEdgeList(Segment const & segment, bool isOutgoing,
+ std::vector<SegmentEdge> & edges) const;
+
+ std::vector<Segment> const & GetEnters() const { return m_enters; }
+ std::vector<Segment> const & GetExits() const { return m_exits; }
+ bool HasWeights() const { return !m_weights.empty(); }
+ bool WeightsWereLoaded() const;
+
+ template <typename CalcWeight>
+ void FillWeights(CalcWeight && calcWeight)
+ {
+ CHECK_EQUAL(m_weightsLoadState, WeightsLoadState::Unknown, ());
+ CHECK(m_weights.empty(), ());
+
+ m_weights.reserve(m_enters.size() * m_exits.size());
+ for (Segment const & enter : m_enters)
+ {
+ for (Segment const & exit : m_exits)
+ {
+ double const weight = calcWeight(enter, exit);
+ // Edges weights should be >= astar heuristic, so use std::ceil.
+ m_weights.push_back(static_cast<Weight>(std::ceil(weight)));
+ }
+ }
+ }
+
+private:
+ // This is an internal type for storing edges weights.
+ // Weight is the time requred for the route to pass.
+ // Weight is measured in seconds rounded upwards.
+ using Weight = uint32_t;
+
+ static Weight constexpr kNoRoute = 0;
+
+ struct Key
+ {
+ Key() = default;
+
+ Key(uint32_t featureId, uint32_t segmentIdx) : m_featureId(featureId), m_segmentIdx(segmentIdx)
+ {
+ }
+
+ bool operator==(Key const & key) const
+ {
+ return m_featureId == key.m_featureId && m_segmentIdx == key.m_segmentIdx;
+ }
+
+ uint32_t m_featureId = 0;
+ uint32_t m_segmentIdx = 0;
+ };
+
+ struct HashKey
+ {
+ size_t operator()(Key const & key) const
+ {
+ return std::hash<uint64_t>()((static_cast<uint64_t>(key.m_featureId) << 32) +
+ static_cast<uint64_t>(key.m_segmentIdx));
+ }
+ };
+
+ struct Transition
+ {
+ Transition() = default;
+
+ Transition(uint32_t enterIdx, uint32_t exitIdx, bool oneWay, bool forwardIsEnter,
+ m2::PointD const & backPoint, m2::PointD const & frontPoint)
+ : m_enterIdx(enterIdx)
+ , m_exitIdx(exitIdx)
+ , m_backPoint(backPoint)
+ , m_frontPoint(frontPoint)
+ , m_oneWay(oneWay)
+ , m_forwardIsEnter(forwardIsEnter)
+ {
+ }
+
+ uint32_t m_enterIdx = 0;
+ uint32_t m_exitIdx = 0;
+ // Endpoints of transition segment.
+ // m_backPoint = points[segmentIdx]
+ // m_frontPoint = points[segmentIdx + 1]
+ m2::PointD m_backPoint = m2::PointD::Zero();
+ m2::PointD m_frontPoint = m2::PointD::Zero();
+ bool m_oneWay = false;
+ // Transition represents both forward and backward segments with same featureId, segmentIdx.
+ // m_forwardIsEnter == true means: forward segment is enter to mwm:
+ // Enter means: m_backPoint is outside mwm borders, m_frontPoint is inside.
+ bool m_forwardIsEnter = false;
+ };
+
+ enum class WeightsLoadState
+ {
+ Unknown,
+ NotExists,
+ ReadyToLoad,
+ Loaded
+ };
+
+ friend class CrossMwmConnectorSerializer;
+ friend std::string DebugPrint(WeightsLoadState state);
+
+ void AddEdge(Segment const & segment, Weight weight, std::vector<SegmentEdge> & edges) const;
+ Transition const & GetTransition(Segment const & segment) const;
+ Weight GetWeight(size_t enterIdx, size_t exitIdx) const;
+
+ NumMwmId const m_mwmId;
+ std::vector<Segment> m_enters;
+ std::vector<Segment> m_exits;
+ std::unordered_map<Key, Transition, HashKey> m_transitions;
+ WeightsLoadState m_weightsLoadState = WeightsLoadState::Unknown;
+ uint64_t m_weightsOffset = 0;
+ std::vector<Weight> m_weights;
+};
+} // namespace routing
diff --git a/routing/cross_mwm_connector_serialization.cpp b/routing/cross_mwm_connector_serialization.cpp
new file mode 100644
index 0000000000..cdc6c2c4ec
--- /dev/null
+++ b/routing/cross_mwm_connector_serialization.cpp
@@ -0,0 +1,30 @@
+#include "routing/cross_mwm_connector_serialization.hpp"
+
+using namespace std;
+
+namespace routing
+{
+// static
+uint32_t constexpr CrossMwmConnectorSerializer::kLastVersion;
+
+// static
+void CrossMwmConnectorSerializer::WriteTransitions(vector<Transition> const & transitions,
+ serial::CodingParams const & codingParams,
+ uint8_t bitsPerMask, vector<uint8_t> & buffer)
+{
+ MemWriter<vector<uint8_t>> memWriter(buffer);
+
+ for (Transition const & transition : transitions)
+ transition.Serialize(codingParams, bitsPerMask, memWriter);
+}
+
+// static
+void CrossMwmConnectorSerializer::WriteWeights(vector<CrossMwmConnector::Weight> const & weights,
+ vector<uint8_t> & buffer)
+{
+ MemWriter<vector<uint8_t>> memWriter(buffer);
+
+ for (auto weight : weights)
+ WriteToSink(memWriter, weight);
+}
+} // namespace routing
diff --git a/routing/cross_mwm_connector_serialization.hpp b/routing/cross_mwm_connector_serialization.hpp
new file mode 100644
index 0000000000..f21bc74a7d
--- /dev/null
+++ b/routing/cross_mwm_connector_serialization.hpp
@@ -0,0 +1,353 @@
+#pragma once
+
+#include "routing/cross_mwm_connector.hpp"
+#include "routing/routing_exceptions.hpp"
+#include "routing/vehicle_mask.hpp"
+
+#include "indexer/coding_params.hpp"
+#include "indexer/geometry_serialization.hpp"
+
+#include "coding/bit_streams.hpp"
+#include "coding/reader.hpp"
+#include "coding/write_to_sink.hpp"
+#include "coding/writer.hpp"
+
+#include "base/checked_cast.hpp"
+
+#include <array>
+#include <cstdint>
+#include <limits>
+#include <vector>
+
+namespace routing
+{
+using CrossMwmConnectorPerVehicleType =
+ std::array<CrossMwmConnector, static_cast<size_t>(VehicleType::Count)>;
+
+class CrossMwmConnectorSerializer final
+{
+public:
+ class Transition final
+ {
+ public:
+ Transition() = default;
+
+ Transition(uint32_t featureId, uint32_t segmentIdx, VehicleMask roadMask,
+ VehicleMask oneWayMask, bool forwardIsEnter, m2::PointD const & backPoint,
+ m2::PointD const & frontPoint)
+ : m_featureId(featureId)
+ , m_segmentIdx(segmentIdx)
+ , m_backPoint(backPoint)
+ , m_frontPoint(frontPoint)
+ , m_roadMask(roadMask)
+ , m_oneWayMask(oneWayMask)
+ , m_forwardIsEnter(forwardIsEnter)
+ {
+ }
+
+ template <class Sink>
+ void Serialize(serial::CodingParams const & codingParams, uint8_t bitsPerMask,
+ Sink & sink) const
+ {
+ WriteToSink(sink, m_featureId);
+ WriteToSink(sink, m_segmentIdx);
+ serial::SavePoint(sink, m_backPoint, codingParams);
+ serial::SavePoint(sink, m_frontPoint, codingParams);
+
+ BitWriter<Sink> writer(sink);
+ writer.WriteAtMost32Bits(base::asserted_cast<uint32_t>(m_roadMask), bitsPerMask);
+ writer.WriteAtMost32Bits(base::asserted_cast<uint32_t>(m_oneWayMask), bitsPerMask);
+ writer.Write(m_forwardIsEnter ? 0 : 1, 1);
+ }
+
+ template <class Source>
+ void Deserialize(serial::CodingParams const & codingParams, uint8_t bitsPerMask, Source & src)
+ {
+ m_featureId = ReadPrimitiveFromSource<decltype(m_featureId)>(src);
+ m_segmentIdx = ReadPrimitiveFromSource<decltype(m_segmentIdx)>(src);
+ m_backPoint = serial::LoadPoint(src, codingParams);
+ m_frontPoint = serial::LoadPoint(src, codingParams);
+
+ BitReader<Source> reader(src);
+ m_roadMask = base::asserted_cast<VehicleMask>(reader.ReadAtMost32Bits(bitsPerMask));
+ m_oneWayMask = base::asserted_cast<VehicleMask>(reader.ReadAtMost32Bits(bitsPerMask));
+ m_forwardIsEnter = reader.Read(1) == 0;
+ }
+
+ uint32_t GetFeatureId() const { return m_featureId; }
+ uint32_t GetSegmentIdx() const { return m_segmentIdx; }
+ m2::PointD const & GetBackPoint() const { return m_backPoint; }
+ m2::PointD const & GetFrontPoint() const { return m_frontPoint; }
+ bool ForwardIsEnter() const { return m_forwardIsEnter; }
+ VehicleMask GetRoadMask() const { return m_roadMask; }
+ VehicleMask GetOneWayMask() const { return m_oneWayMask; }
+
+ private:
+ uint32_t m_featureId = 0;
+ uint32_t m_segmentIdx = 0;
+ m2::PointD m_backPoint = m2::PointD::Zero();
+ m2::PointD m_frontPoint = m2::PointD::Zero();
+ VehicleMask m_roadMask = 0;
+ VehicleMask m_oneWayMask = 0;
+ bool m_forwardIsEnter = false;
+ };
+
+ CrossMwmConnectorSerializer() = delete;
+
+ template <class Sink>
+ static void Serialize(std::vector<Transition> const & transitions,
+ CrossMwmConnectorPerVehicleType const & connectors,
+ serial::CodingParams const & codingParams, Sink & sink)
+ {
+ auto const bitsPerMask = GetBitsPerMask<uint8_t>();
+ std::vector<uint8_t> transitionsBuf;
+ WriteTransitions(transitions, codingParams, bitsPerMask, transitionsBuf);
+
+ Header header(base::checked_cast<uint32_t>(transitions.size()),
+ base::checked_cast<uint64_t>(transitionsBuf.size()), codingParams, bitsPerMask);
+ std::vector<std::vector<uint8_t>> weightBuffers(connectors.size());
+
+ for (size_t i = 0; i < connectors.size(); ++i)
+ {
+ CrossMwmConnector const & connector = connectors[i];
+ if (connector.m_weights.empty())
+ continue;
+
+ std::vector<uint8_t> & buffer = weightBuffers[i];
+ WriteWeights(connector.m_weights, buffer);
+
+ auto const numEnters = base::checked_cast<uint32_t>(connector.GetEnters().size());
+ auto const numExits = base::checked_cast<uint32_t>(connector.GetExits().size());
+ auto const vehicleType = static_cast<VehicleType>(i);
+ header.AddSection(Section(buffer.size(), numEnters, numExits, vehicleType));
+ }
+
+ header.Serialize(sink);
+ FlushBuffer(transitionsBuf, sink);
+
+ for (auto & buffer : weightBuffers)
+ FlushBuffer(buffer, sink);
+ }
+
+ template <class Source>
+ static void DeserializeTransitions(VehicleType requiredVehicle, CrossMwmConnector & connector,
+ Source & src)
+ {
+ CHECK(connector.m_weightsLoadState == CrossMwmConnector::WeightsLoadState::Unknown, ());
+
+ Header header;
+ header.Deserialize(src);
+
+ uint64_t weightsOffset = src.Pos() + header.GetSizeTransitions();
+ VehicleMask const requiredMask = GetVehicleMask(requiredVehicle);
+ auto const numTransitions = base::checked_cast<size_t>(header.GetNumTransitions());
+
+ for (size_t i = 0; i < numTransitions; ++i)
+ {
+ Transition transition;
+ transition.Deserialize(header.GetCodingParams(), header.GetBitsPerMask(), src);
+ AddTransition(transition, requiredMask, connector);
+ }
+
+ if (src.Pos() != weightsOffset)
+ {
+ MYTHROW(CorruptedDataException,
+ ("Wrong position", src.Pos(), "after decoding transitions, expected:",
+ connector.m_weightsOffset, "size:", header.GetSizeTransitions()));
+ }
+
+ for (Section const & section : header.GetSections())
+ {
+ if (section.GetVehicleType() != requiredVehicle)
+ {
+ weightsOffset += section.GetSize();
+ continue;
+ }
+
+ size_t const numEnters = connector.GetEnters().size();
+ size_t const numExits = connector.GetExits().size();
+
+ if (base::checked_cast<size_t>(section.GetNumEnters()) != numEnters)
+ {
+ MYTHROW(CorruptedDataException, ("Mismatch enters number, section:", section.GetNumEnters(),
+ ", connector:", numEnters));
+ }
+
+ if (base::checked_cast<size_t>(section.GetNumExits()) != numExits)
+ {
+ MYTHROW(CorruptedDataException, ("Mismatch exits number, section:", section.GetNumExits(),
+ ", connector:", numExits));
+ }
+
+ connector.m_weightsOffset = weightsOffset;
+ connector.m_weightsLoadState = CrossMwmConnector::WeightsLoadState::ReadyToLoad;
+ return;
+ }
+
+ connector.m_weightsLoadState = CrossMwmConnector::WeightsLoadState::NotExists;
+ }
+
+ template <class Source>
+ static void DeserializeWeights(VehicleType requiredVehicle, CrossMwmConnector & connector,
+ Source & src)
+ {
+ CHECK(connector.m_weightsLoadState == CrossMwmConnector::WeightsLoadState::ReadyToLoad, ());
+
+ src.Skip(connector.m_weightsOffset);
+
+ size_t const amount = connector.GetEnters().size() * connector.GetExits().size();
+ connector.m_weights.reserve(amount);
+ for (size_t i = 0; i < amount; ++i)
+ {
+ auto const weight = ReadPrimitiveFromSource<uint32_t>(src);
+ connector.m_weights.push_back(static_cast<CrossMwmConnector::Weight>(weight));
+ }
+
+ connector.m_weightsLoadState = CrossMwmConnector::WeightsLoadState::Loaded;
+ }
+
+ static void AddTransition(Transition const & transition, VehicleMask requiredMask,
+ CrossMwmConnector & connector)
+ {
+ if ((transition.GetRoadMask() & requiredMask) == 0)
+ return;
+
+ bool const isOneWay = (transition.GetOneWayMask() & requiredMask) != 0;
+ connector.AddTransition(transition.GetFeatureId(), transition.GetSegmentIdx(), isOneWay,
+ transition.ForwardIsEnter(), transition.GetBackPoint(),
+ transition.GetFrontPoint());
+ }
+
+private:
+ static uint32_t constexpr kLastVersion = 0;
+
+ class Section final
+ {
+ public:
+ Section() = default;
+
+ Section(uint64_t size, uint32_t numEnters, uint32_t numExits, VehicleType vehicleType)
+ : m_size(size), m_numEnters(numEnters), m_numExits(numExits), m_vehicleType(vehicleType)
+ {
+ }
+
+ template <class Sink>
+ void Serialize(Sink & sink) const
+ {
+ WriteToSink(sink, m_size);
+ WriteToSink(sink, m_numEnters);
+ WriteToSink(sink, m_numExits);
+ WriteToSink(sink, static_cast<uint8_t>(m_vehicleType));
+ }
+
+ template <class Source>
+ void Deserialize(Source & src)
+ {
+ m_size = ReadPrimitiveFromSource<decltype(m_size)>(src);
+ m_numEnters = ReadPrimitiveFromSource<decltype(m_numEnters)>(src);
+ m_numExits = ReadPrimitiveFromSource<decltype(m_numExits)>(src);
+ m_vehicleType = static_cast<VehicleType>(ReadPrimitiveFromSource<uint8_t>(src));
+ }
+
+ uint64_t GetSize() const { return m_size; }
+ uint32_t GetNumEnters() const { return m_numEnters; }
+ uint32_t GetNumExits() const { return m_numExits; }
+ VehicleType GetVehicleType() const { return m_vehicleType; }
+
+ private:
+ uint64_t m_size = 0;
+ uint32_t m_numEnters = 0;
+ uint32_t m_numExits = 0;
+ VehicleType m_vehicleType = VehicleType::Pedestrian;
+ };
+
+ class Header final
+ {
+ public:
+ Header() = default;
+
+ Header(uint32_t numTransitions, uint64_t sizeTransitions,
+ serial::CodingParams const & codingParams, uint8_t bitsPerMask)
+ : m_numTransitions(numTransitions)
+ , m_sizeTransitions(sizeTransitions)
+ , m_codingParams(codingParams)
+ , m_bitsPerMask(bitsPerMask)
+ {
+ }
+
+ template <class Sink>
+ void Serialize(Sink & sink) const
+ {
+ WriteToSink(sink, m_version);
+ WriteToSink(sink, m_numTransitions);
+ WriteToSink(sink, m_sizeTransitions);
+ m_codingParams.Save(sink);
+ WriteToSink(sink, m_bitsPerMask);
+
+ WriteToSink(sink, base::checked_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 cross mwm section version ", m_version,
+ ", current version ", kLastVersion));
+ }
+
+ m_numTransitions = ReadPrimitiveFromSource<decltype(m_numTransitions)>(src);
+ m_sizeTransitions = ReadPrimitiveFromSource<decltype(m_sizeTransitions)>(src);
+ m_codingParams.Load(src);
+ m_bitsPerMask = ReadPrimitiveFromSource<decltype(m_bitsPerMask)>(src);
+
+ auto const sectionsSize = ReadPrimitiveFromSource<uint32_t>(src);
+ m_sections.resize(base::checked_cast<size_t>(sectionsSize));
+ for (Section & section : m_sections)
+ section.Deserialize(src);
+ }
+
+ void AddSection(Section const & section) { m_sections.push_back(section); }
+
+ uint32_t GetNumTransitions() const { return m_numTransitions; }
+ uint64_t GetSizeTransitions() const { return m_sizeTransitions; }
+ serial::CodingParams const & GetCodingParams() const { return m_codingParams; }
+ uint8_t GetBitsPerMask() const { return m_bitsPerMask; }
+ std::vector<Section> const & GetSections() const { return m_sections; }
+
+ private:
+ uint32_t m_version = kLastVersion;
+ uint32_t m_numTransitions = 0;
+ uint64_t m_sizeTransitions = 0;
+ serial::CodingParams m_codingParams;
+ uint8_t m_bitsPerMask = 0;
+ std::vector<Section> m_sections;
+ };
+
+ template <typename T>
+ static T GetBitsPerMask()
+ {
+ static_assert(
+ static_cast<size_t>(VehicleType::Count) <= static_cast<size_t>(numeric_limits<T>::max()),
+ "Can't pack VehicleType::Count into chosen type");
+ return static_cast<T>(VehicleType::Count);
+ }
+
+ template <class Sink>
+ static void FlushBuffer(std::vector<uint8_t> & buffer, Sink & sink)
+ {
+ sink.Write(buffer.data(), buffer.size());
+ buffer.clear();
+ }
+
+ static void WriteTransitions(std::vector<Transition> const & transitions,
+ serial::CodingParams const & codingParams, uint8_t bitsPerMask,
+ std::vector<uint8_t> & buffer);
+
+ static void WriteWeights(std::vector<CrossMwmConnector::Weight> const & weights,
+ std::vector<uint8_t> & buffer);
+};
+} // namespace routing
diff --git a/routing/edge_estimator.cpp b/routing/edge_estimator.cpp
index e1248ddb28..3a3f8dd01b 100644
--- a/routing/edge_estimator.cpp
+++ b/routing/edge_estimator.cpp
@@ -73,17 +73,20 @@ double CarEdgeEstimator::CalcSegmentWeight(Segment const & segment, RoadGeometry
road.GetPoint(segment.GetPointId(true /* front */)), speedMPS) *
kTimePenalty;
- auto const * trafficColoring = m_trafficStash->Get(segment.GetMwmId());
- if (trafficColoring)
+ if (m_trafficStash)
{
- auto const dir = segment.IsForward() ? TrafficInfo::RoadSegmentId::kForwardDirection
- : TrafficInfo::RoadSegmentId::kReverseDirection;
- auto const it = trafficColoring->find(
- TrafficInfo::RoadSegmentId(segment.GetFeatureId(), segment.GetSegmentIdx(), dir));
- SpeedGroup const speedGroup =
- (it == trafficColoring->cend()) ? SpeedGroup::Unknown : it->second;
- ASSERT_LESS(speedGroup, SpeedGroup::Count, ());
- result *= CalcTrafficFactor(speedGroup);
+ auto const * trafficColoring = m_trafficStash->Get(segment.GetMwmId());
+ if (trafficColoring)
+ {
+ auto const dir = segment.IsForward() ? TrafficInfo::RoadSegmentId::kForwardDirection
+ : TrafficInfo::RoadSegmentId::kReverseDirection;
+ auto const it = trafficColoring->find(
+ TrafficInfo::RoadSegmentId(segment.GetFeatureId(), segment.GetSegmentIdx(), dir));
+ SpeedGroup const speedGroup =
+ (it == trafficColoring->cend()) ? SpeedGroup::Unknown : it->second;
+ ASSERT_LESS(speedGroup, SpeedGroup::Count, ());
+ result *= CalcTrafficFactor(speedGroup);
+ }
}
return result;
diff --git a/routing/routing.pro b/routing/routing.pro
index 6441f1a865..7ba284b0a5 100644
--- a/routing/routing.pro
+++ b/routing/routing.pro
@@ -17,6 +17,8 @@ SOURCES += \
base/followed_polyline.cpp \
bicycle_directions.cpp \
car_router.cpp \
+ cross_mwm_connector.cpp \
+ cross_mwm_connector_serialization.cpp \
cross_mwm_index_graph.cpp \
cross_mwm_road_graph.cpp \
cross_mwm_router.cpp \
@@ -67,6 +69,8 @@ HEADERS += \
base/followed_polyline.hpp \
bicycle_directions.hpp \
car_router.hpp \
+ cross_mwm_connector.hpp \
+ cross_mwm_connector_serialization.hpp \
cross_mwm_index_graph.hpp \
cross_mwm_road_graph.hpp \
cross_mwm_router.hpp \
diff --git a/routing/routing_tests/CMakeLists.txt b/routing/routing_tests/CMakeLists.txt
index b960860ef9..9c1af798b4 100644
--- a/routing/routing_tests/CMakeLists.txt
+++ b/routing/routing_tests/CMakeLists.txt
@@ -8,6 +8,7 @@ set(
astar_progress_test.cpp
astar_router_test.cpp
async_router_test.cpp
+ cross_mwm_connector_test.cpp
cross_routing_tests.cpp
cumulative_restriction_test.cpp
followed_polyline_test.cpp
diff --git a/routing/routing_tests/cross_mwm_connector_test.cpp b/routing/routing_tests/cross_mwm_connector_test.cpp
new file mode 100644
index 0000000000..7973ed088c
--- /dev/null
+++ b/routing/routing_tests/cross_mwm_connector_test.cpp
@@ -0,0 +1,239 @@
+#include "testing/testing.hpp"
+
+#include "routing/cross_mwm_connector_serialization.hpp"
+
+#include "coding/writer.hpp"
+
+using namespace routing;
+using namespace std;
+
+namespace
+{
+NumMwmId constexpr mwmId = 777;
+
+void TestConnectorConsistency(CrossMwmConnector const & connector)
+{
+ for (Segment const & enter : connector.GetEnters())
+ {
+ TEST(connector.IsTransition(enter, true /* isOutgoing */), ("enter:", enter));
+ TEST(!connector.IsTransition(enter, false /* isOutgoing */), ("enter:", enter));
+ }
+
+ for (Segment const & exit : connector.GetExits())
+ {
+ TEST(!connector.IsTransition(exit, true /* isOutgoing */), ("exit:", exit));
+ TEST(connector.IsTransition(exit, false /* isOutgoing */), ("exit:", exit));
+ }
+}
+
+void TestEdges(CrossMwmConnector const & connector, Segment const & from, bool isOutgoing,
+ vector<SegmentEdge> const & expectedEdges)
+{
+ vector<SegmentEdge> edges;
+ connector.GetEdgeList(from, isOutgoing, edges);
+ TEST_EQUAL(edges, expectedEdges, ());
+}
+}
+
+namespace routing_test
+{
+UNIT_TEST(OneWayEnter)
+{
+ uint32_t constexpr featureId = 1;
+ uint32_t constexpr segmentIdx = 1;
+ CrossMwmConnector connector(mwmId);
+ connector.AddTransition(featureId, segmentIdx, true /* oneWay */, true /* forwardIsEnter */,
+ {} /* backPoint */, {} /* frontPoint */);
+
+ TestConnectorConsistency(connector);
+ TEST_EQUAL(connector.GetEnters().size(), 1, ());
+ TEST_EQUAL(connector.GetExits().size(), 0, ());
+ TEST(connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ false /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ false /* isOutgoing */),
+ ());
+}
+
+UNIT_TEST(OneWayExit)
+{
+ uint32_t constexpr featureId = 1;
+ uint32_t constexpr segmentIdx = 1;
+ CrossMwmConnector connector(mwmId);
+ connector.AddTransition(featureId, segmentIdx, true /* oneWay */, false /* forwardIsEnter */,
+ {} /* backPoint */, {} /* frontPoint */);
+
+ TestConnectorConsistency(connector);
+ TEST_EQUAL(connector.GetEnters().size(), 0, ());
+ TEST_EQUAL(connector.GetExits().size(), 1, ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ false /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ false /* isOutgoing */),
+ ());
+}
+
+UNIT_TEST(TwoWayEnter)
+{
+ uint32_t constexpr featureId = 1;
+ uint32_t constexpr segmentIdx = 1;
+ CrossMwmConnector connector(mwmId);
+ connector.AddTransition(featureId, segmentIdx, false /* oneWay */, true /* forwardIsEnter */,
+ {} /* backPoint */, {} /* frontPoint */);
+
+ TestConnectorConsistency(connector);
+ TEST_EQUAL(connector.GetEnters().size(), 1, ());
+ TEST_EQUAL(connector.GetExits().size(), 1, ());
+ TEST(connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ false /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ false /* isOutgoing */),
+ ());
+}
+
+UNIT_TEST(TwoWayExit)
+{
+ uint32_t constexpr featureId = 1;
+ uint32_t constexpr segmentIdx = 1;
+ CrossMwmConnector connector(mwmId);
+ connector.AddTransition(featureId, segmentIdx, false /* oneWay */, false /* forwardIsEnter */,
+ {} /* backPoint */, {} /* frontPoint */);
+
+ TestConnectorConsistency(connector);
+ TEST_EQUAL(connector.GetEnters().size(), 1, ());
+ TEST_EQUAL(connector.GetExits().size(), 1, ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(connector.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */),
+ false /* isOutgoing */),
+ ());
+ TEST(connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */),
+ false /* isOutgoing */),
+ ());
+}
+
+UNIT_TEST(Serialization)
+{
+ float constexpr kEdgesWeight = 333;
+
+ vector<uint8_t> buffer;
+ {
+ vector<CrossMwmConnectorSerializer::Transition> transitions = {
+ /* featureId, segmentIdx, roadMask, oneWayMask, forwardIsEnter, backPoint, frontPoint */
+ {10, 1, kCarMask, kCarMask, true, m2::PointD(1.1, 1.2), m2::PointD(1.3, 1.4)},
+ {20, 2, kCarMask, 0, true, m2::PointD(2.1, 2.2), m2::PointD(2.3, 2.4)},
+ {30, 3, kPedestrianMask, kCarMask, true, m2::PointD(3.1, 3.2), m2::PointD(3.3, 3.4)}};
+
+ CrossMwmConnectorPerVehicleType connectors;
+ CrossMwmConnector & carConnector = connectors[static_cast<size_t>(VehicleType::Car)];
+ for (auto const & transition : transitions)
+ CrossMwmConnectorSerializer::AddTransition(transition, kCarMask, carConnector);
+
+ carConnector.FillWeights(
+ [](Segment const & enter, Segment const & exit) { return kEdgesWeight; });
+
+ serial::CodingParams const codingParams;
+ MemWriter<vector<uint8_t>> writer(buffer);
+ CrossMwmConnectorSerializer::Serialize(transitions, connectors, codingParams, writer);
+ }
+
+ CrossMwmConnector connector(mwmId);
+ {
+ MemReader reader(buffer.data(), buffer.size());
+ ReaderSource<MemReader> source(reader);
+ CrossMwmConnectorSerializer::DeserializeTransitions(VehicleType::Car, connector, source);
+ }
+
+ TestConnectorConsistency(connector);
+
+ TEST_EQUAL(connector.GetEnters().size(), 2, ());
+ TEST_EQUAL(connector.GetExits().size(), 1, ());
+
+ TEST(!connector.IsTransition(Segment(mwmId, 0, 0, true), true /* isOutgoing */), ());
+
+ TEST(connector.IsTransition(Segment(mwmId, 10, 1, true /* forward */), true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, 10, 1, true /* forward */), false /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, 10, 1, false /* forward */), true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, 10, 1, false /* forward */), false /* isOutgoing */),
+ ());
+
+ TEST(connector.IsTransition(Segment(mwmId, 20, 2, true /* forward */), true /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, 20, 2, true /* forward */), false /* isOutgoing */),
+ ());
+ TEST(!connector.IsTransition(Segment(mwmId, 20, 2, false /* forward */), true /* isOutgoing */),
+ ());
+ TEST(connector.IsTransition(Segment(mwmId, 20, 2, false /* forward */), false /* isOutgoing */),
+ ());
+
+ TEST(!connector.IsTransition(Segment(mwmId, 30, 3, true /* forward */), true /* isOutgoing */),
+ ());
+
+ TEST(!connector.WeightsWereLoaded(), ());
+ TEST(!connector.HasWeights(), ());
+
+ {
+ MemReader reader(buffer.data(), buffer.size());
+ ReaderSource<MemReader> source(reader);
+ CrossMwmConnectorSerializer::DeserializeWeights(VehicleType::Car, connector, source);
+ }
+ TEST(connector.WeightsWereLoaded(), ());
+ TEST(connector.HasWeights(), ());
+
+ double constexpr eps = 1e-6;
+ TEST(AlmostEqualAbs(
+ connector.GetPoint(Segment(mwmId, 20, 2, true /* forward */), true /* front */),
+ m2::PointD(2.3, 2.4), eps),
+ ());
+ TEST(AlmostEqualAbs(
+ connector.GetPoint(Segment(mwmId, 20, 2, true /* forward */), false /* front */),
+ m2::PointD(2.1, 2.2), eps),
+ ());
+ TEST(AlmostEqualAbs(
+ connector.GetPoint(Segment(mwmId, 20, 2, false /* forward */), true /* front */),
+ m2::PointD(2.1, 2.2), eps),
+ ());
+ TEST(AlmostEqualAbs(
+ connector.GetPoint(Segment(mwmId, 20, 2, true /* forward */), true /* front */),
+ m2::PointD(2.3, 2.4), eps),
+ ());
+
+ TestEdges(connector, Segment(mwmId, 10, 1, true /* forward */), true /* isOutgoing */,
+ {{Segment(mwmId, 20, 2, false /* forward */), kEdgesWeight}});
+
+ TestEdges(connector, Segment(mwmId, 20, 2, true /* forward */), true /* isOutgoing */,
+ {{Segment(mwmId, 20, 2, false /* forward */), kEdgesWeight}});
+
+ TestEdges(connector, Segment(mwmId, 20, 2, false /* forward */), false /* isOutgoing */,
+ {{Segment(mwmId, 10, 1, true /* forward */), kEdgesWeight},
+ {Segment(mwmId, 20, 2, true /* forward */), kEdgesWeight}});
+}
+} // namespace routing_test
diff --git a/routing/routing_tests/routing_tests.pro b/routing/routing_tests/routing_tests.pro
index c144590a22..5ea3209ae3 100644
--- a/routing/routing_tests/routing_tests.pro
+++ b/routing/routing_tests/routing_tests.pro
@@ -26,6 +26,7 @@ SOURCES += \
astar_progress_test.cpp \
astar_router_test.cpp \
async_router_test.cpp \
+ cross_mwm_connector_test.cpp \
cross_routing_tests.cpp \
cumulative_restriction_test.cpp \
followed_polyline_test.cpp \
diff --git a/routing/segment.hpp b/routing/segment.hpp
index cbeb14d449..1729b22cb2 100644
--- a/routing/segment.hpp
+++ b/routing/segment.hpp
@@ -75,6 +75,11 @@ public:
Segment const & GetTarget() const { return m_target; }
double GetWeight() const { return m_weight; }
+ bool operator==(SegmentEdge const & edge) const
+ {
+ return m_target == edge.m_target && m_weight == edge.m_weight;
+ }
+
private:
// Target is vertex going to for outgoing edges, vertex going from for ingoing edges.
Segment m_target;
@@ -88,4 +93,11 @@ inline string DebugPrint(Segment const & segment)
<< segment.GetSegmentIdx() << ", " << segment.IsForward() << ")";
return out.str();
}
+
+inline string DebugPrint(SegmentEdge const & edge)
+{
+ ostringstream out;
+ out << "Edge(" << DebugPrint(edge.GetTarget()) << ", " << edge.GetWeight() << ")";
+ return out.str();
+}
} // namespace routing
diff --git a/search/nearby_points_sweeper.hpp b/search/nearby_points_sweeper.hpp
index 3bf6db6e2b..cfea4f3013 100644
--- a/search/nearby_points_sweeper.hpp
+++ b/search/nearby_points_sweeper.hpp
@@ -3,6 +3,7 @@
#include "base/assert.hpp"
#include "std/algorithm.hpp"
+#include "std/cmath.hpp"
#include "std/cstdint.hpp"
#include "std/limits.hpp"
#include "std/set.hpp"
diff --git a/search/search_quality/assessment_tool/CMakeLists.txt b/search/search_quality/assessment_tool/CMakeLists.txt
index 3509cf68d5..cf02271f0a 100644
--- a/search/search_quality/assessment_tool/CMakeLists.txt
+++ b/search/search_quality/assessment_tool/CMakeLists.txt
@@ -8,13 +8,21 @@ include_directories(${OMIM_ROOT}/3party/glm)
set(
SRC
- assessment_tool.cc
+ assessment_tool.cpp
+ helpers.cpp
+ helpers.hpp
+ languages_list.cpp
+ languages_list.hpp
main_model.cpp
main_model.hpp
main_model.hpp
main_view.cpp
main_view.hpp
model.hpp
+ sample_view.cpp
+ sample_view.hpp
+ samples_view.cpp
+ samples_view.hpp
view.hpp
)
diff --git a/search/search_quality/assessment_tool/assessment_tool.cc b/search/search_quality/assessment_tool/assessment_tool.cpp
index ca43dd37e8..8967b845b1 100644
--- a/search/search_quality/assessment_tool/assessment_tool.cc
+++ b/search/search_quality/assessment_tool/assessment_tool.cpp
@@ -14,10 +14,6 @@
DEFINE_string(resources_path, "", "Path to resources directory");
DEFINE_string(data_path, "", "Path to data directory");
-namespace
-{
-} // namespace
-
int main(int argc, char ** argv)
{
search::ChangeMaxNumberOfOpenFiles(search::kMaxOpenFiles);
@@ -36,7 +32,7 @@ int main(int argc, char ** argv)
Framework framework;
MainView view(framework);
- MainModel model;
+ MainModel model(framework);
model.SetView(view);
view.SetModel(model);
diff --git a/search/search_quality/assessment_tool/helpers.cpp b/search/search_quality/assessment_tool/helpers.cpp
new file mode 100644
index 0000000000..fccfdc363a
--- /dev/null
+++ b/search/search_quality/assessment_tool/helpers.cpp
@@ -0,0 +1,13 @@
+#include "search/search_quality/assessment_tool/helpers.hpp"
+
+#include "base/string_utils.hpp"
+
+QString ToQString(strings::UniString const & s)
+{
+ return QString::fromUtf8(strings::ToUtf8(s).c_str());
+}
+
+QString ToQString(std::string const & s)
+{
+ return QString::fromUtf8(s.c_str());
+}
diff --git a/search/search_quality/assessment_tool/helpers.hpp b/search/search_quality/assessment_tool/helpers.hpp
new file mode 100644
index 0000000000..f72b873f1a
--- /dev/null
+++ b/search/search_quality/assessment_tool/helpers.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <string>
+#include <utility>
+
+#include <QtCore/QString>
+
+namespace strings
+{
+class UniString;
+}
+
+QString ToQString(strings::UniString const & s);
+QString ToQString(std::string const & s);
+
+template <typename Layout, typename... Args>
+Layout * BuildLayoutWithoutMargins(Args &&... args)
+{
+ auto * layout = new Layout(std::forward<Args>(args)...);
+ layout->setContentsMargins(0 /* left */, 0 /* top */, 0 /* right */, 0 /* bottom */);
+ return layout;
+}
diff --git a/search/search_quality/assessment_tool/languages_list.cpp b/search/search_quality/assessment_tool/languages_list.cpp
new file mode 100644
index 0000000000..73e39d88ce
--- /dev/null
+++ b/search/search_quality/assessment_tool/languages_list.cpp
@@ -0,0 +1,21 @@
+#include "search/search_quality/assessment_tool/languages_list.hpp"
+
+#include "search/search_quality/assessment_tool/helpers.hpp"
+
+#include "coding/multilang_utf8_string.hpp"
+
+LanguagesList::LanguagesList(QWidget * parent) : QComboBox(parent)
+{
+ auto const langs = StringUtf8Multilang::GetSupportedLanguages();
+ for (auto const & lang : langs)
+ addItem(ToQString(lang.m_code));
+}
+
+void LanguagesList::Select(std::string const & lang)
+{
+ auto const index = StringUtf8Multilang::GetLangIndex(lang);
+ if (index != StringUtf8Multilang::kUnsupportedLanguageCode)
+ setCurrentIndex(index);
+ else
+ setCurrentIndex(StringUtf8Multilang::kDefaultCode);
+}
diff --git a/search/search_quality/assessment_tool/languages_list.hpp b/search/search_quality/assessment_tool/languages_list.hpp
new file mode 100644
index 0000000000..c717c0aff4
--- /dev/null
+++ b/search/search_quality/assessment_tool/languages_list.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <string>
+
+#include <QtWidgets/QComboBox>
+
+class QWidget;
+
+class LanguagesList : public QComboBox
+{
+public:
+ explicit LanguagesList(QWidget * parent);
+
+ void Select(std::string const & lang);
+};
diff --git a/search/search_quality/assessment_tool/main_model.cpp b/search/search_quality/assessment_tool/main_model.cpp
index 73b5175f30..c41ecb4c80 100644
--- a/search/search_quality/assessment_tool/main_model.cpp
+++ b/search/search_quality/assessment_tool/main_model.cpp
@@ -2,6 +2,16 @@
#include "search/search_quality/assessment_tool/view.hpp"
+#include "map/framework.hpp"
+
+#include "search/search_params.hpp"
+
+#include "geometry/mercator.hpp"
+
+#include "coding/multilang_utf8_string.hpp"
+
+#include "platform/platform.hpp"
+
#include "base/assert.hpp"
#include "base/logging.hpp"
@@ -9,6 +19,8 @@
#include <fstream>
#include <iterator>
+MainModel::MainModel(Framework & framework) : m_framework(framework) {}
+
void MainModel::Open(std::string const & path)
{
CHECK(m_view, ());
@@ -38,5 +50,38 @@ void MainModel::OnSampleSelected(int index)
CHECK_GREATER_OR_EQUAL(index, 0, ());
CHECK_LESS(index, m_samples.size(), ());
CHECK(m_view, ());
+
+ auto const & sample = m_samples[index];
m_view->ShowSample(m_samples[index]);
+
+ auto & engine = m_framework.GetSearchEngine();
+ {
+ auto latLon = MercatorBounds::ToLatLon(sample.m_pos);
+
+ search::SearchParams params;
+ params.m_query = strings::ToUtf8(sample.m_query);
+ params.m_inputLocale = sample.m_locale;
+ params.m_suggestsEnabled = false;
+ params.SetPosition(latLon.lat, latLon.lon);
+
+ auto const timestamp = ++m_queryTimestamp;
+ m_numShownResults = 0;
+
+ params.m_onResults = [this, timestamp](search::Results const & results) {
+ GetPlatform().RunOnGuiThread([this, timestamp, results]() { OnResults(timestamp, results); });
+ };
+
+ if (auto handle = m_queryHandle.lock())
+ handle->Cancel();
+ m_queryHandle = engine.Search(params, sample.m_viewport);
+ }
+}
+
+void MainModel::OnResults(uint64_t timestamp, search::Results const & results)
+{
+ if (timestamp != m_queryTimestamp)
+ return;
+ CHECK_LESS_OR_EQUAL(m_numShownResults, results.GetCount(), ());
+ m_view->ShowResults(results.begin() + m_numShownResults, results.end());
+ m_numShownResults = results.GetCount();
}
diff --git a/search/search_quality/assessment_tool/main_model.hpp b/search/search_quality/assessment_tool/main_model.hpp
index fbbcced766..868c9a5772 100644
--- a/search/search_quality/assessment_tool/main_model.hpp
+++ b/search/search_quality/assessment_tool/main_model.hpp
@@ -1,19 +1,36 @@
#pragma once
+#include "search/engine.hpp"
#include "search/search_quality/assessment_tool/model.hpp"
#include "search/search_quality/sample.hpp"
+#include <cstdint>
#include <vector>
+#include <memory>
class Framework;
+namespace search
+{
+class Results;
+}
+
class MainModel : public Model
{
public:
+ explicit MainModel(Framework & framework);
+
// Model overrides:
void Open(std::string const & path) override;
void OnSampleSelected(int index) override;
private:
+ void OnResults(uint64_t timestamp, search::Results const & results);
+
+ Framework & m_framework;
std::vector<search::Sample> m_samples;
+
+ std::weak_ptr<search::ProcessorHandle> m_queryHandle;
+ uint64_t m_queryTimestamp = 0;
+ size_t m_numShownResults = 0;
};
diff --git a/search/search_quality/assessment_tool/main_view.cpp b/search/search_quality/assessment_tool/main_view.cpp
index 5ced97c8b2..b0d276237d 100644
--- a/search/search_quality/assessment_tool/main_view.cpp
+++ b/search/search_quality/assessment_tool/main_view.cpp
@@ -1,6 +1,9 @@
#include "search/search_quality/assessment_tool/main_view.hpp"
-#include "search/search_quality/assessment_tool/main_model.hpp"
+#include "search/search_quality/assessment_tool/helpers.hpp"
+#include "search/search_quality/assessment_tool/model.hpp"
+#include "search/search_quality/assessment_tool/sample_view.hpp"
+#include "search/search_quality/assessment_tool/samples_view.hpp"
#include "qt/qt_common/map_widget.hpp"
#include "qt/qt_common/scale_slider.hpp"
@@ -8,14 +11,12 @@
#include "map/framework.hpp"
#include "base/assert.hpp"
-#include "base/stl_add.hpp"
#include "base/string_utils.hpp"
-#include <QtCore/QList>
#include <QtCore/Qt>
+#include <QtWidgets/QDockWidget>
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QHBoxLayout>
-#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QToolBar>
@@ -39,17 +40,20 @@ MainView::~MainView()
void MainView::SetSamples(std::vector<search::Sample> const & samples)
{
- m_samplesModel->removeRows(0, m_samplesModel->rowCount());
- for (auto const & sample : samples)
- {
- m_samplesModel->appendRow(
- new QStandardItem(QString::fromUtf8(strings::ToUtf8(sample.m_query).c_str())));
- }
+ m_samplesView->SetSamples(samples);
}
void MainView::ShowSample(search::Sample const & sample)
{
- // TODO (@y): implement a dock view for search sample.
+ m_framework.ShowRect(sample.m_viewport, -1 /* maxScale */, false /* animation */);
+
+ m_sampleView->SetContents(sample);
+ m_sampleView->show();
+}
+
+void MainView::ShowResults(search::Results::Iter begin, search::Results::Iter end)
+{
+ m_sampleView->ShowResults(begin, end);
}
void MainView::ShowError(std::string const & msg)
@@ -70,84 +74,77 @@ void MainView::OnSampleSelected(QItemSelection const & current)
void MainView::InitMenuBar()
{
- CHECK(m_samplesDock.get(), ());
-
auto * bar = menuBar();
auto * fileMenu = bar->addMenu(tr("&File"));
{
- auto open = make_unique<QAction>(tr("&Open queries..."), this);
+ auto * open = new QAction(tr("&Open queries..."), this /* parent */);
open->setShortcuts(QKeySequence::Open);
open->setStatusTip(tr("Open the file with queries for assessment"));
- connect(open.get(), &QAction::triggered, this, &MainView::Open);
- fileMenu->addAction(open.release());
+ connect(open, &QAction::triggered, this, &MainView::Open);
+ fileMenu->addAction(open);
}
fileMenu->addSeparator();
{
- auto quit = make_unique<QAction>(tr("&Quit"), this);
+ auto * quit = new QAction(tr("&Quit"), this /* parent */);
quit->setShortcuts(QKeySequence::Quit);
quit->setStatusTip(tr("Exit the tool"));
- connect(quit.get(), &QAction::triggered, this, &QWidget::close);
- fileMenu->addAction(quit.release());
+ connect(quit, &QAction::triggered, this, &QWidget::close);
+ fileMenu->addAction(quit);
}
auto * viewMenu = bar->addMenu(tr("&View"));
+
{
+ CHECK(m_samplesDock != nullptr, ());
viewMenu->addAction(m_samplesDock->toggleViewAction());
}
+
+ {
+ CHECK(m_sampleDock != nullptr, ());
+ viewMenu->addAction(m_sampleDock->toggleViewAction());
+ }
}
void MainView::InitMapWidget()
{
- auto widget = make_unique<QWidget>(this /* parent */);
+ auto * widget = new QWidget(this /* parent */);
+ auto * layout = BuildLayoutWithoutMargins<QHBoxLayout>(widget /* parent */);
+ widget->setLayout(layout);
- auto layout = make_unique<QHBoxLayout>(widget.get() /* parent */);
- layout->setContentsMargins(0 /* left */, 0 /* top */, 0 /* right */, 0 /* bottom */);
{
- auto mapWidget = make_unique<qt::common::MapWidget>(m_framework, widget.get() /* parent */);
- auto toolBar = make_unique<QToolBar>(widget.get() /* parent */);
+ auto * mapWidget = new qt::common::MapWidget(m_framework, widget /* parent */);
+ auto * toolBar = new QToolBar(widget /* parent */);
toolBar->setOrientation(Qt::Vertical);
toolBar->setIconSize(QSize(32, 32));
qt::common::ScaleSlider::Embed(Qt::Vertical, *toolBar, *mapWidget);
- layout->addWidget(mapWidget.release());
- layout->addWidget(toolBar.release());
+ layout->addWidget(mapWidget);
+ layout->addWidget(toolBar);
}
- widget->setLayout(layout.release());
- setCentralWidget(widget.release());
+ setCentralWidget(widget);
}
void MainView::InitDocks()
{
- m_samplesTable = my::make_unique<QTableView>(this /* parent */);
- m_samplesTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- m_samplesTable->setSelectionMode(QAbstractItemView::SingleSelection);
-
- {
- auto * header = m_samplesTable->horizontalHeader();
- header->setStretchLastSection(true /* stretch */);
- header->hide();
- }
-
- m_samplesModel =
- my::make_unique<QStandardItemModel>(0 /* rows */, 1 /* columns */, this /* parent */);
-
- m_samplesTable->setModel(m_samplesModel.get());
+ m_samplesView = new SamplesView(this /* parent */);
{
- auto * model = m_samplesTable->selectionModel();
+ auto * model = m_samplesView->selectionModel();
connect(model, SIGNAL(selectionChanged(QItemSelection const &, QItemSelection const &)), this,
SLOT(OnSampleSelected(QItemSelection const &)));
}
- m_samplesDock = my::make_unique<QDockWidget>(tr("Samples"), this /* parent */, Qt::Widget);
- m_samplesDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
- m_samplesDock->setWidget(m_samplesTable.get());
- addDockWidget(Qt::RightDockWidgetArea, m_samplesDock.get());
+ m_samplesDock = CreateDock("Samples", *m_samplesView);
+ addDockWidget(Qt::RightDockWidgetArea, m_samplesDock);
+
+ m_sampleView = new SampleView(this /* parent */);
+ m_sampleDock = CreateDock("Sample", *m_sampleView);
+ addDockWidget(Qt::RightDockWidgetArea, m_sampleDock);
}
void MainView::Open()
@@ -162,3 +159,11 @@ void MainView::Open()
m_model->Open(file);
}
+
+QDockWidget * MainView::CreateDock(std::string const & title, QWidget & widget)
+{
+ auto * dock = new QDockWidget(ToQString(title), this /* parent */, Qt::Widget);
+ dock->setFeatures(QDockWidget::AllDockWidgetFeatures);
+ dock->setWidget(&widget);
+ return dock;
+}
diff --git a/search/search_quality/assessment_tool/main_view.hpp b/search/search_quality/assessment_tool/main_view.hpp
index dcde4ecaeb..beec69483a 100644
--- a/search/search_quality/assessment_tool/main_view.hpp
+++ b/search/search_quality/assessment_tool/main_view.hpp
@@ -2,14 +2,13 @@
#include "search/search_quality/assessment_tool/view.hpp"
-#include <QtGui/QStandardItemModel>
-#include <QtWidgets/QDockWidget>
#include <QtWidgets/QMainWindow>
-#include <QtWidgets/QTableView>
-
-#include <memory>
+class Framework;
+class QDockWidget;
class QItemSelection;
+class SamplesView;
+class SampleView;
namespace qt
{
@@ -19,8 +18,6 @@ class MapWidget;
}
}
-class Framework;
-
class MainView : public QMainWindow, public View
{
Q_OBJECT
@@ -32,21 +29,26 @@ public:
// View overrides:
void SetSamples(std::vector<search::Sample> const & samples) override;
void ShowSample(search::Sample const & sample) override;
+ void ShowResults(search::Results::Iter begin, search::Results::Iter end) override;
void ShowError(std::string const & msg) override;
private Q_SLOTS:
void OnSampleSelected(QItemSelection const & current);
private:
- void InitMenuBar();
void InitMapWidget();
void InitDocks();
+ void InitMenuBar();
void Open();
+ QDockWidget * CreateDock(std::string const & title, QWidget & widget);
+
Framework & m_framework;
- std::unique_ptr<QStandardItemModel> m_samplesModel;
- std::unique_ptr<QTableView> m_samplesTable;
- std::unique_ptr<QDockWidget> m_samplesDock;
+ SamplesView * m_samplesView = nullptr;
+ QDockWidget * m_samplesDock = nullptr;
+
+ SampleView * m_sampleView = nullptr;
+ QDockWidget * m_sampleDock = nullptr;
};
diff --git a/search/search_quality/assessment_tool/sample_view.cpp b/search/search_quality/assessment_tool/sample_view.cpp
new file mode 100644
index 0000000000..cbf37f7bf4
--- /dev/null
+++ b/search/search_quality/assessment_tool/sample_view.cpp
@@ -0,0 +1,106 @@
+#include "search/search_quality/assessment_tool/sample_view.hpp"
+
+#include "search/result.hpp"
+#include "search/search_quality/assessment_tool/helpers.hpp"
+#include "search/search_quality/assessment_tool/languages_list.hpp"
+#include "search/search_quality/sample.hpp"
+
+#include <QtGui/QStandardItem>
+#include <QtGui/QStandardItemModel>
+#include <QtWidgets/QComboBox>
+#include <QtWidgets/QGroupBox>
+#include <QtWidgets/QHBoxLayout>
+#include <QtWidgets/QHeaderView>
+#include <QtWidgets/QLabel>
+#include <QtWidgets/QLineEdit>
+#include <QtWidgets/QListWidget>
+#include <QtWidgets/QVBoxLayout>
+
+namespace
+{
+QWidget * CreateSampleWidget(QWidget & parent, search::Result const & result)
+{
+ auto * widget = new QWidget(&parent);
+ auto * layout = new QVBoxLayout(widget);
+ widget->setLayout(layout);
+
+ layout->addWidget(new QLabel(ToQString(result.GetString())));
+
+ if (result.GetResultType() == search::Result::RESULT_FEATURE && !result.GetFeatureType().empty())
+ {
+ auto * type = new QLabel(ToQString(result.GetFeatureType()), widget);
+ type->setStyleSheet("QLabel { font-size : 8pt }");
+ layout->addWidget(type);
+ }
+
+ if (!result.GetAddress().empty())
+ {
+ auto * address = new QLabel(ToQString(result.GetAddress()), widget);
+ address->setStyleSheet("QLabel { color : green ; font-size : 8pt }");
+ layout->addWidget(address);
+ }
+
+ return widget;
+}
+} // namespace
+
+SampleView::SampleView(QWidget * parent) : QWidget(parent)
+{
+ auto * mainLayout = BuildLayoutWithoutMargins<QVBoxLayout>(this /* parent */);
+
+ {
+ auto * box = new QWidget(this /* parent */);
+ auto * layout = BuildLayoutWithoutMargins<QHBoxLayout>(box /* parent */);
+ box->setLayout(layout);
+
+ m_query = new QLineEdit(this /* parent */);
+ m_query->setToolTip(tr("Query text"));
+ layout->addWidget(m_query);
+
+ m_langs = new LanguagesList(this /* parent */);
+ m_langs->setToolTip(tr("Query input language"));
+ layout->addWidget(m_langs);
+
+ mainLayout->addWidget(box);
+ }
+
+ {
+ auto * box = new QWidget(this /* parent */);
+ auto * layout = BuildLayoutWithoutMargins<QVBoxLayout>(box /* parent */);
+ box->setLayout(layout);
+
+ layout->addWidget(new QLabel(tr("Found results")));
+
+ m_results = new QListWidget(box /* parent */);
+ layout->addWidget(m_results);
+
+ mainLayout->addWidget(box);
+ }
+
+ setLayout(mainLayout);
+ setWindowTitle(tr("Sample"));
+}
+
+void SampleView::SetContents(search::Sample const & sample)
+{
+ m_query->setText(ToQString(sample.m_query));
+ m_query->home(false /* mark */);
+
+ m_langs->Select(sample.m_locale);
+
+ m_results->clear();
+}
+
+void SampleView::ShowResults(search::Results::Iter begin, search::Results::Iter end)
+{
+ for (auto it = begin; it != end; ++it)
+ {
+ auto * item = new QListWidgetItem(m_results);
+ m_results->addItem(item);
+
+ auto * widget = CreateSampleWidget(*m_results /* parent */, *it /* sample */);
+ item->setSizeHint(widget->minimumSizeHint());
+
+ m_results->setItemWidget(item, widget);
+ }
+}
diff --git a/search/search_quality/assessment_tool/sample_view.hpp b/search/search_quality/assessment_tool/sample_view.hpp
new file mode 100644
index 0000000000..ed509bc87c
--- /dev/null
+++ b/search/search_quality/assessment_tool/sample_view.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "search/result.hpp"
+
+#include <QtWidgets/QWidget>
+
+class LanguagesList;
+class QLineEdit;
+class QListWidget;
+
+namespace search
+{
+struct Sample;
+}
+
+class SampleView : public QWidget
+{
+public:
+ explicit SampleView(QWidget * parent);
+
+ void SetContents(search::Sample const & sample);
+ void ShowResults(search::Results::Iter begin, search::Results::Iter end);
+
+private:
+ QLineEdit * m_query = nullptr;
+ LanguagesList * m_langs = nullptr;
+ QListWidget * m_results = nullptr;
+};
diff --git a/search/search_quality/assessment_tool/samples_view.cpp b/search/search_quality/assessment_tool/samples_view.cpp
new file mode 100644
index 0000000000..4e51010fae
--- /dev/null
+++ b/search/search_quality/assessment_tool/samples_view.cpp
@@ -0,0 +1,29 @@
+#include "search/search_quality/assessment_tool/samples_view.hpp"
+
+#include "search/search_quality/assessment_tool/helpers.hpp"
+
+#include <QtGui/QStandardItem>
+#include <QtGui/QStandardItemModel>
+#include <QtWidgets/QHeaderView>
+
+SamplesView::SamplesView(QWidget * parent) : QTableView(parent)
+{
+ setEditTriggers(QAbstractItemView::NoEditTriggers);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+
+ {
+ auto * header = horizontalHeader();
+ header->setStretchLastSection(true /* stretch */);
+ header->hide();
+ }
+
+ m_model = new QStandardItemModel(0 /* rows */, 1 /* columns */, this /* parent */);
+ setModel(m_model);
+}
+
+void SamplesView::SetSamples(std::vector<search::Sample> const & samples)
+{
+ m_model->removeRows(0, m_model->rowCount());
+ for (auto const & sample : samples)
+ m_model->appendRow(new QStandardItem(ToQString(sample.m_query)));
+}
diff --git a/search/search_quality/assessment_tool/samples_view.hpp b/search/search_quality/assessment_tool/samples_view.hpp
new file mode 100644
index 0000000000..43fd0860e1
--- /dev/null
+++ b/search/search_quality/assessment_tool/samples_view.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "search/search_quality/sample.hpp"
+
+#include <vector>
+
+#include <QtWidgets/QTableView>
+
+class QStandardItemModel;
+
+class SamplesView : public QTableView
+{
+public:
+ explicit SamplesView(QWidget * parent);
+
+ void SetSamples(std::vector<search::Sample> const & samples);
+
+private:
+ QStandardItemModel * m_model = nullptr;
+};
diff --git a/search/search_quality/assessment_tool/view.hpp b/search/search_quality/assessment_tool/view.hpp
index 7f7a65adfd..f0643c12ee 100644
--- a/search/search_quality/assessment_tool/view.hpp
+++ b/search/search_quality/assessment_tool/view.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "search/result.hpp"
#include "search/search_quality/sample.hpp"
#include <string>
@@ -16,6 +17,7 @@ public:
virtual void SetSamples(std::vector<search::Sample> const & samples) = 0;
virtual void ShowSample(search::Sample const & sample) = 0;
+ virtual void ShowResults(search::Results::Iter begin, search::Results::Iter end) = 0;
virtual void ShowError(std::string const & msg) = 0;
protected:
diff --git a/xcode/routing/routing.xcodeproj/project.pbxproj b/xcode/routing/routing.xcodeproj/project.pbxproj
index 4810e0ec8e..e7d736ca87 100644
--- a/xcode/routing/routing.xcodeproj/project.pbxproj
+++ b/xcode/routing/routing.xcodeproj/project.pbxproj
@@ -25,6 +25,11 @@
0C5992E21E433BE600203653 /* num_mwm_id.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5992E11E433BE600203653 /* num_mwm_id.hpp */; };
0C5BC9D11E28FD4E0071BFDD /* index_road_graph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5BC9CF1E28FD4E0071BFDD /* index_road_graph.cpp */; };
0C5BC9D21E28FD4E0071BFDD /* index_road_graph.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5BC9D01E28FD4E0071BFDD /* index_road_graph.hpp */; };
+ 0C5F5D201E798B0400307B98 /* cross_mwm_connector_serialization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5F5D1C1E798B0400307B98 /* cross_mwm_connector_serialization.cpp */; };
+ 0C5F5D211E798B0400307B98 /* cross_mwm_connector_serialization.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5F5D1D1E798B0400307B98 /* cross_mwm_connector_serialization.hpp */; };
+ 0C5F5D221E798B0400307B98 /* cross_mwm_connector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5F5D1E1E798B0400307B98 /* cross_mwm_connector.cpp */; };
+ 0C5F5D231E798B0400307B98 /* cross_mwm_connector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5F5D1F1E798B0400307B98 /* cross_mwm_connector.hpp */; };
+ 0C5F5D251E798B3800307B98 /* cross_mwm_connector_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5F5D241E798B3800307B98 /* cross_mwm_connector_test.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 */; };
0C5FEC5E1DDE192A0017688C /* geometry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC561DDE192A0017688C /* geometry.cpp */; };
@@ -271,6 +276,11 @@
0C5992E11E433BE600203653 /* num_mwm_id.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = num_mwm_id.hpp; sourceTree = "<group>"; };
0C5BC9CF1E28FD4E0071BFDD /* index_road_graph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_road_graph.cpp; sourceTree = "<group>"; };
0C5BC9D01E28FD4E0071BFDD /* index_road_graph.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = index_road_graph.hpp; sourceTree = "<group>"; };
+ 0C5F5D1C1E798B0400307B98 /* cross_mwm_connector_serialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cross_mwm_connector_serialization.cpp; sourceTree = "<group>"; };
+ 0C5F5D1D1E798B0400307B98 /* cross_mwm_connector_serialization.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cross_mwm_connector_serialization.hpp; sourceTree = "<group>"; };
+ 0C5F5D1E1E798B0400307B98 /* cross_mwm_connector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cross_mwm_connector.cpp; sourceTree = "<group>"; };
+ 0C5F5D1F1E798B0400307B98 /* cross_mwm_connector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cross_mwm_connector.hpp; sourceTree = "<group>"; };
+ 0C5F5D241E798B3800307B98 /* cross_mwm_connector_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cross_mwm_connector_test.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>"; };
0C5FEC561DDE192A0017688C /* geometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = geometry.cpp; sourceTree = "<group>"; };
@@ -579,6 +589,7 @@
6742ACA71C68A0B1009CB89E /* astar_progress_test.cpp */,
6742ACA81C68A0B1009CB89E /* astar_router_test.cpp */,
6742ACA91C68A0B1009CB89E /* async_router_test.cpp */,
+ 0C5F5D241E798B3800307B98 /* cross_mwm_connector_test.cpp */,
6742ACAA1C68A0B1009CB89E /* cross_routing_tests.cpp */,
6742ACAB1C68A0B1009CB89E /* followed_polyline_test.cpp */,
0C5FEC6C1DDE19A40017688C /* index_graph_test.cpp */,
@@ -704,6 +715,10 @@
56099E311CC9247E00A7772A /* bicycle_directions.hpp */,
56826BCE1DB51C4E00807C62 /* car_router.cpp */,
56826BCF1DB51C4E00807C62 /* car_router.hpp */,
+ 0C5F5D1E1E798B0400307B98 /* cross_mwm_connector.cpp */,
+ 0C5F5D1F1E798B0400307B98 /* cross_mwm_connector.hpp */,
+ 0C5F5D1C1E798B0400307B98 /* cross_mwm_connector_serialization.cpp */,
+ 0C5F5D1D1E798B0400307B98 /* cross_mwm_connector_serialization.hpp */,
A120B3411B4A7BE5002F3808 /* cross_mwm_road_graph.cpp */,
A120B3421B4A7BE5002F3808 /* cross_mwm_road_graph.hpp */,
A120B3431B4A7BE5002F3808 /* cross_mwm_router.cpp */,
@@ -845,6 +860,7 @@
56099E2A1CC7C97D00A7772A /* routing_result_graph.hpp in Headers */,
A120B3481B4A7BE5002F3808 /* cross_mwm_router.hpp in Headers */,
674F9BD31B0A580E00704FFA /* road_graph_router.hpp in Headers */,
+ 0C5F5D231E798B0400307B98 /* cross_mwm_connector.hpp in Headers */,
675344141A3F644F00A0A8C3 /* osrm_data_facade.hpp in Headers */,
6753441F1A3F644F00A0A8C3 /* turns.hpp in Headers */,
0C5FEC611DDE192A0017688C /* index_graph.hpp in Headers */,
@@ -875,6 +891,7 @@
0C8705051E0182F200BCAF71 /* route_point.hpp in Headers */,
A1876BC71BB19C4300C9C743 /* speed_camera.hpp in Headers */,
56EA2FD51D8FD8590083F01A /* routing_helpers.hpp in Headers */,
+ 0C5F5D211E798B0400307B98 /* cross_mwm_connector_serialization.hpp in Headers */,
0C0DF9221DE898B70055A22F /* index_graph_starter.hpp in Headers */,
0C090C881E4E276700D52AFD /* world_graph.hpp in Headers */,
56099E2F1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp in Headers */,
@@ -1106,6 +1123,7 @@
files = (
0C5FEC641DDE192A0017688C /* joint.cpp in Sources */,
0C090C871E4E276700D52AFD /* world_graph.cpp in Sources */,
+ 0C5F5D201E798B0400307B98 /* cross_mwm_connector_serialization.cpp in Sources */,
56CA09E71E30E73B00D05C9A /* restriction_test.cpp in Sources */,
0C5BC9D11E28FD4E0071BFDD /* index_road_graph.cpp in Sources */,
56826BD01DB51C4E00807C62 /* car_router.cpp in Sources */,
@@ -1121,8 +1139,10 @@
670EE5731B664796001E8064 /* pedestrian_directions.cpp in Sources */,
6753441B1A3F644F00A0A8C3 /* route.cpp in Sources */,
674F9BCA1B0A580E00704FFA /* async_router.cpp in Sources */,
+ 0C5F5D221E798B0400307B98 /* cross_mwm_connector.cpp in Sources */,
675344191A3F644F00A0A8C3 /* osrm2feature_map.cpp in Sources */,
670D049E1B0B4A970013A7AC /* nearest_edge_finder.cpp in Sources */,
+ 0C5F5D251E798B3800307B98 /* cross_mwm_connector_test.cpp in Sources */,
674F9BD61B0A580E00704FFA /* turns_generator.cpp in Sources */,
A17B42981BCFBD0E00A1EAE4 /* osrm_helpers.cpp in Sources */,
674F9BD21B0A580E00704FFA /* road_graph_router.cpp in Sources */,