1232 lines
36 KiB
C++
1232 lines
36 KiB
C++
|
|
#include "testing/testing.hpp"
|
||
|
|
|
||
|
|
#include "generator/descriptions_section_builder.hpp"
|
||
|
|
#include "generator/generator_tests_support/test_generator.hpp"
|
||
|
|
|
||
|
|
#include "search/cities_boundaries_table.hpp"
|
||
|
|
#include "search/house_to_street_table.hpp"
|
||
|
|
|
||
|
|
#include "routing/index_graph_loader.hpp"
|
||
|
|
#include "routing/maxspeeds.hpp"
|
||
|
|
|
||
|
|
#include "indexer/classificator.hpp"
|
||
|
|
#include "indexer/feature_algo.hpp"
|
||
|
|
#include "indexer/ftypes_matcher.hpp"
|
||
|
|
|
||
|
|
namespace raw_generator_tests
|
||
|
|
{
|
||
|
|
using TestRawGenerator = generator::tests_support::TestRawGenerator;
|
||
|
|
|
||
|
|
uint32_t GetFeatureType(FeatureType & ft)
|
||
|
|
{
|
||
|
|
uint32_t res = 0;
|
||
|
|
ft.ForEachType([&res](uint32_t t)
|
||
|
|
{
|
||
|
|
TEST_EQUAL(res, 0, ());
|
||
|
|
res = t;
|
||
|
|
});
|
||
|
|
return res;
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/2035
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Towns)
|
||
|
|
{
|
||
|
|
uint32_t const cityType = classif().GetTypeByPath({"place", "city"});
|
||
|
|
uint32_t const townType = classif().GetTypeByPath({"place", "town"});
|
||
|
|
uint32_t const villageType = classif().GetTypeByPath({"place", "village"});
|
||
|
|
|
||
|
|
std::string const mwmName = "Towns";
|
||
|
|
std::string const mwmWorld = WORLD_FILE_NAME;
|
||
|
|
BuildFB("./data/test_data/osm/towns.osm", mwmName, true /* makeWorld */);
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
// LOG(LINFO, (fb));
|
||
|
|
|
||
|
|
TEST(!fb.HasType(cityType), ());
|
||
|
|
|
||
|
|
bool const isTown = (fb.GetName() == "El Dorado");
|
||
|
|
TEST_EQUAL(isTown, fb.HasType(townType), ());
|
||
|
|
TEST_NOT_EQUAL(isTown, fb.HasType(villageType), ());
|
||
|
|
|
||
|
|
TEST(fb.GetRank() > 0, ());
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, 4, ());
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
ForEachFB(mwmWorld, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(!fb.HasType(villageType), ());
|
||
|
|
|
||
|
|
bool const isTown = (fb.GetName() == "El Dorado");
|
||
|
|
TEST(fb.HasType(isTown ? townType : cityType), ());
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
|
||
|
|
// Prepare features data source.
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
std::vector<MwmSet::MwmId> mwmIDs;
|
||
|
|
for (auto const & name : {mwmName, mwmWorld})
|
||
|
|
{
|
||
|
|
BuildFeatures(name);
|
||
|
|
BuildSearch(name);
|
||
|
|
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(name)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
mwmIDs.push_back(std::move(res.first));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Load boundaries.
|
||
|
|
search::CitiesBoundariesTable table(dataSource);
|
||
|
|
TEST(table.Load(), ());
|
||
|
|
TEST_EQUAL(table.GetSize(), 1, ());
|
||
|
|
|
||
|
|
// Iterate for features in World.
|
||
|
|
count = 0;
|
||
|
|
FeaturesLoaderGuard guard(dataSource, mwmIDs[1]);
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
|
||
|
|
std::string_view const name = ft->GetName(StringUtf8Multilang::kDefaultCode);
|
||
|
|
if (!name.empty())
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Point, ());
|
||
|
|
|
||
|
|
search::CitiesBoundariesTable::Boundaries boundary;
|
||
|
|
TEST(table.Get(id, boundary), ());
|
||
|
|
TEST(boundary.HasPoint(ft->GetCenter()), ());
|
||
|
|
|
||
|
|
bool const isTown = (name == "El Dorado");
|
||
|
|
TEST_EQUAL(GetFeatureType(*ft), isTown ? townType : cityType, ());
|
||
|
|
|
||
|
|
++count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/2475
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, HighwayLinks)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Highways";
|
||
|
|
BuildFB("./data/test_data/osm/highway_links.osm", mwmName);
|
||
|
|
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
BuildRouting(mwmName, "Spain");
|
||
|
|
|
||
|
|
auto const fid2osm = LoadFID2OsmID(mwmName);
|
||
|
|
|
||
|
|
using namespace routing;
|
||
|
|
MaxspeedType from120 = 104; // like SpeedMacro::Speed104KmPH
|
||
|
|
std::unordered_map<uint64_t, uint16_t> osmID2Speed = {
|
||
|
|
{23011515, from120}, {23011492, from120}, {10689329, from120}, {371581901, from120}, {1017695671, from120},
|
||
|
|
{577365212, from120}, {23011612, from120}, {1017695670, from120}, {304871606, from120}, {1017695669, from120},
|
||
|
|
{577365213, from120}, {369541035, from120}, {1014336646, from120}, {466365947, from120}, {23011511, from120}};
|
||
|
|
/// @todo Actually, better to assign speed for this way too.
|
||
|
|
std::unordered_set<uint64_t> osmNoSpeed = {23691193, 1017695668};
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(mwmName)));
|
||
|
|
CHECK_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
auto const speeds = routing::LoadMaxspeeds(guard.GetHandle());
|
||
|
|
CHECK(speeds, ());
|
||
|
|
|
||
|
|
size_t speedChecked = 0, noSpeed = 0;
|
||
|
|
|
||
|
|
uint32_t const count = guard.GetNumFeatures();
|
||
|
|
for (uint32_t id = 0; id < count; ++id)
|
||
|
|
{
|
||
|
|
auto const iOsmID = fid2osm.find(id);
|
||
|
|
if (iOsmID == fid2osm.end())
|
||
|
|
continue;
|
||
|
|
auto const osmID = iOsmID->second.GetSerialId();
|
||
|
|
|
||
|
|
auto const iSpeed = osmID2Speed.find(osmID);
|
||
|
|
if (iSpeed != osmID2Speed.end())
|
||
|
|
{
|
||
|
|
++speedChecked;
|
||
|
|
auto const speed = speeds->GetMaxspeed(id);
|
||
|
|
TEST(speed.IsValid(), ());
|
||
|
|
TEST_EQUAL(speed.GetForward(), iSpeed->second, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
auto const iNoSpeed = osmNoSpeed.find(osmID);
|
||
|
|
if (iNoSpeed != osmNoSpeed.end())
|
||
|
|
{
|
||
|
|
++noSpeed;
|
||
|
|
TEST(!speeds->GetMaxspeed(id).IsValid(), ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_EQUAL(speedChecked, osmID2Speed.size(), ());
|
||
|
|
TEST_EQUAL(noSpeed, osmNoSpeed.size(), ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Building3D)
|
||
|
|
{
|
||
|
|
auto const & buildingChecker = ftypes::IsBuildingChecker::Instance();
|
||
|
|
auto const & buildingPartChecker = ftypes::IsBuildingPartChecker::Instance();
|
||
|
|
auto const & buildingHasPartsChecker = ftypes::IsBuildingHasPartsChecker::Instance();
|
||
|
|
|
||
|
|
std::string const mwmName = "Building3D";
|
||
|
|
BuildFB("./data/test_data/osm/building3D.osm", mwmName);
|
||
|
|
|
||
|
|
size_t buildings = 0, buildingParts = 0, buildingHasParts = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
auto const & types = fb.GetTypes();
|
||
|
|
if (buildingChecker(types))
|
||
|
|
++buildings;
|
||
|
|
if (buildingPartChecker(types))
|
||
|
|
++buildingParts;
|
||
|
|
if (buildingHasPartsChecker(types))
|
||
|
|
++buildingHasParts;
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(buildings, 1, ());
|
||
|
|
TEST_GREATER(buildingParts, 0, ());
|
||
|
|
TEST_EQUAL(buildingHasParts, 1, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://www.openstreetmap.org/relation/13430355
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, BuildingRelation)
|
||
|
|
{
|
||
|
|
auto const & buildingChecker = ftypes::IsBuildingChecker::Instance();
|
||
|
|
auto const & buildingPartChecker = ftypes::IsBuildingPartChecker::Instance();
|
||
|
|
auto const & buildingHasPartsChecker = ftypes::IsBuildingHasPartsChecker::Instance();
|
||
|
|
|
||
|
|
std::string const mwmName = "Building";
|
||
|
|
BuildFB("./data/test_data/osm/building_relation.osm", mwmName);
|
||
|
|
|
||
|
|
{
|
||
|
|
size_t buildings = 0, buildingParts = 0, buildingHasParts = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
auto const & types = fb.GetTypes();
|
||
|
|
if (buildingChecker(types))
|
||
|
|
++buildings;
|
||
|
|
if (buildingPartChecker(types))
|
||
|
|
++buildingParts;
|
||
|
|
if (buildingHasPartsChecker(types))
|
||
|
|
++buildingHasParts;
|
||
|
|
});
|
||
|
|
|
||
|
|
/// @todo Should be 1, 3, 1 when will implement one FB with multiple polygons.
|
||
|
|
TEST_EQUAL(buildings, 2, ());
|
||
|
|
TEST_EQUAL(buildingParts, 3, ());
|
||
|
|
TEST_EQUAL(buildingHasParts, 2, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
|
||
|
|
size_t features = 0;
|
||
|
|
double buildings = 0, buildingParts = 0;
|
||
|
|
ForEachFeature(mwmName, [&](std::unique_ptr<FeatureType> ft)
|
||
|
|
{
|
||
|
|
if (ft->GetGeomType() != feature::GeomType::Area)
|
||
|
|
return;
|
||
|
|
|
||
|
|
feature::TypesHolder types(*ft);
|
||
|
|
if (buildingChecker(types))
|
||
|
|
buildings += feature::CalcArea(*ft);
|
||
|
|
else if (buildingPartChecker(types))
|
||
|
|
buildingParts += feature::CalcArea(*ft);
|
||
|
|
|
||
|
|
++features;
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(features, 5, ());
|
||
|
|
TEST_ALMOST_EQUAL_ABS(buildings, buildingParts, 1.0E-4, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, AreaHighway)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "AreaHighway";
|
||
|
|
BuildFB("./data/test_data/osm/highway_area.osm", mwmName);
|
||
|
|
|
||
|
|
uint32_t const waterType = classif().GetTypeByPath({"natural", "water", "tunnel"});
|
||
|
|
uint32_t const pedestrianType = classif().GetTypeByPath({"highway", "pedestrian", "area"});
|
||
|
|
|
||
|
|
size_t waters = 0, pedestrians = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(waterType))
|
||
|
|
++waters;
|
||
|
|
if (fb.HasType(pedestrianType))
|
||
|
|
++pedestrians;
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(waters, 2, ());
|
||
|
|
TEST_EQUAL(pedestrians, 4, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// place=region doesn't have drawing rules, but we keep it in
|
||
|
|
// GetNondrawableStandaloneIndexScale for the search.
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Place_Region)
|
||
|
|
{
|
||
|
|
uint32_t const regionType = classif().GetTypeByPath({"place", "region"});
|
||
|
|
|
||
|
|
std::string const mwmName = "Region";
|
||
|
|
std::string const worldMwmName = WORLD_FILE_NAME;
|
||
|
|
BuildFB("./data/test_data/osm/place_region.osm", mwmName, true /* makeWorld */);
|
||
|
|
|
||
|
|
size_t worldRegions = 0, countryRegions = 0;
|
||
|
|
|
||
|
|
ForEachFB(worldMwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(regionType))
|
||
|
|
{
|
||
|
|
TEST(!fb.GetName().empty(), ());
|
||
|
|
++worldRegions;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(worldRegions, 1, ());
|
||
|
|
worldRegions = 0;
|
||
|
|
|
||
|
|
// Prepare features data source.
|
||
|
|
for (auto const & name : {mwmName, worldMwmName})
|
||
|
|
{
|
||
|
|
BuildFeatures(name);
|
||
|
|
BuildSearch(name);
|
||
|
|
|
||
|
|
ForEachFeature(name, [&](std::unique_ptr<FeatureType> ft)
|
||
|
|
{
|
||
|
|
if (feature::TypesHolder(*ft).Has(regionType))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Point, ());
|
||
|
|
TEST(!ft->GetName(StringUtf8Multilang::kDefaultCode).empty(), ());
|
||
|
|
|
||
|
|
if (name == worldMwmName)
|
||
|
|
++worldRegions;
|
||
|
|
else
|
||
|
|
++countryRegions;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_EQUAL(worldRegions, 1, ());
|
||
|
|
TEST_EQUAL(countryRegions, 0, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, MiniRoundabout)
|
||
|
|
{
|
||
|
|
uint32_t const roadType = classif().GetTypeByPath({"highway", "secondary"});
|
||
|
|
|
||
|
|
std::string const mwmName = "MiniRoundabout";
|
||
|
|
BuildFB("./data/test_data/osm/mini_roundabout.osm", mwmName, false /* makeWorld */);
|
||
|
|
|
||
|
|
size_t roadsCount = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(roadType))
|
||
|
|
++roadsCount;
|
||
|
|
});
|
||
|
|
|
||
|
|
// Splitted on 3 parts + 4 created roundabouts.
|
||
|
|
TEST_EQUAL(roadsCount, 4 + 3, ());
|
||
|
|
|
||
|
|
// Prepare features data source.
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
BuildRouting(mwmName, "United Kingdom");
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(mwmName)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
std::vector<uint32_t> roads, rounds;
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
if (feature::TypesHolder(*ft).Has(roadType))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Line, ());
|
||
|
|
|
||
|
|
ft->ParseGeometry(FeatureType::BEST_GEOMETRY);
|
||
|
|
size_t const ptsCount = ft->GetPointsCount();
|
||
|
|
TEST_GREATER(ptsCount, 1, ());
|
||
|
|
auto const firstPt = ft->GetPoint(0);
|
||
|
|
auto const lastPt = ft->GetPoint(ptsCount - 1);
|
||
|
|
LOG(LINFO, ("==", id, firstPt, lastPt));
|
||
|
|
|
||
|
|
if ((lastPt.x - firstPt.x) > 0.2)
|
||
|
|
roads.push_back(id);
|
||
|
|
if (fabs(lastPt.x - firstPt.x) < 0.1)
|
||
|
|
rounds.push_back(id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_EQUAL(roads, std::vector<uint32_t>({1, 3, 5}), ());
|
||
|
|
TEST_EQUAL(rounds, std::vector<uint32_t>({0, 2, 4, 6}), ());
|
||
|
|
|
||
|
|
using namespace routing;
|
||
|
|
|
||
|
|
RoadAccess access;
|
||
|
|
ReadRoadAccessFromMwm(*(guard.GetHandle().GetValue()), VehicleType::Car, access);
|
||
|
|
LOG(LINFO, (access));
|
||
|
|
|
||
|
|
SpeedCamerasMapT camerasMap;
|
||
|
|
ReadSpeedCamsFromMwm(*(guard.GetHandle().GetValue()), camerasMap);
|
||
|
|
LOG(LINFO, (camerasMap));
|
||
|
|
}
|
||
|
|
|
||
|
|
namespace
|
||
|
|
{
|
||
|
|
std::string_view GetPostcode(FeatureType & ft)
|
||
|
|
{
|
||
|
|
return ft.GetMetadata(feature::Metadata::FMD_POSTCODE);
|
||
|
|
}
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Postcode_Relations)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Postcodes";
|
||
|
|
BuildFB("./data/test_data/osm/postcode_relations.osm", mwmName, false /* makeWorld */);
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFeature(mwmName, [&count](std::unique_ptr<FeatureType> ft)
|
||
|
|
{
|
||
|
|
auto const name = ft->GetName(StringUtf8Multilang::kDefaultCode);
|
||
|
|
if (name == "Boulevard Malesherbes")
|
||
|
|
{
|
||
|
|
TEST_EQUAL(GetPostcode(*ft), "75017", ());
|
||
|
|
++count;
|
||
|
|
}
|
||
|
|
else if (name == "Facebook France")
|
||
|
|
{
|
||
|
|
TEST_EQUAL(GetPostcode(*ft), "75002", ());
|
||
|
|
++count;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 2, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Building_Address)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Address";
|
||
|
|
BuildFB("./data/test_data/osm/building_address.osm", mwmName, false /* makeWorld */);
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (ftypes::IsBuildingChecker::Instance()(fb.GetTypes()))
|
||
|
|
{
|
||
|
|
auto const & params = fb.GetParams();
|
||
|
|
TEST_EQUAL(params.GetStreet(), "Airport Boulevard", ());
|
||
|
|
TEST_EQUAL(params.GetPostcode(), "819666", ());
|
||
|
|
++count;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
BuildSearch(mwmName);
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(mwmName)));
|
||
|
|
CHECK_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
if (ftypes::IsBuildingChecker::Instance()(*ft))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetHouseNumber(), "78", ());
|
||
|
|
TEST_EQUAL(GetPostcode(*ft), "819666", ());
|
||
|
|
++count;
|
||
|
|
|
||
|
|
auto value = guard.GetHandle().GetValue();
|
||
|
|
if (!value->m_house2street)
|
||
|
|
value->m_house2street = search::LoadHouseToStreetTable(*value);
|
||
|
|
|
||
|
|
auto res = value->m_house2street->Get(id);
|
||
|
|
TEST(res, ());
|
||
|
|
|
||
|
|
auto street = guard.GetFeatureByIndex(res->m_streetId);
|
||
|
|
TEST_EQUAL(street->GetName(StringUtf8Multilang::kDefaultCode), "Airport Boulevard", ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/4974
|
||
|
|
UNIT_TEST(Relation_Wiki)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Relation";
|
||
|
|
|
||
|
|
std::string const arrFiles[] = {
|
||
|
|
"./data/test_data/osm/village_relation.osm",
|
||
|
|
"./data/test_data/osm/novenkoe_village.osm",
|
||
|
|
"./data/test_data/osm/nikolaevka_village.osm",
|
||
|
|
};
|
||
|
|
|
||
|
|
std::string const arrWiki[] = {
|
||
|
|
"fr:Charmois-l'Orgueilleux",
|
||
|
|
"ru:Новенькое (Локтевский район)",
|
||
|
|
"ru:Николаевка (Локтевский район)",
|
||
|
|
};
|
||
|
|
|
||
|
|
for (size_t i = 0; i < std::size(arrFiles); ++i)
|
||
|
|
{
|
||
|
|
TestRawGenerator generator;
|
||
|
|
|
||
|
|
uint32_t const villageType = classif().GetTypeByPath({"place", "village"});
|
||
|
|
|
||
|
|
generator.BuildFB(arrFiles[i], mwmName);
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
generator.ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
switch (fb.GetGeomType())
|
||
|
|
{
|
||
|
|
case feature::GeomType::Point:
|
||
|
|
{
|
||
|
|
TEST(fb.HasType(villageType), ());
|
||
|
|
++count;
|
||
|
|
TEST_EQUAL(fb.GetMetadata().Get(feature::Metadata::FMD_WIKIPEDIA), arrWiki[i], ());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case feature::GeomType::Line:
|
||
|
|
{
|
||
|
|
TEST(fb.GetMetadata().Get(feature::Metadata::FMD_WIKIPEDIA).empty(), ());
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
default: TEST(false, ()); break;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, AssociatedStreet_Wiki)
|
||
|
|
{
|
||
|
|
uint32_t const roadType = classif().GetTypeByPath({"highway", "residential"});
|
||
|
|
|
||
|
|
std::string const mwmName = "Street";
|
||
|
|
BuildFB("./data/test_data/osm/associated_street.osm", mwmName, false /* makeWorld */);
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(roadType))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(fb.GetMetadata().Get(feature::Metadata::FMD_WIKIPEDIA), "uk:Вулиця Боричів Тік", ());
|
||
|
|
++count;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 5, ());
|
||
|
|
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
generator::WikidataHelper wikidata(GetMwmPath(mwmName), GetGenInfo().GetIntermediateFileName(kWikidataFilename));
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
ForEachFeature(mwmName, [&](std::unique_ptr<FeatureType> ft)
|
||
|
|
{
|
||
|
|
if (feature::TypesHolder(*ft).Has(roadType))
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
auto const data = wikidata.GetWikidataId(ft->GetID().m_index);
|
||
|
|
TEST(data, ());
|
||
|
|
TEST_EQUAL(*data, "Q4471511", ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 5, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_TEST(Place_CityRelations)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Cities";
|
||
|
|
std::string const worldMwmName = WORLD_FILE_NAME;
|
||
|
|
|
||
|
|
std::string const arrFiles[] = {
|
||
|
|
// 1 Relation with many polygons + 1 Node.
|
||
|
|
"./data/test_data/osm/gorlovka_city.osm",
|
||
|
|
// 2 Relations + 1 Node
|
||
|
|
"./data/test_data/osm/tver_city.osm",
|
||
|
|
// 1 Relation + 1 Node with _different_ names.
|
||
|
|
"./data/test_data/osm/reykjavik_city.osm", "./data/test_data/osm/berlin_city.osm",
|
||
|
|
// Relation boundary is place=suburb, but border_type=city
|
||
|
|
"./data/test_data/osm/riviera_beach_city.osm", "./data/test_data/osm/hotchkiss_town.osm",
|
||
|
|
"./data/test_data/osm/voronezh_city.osm", "./data/test_data/osm/minsk_city.osm",
|
||
|
|
|
||
|
|
// 1 boundary-only Relation + 1 Node
|
||
|
|
"./data/test_data/osm/kadikoy_town.osm",
|
||
|
|
// 2 Relations + 1 Node
|
||
|
|
"./data/test_data/osm/stolbtcy_town.osm",
|
||
|
|
// 1 Way + 1 Relation + 1 Node
|
||
|
|
"./data/test_data/osm/dmitrov_town.osm", "./data/test_data/osm/lesnoy_town.osm",
|
||
|
|
|
||
|
|
"./data/test_data/osm/pushkino_city.osm", "./data/test_data/osm/korday_town.osm",
|
||
|
|
"./data/test_data/osm/bad_neustadt_town.osm",
|
||
|
|
|
||
|
|
/// @todo We don't store villages in World now, but for the future!
|
||
|
|
// 1 Relation + 1 Node (not linked with each other)
|
||
|
|
//"./data/test_data/osm/palm_beach_village.osm",
|
||
|
|
};
|
||
|
|
|
||
|
|
ms::LatLon arrNotInBoundary[] = {
|
||
|
|
{48.2071448, 37.9729054}, // gorlovka
|
||
|
|
{56.9118261, 36.2258988}, // tver
|
||
|
|
{64.0469397, -21.9772409}, // reykjavik
|
||
|
|
{52.4013879, 13.0601531}, // berlin
|
||
|
|
{26.7481191, -80.0836532}, // riviera beach
|
||
|
|
{38.7981690, -107.7347750}, // hotchkiss
|
||
|
|
{51.7505379, 39.5894547}, // voronezh
|
||
|
|
{53.9170050, 27.8576710}, // minsk
|
||
|
|
|
||
|
|
{41.0150982, 29.0213844}, // kadikoy
|
||
|
|
{53.5086454, 26.6979711}, // stolbtcy
|
||
|
|
{56.3752679, 37.3288391}, // dmitrov
|
||
|
|
{54.0026933, 27.6356912}, // lesnoy
|
||
|
|
|
||
|
|
{56.0807652, 37.9277319}, // pushkino
|
||
|
|
{43.2347760, 74.7573240}, // korday
|
||
|
|
{50.4006992, 10.2020744}, // bad_neustadt
|
||
|
|
|
||
|
|
//{26.6757006, -80.0547346}, // palm beach
|
||
|
|
};
|
||
|
|
|
||
|
|
size_t constexpr kManyBoundriesUpperIndex = 8;
|
||
|
|
|
||
|
|
static_assert(std::size(arrFiles) == std::size(arrNotInBoundary));
|
||
|
|
|
||
|
|
for (size_t i = 0; i < std::size(arrFiles); ++i)
|
||
|
|
{
|
||
|
|
TestRawGenerator generator;
|
||
|
|
generator.BuildFB(arrFiles[i], mwmName, true /* makeWorld */);
|
||
|
|
|
||
|
|
auto const & checker = ftypes::IsCityTownOrVillageChecker::Instance();
|
||
|
|
|
||
|
|
// Check that we have only 1 city without duplicates.
|
||
|
|
size_t count = 0;
|
||
|
|
generator.ForEachFB(worldMwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Point)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(checker(fb.GetTypes()), ());
|
||
|
|
TEST(fb.GetRank() > 0, ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
generator.ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (checker(fb.GetTypes()))
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(fb.GetRank() > 0, ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
|
||
|
|
// Build boundaries table.
|
||
|
|
generator.BuildFeatures(worldMwmName);
|
||
|
|
generator.BuildSearch(worldMwmName);
|
||
|
|
|
||
|
|
// Check that we have valid boundary in World.
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res =
|
||
|
|
dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(generator.GetMwmPath(worldMwmName)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
search::CitiesBoundariesTable table(dataSource);
|
||
|
|
TEST(table.Load(), ());
|
||
|
|
TEST_EQUAL(table.GetSize(), 1, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
bool foundCity = false;
|
||
|
|
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
if (checker(*ft))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Point, ());
|
||
|
|
foundCity = true;
|
||
|
|
|
||
|
|
search::CitiesBoundariesTable::Boundaries boundary;
|
||
|
|
TEST(table.Get(ft->GetID(), boundary), ());
|
||
|
|
TEST(boundary.HasPoint(ft->GetCenter()), ());
|
||
|
|
TEST(!boundary.HasPoint(mercator::FromLatLon(arrNotInBoundary[i])), (i));
|
||
|
|
|
||
|
|
if (i < kManyBoundriesUpperIndex)
|
||
|
|
TEST_GREATER(boundary.GetCount(), 1, (i));
|
||
|
|
else
|
||
|
|
TEST_EQUAL(boundary.GetCount(), 1, (i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(foundCity, ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_TEST(Place_CityRelations_IncludePoint)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Cities";
|
||
|
|
std::string const worldMwmName = WORLD_FILE_NAME;
|
||
|
|
|
||
|
|
std::string const arrFiles[] = {
|
||
|
|
"./data/test_data/osm/valentin_alsina_town.osm",
|
||
|
|
};
|
||
|
|
|
||
|
|
ms::LatLon arrInBoundary[] = {
|
||
|
|
{-34.6699107, -58.4302163}, // valentin_alsina
|
||
|
|
};
|
||
|
|
|
||
|
|
for (size_t i = 0; i < std::size(arrFiles); ++i)
|
||
|
|
{
|
||
|
|
TestRawGenerator generator;
|
||
|
|
generator.BuildFB(arrFiles[i], mwmName, true /* makeWorld */);
|
||
|
|
|
||
|
|
auto const & checker = ftypes::IsCityTownOrVillageChecker::Instance();
|
||
|
|
|
||
|
|
// Check that we have only 1 city without duplicates.
|
||
|
|
size_t count = 0;
|
||
|
|
generator.ForEachFB(worldMwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Point)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(checker(fb.GetTypes()), ());
|
||
|
|
TEST(fb.GetRank() > 0, ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
|
||
|
|
// Build boundaries table.
|
||
|
|
generator.BuildFeatures(worldMwmName);
|
||
|
|
generator.BuildSearch(worldMwmName);
|
||
|
|
|
||
|
|
// Check that we have valid boundary in World.
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res =
|
||
|
|
dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(generator.GetMwmPath(worldMwmName)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
search::CitiesBoundariesTable table(dataSource);
|
||
|
|
TEST(table.Load(), ());
|
||
|
|
TEST_EQUAL(table.GetSize(), 1, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
bool foundCity = false;
|
||
|
|
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
if (checker(*ft))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Point, ());
|
||
|
|
foundCity = true;
|
||
|
|
|
||
|
|
search::CitiesBoundariesTable::Boundaries boundary;
|
||
|
|
TEST(table.Get(ft->GetID(), boundary), ());
|
||
|
|
TEST(boundary.HasPoint(ft->GetCenter()), ());
|
||
|
|
TEST(boundary.HasPoint(mercator::FromLatLon(arrInBoundary[i])), (i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(foundCity, ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Place_NoCityBoundaries)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Cities";
|
||
|
|
std::string const worldMwmName = WORLD_FILE_NAME;
|
||
|
|
|
||
|
|
struct TestDataSample
|
||
|
|
{
|
||
|
|
std::string m_osmInput;
|
||
|
|
size_t m_inWorld = 0;
|
||
|
|
size_t m_inCountry = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
TestDataSample const arrInput[] = {
|
||
|
|
// Check that we have only 2 cities without duplicates (Pargas, Қордай).
|
||
|
|
// Boundaries are removed because of "very big".
|
||
|
|
{"./data/test_data/osm/no_boundary_towns.osm", 2, 2},
|
||
|
|
// 3 villages in country and 0 in World.
|
||
|
|
{"./data/test_data/osm/us_villages_like_towns.osm", 0, 3},
|
||
|
|
};
|
||
|
|
|
||
|
|
for (size_t i = 0; i < std::size(arrInput); ++i)
|
||
|
|
{
|
||
|
|
TestRawGenerator generator;
|
||
|
|
generator.BuildFB(arrInput[i].m_osmInput, mwmName, true /* makeWorld */);
|
||
|
|
|
||
|
|
auto const & checker = ftypes::IsCityTownOrVillageChecker::Instance();
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
generator.ForEachFB(worldMwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Point)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST_GREATER(fb.GetRank(), 10, (i));
|
||
|
|
TEST(checker(fb.GetTypes()), (i));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, arrInput[i].m_inWorld, (i));
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
generator.ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Point && checker(fb.GetTypes()))
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST_GREATER(fb.GetRank(), 10, (i));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, arrInput[i].m_inCountry, (i));
|
||
|
|
|
||
|
|
// Build boundaries table.
|
||
|
|
generator.BuildFeatures(worldMwmName);
|
||
|
|
generator.BuildSearch(worldMwmName);
|
||
|
|
|
||
|
|
// Check that we have NO boundaries in World.
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res =
|
||
|
|
dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(generator.GetMwmPath(worldMwmName)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
search::CitiesBoundariesTable table(dataSource);
|
||
|
|
TEST(table.Load(), ());
|
||
|
|
TEST_EQUAL(table.GetSize(), 0, (i));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Place_2Villages)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Villages";
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/tarachevo_villages.osm", mwmName, false /* makeWorld */);
|
||
|
|
|
||
|
|
auto const & checker = ftypes::IsCityTownOrVillageChecker::Instance();
|
||
|
|
|
||
|
|
// Check that we have 2 villages (Тарачево).
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Point)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(checker(fb.GetTypes()), ());
|
||
|
|
TEST_EQUAL(fb.GetName(), "Тарачево", ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 2, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Relation_Fence)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Fences";
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/fence_relation.osm", mwmName);
|
||
|
|
|
||
|
|
uint32_t const fenceType = classif().GetTypeByPath({"barrier", "fence"});
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Line)
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(fb.HasType(fenceType), ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, 2, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://www.openstreetmap.org/changeset/133837637
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Shuttle_Route)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Shuttle";
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/shuttle_route.osm", mwmName);
|
||
|
|
|
||
|
|
uint32_t const railType = classif().GetTypeByPath({"railway", "rail"});
|
||
|
|
uint32_t const shuttleType = classif().GetTypeByPath({"route", "shuttle_train"});
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Line && fb.HasType(railType, 2))
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
TEST(fb.HasType(shuttleType), (fb.GetMostGenericOsmId()));
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_GREATER(count, 30, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/4924
|
||
|
|
UNIT_TEST(MiniRoundabout_Connectivity)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "MiniRoundabout";
|
||
|
|
|
||
|
|
std::string const arrFiles[] = {
|
||
|
|
"./data/test_data/osm/mini_roundabout_1.osm",
|
||
|
|
"./data/test_data/osm/mini_roundabout_2.osm",
|
||
|
|
"./data/test_data/osm/mini_roundabout_3.osm",
|
||
|
|
};
|
||
|
|
|
||
|
|
for (auto const & fileName : arrFiles)
|
||
|
|
{
|
||
|
|
TestRawGenerator generator;
|
||
|
|
|
||
|
|
uint32_t const roundaboutType = classif().GetTypeByPath({"junction", "roundabout"});
|
||
|
|
uint32_t const tertiaryType = classif().GetTypeByPath({"highway", "tertiary"});
|
||
|
|
uint32_t const residentialType = classif().GetTypeByPath({"highway", "residential"});
|
||
|
|
|
||
|
|
generator.BuildFB(fileName, mwmName, false /* makeWorld */);
|
||
|
|
generator.BuildFeatures(mwmName);
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(generator.GetMwmPath(mwmName)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
FeatureType::PointsBufferT roundabout;
|
||
|
|
auto const IsPointInRoundabout = [&roundabout](m2::PointD const & pt)
|
||
|
|
{
|
||
|
|
for (auto const & p : roundabout)
|
||
|
|
if (AlmostEqualAbs(p, pt, kMwmPointAccuracy))
|
||
|
|
return true;
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
feature::TypesHolder types(*ft);
|
||
|
|
if (types.Has(roundaboutType))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Line, ());
|
||
|
|
TEST(roundabout.empty(), ());
|
||
|
|
roundabout = ft->GetPoints(FeatureType::BEST_GEOMETRY);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(!roundabout.empty(), ());
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
feature::TypesHolder types(*ft);
|
||
|
|
if (types.Has(tertiaryType) || types.Has(residentialType))
|
||
|
|
{
|
||
|
|
TEST_EQUAL(ft->GetGeomType(), feature::GeomType::Line, ());
|
||
|
|
auto const & pts = ft->GetPoints(FeatureType::BEST_GEOMETRY);
|
||
|
|
TEST(IsPointInRoundabout(pts.front()) || IsPointInRoundabout(pts.back()), ());
|
||
|
|
|
||
|
|
++count;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_GREATER(count, 1, ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Addr_Interpolation)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Address";
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/addr_interpol.osm", mwmName);
|
||
|
|
|
||
|
|
uint32_t const addrType = classif().GetTypeByPath({"addr:interpolation", "even"});
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.GetGeomType() == feature::GeomType::Line && fb.HasType(addrType))
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
auto const & params = fb.GetParams();
|
||
|
|
TEST_EQUAL(params.ref, "3602:3800", ());
|
||
|
|
TEST_EQUAL(params.GetStreet(), "Juncal", ());
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
BuildSearch(mwmName);
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(mwmName)));
|
||
|
|
CHECK_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
count = 0;
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
if (ftypes::IsAddressInterpolChecker::Instance()(*ft))
|
||
|
|
{
|
||
|
|
++count;
|
||
|
|
|
||
|
|
auto value = guard.GetHandle().GetValue();
|
||
|
|
if (!value->m_house2street)
|
||
|
|
value->m_house2street = search::LoadHouseToStreetTable(*value);
|
||
|
|
|
||
|
|
auto res = value->m_house2street->Get(id);
|
||
|
|
TEST(res, ());
|
||
|
|
|
||
|
|
auto street = guard.GetFeatureByIndex(res->m_streetId);
|
||
|
|
TEST_EQUAL(street->GetName(StringUtf8Multilang::kDefaultCode), "Juncal", ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/4994
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, NamedAddress)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Address";
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/named_address.osm", mwmName);
|
||
|
|
|
||
|
|
uint32_t const addrType = classif().GetTypeByPath({"building", "address"});
|
||
|
|
|
||
|
|
size_t withName = 0, withNumber = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
TEST_EQUAL(fb.GetGeomType(), feature::GeomType::Point, ());
|
||
|
|
TEST(fb.HasType(addrType), ());
|
||
|
|
|
||
|
|
auto const & params = fb.GetParams();
|
||
|
|
TEST(params.house.IsEmpty() != fb.GetName().empty(), ());
|
||
|
|
if (params.house.IsEmpty())
|
||
|
|
++withName;
|
||
|
|
else
|
||
|
|
++withNumber;
|
||
|
|
|
||
|
|
TEST(params.GetStreet().empty(), ());
|
||
|
|
TEST_EQUAL(params.GetPostcode(), "LV-5695", ());
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(withName, 3, ());
|
||
|
|
TEST_EQUAL(withNumber, 0, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/5096
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Place_State)
|
||
|
|
{
|
||
|
|
uint32_t const stateType = classif().GetTypeByPath({"place", "state"});
|
||
|
|
|
||
|
|
std::string const mwmName = "State";
|
||
|
|
std::string const worldMwmName = WORLD_FILE_NAME;
|
||
|
|
BuildFB("./data/test_data/osm/place_state.osm", mwmName, true /* makeWorld */);
|
||
|
|
|
||
|
|
size_t states = 0;
|
||
|
|
|
||
|
|
ForEachFB(worldMwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(stateType))
|
||
|
|
{
|
||
|
|
TEST(!fb.GetName().empty(), ());
|
||
|
|
++states;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(states, 1, ());
|
||
|
|
states = 0;
|
||
|
|
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(stateType))
|
||
|
|
{
|
||
|
|
TEST(!fb.GetName().empty(), ());
|
||
|
|
++states;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(states, 1, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, CycleBarrier)
|
||
|
|
{
|
||
|
|
uint32_t const barrierType = classif().GetTypeByPath({"barrier", "cycle_barrier"});
|
||
|
|
|
||
|
|
std::string const mwmName = "CycleBarrier";
|
||
|
|
BuildFB("./data/test_data/osm/cycle_barrier.osm", mwmName, false /* makeWorld */);
|
||
|
|
|
||
|
|
size_t barriersCount = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
if (fb.HasType(barrierType))
|
||
|
|
++barriersCount;
|
||
|
|
});
|
||
|
|
|
||
|
|
TEST_EQUAL(barriersCount, 1, ());
|
||
|
|
|
||
|
|
// Prepare features data source.
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
BuildRouting(mwmName, "Switzerland");
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(mwmName)));
|
||
|
|
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
using namespace routing;
|
||
|
|
|
||
|
|
RoadAccess carAcc, bicycleAcc;
|
||
|
|
ReadRoadAccessFromMwm(*(guard.GetHandle().GetValue()), VehicleType::Car, carAcc);
|
||
|
|
LOG(LINFO, ("Car access:", carAcc));
|
||
|
|
ReadRoadAccessFromMwm(*(guard.GetHandle().GetValue()), VehicleType::Bicycle, bicycleAcc);
|
||
|
|
LOG(LINFO, ("Bicycle access:", bicycleAcc));
|
||
|
|
|
||
|
|
TEST_EQUAL(carAcc.GetPointToAccess().size(), 1, ());
|
||
|
|
TEST_EQUAL(carAcc, bicycleAcc, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
// https://github.com/organicmaps/organicmaps/issues/9029
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Addr_Street_Place)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Address";
|
||
|
|
|
||
|
|
struct TestData
|
||
|
|
{
|
||
|
|
std::string m_file;
|
||
|
|
size_t m_addrCount;
|
||
|
|
bool m_checkStreet, m_checkPlace;
|
||
|
|
};
|
||
|
|
TestData const arrFiles[] = {
|
||
|
|
{"./data/test_data/osm/addr_street_place.osm", 1, true, true},
|
||
|
|
{"./data/test_data/osm/addr_street_very_far.osm", 2, true, false},
|
||
|
|
{"./data/test_data/osm/zelenograd.osm", 1, false, true},
|
||
|
|
{"./data/test_data/osm/addr_area_street.osm", 1, true, false},
|
||
|
|
};
|
||
|
|
|
||
|
|
for (auto const & data : arrFiles)
|
||
|
|
{
|
||
|
|
TestRawGenerator generator;
|
||
|
|
|
||
|
|
generator.BuildFB(data.m_file, mwmName);
|
||
|
|
generator.BuildFeatures(mwmName);
|
||
|
|
generator.BuildSearch(mwmName);
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(generator.GetMwmPath(mwmName)));
|
||
|
|
CHECK_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
auto value = guard.GetHandle().GetValue();
|
||
|
|
auto const house2street = search::LoadHouseToStreetTable(*value);
|
||
|
|
auto const house2place = search::LoadHouseToPlaceTable(*value);
|
||
|
|
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
size_t count = 0;
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
if (ftypes::IsBuildingChecker::Instance()(*ft))
|
||
|
|
{
|
||
|
|
TEST(!ft->GetHouseNumber().empty(), ());
|
||
|
|
++count;
|
||
|
|
|
||
|
|
if (data.m_checkStreet)
|
||
|
|
TEST(house2street->Get(ft->GetID().m_index), ());
|
||
|
|
if (data.m_checkPlace)
|
||
|
|
TEST(house2place->Get(ft->GetID().m_index), ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
TEST_EQUAL(count, data.m_addrCount, ());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Area_Relation_Bad)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "AreaRel";
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/area_relation_bad.osm", mwmName);
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
TEST_EQUAL(fb.GetGeomType(), feature::GeomType::Area, ());
|
||
|
|
TEST(!fb.GetOuterGeometry().empty(), ());
|
||
|
|
auto const r = fb.GetLimitRect();
|
||
|
|
TEST(!r.IsEmptyInterior(), (r));
|
||
|
|
|
||
|
|
++count;
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, 7, ());
|
||
|
|
|
||
|
|
BuildFeatures(mwmName);
|
||
|
|
|
||
|
|
FrozenDataSource dataSource;
|
||
|
|
auto const res = dataSource.RegisterMap(platform::LocalCountryFile::MakeTemporary(GetMwmPath(mwmName)));
|
||
|
|
CHECK_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||
|
|
|
||
|
|
FeaturesLoaderGuard guard(dataSource, res.first);
|
||
|
|
|
||
|
|
size_t const numFeatures = guard.GetNumFeatures();
|
||
|
|
for (size_t id = 0; id < numFeatures; ++id)
|
||
|
|
{
|
||
|
|
auto ft = guard.GetFeatureByIndex(id);
|
||
|
|
auto const r = ft->GetLimitRect(scales::GetUpperScale());
|
||
|
|
TEST(!r.IsEmptyInterior(), (r));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UNIT_CLASS_TEST(TestRawGenerator, Railway_Station)
|
||
|
|
{
|
||
|
|
std::string const mwmName = "Railway";
|
||
|
|
auto const & cl = classif();
|
||
|
|
|
||
|
|
BuildFB("./data/test_data/osm/railway_station.osm", mwmName);
|
||
|
|
|
||
|
|
size_t count = 0;
|
||
|
|
ForEachFB(mwmName, [&](feature::FeatureBuilder const & fb)
|
||
|
|
{
|
||
|
|
TEST_EQUAL(fb.GetGeomType(), feature::GeomType::Area, ());
|
||
|
|
TEST(!fb.GetOuterGeometry().empty(), ());
|
||
|
|
TEST(fb.HasType(cl.GetTypeByPath({"railway", "station", "subway", "lille"})), (fb));
|
||
|
|
|
||
|
|
++count;
|
||
|
|
});
|
||
|
|
TEST_EQUAL(count, 1, ());
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace raw_generator_tests
|