From 476b5f05b4628e787d9b551e790502ab05907bd0 Mon Sep 17 00:00:00 2001 From: Olga Khlopkova Date: Wed, 2 Oct 2019 18:37:04 +0300 Subject: [PATCH] [generator][routing] Handle mini_roundabouts. added formula --- defines.hpp | 3 + generator/CMakeLists.txt | 6 + generator/collector_interface.hpp | 2 + generator/collector_mini_roundabout.cpp | 152 +++++++++ generator/collector_mini_roundabout.hpp | 75 +++++ .../final_processor_intermediate_mwm.cpp | 35 ++- .../final_processor_intermediate_mwm.hpp | 3 + .../features_tests.cpp | 54 ++-- generator/generator_tests/CMakeLists.txt | 1 + .../generator_tests/mini_roundabout_tests.cpp | 257 ++++++++++++++++ generator/mini_roundabout_info.cpp | 31 ++ generator/mini_roundabout_info.hpp | 49 +++ generator/mini_roundabout_transformer.cpp | 288 ++++++++++++++++++ generator/mini_roundabout_transformer.hpp | 62 ++++ generator/raw_generator.cpp | 1 + generator/translator_country.cpp | 6 +- 16 files changed, 1001 insertions(+), 24 deletions(-) create mode 100644 generator/collector_mini_roundabout.cpp create mode 100644 generator/collector_mini_roundabout.hpp create mode 100644 generator/generator_tests/mini_roundabout_tests.cpp create mode 100644 generator/mini_roundabout_info.cpp create mode 100644 generator/mini_roundabout_info.hpp create mode 100644 generator/mini_roundabout_transformer.cpp create mode 100644 generator/mini_roundabout_transformer.hpp diff --git a/defines.hpp b/defines.hpp index a9bbe43c3e..2f0e82b790 100644 --- a/defines.hpp +++ b/defines.hpp @@ -95,8 +95,11 @@ #define GPS_TRACK_FILENAME "gps_track.dat" #define RESTRICTIONS_FILENAME "restrictions.csv" #define ROAD_ACCESS_FILENAME "road_access.csv" + +#define MINI_ROUNDABOUT_ROADS_EXTENSION ".mini_roundabouts_roads_ids" #define METALINES_FILENAME "metalines.bin" #define CAMERAS_TO_WAYS_FILENAME "cameras_to_ways.bin" +#define MINI_ROUNDABOUTS_FILENAME "mini_roundabouts.bin" #define MAXSPEEDS_FILENAME "maxspeeds.csv" #define CITIES_AREAS_TMP_FILENAME "cities_areas" DATA_FILE_EXTENSION_TMP #define CROSS_MWM_OSM_WAYS_DIR "cross_mwm_osm_ways" diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 8634a0f859..23ce84d050 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -47,6 +47,8 @@ set( collector_collection.cpp collector_collection.hpp collector_interface.hpp + collector_mini_roundabout.cpp + collector_mini_roundabout.hpp collector_tag.cpp collector_tag.hpp complex_loader.cpp @@ -114,6 +116,10 @@ set( maxspeeds_parser.hpp metalines_builder.cpp metalines_builder.hpp + mini_roundabout_info.cpp + mini_roundabout_info.hpp + mini_roundabout_transformer.cpp + mini_roundabout_transformer.hpp node_mixer.cpp node_mixer.hpp opentable_dataset.cpp diff --git a/generator/collector_interface.hpp b/generator/collector_interface.hpp index 1030e4988b..00dcdda493 100644 --- a/generator/collector_interface.hpp +++ b/generator/collector_interface.hpp @@ -38,6 +38,7 @@ class CollectorAddresses; class CollectorCollection; class CollectorTag; class MaxspeedsCollector; +class MiniRoundaboutCollector; class CityAreaCollector; class CrossMwmOsmWaysCollector; namespace cache @@ -70,6 +71,7 @@ public: virtual void MergeInto(CityAreaCollector &) const { FailIfMethodUnsupported(); } virtual void MergeInto(routing::CameraCollector &) const { FailIfMethodUnsupported(); } + virtual void MergeInto(MiniRoundaboutCollector &) const { FailIfMethodUnsupported(); } virtual void MergeInto(routing::RestrictionWriter &) const { FailIfMethodUnsupported(); } virtual void MergeInto(routing::RoadAccessWriter &) const { FailIfMethodUnsupported(); } virtual void MergeInto(CollectorAddresses &) const { FailIfMethodUnsupported(); } diff --git a/generator/collector_mini_roundabout.cpp b/generator/collector_mini_roundabout.cpp new file mode 100644 index 0000000000..842f9dd418 --- /dev/null +++ b/generator/collector_mini_roundabout.cpp @@ -0,0 +1,152 @@ +#include "generator/collector_mini_roundabout.hpp" + +#include "generator/feature_builder.hpp" +#include "generator/intermediate_data.hpp" + +#include "routing/routing_helpers.hpp" + +#include "platform/platform.hpp" + +#include "coding/internal/file_data.hpp" +#include "coding/reader_writer_ops.hpp" +#include "coding/write_to_sink.hpp" + +#include "base/assert.hpp" + +#include +#include + +using namespace feature; + +namespace generator +{ +MiniRoundaboutProcessor::MiniRoundaboutProcessor(std::string const & filename) + : m_waysFilename(filename + MINI_ROUNDABOUT_ROADS_EXTENSION) + , m_waysWriter(std::make_unique(m_waysFilename)) +{ +} + +MiniRoundaboutProcessor::~MiniRoundaboutProcessor() +{ + CHECK(Platform::RemoveFileIfExists(m_waysFilename), ()); +} + +void MiniRoundaboutProcessor::ForEachMiniRoundabout(Fn && toDo) const +{ + for (auto const & p : m_miniRoundabouts) + { + if (m_miniRoundaboutsExceptions.find(p.first) == m_miniRoundaboutsExceptions.end()) + toDo(p.second); + } +} + +void MiniRoundaboutProcessor::ProcessWay(OsmElement const & element) +{ + WriteToSink(*m_waysWriter, element.m_id); + rw::WriteVectorOfPOD(*m_waysWriter, element.m_nodes); +} + +void MiniRoundaboutProcessor::FillMiniRoundaboutsInWays() +{ + FileReader reader(m_waysFilename); + ReaderSource src(reader); + while (src.Size() > 0) + { + uint64_t const wayId = ReadPrimitiveFromSource(src); + std::vector nodes; + rw::ReadVectorOfPOD(src, nodes); + for (auto const & node : nodes) + { + auto const itMiniRoundabout = m_miniRoundabouts.find(node); + if (itMiniRoundabout != m_miniRoundabouts.end()) + itMiniRoundabout->second.m_ways.push_back(wayId); + } + } +} + +void MiniRoundaboutProcessor::ProcessNode(OsmElement const & element) +{ + m_miniRoundabouts.emplace(element.m_id, MiniRoundaboutInfo(element)); +} + +void MiniRoundaboutProcessor::ProcessRestriction(uint64_t osmId) +{ + m_miniRoundaboutsExceptions.insert(osmId); +} + +void MiniRoundaboutProcessor::Finish() { m_waysWriter.reset(); } + +void MiniRoundaboutProcessor::Merge(MiniRoundaboutProcessor const & miniRoundaboutProcessor) +{ + auto const & otherMiniRoundabouts = miniRoundaboutProcessor.m_miniRoundabouts; + m_miniRoundabouts.insert(otherMiniRoundabouts.begin(), otherMiniRoundabouts.end()); + + auto const & otherMiniRoundaboutsExceptions = miniRoundaboutProcessor.m_miniRoundaboutsExceptions; + m_miniRoundaboutsExceptions.insert(otherMiniRoundaboutsExceptions.begin(), + otherMiniRoundaboutsExceptions.end()); + + base::AppendFileToFile(miniRoundaboutProcessor.m_waysFilename, m_waysFilename); +} + +// MiniRoundaboutCollector ------------------------------------------------------------------------- + +MiniRoundaboutCollector::MiniRoundaboutCollector(std::string const & filename) + : generator::CollectorInterface(filename), m_processor(GetTmpFilename()) +{ +} + +std::shared_ptr MiniRoundaboutCollector::Clone( + std::shared_ptr const &) const +{ + return std::make_shared(GetFilename()); +} + +void MiniRoundaboutCollector::Collect(OsmElement const & element) +{ + if (element.IsNode() && element.HasTag("highway", "mini_roundabout")) + { + m_processor.ProcessNode(element); + return; + } + + // Skip mini_roundabouts with role="via" in restrictions + if (element.IsRelation()) + { + for (auto const & member : element.m_members) + { + if (member.m_type == OsmElement::EntityType::Node && member.m_role == "via") + { + m_processor.ProcessRestriction(member.m_ref); + return; + } + } + } +} + +void MiniRoundaboutCollector::CollectFeature(FeatureBuilder const & feature, + OsmElement const & element) +{ + if (feature.IsLine() && routing::IsCarRoad(feature.GetTypes())) + m_processor.ProcessWay(element); +} + +void MiniRoundaboutCollector::Finish() { m_processor.Finish(); } + +void MiniRoundaboutCollector::Save() +{ + m_processor.FillMiniRoundaboutsInWays(); + FileWriter writer(GetFilename()); + m_processor.ForEachMiniRoundabout( + [&](auto const & miniRoundabout) { WriteMiniRoundabout(writer, miniRoundabout); }); +} + +void MiniRoundaboutCollector::Merge(generator::CollectorInterface const & collector) +{ + collector.MergeInto(*this); +} + +void MiniRoundaboutCollector::MergeInto(MiniRoundaboutCollector & collector) const +{ + collector.m_processor.Merge(m_processor); +} +} // namespace generator diff --git a/generator/collector_mini_roundabout.hpp b/generator/collector_mini_roundabout.hpp new file mode 100644 index 0000000000..912cb0b2f8 --- /dev/null +++ b/generator/collector_mini_roundabout.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "generator/collector_interface.hpp" +#include "generator/mini_roundabout_info.hpp" +#include "generator/osm_element.hpp" + +#include "coding/file_writer.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace feature +{ +class FeatureBuilder; +} // namespace feature + +namespace generator +{ +namespace cache +{ +class IntermediateDataReader; +} // namespace cache + +class MiniRoundaboutProcessor +{ +public: + using Fn = std::function; + + explicit MiniRoundaboutProcessor(std::string const & filename); + ~MiniRoundaboutProcessor(); + + void ForEachMiniRoundabout(Fn && toDo) const; + void ProcessNode(OsmElement const & element); + void ProcessWay(OsmElement const & element); + void ProcessRestriction(uint64_t osmId); + + void FillMiniRoundaboutsInWays(); + + void Finish(); + void Merge(MiniRoundaboutProcessor const & MiniRoundaboutProcessor); + +private: + std::string m_waysFilename; + std::unique_ptr m_waysWriter; + std::unordered_map m_miniRoundabouts; + std::set m_miniRoundaboutsExceptions; +}; + +class MiniRoundaboutCollector : public generator::CollectorInterface +{ +public: + explicit MiniRoundaboutCollector(std::string const & filename); + + // CollectorInterface overrides: + std::shared_ptr Clone( + std::shared_ptr const & = {}) const override; + + void Collect(OsmElement const & element) override; + void CollectFeature(feature::FeatureBuilder const & feature, OsmElement const & element) override; + void Finish() override; + void Save() override; + + void Merge(generator::CollectorInterface const & collector) override; + void MergeInto(MiniRoundaboutCollector & collector) const override; + +private: + MiniRoundaboutProcessor m_processor; +}; +} // namespace generator diff --git a/generator/final_processor_intermediate_mwm.cpp b/generator/final_processor_intermediate_mwm.cpp index 2d080bca07..a0dcaf1c54 100644 --- a/generator/final_processor_intermediate_mwm.cpp +++ b/generator/final_processor_intermediate_mwm.cpp @@ -4,6 +4,7 @@ #include "generator/booking_dataset.hpp" #include "generator/feature_builder.hpp" #include "generator/feature_merger.hpp" +#include "generator/mini_roundabout_transformer.hpp" #include "generator/node_mixer.hpp" #include "generator/osm2type.hpp" #include "generator/place_processor.hpp" @@ -30,7 +31,6 @@ #include #include #include -#include #include #include "defines.hpp" @@ -306,6 +306,11 @@ void CountryFinalProcessor::SetFakeNodes(std::string const & filename) m_fakeNodesFilename = filename; } +void CountryFinalProcessor::SetMiniRoundabouts(std::string const & filename) +{ + m_miniRoundaboutsFilename = filename; +} + void CountryFinalProcessor::Process() { if (!m_hotelsFilename.empty()) @@ -314,6 +319,8 @@ void CountryFinalProcessor::Process() ProcessCities(); if (!m_coastlineGeomFilename.empty()) ProcessCoastline(); + if (!m_miniRoundaboutsFilename.empty()) + ProcessRoundabouts(); if (!m_fakeNodesFilename.empty()) AddFakeNodes(); @@ -357,6 +364,32 @@ void CountryFinalProcessor::ProcessBooking() AppendToCountries(fbs, affiliations, m_temporaryMwmPath, m_threadsCount); } +void CountryFinalProcessor::ProcessRoundabouts() +{ + MiniRoundaboutTransformer helper(m_miniRoundaboutsFilename); + + auto const affiliation = CountriesFilesIndexAffiliation(m_borderPath, m_haveBordersForWholeWorld); + { + ThreadPool pool(m_threadsCount); + ForEachCountry(m_temporaryMwmPath, [&](auto const & filename) { + pool.SubmitWork([&, filename]() { + if (!FilenameIsCountry(filename, affiliation)) + return; + + auto const fullPath = base::JoinPath(m_temporaryMwmPath, filename); + auto fbs = ReadAllDatRawFormat(fullPath); + FeatureBuilderWriter writer(fullPath); + + // Adds new way features generated from mini-roundabout nodes with those nodes ids. + // Transforms points on roads to connect them with these new roundabout junctions. + helper.ProcessRoundabouts(affiliation, fbs); + for (auto const & fb : fbs) + writer.Write(fb); + }); + }); + } +} + void CountryFinalProcessor::ProcessCities() { auto const affiliation = CountriesFilesIndexAffiliation(m_borderPath, m_haveBordersForWholeWorld); diff --git a/generator/final_processor_intermediate_mwm.hpp b/generator/final_processor_intermediate_mwm.hpp index cd7a6467fd..f286edb0b9 100644 --- a/generator/final_processor_intermediate_mwm.hpp +++ b/generator/final_processor_intermediate_mwm.hpp @@ -54,6 +54,7 @@ public: void SetCoastlines(std::string const & coastlineGeomFilename, std::string const & worldCoastsFilename); void SetFakeNodes(std::string const & filename); + void SetMiniRoundabouts(std::string const & filename); void DumpCitiesBoundaries(std::string const & filename); @@ -64,6 +65,7 @@ private: void ProcessBooking(); void ProcessCities(); void ProcessCoastline(); + void ProcessRoundabouts(); void AddFakeNodes(); void Finish(); @@ -76,6 +78,7 @@ private: std::string m_worldCoastsFilename; std::string m_citiesFilename; std::string m_fakeNodesFilename; + std::string m_miniRoundaboutsFilename; bool m_haveBordersForWholeWorld; size_t m_threadsCount; }; diff --git a/generator/generator_integration_tests/features_tests.cpp b/generator/generator_integration_tests/features_tests.cpp index 94110eb19c..de322f8249 100644 --- a/generator/generator_integration_tests/features_tests.cpp +++ b/generator/generator_integration_tests/features_tests.cpp @@ -93,6 +93,7 @@ public: TEST(rawGenerator.Execute(), ()); TEST(Platform::IsFileExistsByFullPath(world), ()); + TestCountry(world, 945 /* fbsCnt */, 364406 /* geometryPointsCnt */, 334 /* pointCnt */, 598 /* lineCnt */, 13 /* areaCnt */, 428 /* poiCnt */, 172 /* cityTownOrVillageCnt */, 0 /* bookingHotelsCnt */); @@ -117,17 +118,20 @@ public: rawGenerator.GenerateCountries(); TEST(rawGenerator.Execute(), ()); - TestCountry(northAuckland, 1812060 /* fbsCnt */, 12195237 /* geometryPointsCnt */, - 1007477 /* pointCnt */, 205469 /* lineCnt */, 599114 /* areaCnt */, - 212188 /* poiCnt */, 521 /* cityTownOrVillageCnt */, 3557 /* bookingHotelsCnt */); - TestCountry(northWellington, 797849 /* fbsCnt */, 7772223 /* geometryPointsCnt */, - 460516 /* pointCnt */, 87058 /* lineCnt */, 250275 /* areaCnt */, - 95705 /* poiCnt */, 297 /* cityTownOrVillageCnt */, 1062 /* bookingHotelsCnt */); - TestCountry(southCanterbury, 637239 /* fbsCnt */, 6984529 /* geometryPointsCnt */, - 397939 /* pointCnt */, 81712 /* lineCnt */, 157588 /* areaCnt */, - 89491 /* poiCnt */, 331 /* cityTownOrVillageCnt */, 2085 /* bookingHotelsCnt */); - TestCountry(southSouthland, 340629 /* fbsCnt */, 5343002 /* geometryPointsCnt */, 185979 /* pointCnt */, - 40124 /* lineCnt */, 114526 /* areaCnt */, 40630 /* poiCnt */, + TestCountry(northAuckland, 1812394 /* fbsCnt */, 12200141 /* geometryPointsCnt */, + 1007483 /* pointCnt */, 205797 /* lineCnt */, 599114 /* areaCnt */, + 212516 /* poiCnt */, 521 /* cityTownOrVillageCnt */, 3557 /* bookingHotelsCnt */); + + TestCountry(northWellington, 798177 /* fbsCnt */, 7776932 /* geometryPointsCnt */, + 460516 /* pointCnt */, 87386 /* lineCnt */, 250275 /* areaCnt */, + 96033 /* poiCnt */, 297 /* cityTownOrVillageCnt */, 1062 /* bookingHotelsCnt */); + + TestCountry(southCanterbury, 637567 /* fbsCnt */, 6988959 /* geometryPointsCnt */, + 397939 /* pointCnt */, 82040 /* lineCnt */, 157588 /* areaCnt */, + 89819 /* poiCnt */, 331 /* cityTownOrVillageCnt */, 2085 /* bookingHotelsCnt */); + + TestCountry(southSouthland, 340958 /* fbsCnt */, 5347345 /* geometryPointsCnt */, 185980 /* pointCnt */, + 40452 /* lineCnt */, 114526 /* areaCnt */, 40958 /* poiCnt */, 297 /* cityTownOrVillageCnt */, 1621 /* bookingHotelsCnt */); } @@ -153,24 +157,30 @@ public: rawGenerator.GenerateWorld(true /* needMixTags */); TEST(rawGenerator.Execute(), ()); - TestCountry(northAuckland, 1812060 /* fbsCnt */, 12195237 /* geometryPointsCnt */, - 1007477 /* pointCnt */, 205469 /* lineCnt */, 599114 /* areaCnt */, - 212188 /* poiCnt */, 521 /* cityTownOrVillageCnt */, 3557 /* bookingHotelsCnt */); - TestCountry(northWellington, 797849 /* fbsCnt */, 7772223 /* geometryPointsCnt */, - 460516 /* pointCnt */, 87058 /* lineCnt */, 250275 /* areaCnt */, - 95705 /* poiCnt */, 297 /* cityTownOrVillageCnt */, 1062 /* bookingHotelsCnt */); - TestCountry(southCanterbury, 637239 /* fbsCnt */, 6984529 /* geometryPointsCnt */, - 397939 /* pointCnt */, 81712 /* lineCnt */, 157588 /* areaCnt */, - 89491 /* poiCnt */, 331 /* cityTownOrVillageCnt */, 2085 /* bookingHotelsCnt */); + TestCountry(northAuckland, 1812394 /* fbsCnt */, 12200141 /* geometryPointsCnt */, + 1007483 /* pointCnt */, 205797 /* lineCnt */, 599114 /* areaCnt */, + 212516 /* poiCnt */, 521 /* cityTownOrVillageCnt */, 3557 /* bookingHotelsCnt */); + + TestCountry(northWellington, 798177 /* fbsCnt */, 7776932 /* geometryPointsCnt */, + 460516 /* pointCnt */, 87386 /* lineCnt */, 250275 /* areaCnt */, + 96033 /* poiCnt */, 297 /* cityTownOrVillageCnt */, 1062 /* bookingHotelsCnt */); + + TestCountry(southCanterbury, 637567 /* fbsCnt */, 6988959 /* geometryPointsCnt */, + 397939 /* pointCnt */, 82040 /* lineCnt */, 157588 /* areaCnt */, + 89819 /* poiCnt */, 331 /* cityTownOrVillageCnt */, 2085 /* bookingHotelsCnt */); + size_t partner1CntReal = 0; - TestCountry(southSouthland, 340631 /* fbsCnt */, 5343004 /* geometryPointsCnt */, 185981 /* pointCnt */, - 40124 /* lineCnt */, 114526 /* areaCnt */, 40630 /* poiCnt */, + + TestCountry(southSouthland, 340960 /* fbsCnt */, 5347347 /* geometryPointsCnt */, 185982 /* pointCnt */, + 40452 /* lineCnt */, 114526 /* areaCnt */, 40958 /* poiCnt */, 297 /* cityTownOrVillageCnt */, 1621 /* bookingHotelsCnt */, [&](auto const & fb) { static auto const partner1 = classif().GetTypeByPath({"sponsored", "partner1"}); if (fb.HasType(partner1)) ++partner1CntReal; }); + TEST_EQUAL(partner1CntReal, 4, ()); + TestCountry(world, 945 /* fbsCnt */, 364406 /* geometryPointsCnt */, 334 /* pointCnt */, 598 /* lineCnt */, 13 /* areaCnt */, 428 /* poiCnt */, 172 /* cityTownOrVillageCnt */, 0 /* bookingHotelsCnt */); diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt index 62229f6dae..bf4f29dead 100644 --- a/generator/generator_tests/CMakeLists.txt +++ b/generator/generator_tests/CMakeLists.txt @@ -28,6 +28,7 @@ set( merge_collectors_tests.cpp metadata_parser_test.cpp metalines_tests.cpp + mini_roundabout_tests.cpp node_mixer_test.cpp osm2meta_test.cpp osm_o5m_source_test.cpp diff --git a/generator/generator_tests/mini_roundabout_tests.cpp b/generator/generator_tests/mini_roundabout_tests.cpp new file mode 100644 index 0000000000..dd43851ad6 --- /dev/null +++ b/generator/generator_tests/mini_roundabout_tests.cpp @@ -0,0 +1,257 @@ +#include "testing/testing.hpp" + +#include "generator/mini_roundabout_transformer.hpp" +#include "generator/osm_element.hpp" + +#include "coding/point_coding.hpp" + +#include "geometry/latlon.hpp" +#include "geometry/mercator.hpp" +#include "geometry/point2d.hpp" + +#include "base/math.hpp" + +#include +#include +#include + +using namespace generator; + +namespace +{ +OsmElement MiniRoundabout(uint64_t id, double lat, double lon) +{ + OsmElement miniRoundabout; + miniRoundabout.m_id = id; + miniRoundabout.m_lat = lat; + miniRoundabout.m_lon = lon; + miniRoundabout.m_type = OsmElement::EntityType::Node; + miniRoundabout.AddTag("highway", "mini_roundabout"); + return miniRoundabout; +} + +OsmElement Road(uint64_t id, std::vector && nodes) +{ + OsmElement road; + road.m_id = id; + road.m_type = OsmElement::EntityType::Way; + road.AddTag("highway", "trunk"); + road.m_nodes = nodes; + return road; +} + +OsmElement RoadNode(uint64_t id, double lat, double lon) +{ + OsmElement node; + node.m_id = id; + node.m_lat = lat; + node.m_lon = lon; + return node; +} + +} // namespace + +void TestRunCmpPoints(std::vector const & pointsFact, + std::vector const & pointsPlan, double r) +{ + TEST_EQUAL(pointsFact.size(), pointsPlan.size(), ()); + TEST_GREATER(pointsFact.size(), 2, ()); + for (size_t i = 0; i < pointsFact.size(); ++i) + TEST(AlmostEqualAbs(pointsFact[i], pointsPlan[i], kMwmPointAccuracy), ()); +} + +void TestRunCmpNumbers(double val1, double val2) +{ + TEST(base::AlmostEqualAbs(val1, val2, kMwmPointAccuracy), ()); +} + +UNIT_TEST(PointToPolygon_GeneralProperties) +{ + m2::PointD constexpr center(0.0, 0.0); + double constexpr r = 10.0; + + std::array const anglesDeg{0.0, -30.0, 30.0, 45.0}; + + for (double const & angleDeg : anglesDeg) + { + for (size_t verticesCount = 3; verticesCount < 30; ++verticesCount) + { + std::vector const circlePlain = + PointToPolygon(center, r, verticesCount, angleDeg); + double const vertexLenght = DistanceOnPlain(circlePlain.front(), circlePlain.back()); + + for (size_t i = 0; i < circlePlain.size() - 1; ++i) + { + double const rCurrent = DistanceOnPlain(circlePlain[i], center); + TEST(base::AlmostEqualAbs(rCurrent, r, kMwmPointAccuracy), ()); + + double const vertexLengthCurrent = DistanceOnPlain(circlePlain[i], circlePlain[i + 1]); + TEST(base::AlmostEqualAbs(vertexLengthCurrent, vertexLenght, kMwmPointAccuracy), ()); + } + } + } +} + +UNIT_TEST(TrimSegment_Vertical) +{ + m2::PointD const a(2.0, -1.0); + m2::PointD const b(2.0, 3.0); + double const dist = 1.0; + m2::PointD const point = TrimSegment(a, b, dist); + m2::PointD const pointPlan(2.0, 2.0); + TEST(AlmostEqualAbs(point, pointPlan, kMwmPointAccuracy), ()); +} + +UNIT_TEST(TrimSegment_VerticalNegative) +{ + m2::PointD const a(-3.0, -5.0); + m2::PointD const b(-3.0, 6.0); + double const dist = 4.0; + m2::PointD const point = TrimSegment(a, b, dist); + m2::PointD const pointPlan(-3.0, 2.0); + TEST(AlmostEqualAbs(point, pointPlan, kMwmPointAccuracy), ()); +} + +UNIT_TEST(TrimSegment_ExceptionalCase) +{ + m2::PointD const a(1.0, 2.0); + m2::PointD const b(2.0, 3.0); + double const dist = 10.0; + m2::PointD const point = TrimSegment(a, b, dist); + TEST(AlmostEqualAbs(point, a, kMwmPointAccuracy), ()); +} + +UNIT_TEST(PointToCircle_ZeroMeridian) +{ + ms::LatLon const pointOnZeroMeridian(51.0, 0.0); + m2::PointD const center = mercator::FromLatLon(pointOnZeroMeridian); + double const r = mercator::MetersToMercator(100.0); + auto const circlePlain = PointToPolygon(center, r, 6, 30.0); + + std::vector const circlePlainExpected{{0.00077, 59.48054}, {0.00000, 59.48100}, + {-0.00077, 59.48054}, {-0.00077, 59.47964}, + {0.00000, 59.47920}, {0.00077, 59.47964}}; + + TestRunCmpPoints(circlePlain, circlePlainExpected, r); +} + +UNIT_TEST(PointToCircle_LargeRadius) +{ + ms::LatLon const pointOnZeroMeridian(74.0, 0.1); + m2::PointD const center = mercator::FromLatLon(pointOnZeroMeridian); + double const r = mercator::MetersToMercator(500000.0); + auto const circlePlain = PointToPolygon(center, r, 6, 30.0); + + std::vector const circlePlainExpected{{3.99631, 114.67859}, {0.10000, 116.92812}, + {-3.79631, 114.67859}, {-3.79631, 110.17951}, + {0.10000, 107.92998}, {3.99631, 110.17951}}; + + TestRunCmpPoints(circlePlain, circlePlainExpected, r); +} + +UNIT_TEST(PointToCircle_Equator) +{ + ms::LatLon const pointOnZeroMeridian(0.0, 31.8); + m2::PointD const center = mercator::FromLatLon(pointOnZeroMeridian); + double const r = mercator::MetersToMercator(15.0); + auto const circlePlain = PointToPolygon(center, r, 6, 30.0); + + std::vector const circlePlainExpected{ + {31.80011, 0.00006}, {31.80000, 0.00013}, {31.79988, 0.00006}, + {31.79988, -0.00006}, {31.80000, -0.00013}, {31.80011, -0.00006}, + }; + + TestRunCmpPoints(circlePlain, circlePlainExpected, r); +} + +UNIT_TEST(TrimSegment_Radius3) +{ + m2::PointD const pointOnRoad(10.0, 10.0); + m2::PointD const pointRoundabout(15.0, 17.0); + double const r = 3.0; + + m2::PointD const nextPointOnRoad = TrimSegment(pointOnRoad, pointRoundabout, r); + double const dist = DistanceOnPlain(nextPointOnRoad, pointRoundabout); + TestRunCmpNumbers(dist, r); +} + +// https://www.openstreetmap.org/node/4999694780 +// Simplified example: only one road "Søren R Thornæs veg". +// This road is extended further to Way=511028249 +UNIT_TEST(Manage_MiniRoundabout_1Road) +{ + auto const node1 = RoadNode(1, 64.46649, 11.50000); + auto const node2 = MiniRoundabout(2, 64.46631, 11.50012); + auto const node3 = RoadNode(3, 64.46620, 11.50016); + auto const road = Road(100, {node1.m_id, node2.m_id, node3.m_id}); + + m2::PointD const center = mercator::FromLatLon({node2.m_lat, node2.m_lon}); + m2::PointD const nearest = mercator::FromLatLon({node1.m_lat, node1.m_lon}); + + double const r = mercator::MetersToMercator(2.5); + auto circlePlain = PointToPolygon(center, r, 6, 30.0); + + // Check for "diameters" equality. + double const diameter = r * 2.; + TEST(base::AlmostEqualAbs(DistanceOnPlain(circlePlain[0], circlePlain[3]), diameter, + kMwmPointAccuracy), + ()); + TEST(base::AlmostEqualAbs(DistanceOnPlain(circlePlain[1], circlePlain[4]), diameter, + kMwmPointAccuracy), + ()); + TEST(base::AlmostEqualAbs(DistanceOnPlain(circlePlain[2], circlePlain[5]), diameter, + kMwmPointAccuracy), + ()); + + double const edgeLen = DistanceOnPlain(circlePlain[0], circlePlain[1]); + for (size_t i = 1; i < circlePlain.size(); ++i) + TEST(base::AlmostEqualAbs(DistanceOnPlain(circlePlain[i - 1], circlePlain[i]), edgeLen, + kMwmPointAccuracy), + ()); + + m2::PointD newPointOnRoad = TrimSegment(nearest, center, r); + AddPointToCircle(circlePlain, newPointOnRoad); + + std::vector const circlePlainExpected{ + {11.50013, 85.06309}, {11.50012, 85.06310}, {11.50010, 85.06309}, + {11.50010, 85.06306}, {11.50012, 85.06305}, {11.50013, 85.06306}}; + + TestRunCmpPoints(circlePlain, circlePlainExpected, r); +} + +// https://www.openstreetmap.org/node/1617329231 +// Mini-roundabout as a part of 4 roads +// Hemel Hempstead magic roundabout +UNIT_TEST(Manage_MiniRoundabout_4Roads) +{ + auto const miniRoundabout = MiniRoundabout(1, 51.7460187, -0.4738389); + auto const stationRoadNode = RoadNode(2, 51.7459314, -0.4739951); + auto const plaughRoundaboutNode = RoadNode(3, 51.7461249, -0.4738877); + auto const stationRoadLeftNode = RoadNode(4, 51.7460327, -0.4739356); // End of road + auto const plaughRoundaboutRightNode = RoadNode(5, 51.7458321, -0.4732662); + + m2::PointD const center = + mercator::FromLatLon({miniRoundabout.m_lat, miniRoundabout.m_lon}); + + double const r = mercator::MetersToMercator(2.5); + + auto circlePlain = PointToPolygon(center, r, 6, 30.0); + auto circlePlainBeforeAdd = circlePlain; + AddPointToCircle(circlePlain, TrimSegment(mercator::FromLatLon(stationRoadNode.m_lat, + stationRoadNode.m_lon), + center, r)); + AddPointToCircle(circlePlain, TrimSegment(mercator::FromLatLon(plaughRoundaboutNode.m_lat, + plaughRoundaboutNode.m_lon), + center, r)); + AddPointToCircle(circlePlain, TrimSegment(mercator::FromLatLon(stationRoadLeftNode.m_lat, + stationRoadLeftNode.m_lon), + center, r)); + AddPointToCircle(circlePlain, + TrimSegment(mercator::FromLatLon(plaughRoundaboutRightNode.m_lat, + plaughRoundaboutRightNode.m_lon), + center, r)); + + // No road points are added to the circle, becouse all of them are too close to the + // original circle points. + TestRunCmpPoints(circlePlain, circlePlainBeforeAdd, r); +} diff --git a/generator/mini_roundabout_info.cpp b/generator/mini_roundabout_info.cpp new file mode 100644 index 0000000000..9158df00f9 --- /dev/null +++ b/generator/mini_roundabout_info.cpp @@ -0,0 +1,31 @@ +#include "generator/mini_roundabout_info.hpp" + +#include "coding/file_reader.hpp" + +#include + +namespace generator +{ +MiniRoundaboutInfo::MiniRoundaboutInfo(OsmElement const & element) + : m_id(element.m_id), m_coord(element.m_lat, element.m_lon) +{ +} + +MiniRoundaboutInfo::MiniRoundaboutInfo(uint64_t id, ms::LatLon const & coord, + std::vector && ways) + : m_id(id), m_coord(coord), m_ways(std::move(ways)) +{ +} + +std::vector ReadMiniRoundabouts(std::string const & filePath) +{ + FileReader reader(filePath); + ReaderSource src(reader); + std::vector res; + + while (src.Size() > 0) + res.push_back(ReadMiniRoundabout(src)); + + return res; +} +} // namespace generator diff --git a/generator/mini_roundabout_info.hpp b/generator/mini_roundabout_info.hpp new file mode 100644 index 0000000000..d19a728e35 --- /dev/null +++ b/generator/mini_roundabout_info.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "generator/osm_element.hpp" + +#include "coding/file_writer.hpp" +#include "coding/read_write_utils.hpp" +#include "coding/reader.hpp" + +#include "geometry/latlon.hpp" + +#include + +namespace generator +{ +struct MiniRoundaboutInfo +{ + MiniRoundaboutInfo() = default; + explicit MiniRoundaboutInfo(OsmElement const & element); + MiniRoundaboutInfo(uint64_t id, ms::LatLon const & coord, std::vector && ways); + + uint64_t m_id = 0; + ms::LatLon m_coord; + std::vector m_ways; +}; + +std::vector ReadMiniRoundabouts(std::string const & filePath); + +template +MiniRoundaboutInfo ReadMiniRoundabout(Src & src) +{ + MiniRoundaboutInfo rb; + rb.m_id = ReadPrimitiveFromSource(src); + rb.m_coord.m_lat = ReadPrimitiveFromSource(src); + rb.m_coord.m_lon = ReadPrimitiveFromSource(src); + rw::ReadVectorOfPOD(src, rb.m_ways); + return rb; +} + +template +void WriteMiniRoundabout(Dst & dst, MiniRoundaboutInfo const & rb) +{ + if (rb.m_ways.empty()) + return; + dst.Write(&rb.m_id, sizeof(rb.m_id)); + dst.Write(&rb.m_coord.m_lat, sizeof(rb.m_coord.m_lat)); + dst.Write(&rb.m_coord.m_lon, sizeof(rb.m_coord.m_lon)); + rw::WriteVectorOfPOD(dst, rb.m_ways); +} +} // namespace generator diff --git a/generator/mini_roundabout_transformer.cpp b/generator/mini_roundabout_transformer.cpp new file mode 100644 index 0000000000..8711e28c66 --- /dev/null +++ b/generator/mini_roundabout_transformer.cpp @@ -0,0 +1,288 @@ +#include "generator/mini_roundabout_transformer.hpp" + +#include "routing/routing_helpers.hpp" + +#include "indexer/classificator.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" + +#include +#include +#include +#include +#include + +namespace +{ +double constexpr kDefaultRadiusMeters = 5.0; +} + +namespace generator +{ +MiniRoundaboutTransformer::MiniRoundaboutTransformer(std::string const & intermediateFilePath) + : m_radiusMercator(mercator::MetersToMercator(kDefaultRadiusMeters)) +{ + ReadData(intermediateFilePath); +} + +MiniRoundaboutTransformer::MiniRoundaboutTransformer(std::string const & intermediateFilePath, + double radiusMeters) + : m_radiusMercator(mercator::MetersToMercator(radiusMeters)) +{ + ReadData(intermediateFilePath); +} + +void MiniRoundaboutTransformer::ReadData(std::string const & intermediateFilePath) +{ + m_roundabouts = ReadMiniRoundabouts(intermediateFilePath); + LOG(LINFO, ("Loaded", m_roundabouts.size(), "mini_roundabouts from file", intermediateFilePath)); +} + +void MiniRoundaboutTransformer::UpdateRoadType(FeatureParams::Types const & foundTypes, + uint32_t & roadType) +{ + // Highways are sorted from the most to least important. + static std::array const kHighwayTypes = { + classif().GetTypeByPath({"highway", "motorway"}), + classif().GetTypeByPath({"highway", "motorway_link"}), + classif().GetTypeByPath({"highway", "trunk"}), + classif().GetTypeByPath({"highway", "trunk_link"}), + classif().GetTypeByPath({"highway", "primary"}), + classif().GetTypeByPath({"highway", "primary_link"}), + classif().GetTypeByPath({"highway", "secondary"}), + classif().GetTypeByPath({"highway", "secondary_link"}), + classif().GetTypeByPath({"highway", "tertiary"}), + classif().GetTypeByPath({"highway", "tertiary_link"}), + classif().GetTypeByPath({"highway", "unclassified"}), + classif().GetTypeByPath({"highway", "residential"}), + classif().GetTypeByPath({"highway", "living_street"}), + classif().GetTypeByPath({"highway", "service"})}; + + for (uint32_t t : foundTypes) + { + auto const it = std::find(kHighwayTypes.begin(), kHighwayTypes.end(), t); + if (it == kHighwayTypes.end()) + continue; + + auto const itPrev = std::find(kHighwayTypes.begin(), kHighwayTypes.end(), roadType); + if (itPrev == kHighwayTypes.end() || (itPrev > it && itPrev != kHighwayTypes.end())) + roadType = *it; + + return; + } +} + +bool MiniRoundaboutTransformer::AddRoundaboutToRoad(m2::PointD const & center, + std::vector & roundabout, + feature::FeatureBuilder::PointSeq & road) +{ + auto itPointOnRoad = + std::find_if(road.begin(), road.end(), [¢er](m2::PointD const & pointOnRoad) { + return base::AlmostEqualAbs(pointOnRoad, center, kMwmPointAccuracy); + }); + + CHECK(itPointOnRoad != road.end(), + ("Could not find mini_roundabout on the road ", mercator::ToLatLon(center))); + + auto itPointUpd = itPointOnRoad; + if (itPointOnRoad == road.begin()) + { + ++itPointOnRoad; + } + else if (itPointOnRoad + 1 == road.end()) + { + --itPointOnRoad; + } + else // Roundabout is on the middle of the road so we need to insert 2 points + { + m2::PointD const leftPointOnRoad = TrimSegment(*(itPointOnRoad - 1), center, m_radiusMercator); + if (AlmostEqualAbs(leftPointOnRoad, *(itPointOnRoad - 1), kMwmPointAccuracy)) + return false; + + AddPointToCircle(roundabout, leftPointOnRoad); + itPointOnRoad = road.insert(itPointOnRoad, leftPointOnRoad); + itPointUpd = itPointOnRoad + 1; + itPointOnRoad += 2; + } + + m2::PointD const nextPointOnRoad = TrimSegment(*itPointOnRoad, center, m_radiusMercator); + if (AlmostEqualAbs(nextPointOnRoad, *itPointOnRoad, kMwmPointAccuracy)) + return false; + + AddPointToCircle(roundabout, nextPointOnRoad); + *itPointUpd = nextPointOnRoad; + return true; +} + +std::unordered_map GetFeaturesHashMap( + std::vector const & fbs) +{ + std::unordered_map fbsIdToIndex; + fbsIdToIndex.reserve(fbs.size()); + for (size_t i = 0; i < fbs.size(); ++i) + { + if (routing::IsRoad(fbs[i].GetTypes())) + fbsIdToIndex.insert(std::make_pair(fbs[i].GetMostGenericOsmId(), i)); + } + return fbsIdToIndex; +} + +void UpdateRoadGeometry(feature::FeatureBuilder::PointSeq const & road, + feature::FeatureBuilder & fb) +{ + fb.ResetGeometry(); + for (auto const & p : road) + fb.AddPoint(p); +} + +feature::FeatureBuilder CreateRoundaboutFb(std::vector const & way, uint64_t wayId, + uint32_t roadType) +{ + feature::FeatureBuilder fbRoundabout; + fbRoundabout.SetLinear(); + + for (auto const & point : way) + fbRoundabout.AddPoint(point); + + fbRoundabout.AddPoint(way[0]); + fbRoundabout.SetOsmId(base::MakeOsmWay(wayId)); + + static uint32_t const roundaboutType = classif().GetTypeByPath({"junction", "roundabout"}); + fbRoundabout.AddType(roundaboutType); + static uint32_t const defaultRoadType = classif().GetTypeByPath({"highway", "tertiary"}); + fbRoundabout.AddType(roadType == 0 ? defaultRoadType : roadType); + + return fbRoundabout; +} + +void MiniRoundaboutTransformer::ProcessRoundabouts( + feature::CountriesFilesIndexAffiliation const & affiliation, + std::vector & fbs) +{ + std::vector fbsRoundabouts; + fbsRoundabouts.reserve(m_roundabouts.size()); + + std::unordered_map fbsIdToIndex = GetFeaturesHashMap(fbs); + + for (auto const & rb : m_roundabouts) + { + m2::PointD const center = mercator::FromLatLon(rb.m_coord); + std::vector circlePlain = PointToPolygon(center, m_radiusMercator); + uint32_t roadType = 0; + + bool allRoadsInOneMwm = true; + bool foundRoad = false; + for (auto const & wayId : rb.m_ways) + { + base::GeoObjectId geoWayId = base::MakeOsmWay(wayId); + + // Way affiliated to the current mini_roundabout. + auto pairIdIndex = fbsIdToIndex.find(geoWayId); + if (pairIdIndex == fbsIdToIndex.end()) + continue; + size_t const i = pairIdIndex->second; + + // Transform only mini_roundabouts on roads contained in single mwm + if (affiliation.GetAffiliations(fbs[i]).size() != 1) + { + allRoadsInOneMwm = false; + break; + } + + auto road = fbs[i].GetOuterGeometry(); + + if (!AddRoundaboutToRoad(center, circlePlain, road)) + continue; + + UpdateRoadGeometry(road, fbs[i]); + UpdateRoadType(fbs[i].GetTypes(), roadType); + foundRoad = true; + } + if (!allRoadsInOneMwm || !foundRoad) + continue; + + fbsRoundabouts.push_back(CreateRoundaboutFb(circlePlain, rb.m_id, roadType)); + } + + // Adding new roundabouts to the features. + fbs.insert(fbs.end(), std::make_move_iterator(fbsRoundabouts.begin()), + std::make_move_iterator(fbsRoundabouts.end())); + LOG(LINFO, ("Transformed", fbsRoundabouts.size(), "mini_roundabouts to roundabouts")); +} + +double DistanceOnPlain(m2::PointD const & a, m2::PointD const & b) { return a.Length(b); } + +m2::PointD TrimSegment(m2::PointD const & segPoint, m2::PointD const & target, double r) +{ + double const len = DistanceOnPlain(segPoint, target); + if (len < r) + return segPoint; + + double const k = (len - r) / r; + return (segPoint + target * k) / (1.0 + k); +} + +std::vector PointToPolygon(m2::PointD const & center, double radiusMercator, + size_t verticesCount, double initAngleDeg) +{ + CHECK_GREATER(verticesCount, 2, ()); + CHECK_GREATER(radiusMercator, 0.0, ()); + + std::vector vertices; + vertices.reserve(verticesCount); + + double const kAngularPitch = 2 * math::pi / static_cast(verticesCount); + double angle = base::DegToRad(initAngleDeg); + + for (size_t i = 0; i < verticesCount; ++i) + { + vertices.emplace_back(center.x + radiusMercator * cos(angle), + center.y + radiusMercator * sin(angle)); + angle += kAngularPitch; + } + + return vertices; +} + +void AddPointToCircle(std::vector & circle, m2::PointD const & point) +{ + size_t iDist1 = 0; + size_t iDist2 = 0; + double dist1 = std::numeric_limits::max(); + double dist2 = std::numeric_limits::max(); + + for (size_t i = 0; i < circle.size(); ++i) + { + if (AlmostEqualAbs(circle[i], point, kMwmPointAccuracy)) + return; + + double const dist = DistanceOnPlain(circle[i], point); + if (dist < dist1) + { + dist2 = dist1; + iDist2 = iDist1; + + dist1 = dist; + iDist1 = i; + } + else if (dist < dist2) + { + dist2 = dist; + iDist2 = i; + } + } + + if (iDist1 > iDist2) + std::swap(iDist1, iDist2); + + CHECK(((iDist1 < iDist2) && + ((iDist1 == 0 && iDist2 == circle.size() - 1) || (iDist2 - iDist1 == 1))), + ("Invalid conversion for point", mercator::ToLatLon(point))); + + if (iDist1 == 0 && iDist2 == circle.size() - 1) + circle.push_back(point); + else + circle.insert(circle.begin() + iDist2, point); +} +} // namespace generator diff --git a/generator/mini_roundabout_transformer.hpp b/generator/mini_roundabout_transformer.hpp new file mode 100644 index 0000000000..8ec41cc17b --- /dev/null +++ b/generator/mini_roundabout_transformer.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "generator/affiliation.hpp" +#include "generator/feature_builder.hpp" +#include "generator/mini_roundabout_info.hpp" +#include "generator/osm_element.hpp" + +#include "coding/point_coding.hpp" + +#include "geometry/latlon.hpp" +#include "geometry/mercator.hpp" +#include "geometry/point2d.hpp" + +#include "base/math.hpp" + +#include +#include + +namespace generator +{ +class MiniRoundaboutTransformer +{ +public: + explicit MiniRoundaboutTransformer(std::string const & intermediateFilePath); + MiniRoundaboutTransformer(std::string const & intermediateFilePath, double radiusMeters); + + /// \brief Adds ways with junction=roundabout to |fbs|. + /// These features are obtained from points with highway=mini_roundabout. + void ProcessRoundabouts(feature::CountriesFilesIndexAffiliation const & affiliation, + std::vector & fbs); + +private: + /// \brief Loads info about mini_roundabouts from binary source. + void ReadData(std::string const & intermediateFilePath); + + /// \brief Sets |road_type| to |found_type| if it is a more important road type. + void UpdateRoadType(FeatureParams::Types const & foundTypes, uint32_t & roadType); + + /// \brief Creates new point and add it to |roundabout| circle and to the |road|. + bool AddRoundaboutToRoad(m2::PointD const & center, std::vector & roundabout, + feature::FeatureBuilder::PointSeq & road); + + std::vector m_roundabouts; + double const m_radiusMercator = 0.0; +}; + +/// \brief Calculates Euclidean distance between 2 points on plane. +double DistanceOnPlain(m2::PointD const & a, m2::PointD const & b); + +/// \returns The point that is located on the segment (|segPoint|, |target|) and lies in |r| or less +/// from |target|. +m2::PointD TrimSegment(m2::PointD const & segPoint, m2::PointD const & target, double r); + +/// \brief Creates a regular polygon with |verticesCount| inscribed in a circle with |center| and +/// |radiusMercator|. The polygon is rotated by an angle |initAngleDeg| CCW. +/// \returns vector of polygon vertices. +std::vector PointToPolygon(m2::PointD const & center, double radiusMercator, + size_t verticesCount = 12, double initAngleDeg = 0.0); + +/// \brief Inserts point (which lies on circle) between 2 points already present in the circle. +void AddPointToCircle(std::vector & circle, m2::PointD const & point); +} // namespace generator diff --git a/generator/raw_generator.cpp b/generator/raw_generator.cpp index c1e83bb74c..b378ac7ec6 100644 --- a/generator/raw_generator.cpp +++ b/generator/raw_generator.cpp @@ -109,6 +109,7 @@ RawGenerator::FinalProcessorPtr RawGenerator::CreateCountryFinalProcessor(bool a finalProcessor->SetBooking(m_genInfo.m_bookingDataFilename); finalProcessor->SetCitiesAreas(m_genInfo.GetIntermediateFileName(CITIES_AREAS_TMP_FILENAME)); finalProcessor->SetPromoCatalog(m_genInfo.m_promoCatalogCitiesFilename); + finalProcessor->SetMiniRoundabouts(m_genInfo.GetIntermediateFileName(MINI_ROUNDABOUTS_FILENAME)); if (addAds) finalProcessor->SetFakeNodes(base::JoinPath(GetPlatform().ResourcesDir(), MIXED_NODES_FILE)); diff --git a/generator/translator_country.cpp b/generator/translator_country.cpp index 3d1e031876..c6305c74bf 100644 --- a/generator/translator_country.cpp +++ b/generator/translator_country.cpp @@ -5,6 +5,7 @@ #include "generator/collector_city_area.hpp" #include "generator/collector_collection.hpp" #include "generator/collector_interface.hpp" +#include "generator/collector_mini_roundabout.hpp" #include "generator/collector_tag.hpp" #include "generator/cross_mwm_osm_ways_collector.hpp" #include "generator/feature_maker.hpp" @@ -104,7 +105,7 @@ TranslatorCountry::TranslatorCountry(std::shared_ptr info.GetIntermediateFileName(METALINES_FILENAME))); collectors->Append( std::make_shared(info.GetIntermediateFileName(CITIES_AREAS_TMP_FILENAME))); - // These are the four collector that collect additional information for the future building of + // Collectors for gathering of additional information for the future building of // routing section. collectors->Append( std::make_shared(info.GetIntermediateFileName(MAXSPEEDS_FILENAME))); @@ -114,6 +115,9 @@ TranslatorCountry::TranslatorCountry(std::shared_ptr info.GetIntermediateFileName(ROAD_ACCESS_FILENAME))); collectors->Append(std::make_shared( info.GetIntermediateFileName(CAMERAS_TO_WAYS_FILENAME))); + collectors->Append(std::make_shared( + info.GetIntermediateFileName(MINI_ROUNDABOUTS_FILENAME))); + collectors->Append(std::make_shared( info.m_intermediateDir, info.m_targetDir, info.m_haveBordersForWholeWorld)); if (info.m_genAddresses)