diff options
author | Добрый Ээх <bukharaev@gmail.com> | 2017-03-13 19:24:02 +0300 |
---|---|---|
committer | Vladimir Byko-Ianko <bykoianko@gmail.com> | 2017-03-16 14:02:53 +0300 |
commit | c8d09d4c3088d76d2c3e80472ff64a2e9ac16b1d (patch) | |
tree | 77f87e504692e61071f2749eb28c4c1885cb4591 | |
parent | bf307d05a798bfa56616391b0c1706162e26196b (diff) |
[routing] pull request #5584 review fixes
-rw-r--r-- | coding/file_name_utils.hpp | 13 | ||||
-rw-r--r-- | generator/generator_tool/generator_tool.cpp | 4 | ||||
-rw-r--r-- | generator/routing_index_generator.cpp | 122 | ||||
-rw-r--r-- | routing/CMakeLists.txt | 4 | ||||
-rw-r--r-- | routing/cross_mwm_connector.cpp (renamed from routing/cross_mwm_ramp.cpp) | 62 | ||||
-rw-r--r-- | routing/cross_mwm_connector.hpp (renamed from routing/cross_mwm_ramp.hpp) | 52 | ||||
-rw-r--r-- | routing/cross_mwm_connector_serialization.cpp | 30 | ||||
-rw-r--r-- | routing/cross_mwm_connector_serialization.hpp (renamed from routing/cross_mwm_ramp_serialization.hpp) | 143 | ||||
-rw-r--r-- | routing/cross_mwm_ramp_serialization.cpp | 30 | ||||
-rw-r--r-- | routing/routing.pro | 8 | ||||
-rw-r--r-- | routing/routing_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | routing/routing_tests/cross_mwm_connector_test.cpp | 239 | ||||
-rw-r--r-- | routing/routing_tests/cross_mwm_ramp_test.cpp | 226 | ||||
-rw-r--r-- | routing/routing_tests/routing_tests.pro | 2 | ||||
-rw-r--r-- | xcode/routing/routing.xcodeproj/project.pbxproj | 20 |
15 files changed, 534 insertions, 422 deletions
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/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index cd2d86f292..3cbcd60940 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -69,9 +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 (for old OSRM 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 new AStar routing)."); +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."); diff --git a/generator/routing_index_generator.cpp b/generator/routing_index_generator.cpp index 19c2b33c24..73197f2331 100644 --- a/generator/routing_index_generator.cpp +++ b/generator/routing_index_generator.cpp @@ -1,17 +1,20 @@ #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" -#include "routing/cross_mwm_ramp.hpp" -#include "routing/cross_mwm_ramp_serialization.hpp" #include "routing_common/bicycle_model.hpp" #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" @@ -22,10 +25,10 @@ #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; @@ -33,10 +36,10 @@ using namespace routing; namespace { -class VehicleMaskMaker final +class VehicleMaskBuilder final { public: - explicit VehicleMaskMaker(string const & country) + explicit VehicleMaskBuilder(string const & country) : m_pedestrianModel(PedestrianModelFactory().GetVehicleModelForCountry(country)) , m_bicycleModel(BicycleModelFactory().GetVehicleModelForCountry(country)) , m_carModel(CarModelFactory().GetVehicleModelForCountry(country)) @@ -48,31 +51,31 @@ public: VehicleMask CalcRoadMask(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; + 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> + bool CalcMask(FeatureType const & f, Fn && fn) const + { VehicleMask mask = 0; - if (m_pedestrianModel->IsOneWay(f)) + if (fn(*m_pedestrianModel, f)) mask |= kPedestrianMask; - if (m_bicycleModel->IsOneWay(f)) + if (fn(*m_bicycleModel, f)) mask |= kBicycleMask; - if (m_carModel->IsOneWay(f)) + if (fn(*m_carModel, f)) mask |= kCarMask; return mask; } -private: shared_ptr<IVehicleModel> const m_pedestrianModel; shared_ptr<IVehicleModel> const m_bicycleModel; shared_ptr<IVehicleModel> const m_carModel; @@ -81,8 +84,7 @@ private: class Processor final { public: - explicit Processor(string const & country) : m_maskMaker(country) {} - + explicit Processor(string const & country) : m_maskBuilder(country) {} void ProcessAllFeatures(string const & filename) { feature::ForEachFromDat(filename, bind(&Processor::ProcessFeature, this, _1, _2)); @@ -102,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 = m_maskMaker.CalcRoadMask(f); + VehicleMask const mask = m_maskBuilder.CalcRoadMask(f); if (mask == 0) return; @@ -120,14 +121,14 @@ private: } } - VehicleMaskMaker const m_maskMaker; + VehicleMaskBuilder const m_maskBuilder; unordered_map<uint64_t, Joint> m_posToJoint; unordered_map<uint32_t, VehicleMask> m_masks; }; -bool BordersContains(vector<m2::RegionD> const & borders, m2::PointD const & point) +bool RegionsContain(vector<m2::RegionD> const & regions, m2::PointD const & point) { - for (m2::RegionD const & region : borders) + for (auto const & region : regions) { if (region.Contains(point)) return true; @@ -137,14 +138,14 @@ bool BordersContains(vector<m2::RegionD> const & borders, m2::PointD const & poi } void CalcCrossMwmTransitions(string const & path, string const & mwmFile, string const & country, - vector<CrossMwmRampSerializer::Transition> & transitions, - vector<CrossMwmRamp> & ramps) + vector<CrossMwmConnectorSerializer::Transition> & transitions, + CrossMwmConnectorPerVehicleType & connectors) { - string const polyFile = my::JoinFoldersToPath({path, BORDERS_DIR}, country + BORDERS_EXTENSION); + string const polyFile = my::JoinPath(path, BORDERS_DIR, country + BORDERS_EXTENSION); vector<m2::RegionD> borders; osm::LoadBorders(polyFile, borders); - VehicleMaskMaker const maskMaker(country); + VehicleMaskBuilder const maskMaker(country); feature::ForEachFromDat(mwmFile, [&](FeatureType const & f, uint32_t featureId) { VehicleMask const roadMask = maskMaker.CalcRoadMask(f); @@ -153,51 +154,44 @@ void CalcCrossMwmTransitions(string const & path, string const & mwmFile, string f.ParseGeometry(FeatureType::BEST_GEOMETRY); size_t const pointsCount = f.GetPointsCount(); - if (pointsCount <= 0) + if (pointsCount == 0) return; - bool prevPointIn = BordersContains(borders, f.GetPoint(0)); + bool prevPointIn = RegionsContain(borders, f.GetPoint(0)); for (size_t i = 1; i < pointsCount; ++i) { - bool const pointIn = BordersContains(borders, f.GetPoint(i)); - if (pointIn != prevPointIn) - { - uint32_t const segmentIdx = base::asserted_cast<uint32_t>(i - 1); - VehicleMask const oneWayMask = maskMaker.CalcOneWayMask(f); + bool const currPointIn = RegionsContain(borders, f.GetPoint(i)); + if (currPointIn == prevPointIn) + continue; - transitions.emplace_back(featureId, segmentIdx, roadMask, oneWayMask, pointIn, - f.GetPoint(i - 1), f.GetPoint(i)); + uint32_t const segmentIdx = base::asserted_cast<uint32_t>(i - 1); + VehicleMask const oneWayMask = maskMaker.CalcOneWayMask(f); - for (size_t j = 0; j < ramps.size(); ++j) - { - VehicleMask const mask = GetVehicleMask(static_cast<VehicleType>(j)); - CrossMwmRampSerializer::AddTransition(transitions.back(), mask, ramps[j]); - } + 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 = pointIn; + prevPointIn = currPointIn; } }); } -void FillWeights(string const & path, string const & country, CrossMwmRamp & ramp) +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()); - Index index; - platform::CountryFile countryFile(country); - index.RegisterMap(LocalCountryFile(path, countryFile, 0)); - MwmSet::MwmHandle handle = index.GetMwmHandleByCountryFile(countryFile); - CHECK(handle.IsAlive(), ()); - - Geometry geometry(GeometryLoader::Create(index, handle.GetId(), vehicleModel)); - - ramp.FillWeights([&](Segment const & enter, Segment const & exit) { - return estimator->CalcHeuristic(geometry.GetPoint(enter.GetRoadPoint(true)), - geometry.GetPoint(exit.GetRoadPoint(true))); + 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 @@ -238,12 +232,12 @@ void BuildCrossMwmSection(string const & path, string const & mwmFile, string co LOG(LINFO, ("Building cross mwm section for", country)); my::Timer timer; - vector<CrossMwmRamp> ramps(static_cast<size_t>(VehicleType::Count), kFakeNumMwmId); + CrossMwmConnectorPerVehicleType connectors; - vector<CrossMwmRampSerializer::Transition> transitions; - CalcCrossMwmTransitions(path, mwmFile, country, transitions, ramps); + vector<CrossMwmConnectorSerializer::Transition> transitions; + CalcCrossMwmTransitions(path, mwmFile, country, transitions, connectors); - FillWeights(path, country, ramps[static_cast<size_t>(VehicleType::Car)]); + 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); @@ -252,7 +246,7 @@ void BuildCrossMwmSection(string const & path, string const & mwmFile, string co serial::CodingParams const & codingParams = dataHeader.GetDefCodingParams(); auto const startPos = writer.Pos(); - CrossMwmRampSerializer::Serialize(transitions, ramps, codingParams, writer); + CrossMwmConnectorSerializer::Serialize(transitions, connectors, codingParams, writer); auto const sectionSize = writer.Pos() - startPos; LOG(LINFO, ("Cross mwm section for", country, "generated in", timer.ElapsedSeconds(), 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_ramp.cpp b/routing/cross_mwm_connector.cpp index 8a5e82b301..cf6d62469f 100644 --- a/routing/cross_mwm_ramp.cpp +++ b/routing/cross_mwm_connector.cpp @@ -1,4 +1,4 @@ -#include "routing/cross_mwm_ramp.hpp" +#include "routing/cross_mwm_connector.hpp" namespace { @@ -8,23 +8,23 @@ uint32_t constexpr kFakeId = std::numeric_limits<uint32_t>::max(); namespace routing { // static -CrossMwmRamp::Weight constexpr CrossMwmRamp::kNoRoute; +CrossMwmConnector::Weight constexpr CrossMwmConnector::kNoRoute; -void CrossMwmRamp::AddTransition(uint32_t featureId, uint32_t segmentIdx, bool oneWay, - bool forwardIsEnter, m2::PointD const & backPoint, - m2::PointD const & frontPoint) +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); + 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); + m_exits.emplace_back(m_mwmId, featureId, segmentIdx, true /* forward */); } if (!oneWay) @@ -32,19 +32,19 @@ void CrossMwmRamp::AddTransition(uint32_t featureId, uint32_t segmentIdx, bool o if (forwardIsEnter) { transition.m_exitIdx = base::asserted_cast<uint32_t>(m_exits.size()); - m_exits.emplace_back(m_mwmId, featureId, segmentIdx, false); + 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); + m_enters.emplace_back(m_mwmId, featureId, segmentIdx, false /* forward */); } } m_transitions[Key(featureId, segmentIdx)] = transition; } -bool CrossMwmRamp::IsTransition(Segment const & segment, bool isOutgoing) const +bool CrossMwmConnector::IsTransition(Segment const & segment, bool isOutgoing) const { auto it = m_transitions.find(Key(segment.GetFeatureId(), segment.GetSegmentIdx())); if (it == m_transitions.cend()) @@ -57,14 +57,14 @@ bool CrossMwmRamp::IsTransition(Segment const & segment, bool isOutgoing) const return (segment.IsForward() == transition.m_forwardIsEnter) == isOutgoing; } -m2::PointD const & CrossMwmRamp::GetPoint(Segment const & segment, bool front) const +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 CrossMwmRamp::GetEdgeList(Segment const & segment, bool isOutgoing, - std::vector<SegmentEdge> & edges) const +void CrossMwmConnector::GetEdgeList(Segment const & segment, bool isOutgoing, + std::vector<SegmentEdge> & edges) const { Transition const & transition = GetTransition(segment); if (isOutgoing) @@ -87,22 +87,48 @@ void CrossMwmRamp::GetEdgeList(Segment const & segment, bool isOutgoing, } } -void CrossMwmRamp::AddEdge(Segment const & segment, Weight weight, - std::vector<SegmentEdge> & edges) const +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)); } -CrossMwmRamp::Transition const & CrossMwmRamp::GetTransition(Segment const & segment) const +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 transition segment:", segment)); + CHECK(it != m_transitions.cend(), ("Not a transition segment:", segment)); return it->second; } -CrossMwmRamp::Weight CrossMwmRamp::GetWeight(size_t enterIdx, size_t exitIdx) const +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]; diff --git a/routing/cross_mwm_ramp.hpp b/routing/cross_mwm_connector.hpp index e8ac49101b..22ef84de61 100644 --- a/routing/cross_mwm_ramp.hpp +++ b/routing/cross_mwm_connector.hpp @@ -2,10 +2,10 @@ #include "routing/segment.hpp" -#include "base/assert.hpp" - #include "geometry/point2d.hpp" +#include "base/assert.hpp" + #include <cmath> #include <limits> #include <unordered_map> @@ -13,10 +13,12 @@ namespace routing { -class CrossMwmRamp final +class CrossMwmConnector final { public: - CrossMwmRamp(NumMwmId mwmId) : m_mwmId(mwmId) {} + 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); @@ -28,24 +30,28 @@ public: 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 { return m_weightsWereLoaded; } + 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 (size_t i = 0; i < m_enters.size(); ++i) + for (Segment const & enter : m_enters) { - for (size_t j = 0; j < m_exits.size(); ++j) + for (Segment const & exit : m_exits) { - double const weight = calcWeight(m_enters[i], m_exits[j]); + 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 internal type used for storing edges weights. + // 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; @@ -60,7 +66,7 @@ private: { } - bool operator==(const Key & key) const + bool operator==(Key const & key) const { return m_featureId == key.m_featureId && m_segmentIdx == key.m_segmentIdx; } @@ -71,7 +77,7 @@ private: struct HashKey { - size_t operator()(const Key & key) const + 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)); @@ -95,13 +101,28 @@ private: uint32_t m_enterIdx = 0; uint32_t m_exitIdx = 0; - m2::PointD m_backPoint = {0.0, 0.0}; - m2::PointD m_frontPoint = {0.0, 0.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; }; - friend class CrossMwmRampSerializer; + 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; @@ -111,7 +132,8 @@ private: 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; - bool m_weightsWereLoaded = false; }; } // 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_ramp_serialization.hpp b/routing/cross_mwm_connector_serialization.hpp index dbc0d7f42b..f21bc74a7d 100644 --- a/routing/cross_mwm_ramp_serialization.hpp +++ b/routing/cross_mwm_connector_serialization.hpp @@ -1,6 +1,6 @@ #pragma once -#include "routing/cross_mwm_ramp.hpp" +#include "routing/cross_mwm_connector.hpp" #include "routing/routing_exceptions.hpp" #include "routing/vehicle_mask.hpp" @@ -14,12 +14,17 @@ #include "base/checked_cast.hpp" -#include <stdint.h> +#include <array> +#include <cstdint> +#include <limits> #include <vector> namespace routing { -class CrossMwmRampSerializer final +using CrossMwmConnectorPerVehicleType = + std::array<CrossMwmConnector, static_cast<size_t>(VehicleType::Count)>; + +class CrossMwmConnectorSerializer final { public: class Transition final @@ -50,8 +55,8 @@ public: serial::SavePoint(sink, m_frontPoint, codingParams); BitWriter<Sink> writer(sink); - writer.WriteAtMost32Bits(static_cast<uint32_t>(m_roadMask), bitsPerMask); - writer.WriteAtMost32Bits(static_cast<uint32_t>(m_oneWayMask), bitsPerMask); + 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); } @@ -64,8 +69,8 @@ public: m_frontPoint = serial::LoadPoint(src, codingParams); BitReader<Source> reader(src); - m_roadMask = reader.ReadAtMost32Bits(bitsPerMask); - m_oneWayMask = reader.ReadAtMost32Bits(bitsPerMask); + m_roadMask = base::asserted_cast<VehicleMask>(reader.ReadAtMost32Bits(bitsPerMask)); + m_oneWayMask = base::asserted_cast<VehicleMask>(reader.ReadAtMost32Bits(bitsPerMask)); m_forwardIsEnter = reader.Read(1) == 0; } @@ -80,39 +85,39 @@ public: private: uint32_t m_featureId = 0; uint32_t m_segmentIdx = 0; - m2::PointD m_backPoint = {0.0, 0.0}; - m2::PointD m_frontPoint = {0.0, 0.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; }; - CrossMwmRampSerializer() = delete; + CrossMwmConnectorSerializer() = delete; template <class Sink> static void Serialize(std::vector<Transition> const & transitions, - vector<CrossMwmRamp> const & ramps, + CrossMwmConnectorPerVehicleType const & connectors, serial::CodingParams const & codingParams, Sink & sink) { - auto const bitsPerMask = static_cast<uint8_t>(VehicleType::Count); - vector<uint8_t> transitionsBuf; + 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); - vector<vector<uint8_t>> weightBuffers(ramps.size()); + std::vector<std::vector<uint8_t>> weightBuffers(connectors.size()); - for (size_t i = 0; i < ramps.size(); ++i) + for (size_t i = 0; i < connectors.size(); ++i) { - CrossMwmRamp const & ramp = ramps[i]; - if (!ramp.HasWeights()) + CrossMwmConnector const & connector = connectors[i]; + if (connector.m_weights.empty()) continue; - vector<uint8_t> & buffer = weightBuffers[i]; - WriteWeights(ramp.m_weights, buffer); + std::vector<uint8_t> & buffer = weightBuffers[i]; + WriteWeights(connector.m_weights, buffer); - auto numEnters = base::checked_cast<uint32_t>(ramp.GetEnters().size()); - auto numExits = base::checked_cast<uint32_t>(ramp.GetExits().size()); + 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)); } @@ -125,12 +130,15 @@ public: } template <class Source> - static void DeserializeTransitions(VehicleType requiredVehicle, CrossMwmRamp & ramp, Source & src) + static void DeserializeTransitions(VehicleType requiredVehicle, CrossMwmConnector & connector, + Source & src) { + CHECK(connector.m_weightsLoadState == CrossMwmConnector::WeightsLoadState::Unknown, ()); + Header header; header.Deserialize(src); - uint64_t const transitionsEnd = src.Pos() + header.GetSizeTransitions(); + uint64_t weightsOffset = src.Pos() + header.GetSizeTransitions(); VehicleMask const requiredMask = GetVehicleMask(requiredVehicle); auto const numTransitions = base::checked_cast<size_t>(header.GetNumTransitions()); @@ -138,72 +146,76 @@ public: { Transition transition; transition.Deserialize(header.GetCodingParams(), header.GetBitsPerMask(), src); - AddTransition(transition, requiredMask, ramp); + AddTransition(transition, requiredMask, connector); } - if (src.Pos() != transitionsEnd) + if (src.Pos() != weightsOffset) { MYTHROW(CorruptedDataException, - ("Wrong position", src.Pos(), "after decoding transitions, expected:", transitionsEnd, - "size:", header.GetSizeTransitions())); + ("Wrong position", src.Pos(), "after decoding transitions, expected:", + connector.m_weightsOffset, "size:", header.GetSizeTransitions())); } - } - - template <class Source> - static void DeserializeWeights(VehicleType requiredVehicle, CrossMwmRamp & ramp, Source & src) - { - CHECK(!ramp.WeightsWereLoaded(), ()); - - Header header; - header.Deserialize(src); - src.Skip(header.GetSizeTransitions()); for (Section const & section : header.GetSections()) { if (section.GetVehicleType() != requiredVehicle) { - src.Skip(section.GetSize()); + weightsOffset += section.GetSize(); continue; } - size_t const numEnters = ramp.GetEnters().size(); - size_t const numExits = ramp.GetExits().size(); + 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(), ", ramp:", 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(), ", ramp:", numExits)); + MYTHROW(CorruptedDataException, ("Mismatch exits number, section:", section.GetNumExits(), + ", connector:", numExits)); } - size_t const size = numEnters * numExits; - ramp.m_weights.reserve(size); - for (size_t i = 0; i < size; ++i) - { - auto const weight = ReadPrimitiveFromSource<uint32_t>(src); - ramp.m_weights.push_back(static_cast<float>(weight)); - } - break; + connector.m_weightsOffset = weightsOffset; + connector.m_weightsLoadState = CrossMwmConnector::WeightsLoadState::ReadyToLoad; + return; } - ramp.m_weightsWereLoaded = true; + 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, - CrossMwmRamp & ramp) + CrossMwmConnector & connector) { if ((transition.GetRoadMask() & requiredMask) == 0) return; bool const isOneWay = (transition.GetOneWayMask() & requiredMask) != 0; - ramp.AddTransition(transition.GetFeatureId(), transition.GetSegmentIdx(), isOneWay, - transition.ForwardIsEnter(), transition.GetBackPoint(), - transition.GetFrontPoint()); + connector.AddTransition(transition.GetFeatureId(), transition.GetSegmentIdx(), isOneWay, + transition.ForwardIsEnter(), transition.GetBackPoint(), + transition.GetFrontPoint()); } private: @@ -304,7 +316,7 @@ private: uint64_t GetSizeTransitions() const { return m_sizeTransitions; } serial::CodingParams const & GetCodingParams() const { return m_codingParams; } uint8_t GetBitsPerMask() const { return m_bitsPerMask; } - vector<Section> const & GetSections() const { return m_sections; } + std::vector<Section> const & GetSections() const { return m_sections; } private: uint32_t m_version = kLastVersion; @@ -312,11 +324,20 @@ private: uint64_t m_sizeTransitions = 0; serial::CodingParams m_codingParams; uint8_t m_bitsPerMask = 0; - vector<Section> m_sections; + 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(vector<uint8_t> & buffer, Sink & sink) + static void FlushBuffer(std::vector<uint8_t> & buffer, Sink & sink) { sink.Write(buffer.data(), buffer.size()); buffer.clear(); @@ -326,7 +347,7 @@ private: serial::CodingParams const & codingParams, uint8_t bitsPerMask, std::vector<uint8_t> & buffer); - static void WriteWeights(std::vector<CrossMwmRamp::Weight> const & weights, + static void WriteWeights(std::vector<CrossMwmConnector::Weight> const & weights, std::vector<uint8_t> & buffer); }; } // namespace routing diff --git a/routing/cross_mwm_ramp_serialization.cpp b/routing/cross_mwm_ramp_serialization.cpp deleted file mode 100644 index 46d1dda389..0000000000 --- a/routing/cross_mwm_ramp_serialization.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "routing/cross_mwm_ramp_serialization.hpp" - -using namespace std; - -namespace routing -{ -// static -uint32_t constexpr CrossMwmRampSerializer::kLastVersion; - -// static -void CrossMwmRampSerializer::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 CrossMwmRampSerializer::WriteWeights(vector<CrossMwmRamp::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/routing.pro b/routing/routing.pro index f2aac961f0..7ba284b0a5 100644 --- a/routing/routing.pro +++ b/routing/routing.pro @@ -17,9 +17,9 @@ 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_ramp.cpp \ - cross_mwm_ramp_serialization.cpp \ cross_mwm_road_graph.cpp \ cross_mwm_router.cpp \ cross_routing_context.cpp \ @@ -69,9 +69,9 @@ 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_ramp.hpp \ - cross_mwm_ramp_serialization.hpp \ cross_mwm_road_graph.hpp \ cross_mwm_router.hpp \ cross_routing_context.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/cross_mwm_ramp_test.cpp b/routing/routing_tests/cross_mwm_ramp_test.cpp deleted file mode 100644 index 18ac375124..0000000000 --- a/routing/routing_tests/cross_mwm_ramp_test.cpp +++ /dev/null @@ -1,226 +0,0 @@ -#include "testing/testing.hpp" - -#include "routing/cross_mwm_ramp_serialization.hpp" - -#include "coding/writer.hpp" - -using namespace routing; -using namespace std; - -namespace -{ -NumMwmId constexpr mwmId = 777; - -void CheckRampConsistency(CrossMwmRamp const & ramp) -{ - for (Segment const & enter : ramp.GetEnters()) - { - TEST(ramp.IsTransition(enter, true /* isOutgoing */), ()); - TEST(!ramp.IsTransition(enter, false /* isOutgoing */), ()); - } - - for (Segment const & exit : ramp.GetExits()) - { - TEST(!ramp.IsTransition(exit, true /* isOutgoing */), ()); - TEST(ramp.IsTransition(exit, false /* isOutgoing */), ()); - } -} - -void CheckEdges(CrossMwmRamp const & ramp, Segment const & from, bool isOutgoing, - vector<SegmentEdge> const & expectedEdges) -{ - vector<SegmentEdge> edges; - ramp.GetEdgeList(from, isOutgoing, edges); - TEST_EQUAL(edges, expectedEdges, ()); -} -} - -namespace routing_test -{ -UNIT_TEST(OneWayEnter) -{ - uint32_t constexpr featureId = 1; - uint32_t constexpr segmentIdx = 1; - CrossMwmRamp ramp(mwmId); - ramp.AddTransition(featureId, segmentIdx, true /* oneWay */, true /* forwardIsEnter */, - {} /* backPoint */, {} /* frontPoint */); - - CheckRampConsistency(ramp); - TEST_EQUAL(ramp.GetEnters().size(), 1, ()); - TEST_EQUAL(ramp.GetExits().size(), 0, ()); - TEST(ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - true /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - false /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - true /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - false /* isOutgoing */), - ()); -} - -UNIT_TEST(OneWayExit) -{ - uint32_t constexpr featureId = 1; - uint32_t constexpr segmentIdx = 1; - CrossMwmRamp ramp(mwmId); - ramp.AddTransition(featureId, segmentIdx, true /* oneWay */, false /* forwardIsEnter */, - {} /* backPoint */, {} /* frontPoint */); - - CheckRampConsistency(ramp); - TEST_EQUAL(ramp.GetEnters().size(), 0, ()); - TEST_EQUAL(ramp.GetExits().size(), 1, ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - true /* isOutgoing */), - ()); - TEST(ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - false /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - true /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - false /* isOutgoing */), - ()); -} - -UNIT_TEST(TwoWayEnter) -{ - uint32_t constexpr featureId = 1; - uint32_t constexpr segmentIdx = 1; - CrossMwmRamp ramp(mwmId); - ramp.AddTransition(featureId, segmentIdx, false /* oneWay */, true /* forwardIsEnter */, - {} /* backPoint */, {} /* frontPoint */); - - CheckRampConsistency(ramp); - TEST_EQUAL(ramp.GetEnters().size(), 1, ()); - TEST_EQUAL(ramp.GetExits().size(), 1, ()); - TEST(ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - true /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - false /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - true /* isOutgoing */), - ()); - TEST(ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - false /* isOutgoing */), - ()); -} - -UNIT_TEST(TwoWayExit) -{ - uint32_t constexpr featureId = 1; - uint32_t constexpr segmentIdx = 1; - CrossMwmRamp ramp(mwmId); - ramp.AddTransition(featureId, segmentIdx, false /* oneWay */, false /* forwardIsEnter */, - {} /* backPoint */, {} /* frontPoint */); - - CheckRampConsistency(ramp); - TEST_EQUAL(ramp.GetEnters().size(), 1, ()); - TEST_EQUAL(ramp.GetExits().size(), 1, ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - true /* isOutgoing */), - ()); - TEST(ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, true /* forward */), - false /* isOutgoing */), - ()); - TEST(ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - true /* isOutgoing */), - ()); - TEST(!ramp.IsTransition(Segment(mwmId, featureId, segmentIdx, false /* forward */), - false /* isOutgoing */), - ()); -} - -UNIT_TEST(Serialization) -{ - float constexpr kEdgesWeight = 333; - - vector<uint8_t> buffer; - { - vector<CrossMwmRampSerializer::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)}}; - - vector<CrossMwmRamp> ramps(static_cast<size_t>(VehicleType::Count), mwmId); - - CrossMwmRamp & carRamp = ramps[static_cast<size_t>(VehicleType::Car)]; - for (auto const & transition : transitions) - CrossMwmRampSerializer::AddTransition(transition, kCarMask, carRamp); - - carRamp.FillWeights([](Segment const & enter, Segment const & exit) { return kEdgesWeight; }); - - serial::CodingParams const codingParams; - MemWriter<vector<uint8_t>> writer(buffer); - CrossMwmRampSerializer::Serialize(transitions, ramps, codingParams, writer); - } - - CrossMwmRamp ramp(mwmId); - { - MemReader reader(buffer.data(), buffer.size()); - ReaderSource<MemReader> source(reader); - CrossMwmRampSerializer::DeserializeTransitions(VehicleType::Car, ramp, source); - } - - CheckRampConsistency(ramp); - - TEST_EQUAL(ramp.GetEnters().size(), 2, ()); - TEST_EQUAL(ramp.GetExits().size(), 1, ()); - - TEST(!ramp.IsTransition(Segment(mwmId, 0, 0, true), true /* isOutgoing */), ()); - - TEST(ramp.IsTransition(Segment(mwmId, 10, 1, true /* forward */), true /* isOutgoing */), ()); - TEST(!ramp.IsTransition(Segment(mwmId, 10, 1, true /* forward */), false /* isOutgoing */), ()); - TEST(!ramp.IsTransition(Segment(mwmId, 10, 1, false /* forward */), true /* isOutgoing */), ()); - TEST(!ramp.IsTransition(Segment(mwmId, 10, 1, false /* forward */), false /* isOutgoing */), ()); - - TEST(ramp.IsTransition(Segment(mwmId, 20, 2, true /* forward */), true /* isOutgoing */), ()); - TEST(!ramp.IsTransition(Segment(mwmId, 20, 2, true /* forward */), false /* isOutgoing */), ()); - TEST(!ramp.IsTransition(Segment(mwmId, 20, 2, false /* forward */), true /* isOutgoing */), ()); - TEST(ramp.IsTransition(Segment(mwmId, 20, 2, false /* forward */), false /* isOutgoing */), ()); - - TEST(!ramp.IsTransition(Segment(mwmId, 30, 3, true /* forward */), true /* isOutgoing */), ()); - - TEST(!ramp.WeightsWereLoaded(), ()); - TEST(!ramp.HasWeights(), ()); - - { - MemReader reader(buffer.data(), buffer.size()); - ReaderSource<MemReader> source(reader); - CrossMwmRampSerializer::DeserializeWeights(VehicleType::Car, ramp, source); - } - TEST(ramp.WeightsWereLoaded(), ()); - TEST(ramp.HasWeights(), ()); - - double constexpr eps = 1e-6; - TEST(AlmostEqualAbs(ramp.GetPoint(Segment(mwmId, 20, 2, true /* forward */), true /* front */), - m2::PointD(2.3, 2.4), eps), - ()); - TEST(AlmostEqualAbs(ramp.GetPoint(Segment(mwmId, 20, 2, true /* forward */), false /* front */), - m2::PointD(2.1, 2.2), eps), - ()); - TEST(AlmostEqualAbs(ramp.GetPoint(Segment(mwmId, 20, 2, false /* forward */), true /* front */), - m2::PointD(2.1, 2.2), eps), - ()); - TEST(AlmostEqualAbs(ramp.GetPoint(Segment(mwmId, 20, 2, true /* forward */), true /* front */), - m2::PointD(2.3, 2.4), eps), - ()); - - CheckEdges(ramp, Segment(mwmId, 10, 1, true /* forward */), true /* isOutgoing */, - {{Segment(mwmId, 20, 2, false /* forward */), kEdgesWeight}}); - - CheckEdges(ramp, Segment(mwmId, 20, 2, true /* forward */), true /* isOutgoing */, - {{Segment(mwmId, 20, 2, false /* forward */), kEdgesWeight}}); - - CheckEdges(ramp, 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 3788a26582..5ea3209ae3 100644 --- a/routing/routing_tests/routing_tests.pro +++ b/routing/routing_tests/routing_tests.pro @@ -26,7 +26,7 @@ SOURCES += \ astar_progress_test.cpp \ astar_router_test.cpp \ async_router_test.cpp \ - cross_mwm_ramp_test.cpp \ + cross_mwm_connector_test.cpp \ cross_routing_tests.cpp \ cumulative_restriction_test.cpp \ followed_polyline_test.cpp \ 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 */, |