[routing] Adding test on maxspeed section.

This commit is contained in:
Vladimir Byko-Ianko 2018-10-31 17:34:38 +03:00 committed by mpimenov
parent 59e6a501ac
commit 1e67ea4da0
16 changed files with 465 additions and 78 deletions

View file

@ -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

View file

@ -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<TPoint3DList> 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);

View file

@ -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<uint64_t> && 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);

View file

@ -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 <algorithm>
#include <fstream>
#include <map>
#include <string>
#include <vector>
namespace
{
using namespace measurement_utils;
using namespace platform;
using namespace platform::tests_support;
using namespace routing;
using namespace std;
using FeatureVector = vector<vector<m2::PointD>>;
// 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<uint32_t, base::GeoObjectId> 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<MwmValue>();
vector<FeatureMaxspeed> maxspeeds;
if (mwmValue.m_cont.IsExist(MAXSPEED_FILE_TAG))
{
try
{
auto const & reader = mwmValue.m_cont.GetReader(MAXSPEED_FILE_TAG);
ReaderSource<FilesContainerR::TReader> 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<uint32_t, base::GeoObjectId> 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<uint32_t, base::GeoObjectId> 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<uint32_t, base::GeoObjectId> 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<uint32_t, base::GeoObjectId> 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<uint32_t, base::GeoObjectId> 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<uint32_t, base::GeoObjectId> 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

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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 <algorithm>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <utility>
#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<uint32_t, base::GeoObjectId> const & featureIdToOsmId,
std::string const & maxspeedFilename);
std::vector<FeatureMaxspeed> && StealMaxspeeds() { return move(m_maxspeeds); }
private:
std::vector<FeatureMaxspeed> m_maxspeeds;
};
MaxspeedMwmCollector::MaxspeedMwmCollector(
string const & dataPath, map<uint32_t, base::GeoObjectId> 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<FeatureMaxspeed> && 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<uint32_t, base::GeoObjectId> 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<uint32_t, base::GeoObjectId> featureIdToOsmId;
CHECK(ParseFeatureIdToOsmIdMapping(osmToFeaturePath, featureIdToOsmId), ());
LOG(LINFO, ("BuildMaxspeed() featureIdToOsmId size:", featureIdToOsmId.size()));
BuildMaxspeed(dataPath, featureIdToOsmId, maxspeedFilename);
}
vector<FeatureMaxspeed> 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

View file

@ -5,6 +5,7 @@
#include "base/geo_object_id.hpp"
#include <cstdint>
#include <map>
#include <string>
#include <vector>
@ -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<base::GeoObjectId, ParsedMaxspeed>;
/// \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<FeatureMaxspeed> && speeds);
void BuildMaxspeed(std::string const & dataPath,
std::map<uint32_t, base::GeoObjectId> 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<FeatureMaxspeed
/// 1. GenerateIntermediateData(). Saves to a file data about maxspeed tags value of road features
/// 2. GenerateFeatures()
/// 3. Generates geometry
bool BuildMaxspeed(std::string const & dataPath, std::string const & osmToFeaturePath,
void BuildMaxspeed(std::string const & dataPath, std::string const & osmToFeaturePath,
std::string const & maxspeedFilename);
std::string DebugPrint(ParsedMaxspeed const & parsedMaxspeed);
} // namespace routing

View file

@ -7,8 +7,9 @@
namespace feature
{
/// \brief Saves csv file. Every line describes maxspeed, maxspeed:forward and maxspeed:backward
/// tags of linear features. The format of the lines is described below.
/// \brief Collects all maxspeed tags value and saves them to a csv file.
/// Every line describes maxspeed, maxspeed:forward and maxspeed:backward
/// tags of features. The format of the lines is described below.
class MaxspeedCollector
{
public:
@ -31,10 +32,10 @@ private:
// 13243214,Imperial,60
// 3243245345,Metric,60,80
// 134243,Imperial,30,50
// 45432423,Metric,60,65535
// 53445423,Metric,60,65534
// 45432423,Metric,60,65534
// 53445423,Metric,60,65533
//
// Note 1. 65535 means kNoneMaxSpeed and 65534 means kWalkMaxSpeed. They are constants for
// Note 1. 65534 means kNoneMaxSpeed and 65533 means kWalkMaxSpeed. They are constants for
// maxspeed tag value "none" and "walk" correspondingly.
// Note 2. Saying osm id means osm id of features with OsmElement::EntityType::Way type without
// any prefixes. It's done so to simplify the debugging process. This way it's very easy knowing

View file

@ -34,7 +34,7 @@ using namespace std;
namespace
{
string const kTestDir = "openlr_decoded_path_test";
string const kTestMwm = "test";
string const kTest = "test";
double RoughUpToFive(double d)
{
@ -123,9 +123,9 @@ void WithRoad(vector<m2::PointD> 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);
{

View file

@ -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

View file

@ -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.

View file

@ -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<uint32_t>(speeds.size()));
header.Serialize(sink);

View file

@ -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"