From 59e6a501acf6d44f2e7f92e214a897b67cc8435a Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Fri, 26 Oct 2018 18:44:59 +0300 Subject: [PATCH] [routing] Quick build maxspeed section implementation. --- base/base_tests/geo_object_id_tests.cpp | 6 +- base/geo_object_id.cpp | 6 +- generator/generator_tool/generator_tool.cpp | 2 +- generator/maxspeed_builder.cpp | 152 +++++++++++++++++++- generator/maxspeed_builder.hpp | 28 +++- tools/unix/generate_planet.sh | 2 +- 6 files changed, 179 insertions(+), 17 deletions(-) diff --git a/base/base_tests/geo_object_id_tests.cpp b/base/base_tests/geo_object_id_tests.cpp index 6ce7e8b671..9467d94857 100644 --- a/base/base_tests/geo_object_id_tests.cpp +++ b/base/base_tests/geo_object_id_tests.cpp @@ -13,17 +13,17 @@ UNIT_TEST(GeoObjectId) GeoObjectId const node(GeoObjectId::Type::ObsoleteOsmNode, 12345); TEST_EQUAL(node.GetSerialId(), 12345ULL, ()); TEST_EQUAL(node.GetType(), GeoObjectId::Type::ObsoleteOsmNode, ()); - TEST_EQUAL(DebugPrint(node), "Osm Node 12345", ()); + TEST_EQUAL(DebugPrint(node), "Obsolete Osm Node 12345", ()); GeoObjectId const way(GeoObjectId::Type::ObsoleteOsmWay, 93245123456332ULL); TEST_EQUAL(way.GetSerialId(), 93245123456332ULL, ()); TEST_EQUAL(way.GetType(), GeoObjectId::Type::ObsoleteOsmWay, ()); - TEST_EQUAL(DebugPrint(way), "Osm Way 93245123456332", ()); + TEST_EQUAL(DebugPrint(way), "Obsolete Osm Way 93245123456332", ()); GeoObjectId const relation(GeoObjectId::Type::ObsoleteOsmRelation, 5); TEST_EQUAL(relation.GetSerialId(), 5ULL, ()); TEST_EQUAL(relation.GetType(), GeoObjectId::Type::ObsoleteOsmRelation, ()); - TEST_EQUAL(DebugPrint(relation), "Osm Relation 5", ()); + TEST_EQUAL(DebugPrint(relation), "Obsolete Osm Relation 5", ()); // 2^48 - 1, maximal possible serial id. GeoObjectId const surrogate(GeoObjectId::Type::OsmSurrogate, 281474976710655ULL); diff --git a/base/geo_object_id.cpp b/base/geo_object_id.cpp index adaf312449..232cdae355 100644 --- a/base/geo_object_id.cpp +++ b/base/geo_object_id.cpp @@ -84,9 +84,9 @@ std::string DebugPrint(GeoObjectId::Type const & t) case GeoObjectId::Type::BookingComNode: return "Booking.com"; case GeoObjectId::Type::OsmSurrogate: return "Osm Surrogate"; case GeoObjectId::Type::Fias: return "FIAS"; - case GeoObjectId::Type::ObsoleteOsmNode: return "Osm Node"; - case GeoObjectId::Type::ObsoleteOsmWay: return "Osm Way"; - case GeoObjectId::Type::ObsoleteOsmRelation: return "Osm Relation"; + case GeoObjectId::Type::ObsoleteOsmNode: return "Obsolete Osm Node"; + case GeoObjectId::Type::ObsoleteOsmWay: return "Obsolete Osm Way"; + case GeoObjectId::Type::ObsoleteOsmRelation: return "Obsolete Osm Relation"; } CHECK_SWITCH(); } diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 80e88348ab..4d3949ce8d 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -532,7 +532,7 @@ int main(int argc, char ** argv) { LOG(LINFO, ("Generating maxspeed section for", datFile)); string const maxspeedFilename = genInfo.GetIntermediateFileName(MAXSPEED_FILENAME); - CHECK(BuildMaxspeed(datFile, osmToFeatureFilename, maxspeedFilename), + CHECK(routing::BuildMaxspeed(datFile, osmToFeatureFilename, maxspeedFilename), ("Generating maxspeed section error.")); } diff --git a/generator/maxspeed_builder.cpp b/generator/maxspeed_builder.cpp index 511cc853ff..a6bb5f1541 100644 --- a/generator/maxspeed_builder.cpp +++ b/generator/maxspeed_builder.cpp @@ -1,12 +1,152 @@ #include "generator/maxspeed_builder.hpp" -#include "routing/maxspeed_conversion.hpp" +#include "generator/maxspeed_parser.hpp" +#include "generator/routing_helpers.hpp" -namespace generator +#include "routing/maxspeed_conversion.hpp" +#include "routing/maxspeed_serialization.hpp" + +#include "indexer/feature.hpp" +#include "indexer/feature_data.hpp" +#include "indexer/feature_processor.hpp" + +#include "coding/file_container.hpp" +#include "coding/file_writer.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" +#include "base/string_utils.hpp" + +#include +#include +#include +#include + +#include "defines.hpp" + +// Important note. The code below in this file will be rewritten and covered by tests within the PR. +// Now it's written quickly to make a test map build this weekend. + +namespace { -bool BuildMaxspeed(std::string const & dataPath, std::string const & osmToFeaturePath, - std::string const & maxspeedFilename) +char const kDelim[] = ", \t\r\n"; + +bool ParseOneSpeedValue(strings::SimpleTokenizer & iter, uint16_t & value) { - return false; + uint64_t parsedSpeed = 0; + if (!strings::to_uint64(*iter, parsedSpeed)) + return false; + if (parsedSpeed > std::numeric_limits::max()) + return false; + value = static_cast(parsedSpeed); + ++iter; + return true; } -} // namespace generator +} // namespace + +namespace routing +{ +using namespace feature; +using namespace generator; +using namespace std; + +// @TODO(bykoianko) Consider implement a maxspeed collector class instead of ParseMaxspeeds() and +// part of BuildMaxspeed() methods. +bool ParseMaxspeeds(string const & maxspeedFilename, OsmIdToMaxspeed & osmIdToMaxspeed) +{ + osmIdToMaxspeed.clear(); + + ifstream stream(maxspeedFilename); + if (stream.fail()) + return false; + + string line; + while (std::getline(stream, line)) + { + strings::SimpleTokenizer iter(line, kDelim); + if (!iter) // the line is empty + return false; + + uint64_t osmId = 0; + if (!strings::to_uint64(*iter, osmId)) + return false; + ++iter; + + ParsedMaxspeed speed; + speed.m_units = StringToUnits(*iter); + ++iter; + + if (!ParseOneSpeedValue(iter, speed.m_forward)) + return false; + + if (iter) + { + // There's backward maxspeed limit. + if (!ParseOneSpeedValue(iter, speed.m_backward)) + return false; + + if (iter) + return false; + } + + auto const res = osmIdToMaxspeed.insert(make_pair(base::MakeOsmWay(osmId), speed)); + if (!res.second) + return false; + } + return true; +} + +void SerializeMaxspeed(string const & dataPath, vector && speeds) +{ + LOG(LINFO, ("SerializeMaxspeed(", dataPath, ", ...) speeds size:", speeds.size())); + if (speeds.empty()) + return; + + LOG(LINFO, ("SerializeMaxspeed() The fisrt speed", speeds[0])); + + FilesContainerW cont(dataPath, FileWriter::OP_WRITE_EXISTING); + FileWriter writer = cont.GetWriter(MAXSPEED_FILE_TAG); + + MaxspeedSerializer::Serialize(speeds, writer); +} + +bool BuildMaxspeed(string const & dataPath, string const & osmToFeaturePath, + string const & maxspeedFilename) +{ + LOG(LINFO, ("BuildMaxspeed(", dataPath, ",", osmToFeaturePath, ",", maxspeedFilename, ")")); + + OsmIdToMaxspeed osmIdToMaxspeed; + CHECK(ParseMaxspeeds(maxspeedFilename, osmIdToMaxspeed), ()); + LOG(LINFO, ("BuildMaxspeed() osmIdToMaxspeed size:", osmIdToMaxspeed.size())); + + map featureIdToOsmId; + CHECK(ParseFeatureIdToOsmIdMapping(osmToFeaturePath, featureIdToOsmId), ()); + LOG(LINFO, ("BuildMaxspeed() featureIdToOsmId size:", featureIdToOsmId.size())); + + vector speeds; + ForEachFromDat(dataPath, [&](FeatureType & ft, uint32_t fid) { + if (!routing::IsCarRoad(TypesHolder(ft))) + return; + + auto const osmIdIt = featureIdToOsmId.find(fid); + if (osmIdIt == featureIdToOsmId.cend()) + return; + + // @TODO Consider adding check here. |fid| should be in |featureIdToOsmId| anyway. + auto const maxspeedIt = osmIdToMaxspeed.find(osmIdIt->second); + if (maxspeedIt == osmIdToMaxspeed.cend()) + return; + + auto const & parsedMaxspeed = maxspeedIt->second; + // Note. It's wrong that by default if there's no maxspeed backward SpeedInUnits::m_units + // is Metric and according to this code it's be saved as Imperial for country + // with imperial metrics. Anyway this code should be rewritten before merge. + speeds.push_back( + FeatureMaxspeed(fid, SpeedInUnits(parsedMaxspeed.m_forward, parsedMaxspeed.m_units), + SpeedInUnits(parsedMaxspeed.m_backward, parsedMaxspeed.m_units))); + }); + + SerializeMaxspeed(dataPath, move(speeds)); + return true; +} +} // namespace routing diff --git a/generator/maxspeed_builder.hpp b/generator/maxspeed_builder.hpp index 1c66922471..0a71ebed48 100644 --- a/generator/maxspeed_builder.hpp +++ b/generator/maxspeed_builder.hpp @@ -1,10 +1,32 @@ #pragma once +#include "routing/maxspeed_conversion.hpp" +#include "platform/measurement_utils.hpp" + +#include "base/geo_object_id.hpp" + +#include #include +#include -namespace generator +namespace routing { -/// \brief Builds maxspeed section. +struct ParsedMaxspeed +{ + measurement_utils::Units m_units = measurement_utils::Units::Metric; + uint16_t m_forward = routing::kInvalidSpeed; + uint16_t m_backward = routing::kInvalidSpeed; +}; + +using OsmIdToMaxspeed = std::map; + +bool ParseMaxspeeds(std::string const & maxspeedFilename, OsmIdToMaxspeed & osmIdToMaxspeed); + +/// \brief Write |speeds| to maxspeed section to mwm with |dataPath|. +void SerializeMaxspeed(std::string const & dataPath, std::vector && speeds); + +/// \brief Builds maxspeed section in mwm with |dataPath|. This section contains max speed limits +/// if it's available. /// \param maxspeedFilename file name to csv file with maxspeed tag values. /// \note To start building the section, the following data must be ready: /// 1. GenerateIntermediateData(). Saves to a file data about maxspeed tags value of road features @@ -12,4 +34,4 @@ namespace generator /// 3. Generates geometry bool BuildMaxspeed(std::string const & dataPath, std::string const & osmToFeaturePath, std::string const & maxspeedFilename); -} // namespace generator +} // namespace routing diff --git a/tools/unix/generate_planet.sh b/tools/unix/generate_planet.sh index 76208ab7d6..1f80cadb67 100755 --- a/tools/unix/generate_planet.sh +++ b/tools/unix/generate_planet.sh @@ -512,7 +512,7 @@ if [ "$MODE" == "mwm" ]; then fi if [ -z "$NO_REGIONS" ]; then - PARAMS_WITH_SEARCH="$PARAMS --generate_search_index --cities_boundaries_data=$CITIES_BOUNDARIES_DATA --make_city_roads" + PARAMS_WITH_SEARCH="$PARAMS --generate_search_index --cities_boundaries_data=$CITIES_BOUNDARIES_DATA --make_city_roads --generate_maxspeed" [ -n "${SRTM_PATH-}" -a -d "${SRTM_PATH-}" ] && PARAMS_WITH_SEARCH="$PARAMS_WITH_SEARCH --srtm_path=$SRTM_PATH" [ -f "$UGC_FILE" ] && PARAMS_WITH_SEARCH="$PARAMS_WITH_SEARCH --ugc_data=$UGC_FILE" [ -f "$POPULAR_PLACES_FILE" ] && PARAMS_WITH_SEARCH="$PARAMS_WITH_SEARCH --popular_places_data=$POPULAR_PLACES_FILE --generate_popular_places"