From fcb95644c868a883634c3638b3514e3bec60437a Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Wed, 15 Mar 2017 20:52:11 +0300 Subject: [PATCH] [routing] [generator] A component to store road accessibility info. --- defines.hpp | 2 + generator/CMakeLists.txt | 4 + generator/generator.pro | 4 + generator/generator_tests/CMakeLists.txt | 1 + generator/generator_tests/generator_tests.pro | 1 + .../restriction_collector_test.cpp | 2 +- .../generator_tests/restriction_test.cpp | 3 +- .../generator_tests/road_access_test.cpp | 130 ++++++++++++++ .../generator_tests_support/CMakeLists.txt | 4 +- .../generator_tests_support.pro | 4 +- ...iction_helpers.cpp => routing_helpers.cpp} | 2 +- ...iction_helpers.hpp => routing_helpers.hpp} | 0 generator/generator_tool/generator_tool.cpp | 9 +- generator/osm2type.cpp | 21 +-- generator/osm_source.cpp | 4 +- generator/osm_translator.hpp | 40 +++-- generator/restriction_collector.cpp | 38 +--- generator/restriction_collector.hpp | 14 -- generator/restriction_generator.cpp | 4 +- generator/restriction_generator.hpp | 16 +- generator/restriction_writer.cpp | 7 +- generator/restriction_writer.hpp | 6 +- generator/road_access_generator.cpp | 162 ++++++++++++++++++ generator/road_access_generator.hpp | 54 ++++++ generator/routing_helpers.cpp | 44 +++++ generator/routing_helpers.hpp | 30 ++++ routing/CMakeLists.txt | 3 + routing/road_access.hpp | 27 +++ routing/road_access_serialization.cpp | 7 + routing/road_access_serialization.hpp | 57 ++++++ routing/routing.pro | 3 + routing/routing_tests/CMakeLists.txt | 1 + routing/routing_tests/road_access_test.cpp | 44 +++++ routing/routing_tests/routing_tests.pro | 1 + 34 files changed, 654 insertions(+), 95 deletions(-) create mode 100644 generator/generator_tests/road_access_test.cpp rename generator/generator_tests_support/{restriction_helpers.cpp => routing_helpers.cpp} (94%) rename generator/generator_tests_support/{restriction_helpers.hpp => routing_helpers.hpp} (100%) create mode 100644 generator/road_access_generator.cpp create mode 100644 generator/road_access_generator.hpp create mode 100644 generator/routing_helpers.cpp create mode 100644 generator/routing_helpers.hpp create mode 100644 routing/road_access.hpp create mode 100644 routing/road_access_serialization.cpp create mode 100644 routing/road_access_serialization.hpp create mode 100644 routing/routing_tests/road_access_test.cpp diff --git a/defines.hpp b/defines.hpp index c8d87a2e8f..45dce1ea18 100644 --- a/defines.hpp +++ b/defines.hpp @@ -27,6 +27,7 @@ #define METADATA_FILE_TAG "meta" #define METADATA_INDEX_FILE_TAG "metaidx" #define ALTITUDES_FILE_TAG "altitudes" +#define ROAD_ACCESS_FILE_TAG "roadaccess" #define RESTRICTIONS_FILE_TAG "restrictions" #define ROUTING_FILE_TAG "routing" #define CROSS_MWM_FILE_TAG "cross_mwm" @@ -77,6 +78,7 @@ #define GPS_TRACK_FILENAME "gps_track.dat" #define RESTRICTIONS_FILENAME "restrictions.csv" +#define ROAD_ACCESS_FILENAME "road_access.csv" #define TRAFFIC_FILE_EXTENSION ".traffic" diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 3b285bf783..124dd44dda 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -61,8 +61,12 @@ set(SRC restriction_generator.hpp restriction_writer.cpp restriction_writer.hpp + road_access_generator.cpp + road_access_generator.hpp routing_generator.cpp routing_generator.hpp + routing_helpers.cpp + routing_helpers.hpp routing_index_generator.cpp routing_index_generator.hpp search_index_builder.cpp diff --git a/generator/generator.pro b/generator/generator.pro index 5b7f5a7acb..69effdadac 100644 --- a/generator/generator.pro +++ b/generator/generator.pro @@ -39,7 +39,9 @@ SOURCES += \ restriction_collector.cpp \ restriction_generator.cpp \ restriction_writer.cpp \ + road_access_generator.cpp \ routing_generator.cpp \ + routing_helpers.cpp \ routing_index_generator.cpp \ search_index_builder.cpp \ sponsored_scoring.cpp \ @@ -81,7 +83,9 @@ HEADERS += \ restriction_collector.hpp \ restriction_generator.hpp \ restriction_writer.hpp \ + road_access_generator.hpp \ routing_generator.hpp \ + routing_helpers.hpp \ routing_index_generator.hpp \ search_index_builder.hpp \ sponsored_dataset.hpp \ diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt index cdc71a09b4..cf21475da7 100644 --- a/generator/generator_tests/CMakeLists.txt +++ b/generator/generator_tests/CMakeLists.txt @@ -12,6 +12,7 @@ set( osm_id_test.cpp osm_o5m_source_test.cpp osm_type_test.cpp + road_access_test.cpp restriction_collector_test.cpp restriction_test.cpp source_data.cpp diff --git a/generator/generator_tests/generator_tests.pro b/generator/generator_tests/generator_tests.pro index 7315d9fa24..abf206292d 100644 --- a/generator/generator_tests/generator_tests.pro +++ b/generator/generator_tests/generator_tests.pro @@ -38,6 +38,7 @@ SOURCES += \ osm_id_test.cpp \ osm_o5m_source_test.cpp \ osm_type_test.cpp \ + road_access_test.cpp \ restriction_collector_test.cpp \ restriction_test.cpp \ source_data.cpp \ diff --git a/generator/generator_tests/restriction_collector_test.cpp b/generator/generator_tests/restriction_collector_test.cpp index 7dd9556b32..78896221c4 100644 --- a/generator/generator_tests/restriction_collector_test.cpp +++ b/generator/generator_tests/restriction_collector_test.cpp @@ -1,6 +1,6 @@ #include "testing/testing.hpp" -#include "generator/generator_tests_support/restriction_helpers.hpp" +#include "generator/generator_tests_support/routing_helpers.hpp" #include "generator/osm_id.hpp" #include "generator/restriction_collector.hpp" diff --git a/generator/generator_tests/restriction_test.cpp b/generator/generator_tests/restriction_test.cpp index e6b76a88f2..c4e7b7957a 100644 --- a/generator/generator_tests/restriction_test.cpp +++ b/generator/generator_tests/restriction_test.cpp @@ -1,6 +1,6 @@ #include "testing/testing.hpp" -#include "generator/generator_tests_support/restriction_helpers.hpp" +#include "generator/generator_tests_support/routing_helpers.hpp" #include "generator/generator_tests_support/test_feature.hpp" #include "generator/generator_tests_support/test_mwm_builder.hpp" @@ -21,7 +21,6 @@ #include "platform/platform.hpp" #include "base/logging.hpp" -#include "base/scope_guard.hpp" #include "std/string.hpp" diff --git a/generator/generator_tests/road_access_test.cpp b/generator/generator_tests/road_access_test.cpp new file mode 100644 index 0000000000..652f30e8cf --- /dev/null +++ b/generator/generator_tests/road_access_test.cpp @@ -0,0 +1,130 @@ +#include "testing/testing.hpp" + +#include "generator/generator_tests_support/routing_helpers.hpp" +#include "generator/generator_tests_support/test_feature.hpp" +#include "generator/generator_tests_support/test_mwm_builder.hpp" + +#include "generator/road_access_generator.hpp" + +#include "routing/road_access_serialization.hpp" + +#include "indexer/index.hpp" +#include "indexer/mwm_set.hpp" + +#include "coding/file_name_utils.hpp" + +#include "platform/platform_tests_support/scoped_dir.hpp" +#include "platform/platform_tests_support/scoped_file.hpp" + +#include "platform/country_file.hpp" +#include "platform/platform.hpp" + +#include "base/logging.hpp" + +#include "std/string.hpp" + +using namespace feature; +using namespace generator; +using namespace platform::tests_support; +using namespace platform; +using namespace routing; + +namespace +{ +string const kTestDir = "road_access_generation_test"; +string const kTestMwm = "test"; +string const kRoadAccessFilename = "road_access_in_osm_ids.csv"; +string const kOsmIdsToFeatureIdsName = "osm_ids_to_feature_ids" OSM2FEATURE_FILE_EXTENSION; + +void BuildEmptyMwm(LocalCountryFile & country) +{ + generator::tests_support::TestMwmBuilder builder(country, feature::DataHeader::country); +} + +void LoadRoadAccess(MwmValue const & mwmValue, RoadAccess & roadAccess) +{ + TEST(mwmValue.m_cont.IsExist(ROAD_ACCESS_FILE_TAG), ()); + + try + { + FilesContainerR::TReader const reader = mwmValue.m_cont.GetReader(ROAD_ACCESS_FILE_TAG); + ReaderSource src(reader); + + RoadAccessSerializer::Deserialize(src, roadAccess); + } + catch (Reader::OpenException const & e) + { + LOG(LERROR, ("Error while reading", ROAD_ACCESS_FILE_TAG, "section.", e.Msg())); + } +} + +// todo(@m) This helper function is almost identical to the one in restriction_test.cpp. +void TestRoadAccess(string const & roadAccessContent, string const & mappingContent) +{ + Platform & platform = GetPlatform(); + string const writableDir = platform.WritableDir(); + + // Building empty mwm. + LocalCountryFile country(my::JoinFoldersToPath(writableDir, kTestDir), CountryFile(kTestMwm), 1); + ScopedDir const scopedDir(kTestDir); + string const mwmRelativePath = my::JoinFoldersToPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION); + ScopedFile const scopedMwm(mwmRelativePath); + BuildEmptyMwm(country); + + // Creating a file with road access. + string const roadAccessRelativePath = my::JoinFoldersToPath(kTestDir, kRoadAccessFilename); + ScopedFile const roadAccessFile(roadAccessRelativePath, roadAccessContent); + + // Creating osm ids to feature ids mapping. + string const mappingRelativePath = my::JoinFoldersToPath(kTestDir, kOsmIdsToFeatureIdsName); + ScopedFile const mappingScopedFile(mappingRelativePath); + string const mappingFullPath = my::JoinFoldersToPath(writableDir, mappingRelativePath); + ReEncodeOsmIdsToFeatureIdsMapping(mappingContent, mappingFullPath); + + // Adding road access section to mwm. + string const roadAccessFullPath = my::JoinFoldersToPath(writableDir, roadAccessRelativePath); + string const mwmFullPath = my::JoinFoldersToPath(writableDir, mwmRelativePath); + BuildRoadAccessInfo(mwmFullPath, roadAccessFullPath, mappingFullPath); + + // Reading from mwm section and testing road access. + Index index; + auto const regResult = index.RegisterMap(country); + TEST_EQUAL(regResult.second, MwmSet::RegResult::Success, ()); + + MwmSet::MwmHandle mwmHandle = index.GetMwmHandleById(regResult.first); + TEST(mwmHandle.IsAlive(), ()); + + RoadAccess roadAccessFromMwm; + LoadRoadAccess(*mwmHandle.GetValue(), roadAccessFromMwm); + RoadAccessCollector const collector(roadAccessFullPath, mappingFullPath); + TEST(collector.IsValid(), ()); + TEST(roadAccessFromMwm == collector.GetRoadAccess(), ()); +} + +UNIT_TEST(RoadAccess_Smoke) +{ + string const roadAccessContent = ""; + string const osmIdsToFeatureIdsContent = ""; + TestRoadAccess(roadAccessContent, osmIdsToFeatureIdsContent); +} + +UNIT_TEST(RoadAccess_AccessPrivate) +{ + string const roadAccessContent = R"(access=private 0)"; + string const osmIdsToFeatureIdsContent = R"(0, 0,)"; + TestRoadAccess(roadAccessContent, osmIdsToFeatureIdsContent); +} + +UNIT_TEST(RoadAccess_Access_And_Barriers) +{ + string const roadAccessContent = R"(access=private 10 + access=private 20 + barrier=gate 30 + barrier=gate 40)"; + string const osmIdsToFeatureIdsContent = R"(10, 1, + 20, 2, + 30, 3, + 40, 4,)"; + TestRoadAccess(roadAccessContent, osmIdsToFeatureIdsContent); +} +} // namespace diff --git a/generator/generator_tests_support/CMakeLists.txt b/generator/generator_tests_support/CMakeLists.txt index 0dddb725cf..f90f4dda68 100644 --- a/generator/generator_tests_support/CMakeLists.txt +++ b/generator/generator_tests_support/CMakeLists.txt @@ -2,8 +2,8 @@ project(generator_tests_support) set( SRC - restriction_helpers.cpp - restriction_helpers.hpp + routing_helpers.cpp + routing_helpers.hpp test_feature.cpp test_feature.hpp test_mwm_builder.cpp diff --git a/generator/generator_tests_support/generator_tests_support.pro b/generator/generator_tests_support/generator_tests_support.pro index 46b0560b79..60a2617871 100644 --- a/generator/generator_tests_support/generator_tests_support.pro +++ b/generator/generator_tests_support/generator_tests_support.pro @@ -7,11 +7,11 @@ ROOT_DIR = ../.. include($$ROOT_DIR/common.pri) SOURCES += \ - restriction_helpers.cpp \ + routing_helpers.cpp \ test_feature.cpp \ test_mwm_builder.cpp \ HEADERS += \ - restriction_helpers.hpp \ + routing_helpers.hpp \ test_feature.hpp \ test_mwm_builder.hpp \ diff --git a/generator/generator_tests_support/restriction_helpers.cpp b/generator/generator_tests_support/routing_helpers.cpp similarity index 94% rename from generator/generator_tests_support/restriction_helpers.cpp rename to generator/generator_tests_support/routing_helpers.cpp index d4ff6cba77..8516fec728 100644 --- a/generator/generator_tests_support/restriction_helpers.cpp +++ b/generator/generator_tests_support/routing_helpers.cpp @@ -1,4 +1,4 @@ -#include "generator/generator_tests_support/restriction_helpers.hpp" +#include "generator/generator_tests_support/routing_helpers.hpp" #include "testing/testing.hpp" diff --git a/generator/generator_tests_support/restriction_helpers.hpp b/generator/generator_tests_support/routing_helpers.hpp similarity index 100% rename from generator/generator_tests_support/restriction_helpers.hpp rename to generator/generator_tests_support/routing_helpers.hpp diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 3cbcd60940..d5cc30cd09 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -8,6 +8,7 @@ #include "generator/feature_sorter.hpp" #include "generator/generate_info.hpp" #include "generator/osm_source.hpp" +#include "generator/road_access_generator.hpp" #include "generator/restriction_generator.hpp" #include "generator/routing_generator.hpp" #include "generator/routing_index_generator.hpp" @@ -250,10 +251,12 @@ int main(int argc, char ** argv) if (FLAGS_make_routing_index) { - routing::BuildRoadRestrictions( - datFile, genInfo.GetIntermediateFileName(RESTRICTIONS_FILENAME, ""), - genInfo.GetTargetFileName(country) + OSM2FEATURE_FILE_EXTENSION); + string const osmToFeatureFilename = genInfo.GetTargetFileName(country) + OSM2FEATURE_FILE_EXTENSION; + string const restrictionsFilename = genInfo.GetIntermediateFileName(RESTRICTIONS_FILENAME, ""); + string const roadAccessFilename = genInfo.GetIntermediateFileName(ROAD_ACCESS_FILENAME, ""); + routing::BuildRoadRestrictions(datFile, restrictionsFilename, osmToFeatureFilename); + routing::BuildRoadAccessInfo(datFile, roadAccessFilename, osmToFeatureFilename); routing::BuildRoutingIndex(datFile, country); } diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index 434319cf64..b2ea830ac5 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -219,32 +219,29 @@ namespace ftype public: enum EType { ENTRANCE, HIGHWAY, ADDRESS, ONEWAY, PRIVATE, LIT, NOFOOT, YESFOOT, NOBICYCLE, YESBICYCLE, BICYCLE_BIDIR, SURFPGOOD, SURFPBAD, SURFUGOOD, SURFUBAD, - HASPARTS, NOCAR, YESCAR, WLAN, - RW_STATION, RW_STATION_SUBWAY, WHEELCHAIR_YES }; + HASPARTS, NOCAR, YESCAR, WLAN, RW_STATION, RW_STATION_SUBWAY, WHEELCHAIR_YES, + BARRIER_GATE + }; CachedTypes() { Classificator const & c = classif(); - for (auto const & e : (StringIL[]) { {"entrance"}, {"highway"} }) - m_types.push_back(c.GetTypeByPath(e)); - StringIL arr[] = { + {"entrance"}, {"highway"}, {"building", "address"}, {"hwtag", "oneway"}, {"hwtag", "private"}, {"hwtag", "lit"}, {"hwtag", "nofoot"}, {"hwtag", "yesfoot"}, {"hwtag", "nobicycle"}, {"hwtag", "yesbicycle"}, {"hwtag", "bidir_bicycle"}, {"psurface", "paved_good"}, {"psurface", "paved_bad"}, {"psurface", "unpaved_good"}, {"psurface", "unpaved_bad"}, {"building", "has_parts"}, {"hwtag", "nocar"}, {"hwtag", "yescar"}, - {"internet_access", "wlan"} + {"internet_access", "wlan"}, {"railway", "station"}, {"railway", "station", "subway"}, + {"wheelchair", "yes"}, {"barrier", "gate"} }; + for (auto const & e : arr) m_types.push_back(c.GetTypeByPath(e)); - - m_types.push_back(c.GetTypeByPath({ "railway", "station" })); - m_types.push_back(c.GetTypeByPath({ "railway", "station", "subway" })); - m_types.push_back(c.GetTypeByPath({ "wheelchair", "yes" })); } uint32_t Get(EType t) const { return m_types[t]; } @@ -254,10 +251,12 @@ namespace ftype ftype::TruncValue(t, 1); return t == Get(HIGHWAY); } + bool IsRwStation(uint32_t t) const { return t == Get(RW_STATION); } + bool IsRwSubway(uint32_t t) const { ftype::TruncValue(t, 3); @@ -582,6 +581,8 @@ namespace ftype { "access", "private", [¶ms] { params.AddType(types.Get(CachedTypes::PRIVATE)); }}, { "access", "!", [¶ms] { params.AddType(types.Get(CachedTypes::PRIVATE)); }}, + { "barrier", "gate", [¶ms] { params.AddType(types.Get(CachedTypes::BARRIER_GATE)); }}, + { "lit", "~", [¶ms] { params.AddType(types.Get(CachedTypes::LIT)); }}, { "foot", "!", [¶ms] { params.AddType(types.Get(CachedTypes::NOFOOT)); }}, diff --git a/generator/osm_source.cpp b/generator/osm_source.cpp index 0620773362..64eac80005 100644 --- a/generator/osm_source.cpp +++ b/generator/osm_source.cpp @@ -686,7 +686,9 @@ bool GenerateFeaturesImpl(feature::GenerateInfo & info, EmitterBase & emitter) // TODO(mgsergio): Get rid of EmitterBase template parameter. OsmToFeatureTranslator parser( emitter, cache, info.m_makeCoasts ? classif().GetCoastType() : 0, - info.GetAddressesFileName(), info.GetIntermediateFileName(RESTRICTIONS_FILENAME, "")); + info.GetAddressesFileName(), info.GetIntermediateFileName(RESTRICTIONS_FILENAME, ""), + info.GetIntermediateFileName(ROAD_ACCESS_FILENAME, "") + ); TagAdmixer tagAdmixer(info.GetIntermediateFileName("ways", ".csv"), info.GetIntermediateFileName("towns", ".csv")); diff --git a/generator/osm_translator.hpp b/generator/osm_translator.hpp index 3c8ecf72d7..4e1c559285 100644 --- a/generator/osm_translator.hpp +++ b/generator/osm_translator.hpp @@ -4,6 +4,7 @@ #include "generator/osm2type.hpp" #include "generator/osm_element.hpp" #include "generator/restriction_writer.hpp" +#include "generator/routing_helpers.hpp" #include "generator/ways_merger.hpp" #include "indexer/classificator.hpp" @@ -29,8 +30,8 @@ namespace class RelationTagsBase { public: - RelationTagsBase(routing::RestrictionWriter & restrictionWriter) - : m_restrictionWriter(restrictionWriter), m_cache(14) + RelationTagsBase(routing::TagsProcessor & tagsProcessor) + : m_routingTagsProcessor(tagsProcessor), m_cache(14) { } @@ -77,7 +78,7 @@ protected: protected: uint64_t m_featureID; OsmElement * m_current; - routing::RestrictionWriter & m_restrictionWriter; + routing::TagsProcessor & m_routingTagsProcessor; private: my::Cache m_cache; @@ -88,10 +89,7 @@ class RelationTagsNode : public RelationTagsBase using TBase = RelationTagsBase; public: - RelationTagsNode(routing::RestrictionWriter & restrictionWriter) - : RelationTagsBase(restrictionWriter) - { - } + RelationTagsNode(routing::TagsProcessor & tagsProcessor) : RelationTagsBase(tagsProcessor) {} protected: void Process(RelationElement const & e) override @@ -102,7 +100,7 @@ protected: if (type == "restriction") { - m_restrictionWriter.Write(e); + m_routingTagsProcessor.m_restrictionWriter.Write(e); return; } @@ -131,8 +129,8 @@ protected: class RelationTagsWay : public RelationTagsBase { public: - RelationTagsWay(routing::RestrictionWriter & restrictionWriter) - : RelationTagsBase(restrictionWriter) + RelationTagsWay(routing::TagsProcessor & routingTagsProcessor) + : RelationTagsBase(routingTagsProcessor) { } @@ -161,7 +159,7 @@ protected: if (type == "restriction") { - m_restrictionWriter.Write(e); + m_routingTagsProcessor.m_restrictionWriter.Write(e); return; } @@ -213,7 +211,7 @@ class OsmToFeatureTranslator uint32_t m_coastType; unique_ptr m_addrWriter; - routing::RestrictionWriter m_restrictionWriter; + routing::TagsProcessor m_routingTagsProcessor; RelationTagsNode m_nodeRelations; RelationTagsWay m_wayRelations; @@ -290,7 +288,11 @@ class OsmToFeatureTranslator // Get params from element tags. ftype::GetNameAndType(p, params); - return params.IsValid(); + if (!params.IsValid()) + return false; + + m_routingTagsProcessor.m_roadAccessWriter.Process(p, params); + return true; } void EmitFeatureBase(FeatureBuilder1 & ft, FeatureParams const & params) const @@ -517,17 +519,21 @@ public: public: OsmToFeatureTranslator(TEmitter & emitter, TCache & holder, uint32_t coastType, - string const & addrFilePath = {}, string const & restrictionsFilePath = {}) + string const & addrFilePath = {}, string const & restrictionsFilePath = {}, + string const & roadAccessFilePath = {}) : m_emitter(emitter) , m_holder(holder) , m_coastType(coastType) - , m_nodeRelations(m_restrictionWriter) - , m_wayRelations(m_restrictionWriter) + , m_nodeRelations(m_routingTagsProcessor) + , m_wayRelations(m_routingTagsProcessor) { if (!addrFilePath.empty()) m_addrWriter.reset(new FileWriter(addrFilePath)); if (!restrictionsFilePath.empty()) - m_restrictionWriter.Open(restrictionsFilePath); + m_routingTagsProcessor.m_restrictionWriter.Open(restrictionsFilePath); + + if (!roadAccessFilePath.empty()) + m_routingTagsProcessor.m_roadAccessWriter.Open(roadAccessFilePath); } }; diff --git a/generator/restriction_collector.cpp b/generator/restriction_collector.cpp index b2faddb556..9d53630f2a 100644 --- a/generator/restriction_collector.cpp +++ b/generator/restriction_collector.cpp @@ -1,9 +1,6 @@ #include "generator/restriction_collector.hpp" -#include "generator/gen_mwm_info.hpp" - -#include "coding/file_reader.hpp" -#include "coding/reader.hpp" +#include "generator/routing_helpers.hpp" #include "base/assert.hpp" #include "base/logging.hpp" @@ -43,7 +40,7 @@ RestrictionCollector::RestrictionCollector(string const & restrictionPath, m_restrictions.clear(); }); - if (!ParseOsmIdToFeatureIdMapping(osmIdsToFeatureIdPath)) + if (!ParseOsmIdToFeatureIdMapping(osmIdsToFeatureIdPath, m_osmIdToFeatureId)) { LOG(LWARNING, ("An error happened while parsing feature id to osm ids mapping from file:", osmIdsToFeatureIdPath)); @@ -70,28 +67,6 @@ bool RestrictionCollector::IsValid() const [](Restriction const & r) { return !r.IsValid(); }) == end(m_restrictions); } -bool RestrictionCollector::ParseOsmIdToFeatureIdMapping(string const & osmIdsToFeatureIdPath) -{ - gen::OsmID2FeatureID osmIdsToFeatureIds; - try - { - FileReader reader(osmIdsToFeatureIdPath); - ReaderSource src(reader); - osmIdsToFeatureIds.Read(src); - } - catch (FileReader::Exception const & e) - { - LOG(LWARNING, ("Exception while reading file:", osmIdsToFeatureIdPath, ". Msg:", e.Msg())); - return false; - } - - osmIdsToFeatureIds.ForEach([this](gen::OsmID2FeatureID::ValueT const & p) { - AddFeatureId(p.second /* feature id */, p.first /* osm id */); - }); - - return true; -} - bool RestrictionCollector::ParseRestrictions(string const & path) { ifstream stream(path); @@ -148,14 +123,7 @@ bool RestrictionCollector::AddRestriction(Restriction::Type type, vectorsecond)); - } + ::routing::AddFeatureId(m_osmIdToFeatureId, featureId, osmId); } bool FromString(string str, Restriction::Type & type) diff --git a/generator/restriction_collector.hpp b/generator/restriction_collector.hpp index e9df69a428..5f6ad92c2e 100644 --- a/generator/restriction_collector.hpp +++ b/generator/restriction_collector.hpp @@ -35,18 +35,6 @@ private: friend void UnitTest_RestrictionTest_ParseRestrictions(); friend void UnitTest_RestrictionTest_ParseFeatureId2OsmIdsMapping(); - /// \brief Parses comma separated text file with line in following format: - /// , , , and so - /// on - /// For example: - /// 137999, 5170186, - /// 138000, 5170209, 5143342, - /// 138001, 5170228, - /// \param osmIdsToFeatureIdPath path to the text file. - /// \note Most restrictions consist of type and two linear(road) features. - /// \note For the time being only line-point-line restrictions are supported. - bool ParseOsmIdToFeatureIdMapping(string const & osmIdsToFeatureIdPath); - /// \brief Parses comma separated text file with line in following format: /// , , , and so on /// For example: @@ -57,8 +45,6 @@ private: bool ParseRestrictions(string const & path); /// \brief Adds feature id and corresponding |osmId| to |m_osmIdToFeatureId|. - /// \note In general one feature id (|featureId|) may correspond to several osm ids (|osmIds|). - /// But for road feature one feature id corresponds one osm id. void AddFeatureId(uint32_t featureId, uint64_t osmId); /// \brief Adds a restriction (vector of osm id). diff --git a/generator/restriction_generator.cpp b/generator/restriction_generator.cpp index 5ab6d9b395..3c5e433f3b 100644 --- a/generator/restriction_generator.cpp +++ b/generator/restriction_generator.cpp @@ -38,8 +38,8 @@ bool BuildRoadRestrictions(string const & mwmPath, string const & restrictionPat header.m_noRestrictionCount = base::checked_cast(distance(restrictions.cbegin(), firstOnlyIt)); header.m_onlyRestrictionCount = base::checked_cast(restrictions.size() - header.m_noRestrictionCount); - LOG(LINFO, ("Header info. There are", header.m_noRestrictionCount, "of type No restrictions and", - header.m_onlyRestrictionCount, "of type Only restrictions")); + LOG(LINFO, ("Header info. There are", header.m_noRestrictionCount, "restrictions of type No and", + header.m_onlyRestrictionCount, "restrictions of type Only")); FilesContainerW cont(mwmPath, FileWriter::OP_WRITE_EXISTING); FileWriter w = cont.GetWriter(RESTRICTIONS_FILE_TAG); diff --git a/generator/restriction_generator.hpp b/generator/restriction_generator.hpp index d960f8149c..12c3286ccb 100644 --- a/generator/restriction_generator.hpp +++ b/generator/restriction_generator.hpp @@ -4,6 +4,20 @@ namespace routing { +// This function is the generator tool's interface to building the mwm +// section which contains road restrictions. (See http://wiki.openstreetmap.org/wiki/Restriction) +// As long as the restrictions are built later than the road features themselves +// during the generation process, we have to store a mapping between osm ids and feature ids: +// the restrictions are written in OSM terms while for the road features only their feature ids +// are known. +// This results in the following pipeline: +// -- OsmToFeatureTranslator uses RestrictionsWriter to prepare a .csv file +// with resctrictions in terms of OSM ids while parsing the OSM source. +// -- OsmID2FeatureID saves the OSM id -> feature id mapping. +// -- After all features have been created, RestrictionCollector reads the csv +// and builds the mwm section with restrictions. The serialization/deserialization +// code is in the routing library. + /// \brief Builds section with road restrictions. /// \param mwmPath path to mwm which will be added with road restriction section. /// \param restrictionPath comma separated (csv like) file with road restrictions in osm ids terms @@ -13,7 +27,7 @@ namespace routing /// Only, 335049632, 49356687, /// No, 157616940, 157616940, /// \param osmIdsToFeatureIdsPath a binary file with mapping form osm ids to feature ids. -/// One osm id is mapped to one feature is. The file should be saved with the help of +/// One osm id is mapped to one feature id. The file should be saved with the help of /// OsmID2FeatureID class or using a similar way. bool BuildRoadRestrictions(string const & mwmPath, string const & restrictionPath, string const & osmIdsToFeatureIdsPath); diff --git a/generator/restriction_writer.cpp b/generator/restriction_writer.cpp index 97aee60ada..596754fa69 100644 --- a/generator/restriction_writer.cpp +++ b/generator/restriction_writer.cpp @@ -52,12 +52,13 @@ void RestrictionWriter::Open(string const & fullPath) LOG(LINFO, ("Cannot open file", fullPath)); } -bool RestrictionWriter::IsOpened() { return m_stream.is_open() && !m_stream.fail(); } - void RestrictionWriter::Write(RelationElement const & relationElement) { if (!IsOpened()) + { + LOG(LWARNING, ("Tried to write to a closed restrictions writer")); return; + } CHECK_EQUAL(relationElement.GetType(), "restriction", ()); @@ -96,4 +97,6 @@ void RestrictionWriter::Write(RelationElement const & relationElement) // Adding restriction. m_stream << ToString(type) << "," << fromIt->first << ", " << toIt->first << '\n'; } + +bool RestrictionWriter::IsOpened() { return m_stream.is_open() && !m_stream.fail(); } } // namespace routing diff --git a/generator/restriction_writer.hpp b/generator/restriction_writer.hpp index 99ff70581b..6aabb16143 100644 --- a/generator/restriction_writer.hpp +++ b/generator/restriction_writer.hpp @@ -11,15 +11,17 @@ class RestrictionWriter { public: void Open(string const & fullPath); - bool IsOpened(); /// \brief Writes |relationElement| to |m_stream| if |relationElement| is a supported restriction. + /// See restriction_generator.hpp for the description of the format. /// \note For the time being only line-point-line restrictions are processed. The other /// restrictions are ignored. // @TODO(bykoianko) It's necessary to process all kind of restrictions. void Write(RelationElement const & relationElement); private: - ofstream m_stream; + bool IsOpened(); + + ofstream m_stream; }; } // namespace routing diff --git a/generator/road_access_generator.cpp b/generator/road_access_generator.cpp new file mode 100644 index 0000000000..0dbac01f72 --- /dev/null +++ b/generator/road_access_generator.cpp @@ -0,0 +1,162 @@ +#include "generator/road_access_generator.hpp" + +#include "generator/osm_element.hpp" +#include "generator/routing_helpers.hpp" + +#include "routing/road_access.hpp" +#include "routing/road_access_serialization.hpp" + +#include "indexer/classificator.hpp" +#include "indexer/feature_data.hpp" + +#include "coding/file_container.hpp" +#include "coding/file_writer.hpp" + +#include "base/logging.hpp" +#include "base/scope_guard.hpp" +#include "base/string_utils.hpp" + +#include "std/initializer_list.hpp" + +#include "defines.hpp" + +#include +#include +#include +#include + +using namespace std; + +namespace +{ +char const kAccessPrivate[] = "access=private"; +char const kBarrierGate[] = "barrier=gate"; +char const kDelim[] = " \t\r\n"; +} // namespace + +namespace routing +{ +// RoadAccessWriter ------------------------------------------------------------ + +void RoadAccessWriter::Open(string const & filePath) +{ + LOG(LINFO, + ("Saving information about barriers and road access classes in osm id terms to", filePath)); + m_stream.open(filePath, ofstream::out); + + if (!IsOpened()) + LOG(LINFO, ("Cannot open file", filePath)); +} + +void RoadAccessWriter::Process(OsmElement * p, FeatureParams & params) +{ + if (!IsOpened()) + { + LOG(LWARNING, ("Tried to write to a closed barriers writer")); + return; + } + + auto const & c = classif(); + + StringIL const forbiddenRoadTypes[] = { + {"hwtag", "private"} + }; + + for (auto const & f : forbiddenRoadTypes) + { + auto const t = c.GetTypeByPath(f); + if (params.IsTypeExist(t) && p->type == OsmElement::EntityType::Way) + m_stream << kAccessPrivate << " " << p->id << "\n"; + } + + auto t = c.GetTypeByPath({"barrier", "gate"}); + if (params.IsTypeExist(t)) + m_stream << kBarrierGate << " " << p->id << "\n"; +} + +bool RoadAccessWriter::IsOpened() { return m_stream.is_open() && !m_stream.fail(); } +// RoadAccessCollector ---------------------------------------------------------- + +RoadAccessCollector::RoadAccessCollector(string const & roadAccessPath, + string const & osmIdsToFeatureIdsPath) +{ + MY_SCOPE_GUARD(clean, [this]() { + m_osmIdToFeatureId.clear(); + m_roadAccess.Clear(); + }); + + m_valid = true; + + if (!ParseOsmIdToFeatureIdMapping(osmIdsToFeatureIdsPath, m_osmIdToFeatureId)) + { + LOG(LWARNING, ("An error happened while parsing feature id to osm ids mapping from file:", + osmIdsToFeatureIdsPath)); + m_valid = false; + return; + } + + if (!ParseRoadAccess(roadAccessPath)) + { + LOG(LWARNING, ("An error happened while parsing road access from file:", roadAccessPath)); + m_valid = false; + return; + } + + clean.release(); +} + +bool RoadAccessCollector::ParseRoadAccess(string const & roadAccessPath) +{ + ifstream stream(roadAccessPath); + if (stream.fail()) + return false; + + string line; + while (getline(stream, line)) + { + strings::SimpleTokenizer iter(line, kDelim); + + // Empty line. + if (!iter) + return false; + + string const s = *iter; + ++iter; + + uint64_t osmId; + if (!iter || !strings::to_uint64(*iter, osmId)) + return false; + + auto const it = m_osmIdToFeatureId.find(osmId); + if (it == m_osmIdToFeatureId.cend()) + return false; + + uint32_t const featureId = it->second; + m_roadAccess.GetPrivateRoads().emplace_back(featureId); + } + + return true; +} + +// Functions ------------------------------------------------------------------ + +void BuildRoadAccessInfo(string const & dataFilePath, string const & roadAccessPath, + string const & osmIdsToFeatureIdsPath) +{ + LOG(LINFO, ("Generating road access info for", dataFilePath)); + + RoadAccessCollector collector(roadAccessPath, osmIdsToFeatureIdsPath); + + if (!collector.IsValid()) + { + LOG(LWARNING, ("Unable to parse road access in osm terms")); + return; + } + + FilesContainerW cont(dataFilePath, FileWriter::OP_WRITE_EXISTING); + FileWriter writer = cont.GetWriter(ROAD_ACCESS_FILE_TAG); + + RoadAccessSerializer serializer; + serializer.Serialize(writer, collector.GetRoadAccess()); +} +} // namespace routing diff --git a/generator/road_access_generator.hpp b/generator/road_access_generator.hpp new file mode 100644 index 0000000000..109e1b9dd2 --- /dev/null +++ b/generator/road_access_generator.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include "routing/road_access.hpp" + +#include "generator/intermediate_elements.hpp" + +#include +#include +#include + +struct OsmElement; +class FeatureParams; + +// The road accessibility information is collected in the same manner +// as the restrictions are. +// See generator/restriction_generator.hpp for details. +namespace routing +{ +class RoadAccessWriter +{ +public: + void Open(std::string const & filePath); + + void Process(OsmElement * p, FeatureParams & params); + +private: + bool IsOpened(); + + std::ofstream m_stream; +}; + +class RoadAccessCollector +{ +public: + RoadAccessCollector(std::string const & roadAccessPath, std::string const & osmIdsToFeatureIdsPath); + + RoadAccess & GetRoadAccess() { return m_roadAccess; } + RoadAccess const & GetRoadAccess() const { return m_roadAccess; } + + bool IsValid() const { return m_valid; } + +private: + bool ParseRoadAccess(std::string const & roadAccessPath); + + map m_osmIdToFeatureId; + RoadAccess m_roadAccess; + bool m_valid; +}; + +// The generator tool's interface to writing the section with +// road accessibility information for one mwm file. +void BuildRoadAccessInfo(std::string const & dataFilePath, std::string const & roadAccessPath, + std::string const & osmIdsToFeatureIdsPath); +} // namespace routing diff --git a/generator/routing_helpers.cpp b/generator/routing_helpers.cpp new file mode 100644 index 0000000000..75eac294f1 --- /dev/null +++ b/generator/routing_helpers.cpp @@ -0,0 +1,44 @@ +#include "generator/routing_helpers.hpp" + +#include "generator/gen_mwm_info.hpp" + +#include "coding/file_reader.hpp" +#include "coding/reader.hpp" + +#include "base/logging.hpp" + +namespace routing +{ +void AddFeatureId(map & osmIdToFeatureId, uint32_t featureId, uint64_t osmId) +{ + auto const result = osmIdToFeatureId.insert(make_pair(osmId, featureId)); + if (!result.second) + { + LOG(LERROR, ("Osm id", osmId, "is included in two feature ids:", featureId, + osmIdToFeatureId.find(osmId)->second)); + } +} + +bool ParseOsmIdToFeatureIdMapping(string const & osmIdsToFeatureIdPath, + map & osmIdToFeatureId) +{ + gen::OsmID2FeatureID osmIdsToFeatureIds; + try + { + FileReader reader(osmIdsToFeatureIdPath); + ReaderSource src(reader); + osmIdsToFeatureIds.Read(src); + } + catch (FileReader::Exception const & e) + { + LOG(LWARNING, ("Exception while reading file:", osmIdsToFeatureIdPath, ". Msg:", e.Msg())); + return false; + } + + osmIdsToFeatureIds.ForEach([&](gen::OsmID2FeatureID::ValueT const & p) { + AddFeatureId(osmIdToFeatureId, p.second /* feature id */, p.first /* osm id */); + }); + + return true; +} +} // namespace routing diff --git a/generator/routing_helpers.hpp b/generator/routing_helpers.hpp new file mode 100644 index 0000000000..940644c0e5 --- /dev/null +++ b/generator/routing_helpers.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "generator/road_access_generator.hpp" +#include "generator/restriction_writer.hpp" + +#include +#include + +namespace routing +{ +struct TagsProcessor +{ + RoadAccessWriter m_roadAccessWriter; + RestrictionWriter m_restrictionWriter; +}; + +// Adds feature id and corresponding |osmId| to |osmIdToFeatureId|. +// Note. In general, one |featureId| may correspond to several osm ids. +// But for a road feature |featureId| corresponds to exactly one osm id. +void AddFeatureId(std::map & osmIdToFeatureId, uint32_t featureId, uint64_t osmId); + +// Parses comma separated text file with line in following format: +// , , , and so +// on +// For example: +// 137999, 5170186, +// 138000, 5170209, 5143342, +// 138001, 5170228, +bool ParseOsmIdToFeatureIdMapping(std::string const & osmIdsToFeatureIdPath, std::map & m_osmIdToFeatureId); +} // namespace routing diff --git a/routing/CMakeLists.txt b/routing/CMakeLists.txt index 16b4374e17..143fa4d2f0 100644 --- a/routing/CMakeLists.txt +++ b/routing/CMakeLists.txt @@ -77,6 +77,9 @@ set( restriction_loader.hpp restrictions_serialization.cpp restrictions_serialization.hpp + road_access.hpp + road_access_serialization.cpp + road_access_serialization.hpp road_graph.cpp road_graph.hpp road_graph_router.cpp diff --git a/routing/road_access.hpp b/routing/road_access.hpp new file mode 100644 index 0000000000..07f4e882ac --- /dev/null +++ b/routing/road_access.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include + +namespace routing +{ +// This class provides information about road access classes. +// For now, only restrictive types (such as barrier=gate and access=private) +// and only car routing are supported. +class RoadAccess +{ +public: + RoadAccess() = default; + + std::vector & GetPrivateRoads() { return m_privateRoads; } + std::vector const & GetPrivateRoads() const { return m_privateRoads; } + + void Clear() { m_privateRoads.clear(); } + + bool operator==(RoadAccess const & rhs) { return m_privateRoads == rhs.m_privateRoads; } + +private: + // Feature ids of blocked features in the corresponding mwm. + std::vector m_privateRoads; +}; +} // namespace routing diff --git a/routing/road_access_serialization.cpp b/routing/road_access_serialization.cpp new file mode 100644 index 0000000000..acdd59f22d --- /dev/null +++ b/routing/road_access_serialization.cpp @@ -0,0 +1,7 @@ +#include "routing/road_access_serialization.hpp" + +namespace routing +{ +// static +uint32_t const RoadAccessSerializer::kLatestVersion = 0; +} // namespace routing diff --git a/routing/road_access_serialization.hpp b/routing/road_access_serialization.hpp new file mode 100644 index 0000000000..a7244238c4 --- /dev/null +++ b/routing/road_access_serialization.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "routing/road_access.hpp" + +#include "coding/reader.hpp" +#include "coding/varint.hpp" +#include "coding/write_to_sink.hpp" + +#include "base/assert.hpp" +#include "base/checked_cast.hpp" + +#include +#include + +namespace routing +{ +class RoadAccessSerializer +{ +public: + uint32_t static const kLatestVersion; + + template + static void Serialize(Sink & sink, RoadAccess const & roadAccess) + { + uint32_t const header = kLatestVersion; + WriteToSink(sink, header); + + auto const & privateRoads = roadAccess.GetPrivateRoads(); + ASSERT(std::is_sorted(privateRoads.begin(), privateRoads.end()), ()); + WriteToSink(sink, base::checked_cast(privateRoads.size())); + if (!privateRoads.empty()) + WriteVarUint(sink, privateRoads[0]); + for (size_t i = 1; i < privateRoads.size(); ++i) + { + uint32_t const delta = privateRoads[i] - privateRoads[i - 1]; + WriteVarUint(sink, delta); + } + } + + template + static void Deserialize(Source & src, RoadAccess & roadAccess) + { + uint32_t const header = ReadPrimitiveFromSource(src); + CHECK_EQUAL(header, kLatestVersion, ()); + size_t numPrivateRoads = base::checked_cast(ReadPrimitiveFromSource(src)); + auto & privateRoads = roadAccess.GetPrivateRoads(); + privateRoads.resize(numPrivateRoads); + if (numPrivateRoads > 0) + privateRoads[0] = ReadVarUint(src); + for (size_t i = 1; i < numPrivateRoads; ++i) + { + uint32_t delta = ReadVarUint(src); + privateRoads[i] = privateRoads[i - 1] + delta; + } + } +}; +} // namespace routing diff --git a/routing/routing.pro b/routing/routing.pro index 7ba284b0a5..fb6490b4ab 100644 --- a/routing/routing.pro +++ b/routing/routing.pro @@ -43,6 +43,7 @@ SOURCES += \ osrm_helpers.cpp \ osrm_path_segment_factory.cpp \ pedestrian_directions.cpp \ + road_access_serialization.cpp \ restriction_loader.cpp \ restrictions_serialization.cpp \ road_graph.cpp \ @@ -100,6 +101,8 @@ HEADERS += \ pedestrian_directions.hpp \ restriction_loader.hpp \ restrictions_serialization.hpp \ + road_access.hpp \ + road_access_serialization.hpp \ road_graph.hpp \ road_graph_router.hpp \ road_index.hpp \ diff --git a/routing/routing_tests/CMakeLists.txt b/routing/routing_tests/CMakeLists.txt index 9c1af798b4..349191b673 100644 --- a/routing/routing_tests/CMakeLists.txt +++ b/routing/routing_tests/CMakeLists.txt @@ -17,6 +17,7 @@ set( nearest_edge_finder_tests.cpp online_cross_fetcher_test.cpp osrm_router_test.cpp + road_access_test.cpp restriction_test.cpp road_graph_builder.cpp road_graph_builder.hpp diff --git a/routing/routing_tests/road_access_test.cpp b/routing/routing_tests/road_access_test.cpp new file mode 100644 index 0000000000..0f08eb855f --- /dev/null +++ b/routing/routing_tests/road_access_test.cpp @@ -0,0 +1,44 @@ +#include "testing/testing.hpp" + +#include "routing/road_access.hpp" +#include "routing/road_access_serialization.hpp" + +#include "coding/reader.hpp" +#include "coding/writer.hpp" + +#include +#include +#include + +using namespace routing; +using namespace std; + +namespace +{ +UNIT_TEST(RoadAccess_Serialization) +{ + vector privateRoads = {1, 2, 3, 100}; + RoadAccess roadAccess; + roadAccess.StealPrivateRoads(move(privateRoads)); + + vector buf; + { + MemWriter writer(buf); + RoadAccessSerializer::Serialize(writer, roadAccess); + } + + RoadAccess deserializedRoadAccess; + { + MemReader memReader(buf.data(), buf.size()); + ReaderSource src(memReader); + RoadAccessSerializer::Deserialize(src, deserializedRoadAccess); + } + + TEST_EQUAL(roadAccess.GetPrivateRoads(), deserializedRoadAccess.GetPrivateRoads(), ()); + + { + auto const & b = deserializedRoadAccess.GetPrivateRoads(); + TEST(is_sorted(b.begin(), b.end()), ()); + } +} +} // namespace diff --git a/routing/routing_tests/routing_tests.pro b/routing/routing_tests/routing_tests.pro index 5ea3209ae3..80f07ed450 100644 --- a/routing/routing_tests/routing_tests.pro +++ b/routing/routing_tests/routing_tests.pro @@ -36,6 +36,7 @@ SOURCES += \ online_cross_fetcher_test.cpp \ osrm_router_test.cpp \ restriction_test.cpp \ + road_access_test.cpp \ road_graph_builder.cpp \ road_graph_nearest_edges_test.cpp \ route_tests.cpp \