diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt index 327f049316..2cd4e60002 100644 --- a/generator/generator_tests/CMakeLists.txt +++ b/generator/generator_tests/CMakeLists.txt @@ -13,6 +13,7 @@ set( feature_merger_test.cpp filter_elements_tests.cpp intermediate_data_test.cpp + maxspeed_tests.cpp metadata_parser_test.cpp node_mixer_test.cpp osm2meta_test.cpp diff --git a/generator/generator_tests/altitude_test.cpp b/generator/generator_tests/altitude_test.cpp index 8d97dd968b..10b84db2e2 100644 --- a/generator/generator_tests/altitude_test.cpp +++ b/generator/generator_tests/altitude_test.cpp @@ -50,7 +50,7 @@ namespace // Directory name for creating test mwm and temporary files. std::string const kTestDir = "altitude_generation_test"; // Temporary mwm name for testing. -std::string const kTestMwm = "test"; +std::string const kTest = "test"; struct Point3D { @@ -169,9 +169,9 @@ void TestAltitudesBuilding(vector const & roads, bool hasAltitudeE std::string const testDirFullPath = base::JoinPath(platform.WritableDir(), kTestDir); // Building mwm without altitude section. - LocalCountryFile country(testDirFullPath, CountryFile(kTestMwm), 1); + LocalCountryFile country(testDirFullPath, CountryFile(kTest), 1); ScopedDir testScopedDir(kTestDir); - ScopedFile testScopedMwm(base::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION), + ScopedFile testScopedMwm(base::JoinPath(kTestDir, kTest + DATA_FILE_EXTENSION), ScopedFile::Mode::Create); BuildMwmWithoutAltitudes(roads, country); diff --git a/generator/generator_tests/city_roads_tests.cpp b/generator/generator_tests/city_roads_tests.cpp index 1c3ab117bd..7fe1463d20 100644 --- a/generator/generator_tests/city_roads_tests.cpp +++ b/generator/generator_tests/city_roads_tests.cpp @@ -43,7 +43,7 @@ namespace // Directory name for creating test mwm and temporary files. string const kTestDir = "city_roads_generation_test"; // Temporary mwm name for testing. -string const kTestMwm = "test"; +string const kTest = "test"; void BuildEmptyMwm(LocalCountryFile & country) { @@ -73,11 +73,11 @@ void TestCityRoadsBuilding(vector && cityRoadFeatureIds) string const writableDir = GetPlatform().WritableDir(); // Building empty mwm. - LocalCountryFile country(base::JoinPath(writableDir, kTestDir), CountryFile(kTestMwm), + LocalCountryFile country(base::JoinPath(writableDir, kTestDir), CountryFile(kTest), 0 /* version */); ScopedDir const scopedDir(kTestDir); - string const mwmRelativePath = base::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION); + string const mwmRelativePath = base::JoinPath(kTestDir, kTest + DATA_FILE_EXTENSION); ScopedFile const scopedMwm(mwmRelativePath, ScopedFile::Mode::Create); BuildEmptyMwm(country); diff --git a/generator/generator_tests/maxspeed_tests.cpp b/generator/generator_tests/maxspeed_tests.cpp new file mode 100644 index 0000000000..05905c9ef8 --- /dev/null +++ b/generator/generator_tests/maxspeed_tests.cpp @@ -0,0 +1,338 @@ +#include "testing/testing.hpp" + +#include "generator/generator_tests_support/test_feature.cpp" +#include "generator/generator_tests_support/test_mwm_builder.hpp" +#include "generator/maxspeed_builder.hpp" +#include "generator/routing_helpers.hpp" + +#include "routing/maxspeed_serialization.hpp" + +#include "indexer/classificator_loader.hpp" +#include "indexer/data_source.hpp" +#include "indexer/feature.hpp" +#include "indexer/feature_processor.hpp" +#include "indexer/mwm_set.hpp" + +#include "coding/file_name_utils.hpp" +#include "coding/reader.hpp" +#include "coding/writer.hpp" + +#include "geometry/point2d.hpp" + +#include "platform/local_country_file.hpp" +#include "platform/measurement_utils.hpp" +#include "platform/platform.hpp" +#include "platform/platform_tests_support/scoped_dir.hpp" +#include "platform/platform_tests_support/scoped_file.hpp" + +#include "base/geo_object_id.hpp" +#include "base/logging.hpp" + +#include +#include +#include +#include +#include + +namespace +{ +using namespace measurement_utils; +using namespace platform; +using namespace platform::tests_support; +using namespace routing; +using namespace std; + +using FeatureVector = vector>; + +// Directory name for creating test mwm and temporary files. +string const kTestDir = "maxspeed_generation_test"; +// Temporary mwm name for testing. +string const kTest = "test"; +// File name for keeping maxspeeds. +string const kCsv = "maxspeed.csv"; + +void BuldGeometry(FeatureVector const & roads, LocalCountryFile & country) +{ + generator::tests_support::TestMwmBuilder builder(country, feature::DataHeader::country); + for (auto const & road : roads) + builder.Add(generator::tests_support::TestStreet(road, string(), string())); +} + +void CreateTextFileByContent(string const & fileName, string const & fileContent) +{ + ofstream ofs(fileName); + TEST(ofs, ()); + ofs << fileContent; +} + +void TestMaxspeedSection(FeatureVector const & roads, string const & maxspeedCsvContent, + map const & featureIdToOsmId) +{ + classificator::Load(); + string const testDirFullPath = base::JoinPath(GetPlatform().WritableDir(), kTestDir); + ScopedDir testScopedDir(kTestDir); + + // Writing |maxspeedCsvContent| to a file in |kTestDir|. + ScopedFile testScopedMaxspeedCsv(base::JoinPath(kTestDir, kCsv), ScopedFile::Mode::Create); + string const csvFullPath = base::JoinPath(testDirFullPath, kCsv); + CreateTextFileByContent(csvFullPath, maxspeedCsvContent); + + // Writing |roads| to test mwm. + LocalCountryFile country(testDirFullPath, CountryFile(kTest), 1); + string const testMwm = kTest + DATA_FILE_EXTENSION; + ScopedFile testScopedMwm(base::JoinPath(kTestDir, testMwm), ScopedFile::Mode::Create); + BuldGeometry(roads, country); + + // Creating maxspeed section in test.mwm. + string const testMwmFullPath = base::JoinPath(testDirFullPath, testMwm); + BuildMaxspeed(testMwmFullPath, featureIdToOsmId, csvFullPath); + + // Deserializing maxspeed section. + // @TODO(bykoianko) When MaxspeedLoader is implemented it should be test here. + FrozenDataSource dataSource; + auto const regResult = dataSource.RegisterMap(country); + TEST_EQUAL(regResult.second, MwmSet::RegResult::Success, ()); + auto const & mwmId = regResult.first; + auto const handle = dataSource.GetMwmHandleById(mwmId); + TEST(handle.IsAlive(), ()); + auto const & mwmValue = *handle.GetValue(); + + vector maxspeeds; + if (mwmValue.m_cont.IsExist(MAXSPEED_FILE_TAG)) + { + try + { + auto const & reader = mwmValue.m_cont.GetReader(MAXSPEED_FILE_TAG); + ReaderSource src(reader); + MaxspeedSerializer::Deserialize(src, maxspeeds); + TEST(is_sorted(maxspeeds.cbegin(), maxspeeds.cend()), ()); + } + catch (Reader::OpenException const & e) + { + TEST(false, ("Error while reading maxspeed section from", country)); + } + } + + // Testing maxspeed section content. + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseMaxspeeds(base::JoinPath(testDirFullPath, kCsv), osmIdToMaxspeed), ()); + auto processor = [&](FeatureType & f, uint32_t const & id) { + TEST(IsRoad(feature::TypesHolder(f)), ()); + + // Looking for maxspeed from csv. + auto const itOsmId = featureIdToOsmId.find(id); + TEST(itOsmId != featureIdToOsmId.cend(), ()); + + auto const itMaxspeedCsv = osmIdToMaxspeed.find(itOsmId->second); + if (itMaxspeedCsv == osmIdToMaxspeed.cend()) + return; // No maxspeed for feature |id|. + + ParsedMaxspeed const maxspeedCsv = itMaxspeedCsv->second; + + // Looking for maxspeed form mwm. + // Note. FeatureMaxspeed::operator<() is base only on FeatureMaxspeed::m_featureId. + auto const it = + equal_range(maxspeeds.cbegin(), maxspeeds.cend(), FeatureMaxspeed(id, SpeedInUnits())); + + TEST_EQUAL(it.second - it.first, 1, + ("If there's no maxspeed in mwm for", id, + "feature id, this maxspeed should not be found in csv.")); + FeatureMaxspeed const maxspeedMwm = *it.first; + + // Comparing maxspeed from csv and maxspeed from mwm section. + TEST_EQUAL(id, maxspeedMwm.GetFeatureId(), ()); + TEST_EQUAL(maxspeedCsv.m_units, maxspeedMwm.GetForward().m_units, ()); + TEST_EQUAL(maxspeedCsv.m_units, maxspeedMwm.GetBackward().m_units, ()); + TEST_EQUAL(maxspeedCsv.m_forward, maxspeedMwm.GetForward().m_speed, ()); + TEST_EQUAL(maxspeedCsv.m_backward, maxspeedMwm.GetBackward().m_speed, ()); + }; + feature::ForEachFromDat(testMwmFullPath, processor); +} + +// Note. ParseMaxspeeds() is not tested in TestMaxspeedSection() because it's used twice there. +// So it's important to test the function separateю +bool ParseCsv(string const & maxspeedCsvContent, OsmIdToMaxspeed & mapping) +{ + string const testDirFullPath = base::JoinPath(GetPlatform().WritableDir(), kTestDir); + ScopedDir testScopedDir(kTestDir); + + ScopedFile testScopedMaxspeedCsv(base::JoinPath(kTestDir, kCsv), ScopedFile::Mode::Create); + CreateTextFileByContent(base::JoinPath(testDirFullPath, kCsv), maxspeedCsvContent); + + return ParseMaxspeeds(base::JoinPath(testDirFullPath, kCsv), mapping); +} + +UNIT_TEST(ParseMaxspeeds_Smoke) +{ + string const maxspeedCsvContent; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); + TEST(osmIdToMaxspeed.empty(), ()); +} + +UNIT_TEST(ParseMaxspeeds1) +{ + string const maxspeedCsvContent = "10,Metric,60\n11,Metric,90\n"; + OsmIdToMaxspeed const expectedMapping = { + {base::MakeOsmWay(10), {Units::Metric, 60, kInvalidSpeed}}, + {base::MakeOsmWay(11), {Units::Metric, 90, kInvalidSpeed}}}; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); + TEST_EQUAL(osmIdToMaxspeed, expectedMapping, ()); +} + +UNIT_TEST(ParseMaxspeeds2) +{ + string const maxspeedCsvContent = "10,Metric,60,80\n11,Metric,120\n"; + OsmIdToMaxspeed const expectedMapping = { + {base::MakeOsmWay(10), {Units::Metric, 60, 80}}, + {base::MakeOsmWay(11), {Units::Metric, 120, kInvalidSpeed}}}; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); + TEST_EQUAL(osmIdToMaxspeed, expectedMapping, ()); +} + +UNIT_TEST(ParseMaxspeeds3) +{ + string const maxspeedCsvContent = "184467440737095516,Imperial,60,80\n184467440737095517,Metric,120\n"; + OsmIdToMaxspeed const expectedMapping = { + {base::MakeOsmWay(184467440737095516), {Units::Imperial, 60, 80}}, + {base::MakeOsmWay(184467440737095517), {Units::Metric, 120, kInvalidSpeed}}}; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); + TEST_EQUAL(osmIdToMaxspeed, expectedMapping, ()); +} + +UNIT_TEST(ParseMaxspeeds4) +{ + // Note. kNoneMaxSpeed == 65534 and kWalkMaxSpeed == 65533. + string const maxspeedCsvContent = "1,Metric,200,65534\n2,Metric,65533\n"; + OsmIdToMaxspeed const expectedMapping = { + {base::MakeOsmWay(1), {Units::Metric, 200, kNoneMaxSpeed}}, + {base::MakeOsmWay(2), {Units::Metric, kWalkMaxSpeed, kInvalidSpeed}}}; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); + TEST_EQUAL(osmIdToMaxspeed, expectedMapping, ()); +} + +UNIT_TEST(ParseMaxspeeds5) +{ + string const maxspeedCsvContent = "\n2,Metric,10\n"; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(!ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); +} + +UNIT_TEST(ParseMaxspeeds6) +{ + string const maxspeedCsvContent = "2U,Metric,10\n"; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(!ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); +} + +UNIT_TEST(ParseMaxspeeds7) +{ + string const maxspeedCsvContent = "2,Metric\n"; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(!ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); +} + +UNIT_TEST(ParseMaxspeeds8) +{ + string const maxspeedCsvContent = "2,Metric,10,11m\n"; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(!ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); +} + +UNIT_TEST(ParseMaxspeeds_Big) +{ + // Note. kNoneMaxSpeed == 65534. + string const maxspeedCsvContent = "100,Metric,200,65534\n101,Metric,60,90\n102,Metric,60\n103,Metric,90\n"; + OsmIdToMaxspeed const expectedMapping = { + {base::MakeOsmWay(100), {Units::Metric, 200, kNoneMaxSpeed}}, + {base::MakeOsmWay(101), {Units::Metric, 60, 90}}, + {base::MakeOsmWay(102), {Units::Metric, 60, kInvalidSpeed}}, + {base::MakeOsmWay(103), {Units::Metric, 90, kInvalidSpeed}}}; + OsmIdToMaxspeed osmIdToMaxspeed; + TEST(ParseCsv(maxspeedCsvContent, osmIdToMaxspeed), ()); + TEST_EQUAL(osmIdToMaxspeed, expectedMapping, ()); +} + +UNIT_TEST(MaxspeedSection_Smoke) +{ + FeatureVector const roads; + string const maxspeedCsvContent; + map const featureIdToOsmId; + TestMaxspeedSection(roads, maxspeedCsvContent, featureIdToOsmId); +} + +UNIT_TEST(MaxspeedSection1) +{ + FeatureVector const roads = {{{0.0, 0.0}, {0.0, 1.0}, {0.0, 2.0}} /* Point of feature 0 */, + {{1.0, 0.0}, {1.0, 1.0}, {1.0, 2.0}} /* Point of feature 1 */}; + string const maxspeedCsvContent = "25258932,Metric,60\n25258943,Metric,90\n"; + map const featureIdToOsmId = { + {0 /* feature id */, base::MakeOsmWay(25258932)}, + {1 /* feature id */, base::MakeOsmWay(25258943)}}; + TestMaxspeedSection(roads, maxspeedCsvContent, featureIdToOsmId); +} + +UNIT_TEST(MaxspeedSection2) +{ + FeatureVector const roads = {{{0.0, 0.0}, {0.0, 1.0}} /* Point of feature 0 */, + {{1.0, 0.0}, {1.0, 2.0}} /* Point of feature 1 */, + {{1.0, 2.0}, {1.0, 3.0}} /* Point of feature 2 */}; + string const maxspeedCsvContent = "25258932,Metric,60,40\n32424,Metric,120\n"; + map const featureIdToOsmId = { + {0 /* feature id */, base::MakeOsmWay(25258932)}, + {1 /* feature id */, base::MakeOsmWay(25258943)}, + {2 /* feature id */, base::MakeOsmWay(32424)}}; + TestMaxspeedSection(roads, maxspeedCsvContent, featureIdToOsmId); +} + +UNIT_TEST(MaxspeedSection3) +{ + FeatureVector const roads = {{{0.0, 0.0}, {0.0, 1.0}} /* Point of feature 0 */, + {{1.0, 0.0}, {1.0, 2.0}} /* Point of feature 1 */, + {{1.0, 2.0}, {1.0, 3.0}} /* Point of feature 2 */}; + // Note. kNoneMaxSpeed == 65535 and kWalkMaxSpeed == 65534. + string const maxspeedCsvContent = + "25252,Metric,120,65534\n258943,Metric,65533\n32424,Metric,10,65533\n"; + map const featureIdToOsmId = { + {0 /* feature id */, base::MakeOsmWay(25252)}, + {1 /* feature id */, base::MakeOsmWay(258943)}, + {2 /* feature id */, base::MakeOsmWay(32424)}}; + TestMaxspeedSection(roads, maxspeedCsvContent, featureIdToOsmId); +} + +UNIT_TEST(MaxspeedSection4) +{ + FeatureVector const roads = {{{0.0, 0.0}, {0.0, 1.0}} /* Point of feature 0 */, + {{1.0, 0.0}, {0.0, 0.0}} /* Point of feature 1 */}; + string const maxspeedCsvContent = "50000000000,Imperial,30\n50000000001,Imperial,50\n"; + map const featureIdToOsmId = { + {0 /* feature id */, base::MakeOsmWay(50000000000)}, + {1 /* feature id */, base::MakeOsmWay(50000000001)}}; + TestMaxspeedSection(roads, maxspeedCsvContent, featureIdToOsmId); +} + +UNIT_TEST(MaxspeedSection_Big) +{ + FeatureVector const roads = {{{0.0, 0.0}, {0.0, 1.0}} /* Point of feature 0 */, + {{1.0, 0.0}, {1.0, 2.0}} /* Point of feature 1 */, + {{1.0, 2.0}, {1.0, 3.0}} /* Point of feature 2 */, + {{1.0, 2.0}, {1.0, 4.0}} /* Point of feature 3 */, + {{1.0, 2.0}, {2.0, 3.0}} /* Point of feature 4 */, + {{1.0, 2.0}, {2.0, 7.0}} /* Point of feature 5 */, + {{1.0, 2.0}, {7.0, 4.0}} /* Point of feature 6 */}; + // Note. kNoneMaxSpeed == 65534. + string const maxspeedCsvContent = + "100,Imperial,100,65534\n200,Imperial,50\n300,Imperial,30\n400,Imperial,10,20\n600," + "Imperial,50,20\n700,Imperial,10\n"; + map const featureIdToOsmId = { + {0 /* feature id */, base::MakeOsmWay(100)}, {1 /* feature id */, base::MakeOsmWay(200)}, + {2 /* feature id */, base::MakeOsmWay(300)}, {3 /* feature id */, base::MakeOsmWay(400)}, + {4 /* feature id */, base::MakeOsmWay(500)}, {5 /* feature id */, base::MakeOsmWay(600)}, + {6 /* feature id */, base::MakeOsmWay(700)}}; + TestMaxspeedSection(roads, maxspeedCsvContent, featureIdToOsmId); +} +} // namespace diff --git a/generator/generator_tests/restriction_test.cpp b/generator/generator_tests/restriction_test.cpp index 4a8efd0461..1f2c680e4f 100644 --- a/generator/generator_tests/restriction_test.cpp +++ b/generator/generator_tests/restriction_test.cpp @@ -34,7 +34,7 @@ namespace // Directory name for creating test mwm and temporary files. string const kTestDir = "restriction_generation_test"; // Temporary mwm name for testing. -string const kTestMwm = "test"; +string const kTest = "test"; string const kRestrictionFileName = "restrictions_in_osm_ids.csv"; string const kOsmIdsToFeatureIdsName = "osm_ids_to_feature_ids" OSM2FEATURE_FILE_EXTENSION; @@ -76,10 +76,10 @@ void TestRestrictionBuilding(string const & restrictionContent, string const & m string const writableDir = platform.WritableDir(); // Building empty mwm. - LocalCountryFile country(base::JoinPath(writableDir, kTestDir), CountryFile(kTestMwm), + LocalCountryFile country(base::JoinPath(writableDir, kTestDir), CountryFile(kTest), 0 /* version */); ScopedDir const scopedDir(kTestDir); - string const mwmRelativePath = base::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION); + string const mwmRelativePath = base::JoinPath(kTestDir, kTest + DATA_FILE_EXTENSION); ScopedFile const scopedMwm(mwmRelativePath, ScopedFile::Mode::Create); BuildEmptyMwm(country); diff --git a/generator/generator_tests/road_access_test.cpp b/generator/generator_tests/road_access_test.cpp index 84f7fcf2f0..11485641a7 100644 --- a/generator/generator_tests/road_access_test.cpp +++ b/generator/generator_tests/road_access_test.cpp @@ -41,7 +41,7 @@ using namespace std; namespace { string const kTestDir = "road_access_generation_test"; -string const kTestMwm = "test"; +string const kTest = "test"; string const kRoadAccessFilename = "road_access_in_osm_ids.csv"; string const kOsmIdsToFeatureIdsName = "osm_ids_to_feature_ids" OSM2FEATURE_FILE_EXTENSION; @@ -89,10 +89,10 @@ RoadAccessCollector::RoadAccessByVehicleType SaveAndLoadRoadAccess(string const string const & writableDir = platform.WritableDir(); // Building empty mwm. - LocalCountryFile country(base::JoinPath(writableDir, kTestDir), CountryFile(kTestMwm), + LocalCountryFile country(base::JoinPath(writableDir, kTestDir), CountryFile(kTest), 0 /* version */); ScopedDir const scopedDir(kTestDir); - string const mwmRelativePath = base::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION); + string const mwmRelativePath = base::JoinPath(kTestDir, kTest + DATA_FILE_EXTENSION); ScopedFile const scopedMwm(mwmRelativePath, ScopedFile::Mode::Create); BuildTestMwmWithRoads(country); diff --git a/generator/generator_tests/speed_cameras_test.cpp b/generator/generator_tests/speed_cameras_test.cpp index 31121c4786..92c37d8551 100644 --- a/generator/generator_tests/speed_cameras_test.cpp +++ b/generator/generator_tests/speed_cameras_test.cpp @@ -57,7 +57,7 @@ namespace string const kTestDir = "speed_camera_generation_test"; // Temporary mwm name for testing. -string const kTestMwm = "test"; +string const kTest = "test"; string const kSpeedCameraDataFileName = "speedcamera_in_osm_ids.bin"; string const kOsmIdsToFeatureIdsName = "osm_ids_to_feature_ids" OSM2FEATURE_FILE_EXTENSION; @@ -154,8 +154,8 @@ void TestSpeedCameraSectionBuilding(string const & osmContent, CameraMap const & // Step 1. Generate intermediate data. GenerateInfo genInfo; - genInfo.m_fileName = kTestMwm; - genInfo.m_bucketNames.push_back(kTestMwm); + genInfo.m_fileName = kTest; + genInfo.m_bucketNames.push_back(kTest); genInfo.m_tmpDir = testDirFullPath; genInfo.m_targetDir = testDirFullPath; genInfo.m_intermediateDir = testDirFullPath; @@ -166,8 +166,8 @@ void TestSpeedCameraSectionBuilding(string const & osmContent, CameraMap const & TEST(GenerateIntermediateData(genInfo), ("Can not generate intermediate data for speed cam")); // Building empty mwm. - LocalCountryFile country(base::JoinPath(tmpDir, kTestDir), CountryFile(kTestMwm), 0 /* version */); - string const mwmRelativePath = base::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION); + LocalCountryFile country(base::JoinPath(tmpDir, kTestDir), CountryFile(kTest), 0 /* version */); + string const mwmRelativePath = base::JoinPath(kTestDir, kTest + DATA_FILE_EXTENSION); ScopedFile const scopedMwm(mwmRelativePath, ScopedFile::Mode::Create); // Step 2. Generate binary file about cameras. @@ -204,7 +204,7 @@ void TestSpeedCameraSectionBuilding(string const & osmContent, CameraMap const & } string const osmToFeatureFilename = - genInfo.GetTargetFileName(kTestMwm) + OSM2FEATURE_FILE_EXTENSION; + genInfo.GetTargetFileName(kTest) + OSM2FEATURE_FILE_EXTENSION; BuildCamerasInfo(mwmFullPath, camerasFilename, osmToFeatureFilename); diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 4d3949ce8d..4462be760d 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -532,8 +532,7 @@ int main(int argc, char ** argv) { LOG(LINFO, ("Generating maxspeed section for", datFile)); string const maxspeedFilename = genInfo.GetIntermediateFileName(MAXSPEED_FILENAME); - CHECK(routing::BuildMaxspeed(datFile, osmToFeatureFilename, maxspeedFilename), - ("Generating maxspeed section error.")); + routing::BuildMaxspeed(datFile, osmToFeatureFilename, maxspeedFilename); } if (FLAGS_make_cross_mwm || FLAGS_make_transit_cross_mwm) diff --git a/generator/maxspeed_builder.cpp b/generator/maxspeed_builder.cpp index a6bb5f1541..5c43400f9c 100644 --- a/generator/maxspeed_builder.cpp +++ b/generator/maxspeed_builder.cpp @@ -13,13 +13,15 @@ #include "coding/file_container.hpp" #include "coding/file_writer.hpp" +#include "platform/measurement_utils.hpp" + #include "base/assert.hpp" #include "base/logging.hpp" #include "base/string_utils.hpp" #include -#include #include +#include #include #include "defines.hpp" @@ -27,12 +29,20 @@ // 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. +using namespace feature; +using namespace generator; +using namespace routing; +using namespace std; + namespace { char const kDelim[] = ", \t\r\n"; bool ParseOneSpeedValue(strings::SimpleTokenizer & iter, uint16_t & value) { + if (!iter) + return false; + uint64_t parsedSpeed = 0; if (!strings::to_uint64(*iter, parsedSpeed)) return false; @@ -42,16 +52,54 @@ bool ParseOneSpeedValue(strings::SimpleTokenizer & iter, uint16_t & value) ++iter; return true; } + +/// \brief Collects all maxspeed tag value of specified mwm based on maxspeed.csv file. +class MaxspeedMwmCollector +{ +public: + MaxspeedMwmCollector(std::string const & dataPath, + std::map const & featureIdToOsmId, + std::string const & maxspeedFilename); + + std::vector && StealMaxspeeds() { return move(m_maxspeeds); } + +private: + std::vector m_maxspeeds; +}; + +MaxspeedMwmCollector::MaxspeedMwmCollector( + string const & dataPath, map const & featureIdToOsmId, + string const & maxspeedFilename) +{ + OsmIdToMaxspeed osmIdToMaxspeed; + CHECK(ParseMaxspeeds(maxspeedFilename, osmIdToMaxspeed), (maxspeedFilename)); + + 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. + m_maxspeeds.push_back( + FeatureMaxspeed(fid, SpeedInUnits(parsedMaxspeed.m_forward, parsedMaxspeed.m_units), + SpeedInUnits(parsedMaxspeed.m_backward, parsedMaxspeed.m_units))); + }); +} } // 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(); @@ -67,10 +115,14 @@ bool ParseMaxspeeds(string const & maxspeedFilename, OsmIdToMaxspeed & osmIdToMa if (!iter) // the line is empty return false; + // @TODO(bykoianko) trings::to_uint64 returns not-zero value if |*iter| is equal to + // a too long string of numbers. But ParseMaxspeeds() should return false in this case. uint64_t osmId = 0; if (!strings::to_uint64(*iter, osmId)) return false; - ++iter; + ++iter; + if (!iter) + return false; ParsedMaxspeed speed; speed.m_units = StringToUnits(*iter); @@ -98,55 +150,39 @@ bool ParseMaxspeeds(string const & maxspeedFilename, OsmIdToMaxspeed & osmIdToMa 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); + LOG(LINFO, ("SerializeMaxspeed(", dataPath, ", ...) serialized:", speeds.size(), "maxspeed tags.")); } -bool BuildMaxspeed(string const & dataPath, string const & osmToFeaturePath, +void BuildMaxspeed(string const & dataPath, map const & featureIdToOsmId, + string const & maxspeedFilename) +{ + MaxspeedMwmCollector collector(dataPath, featureIdToOsmId, maxspeedFilename); + SerializeMaxspeed(dataPath, collector.StealMaxspeeds()); +} + +void 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())); + BuildMaxspeed(dataPath, featureIdToOsmId, maxspeedFilename); +} - 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; +std::string DebugPrint(ParsedMaxspeed const & parsedMaxspeed) +{ + std::ostringstream oss; + oss << "ParsedMaxspeed [ m_units:" << DebugPrint(parsedMaxspeed.m_units) + << " m_forward:" << parsedMaxspeed.m_forward + << " m_backward:" << parsedMaxspeed.m_backward << " ]"; + return oss.str(); } } // namespace routing diff --git a/generator/maxspeed_builder.hpp b/generator/maxspeed_builder.hpp index 0a71ebed48..0a944f4465 100644 --- a/generator/maxspeed_builder.hpp +++ b/generator/maxspeed_builder.hpp @@ -5,6 +5,7 @@ #include "base/geo_object_id.hpp" +#include #include #include #include @@ -16,15 +17,26 @@ struct ParsedMaxspeed measurement_utils::Units m_units = measurement_utils::Units::Metric; uint16_t m_forward = routing::kInvalidSpeed; uint16_t m_backward = routing::kInvalidSpeed; + + bool operator==(ParsedMaxspeed const & rhs) const + { + return m_units == rhs.m_units && m_forward == rhs.m_forward && m_backward == rhs.m_backward; + } }; using OsmIdToMaxspeed = std::map; +/// \brief Parses csv file with path |maxspeedFilename| and keep the result in |osmIdToMaxspeed|. +/// \note There's a detailed description of the csv file in generator/maxspeed_collector.hpp. 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); +void BuildMaxspeed(std::string const & dataPath, + std::map const & featureIdToOsmId, + std::string const & maxspeedFilename); + /// \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. @@ -32,6 +44,8 @@ void SerializeMaxspeed(std::string const & dataPath, std::vector const & points, Func && fn) auto const mwmPath = base::JoinPath(platform.WritableDir(), kTestDir); - LocalCountryFile country(mwmPath, CountryFile(kTestMwm), 0 /* version */); + LocalCountryFile country(mwmPath, CountryFile(kTest), 0 /* version */); ScopedDir testScopedDir(kTestDir); - ScopedFile testScopedMwm(base::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION), + ScopedFile testScopedMwm(base::JoinPath(kTestDir, kTest + DATA_FILE_EXTENSION), ScopedFile::Mode::Create); { diff --git a/routing/maxspeed_conversion.cpp b/routing/maxspeed_conversion.cpp index 441561a0d3..fea176b855 100644 --- a/routing/maxspeed_conversion.cpp +++ b/routing/maxspeed_conversion.cpp @@ -16,9 +16,8 @@ bool SpeedInUnits::operator==(SpeedInUnits const & rhs) const bool SpeedInUnits::operator<(SpeedInUnits const & rhs) const { - if (m_speed != rhs.m_speed) - return m_speed < rhs.m_speed; - return m_units < rhs.m_units; + return (m_units == Units::Metric ? m_speed : MphToKmph(m_speed)) < + (rhs.m_units == Units::Metric ? rhs.m_speed : MphToKmph(rhs.m_speed)); } bool SpeedInUnits::IsNumeric() const diff --git a/routing/maxspeed_conversion.hpp b/routing/maxspeed_conversion.hpp index 638dc6d2aa..d59714db42 100644 --- a/routing/maxspeed_conversion.hpp +++ b/routing/maxspeed_conversion.hpp @@ -166,8 +166,6 @@ struct SpeedInUnits SpeedInUnits(uint16_t speed, measurement_utils::Units units) noexcept : m_speed(speed), m_units(units) {} bool operator==(SpeedInUnits const & rhs) const; - /// \note While comparing speeds are not converted to the same units. So according to - /// this compare operator 80 km per hour is more then 79 mile per hour. bool operator<(SpeedInUnits const & rhs) const; bool IsNumeric() const; @@ -177,7 +175,7 @@ struct SpeedInUnits measurement_utils::Units m_units = measurement_utils::Units::Metric; }; -/// \breif Maxspeed tag value for feature id. |m_forward| and |m_backward| fields reflect the fact +/// \brief Maxspeed tag value for feature id. |m_forward| and |m_backward| fields reflect the fact /// that a feature may have different maxspeed tag value for different directions. /// If |m_backward| is invalid it means that |m_forward| tag contains maxspeed for the both /// directions. diff --git a/routing/maxspeed_serialization.hpp b/routing/maxspeed_serialization.hpp index fb9a67b807..6d745885b2 100644 --- a/routing/maxspeed_serialization.hpp +++ b/routing/maxspeed_serialization.hpp @@ -24,7 +24,7 @@ public: CHECK(std::is_sorted(speeds.cbegin(), speeds.cend()), ()); // @TODO(bykoianko) Now serialization is implemented in the simplest way for research purposes. - // It should be rewrite in a better way using MaxspeedConverter before before the PR is merged. + // It should be rewrite in a better way using MaxspeedConverter before the PR is merged. Header header(static_cast(speeds.size())); header.Serialize(sink); diff --git a/routing/routing_tests/maxspeed_tests.cpp b/routing/routing_tests/maxspeed_tests.cpp index 86384a8d99..c6a86b1981 100644 --- a/routing/routing_tests/maxspeed_tests.cpp +++ b/routing/routing_tests/maxspeed_tests.cpp @@ -3,6 +3,7 @@ #include "routing/maxspeed_conversion.hpp" #include "routing/maxspeed_serialization.hpp" +#include "coding/file_name_utils.hpp" #include "coding/reader.hpp" #include "coding/writer.hpp"