Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladimir Byko-Ianko <v.bykoianko@corp.mail.ru>2018-08-27 15:33:52 +0300
committermpimenov <mpimenov@users.noreply.github.com>2018-09-11 20:36:13 +0300
commit3a7f97687030a1840e6ff68f7de2fe9cbe1680ae (patch)
tree7cfde2c283e8de069e8786064a4bb7e171a2f1b5
parent864081aa35091819e3c11ae2a9f591062547d81a (diff)
City roads section and tests.
-rw-r--r--defines.hpp1
-rw-r--r--generator/CMakeLists.txt4
-rw-r--r--generator/cities_boundaries_checker.cpp25
-rw-r--r--generator/cities_boundaries_checker.hpp26
-rw-r--r--generator/city_roads_generator.cpp116
-rw-r--r--generator/city_roads_generator.hpp19
-rw-r--r--generator/generator_tests/CMakeLists.txt2
-rw-r--r--generator/generator_tests/cities_boundaries_checker_tests.cpp79
-rw-r--r--generator/generator_tests/city_roads_tests.cpp149
-rw-r--r--generator/generator_tool/generator_tool.cpp19
-rw-r--r--geometry/bounding_box.hpp3
-rw-r--r--routing/CMakeLists.txt1
-rw-r--r--routing/city_roads_serialization.hpp50
-rwxr-xr-xtools/unix/generate_mwm.sh4
-rwxr-xr-xtools/unix/generate_planet.sh2
-rw-r--r--xcode/generator/generator.xcodeproj/project.pbxproj60
-rw-r--r--xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj8
-rw-r--r--xcode/routing/routing.xcodeproj/project.pbxproj4
18 files changed, 554 insertions, 18 deletions
diff --git a/defines.hpp b/defines.hpp
index d05d8e21e8..bb068f2ce5 100644
--- a/defines.hpp
+++ b/defines.hpp
@@ -53,6 +53,7 @@
#define TRANSIT_CROSS_MWM_FILE_TAG "transit_cross_mwm"
#define TRANSIT_FILE_TAG "transit"
#define UGC_FILE_TAG "ugc"
+#define CITY_ROADS_FILE_TAG "city_roads"
#define LOCALITY_DATA_FILE_TAG "locdata"
#define GEO_OBJECTS_INDEX_FILE_TAG "locidx"
diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt
index 22d215640d..4039a55f72 100644
--- a/generator/CMakeLists.txt
+++ b/generator/CMakeLists.txt
@@ -25,6 +25,10 @@ set(SRC
check_model.hpp
cities_boundaries_builder.cpp
cities_boundaries_builder.hpp
+ cities_boundaries_checker.cpp
+ cities_boundaries_checker.hpp
+ city_roads_generator.cpp
+ city_roads_generator.hpp
coastlines_generator.cpp
coastlines_generator.hpp
dumper.cpp
diff --git a/generator/cities_boundaries_checker.cpp b/generator/cities_boundaries_checker.cpp
new file mode 100644
index 0000000000..c56e23f981
--- /dev/null
+++ b/generator/cities_boundaries_checker.cpp
@@ -0,0 +1,25 @@
+#include "generator/cities_boundaries_checker.hpp"
+
+#include "geometry/rect2d.hpp"
+
+namespace generator
+{
+CitiesBoundariesChecker::CitiesBoundariesChecker(CitiesBoundaries const & citiesBoundaries)
+{
+ for (auto const & cb : citiesBoundaries)
+ m_tree.Add(cb, cb.m_bbox.ToRect());
+}
+
+bool CitiesBoundariesChecker::InCity(m2::PointD const & point) const
+{
+ bool result = false;
+ m_tree.ForEachInRect(m2::RectD(point, point), [&](indexer::CityBoundary const & cityBoundary) {
+ if (result)
+ return;
+
+ result = cityBoundary.HasPoint(point);
+ });
+
+ return result;
+}
+} // namespace generator
diff --git a/generator/cities_boundaries_checker.hpp b/generator/cities_boundaries_checker.hpp
new file mode 100644
index 0000000000..c992929826
--- /dev/null
+++ b/generator/cities_boundaries_checker.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "indexer/city_boundary.hpp"
+
+#include "geometry/point2d.hpp"
+#include "geometry/tree4d.hpp"
+
+#include <vector>
+
+namespace generator
+{
+/// \brief Checks whether a given point belongs to a city or a town.
+class CitiesBoundariesChecker
+{
+public:
+ using CitiesBoundaries = std::vector<indexer::CityBoundary>;
+
+ explicit CitiesBoundariesChecker(CitiesBoundaries const & citiesBoundaries);
+
+ /// \returns true if |point| is inside a city or a town and false otherwise.
+ bool InCity(m2::PointD const & point) const;
+
+private:
+ m4::Tree<indexer::CityBoundary> m_tree;
+};
+} // namespace generator
diff --git a/generator/city_roads_generator.cpp b/generator/city_roads_generator.cpp
new file mode 100644
index 0000000000..5b1fe0f0ed
--- /dev/null
+++ b/generator/city_roads_generator.cpp
@@ -0,0 +1,116 @@
+#include "generator/city_roads_generator.hpp"
+
+#include "generator/cities_boundaries_checker.hpp"
+
+#include "routing/city_roads_serialization.hpp"
+#include "routing/routing_helpers.hpp"
+
+#include "indexer/feature.hpp"
+#include "indexer/feature_data.cpp"
+#include "indexer/feature_processor.hpp"
+
+#include "coding/compressed_bit_vector.hpp"
+
+#include "base/assert.hpp"
+#include "base/geo_object_id.hpp"
+
+#include <algorithm>
+#include <utility>
+
+#include "defines.hpp"
+
+using namespace generator;
+using namespace std;
+
+namespace
+{
+void TableToVector(OsmIdToBoundariesTable & table,
+ CitiesBoundariesChecker::CitiesBoundaries & result)
+{
+ table.ForEachCluster([&result](vector<base::GeoObjectId> const & /* id */,
+ vector<indexer::CityBoundary> const & cb) {
+ result.insert(result.end(), cb.cbegin(), cb.cend());
+ });
+}
+
+/// \brief Fills |cityRoadFeatureIds| with road feature ids if more then
+/// |kInCityPointsRatio| * <feature point number> points of the feature belongs to a city or a town
+/// according to |table|.
+void CalcRoadFeatureIds(string const & dataPath, OsmIdToBoundariesTable & table,
+ vector<uint64_t> & cityRoadFeatureIds)
+{
+ double constexpr kInCityPointsRatio = 0.2;
+
+ CitiesBoundariesChecker::CitiesBoundaries citiesBoundaries;
+ TableToVector(table, citiesBoundaries);
+ CitiesBoundariesChecker const checker(citiesBoundaries);
+
+ ForEachFromDat(dataPath, [&cityRoadFeatureIds, &checker](FeatureType & ft, uint32_t fid) {
+ if (!routing::IsRoad(TypesHolder(ft)))
+ return;
+
+ ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
+
+ size_t inCityPointsCounter = 0;
+ for (size_t i = 0; i < ft.GetPointsCount(); ++i)
+ {
+ if (checker.InCity(ft.GetPoint(i)))
+ ++inCityPointsCounter;
+ }
+
+ if (inCityPointsCounter > kInCityPointsRatio * ft.GetPointsCount())
+ cityRoadFeatureIds.push_back(ft.GetID().m_index);
+ });
+}
+} // namespace
+
+namespace routing
+{
+void SerializeCityRoads(string const & dataPath, vector<uint64_t> && cityRoadFeatureIds)
+{
+ if (cityRoadFeatureIds.empty())
+ return;
+
+ sort(cityRoadFeatureIds.begin(), cityRoadFeatureIds.end());
+
+ FilesContainerW cont(dataPath, FileWriter::OP_WRITE_EXISTING);
+ FileWriter w = cont.GetWriter(CITY_ROADS_FILE_TAG);
+ CityRoadsHeader header;
+ header.Serialize(w);
+
+ auto const cbv = coding::CompressedBitVectorBuilder::FromBitPositions(move(cityRoadFeatureIds));
+ CHECK(cbv, ());
+
+ CityRoadsSerializer::Serialize(*cbv, w);
+}
+
+bool BuildCityRoads(string const & dataPath, OsmIdToBoundariesTable & table)
+{
+ LOG(LDEBUG, ("BuildCityRoads(", dataPath, ");"));
+ vector<uint64_t> cityRoadFeatureIds;
+ size_t cityRoadFeatureIdsSz = 0;
+ try
+ {
+ // @TODO(bykoianko) The generation city roads section process is based on two stages now:
+ // * dumping cities boundaries on feature generation step
+ // * calculating feature ids and building section when feature ids are available
+ // As a result of dumping cities boundaries instansed of indexer::CityBoundary objects
+ // are generated and dumped. These objects are used for generating city roads section.
+ // Using real geometry of cities boundaries should be considered for generating city road
+ // features. That mean that the real geometry of cities boundaries should be dumped
+ // on the first step. And then to try using the real geometry should be used for generating city
+ // road features. But there's a chance that it takes to long time.
+ CalcRoadFeatureIds(dataPath, table, cityRoadFeatureIds);
+ cityRoadFeatureIdsSz = cityRoadFeatureIds.size();
+ SerializeCityRoads(dataPath, move(cityRoadFeatureIds));
+ }
+ catch (Reader::Exception const & e)
+ {
+ LOG(LERROR, ("Error while building section city_roads in", dataPath, ". Message:", e.Msg()));
+ return false;
+ }
+ LOG(LINFO, ("city_roads section is built in", dataPath, ". Serialized", cityRoadFeatureIdsSz,
+ "road feature ids in cities."));
+ return true;
+}
+} // namespace routing
diff --git a/generator/city_roads_generator.hpp b/generator/city_roads_generator.hpp
new file mode 100644
index 0000000000..f4f92c7072
--- /dev/null
+++ b/generator/city_roads_generator.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "generator/cities_boundaries_builder.hpp"
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace routing
+{
+/// \brief Write |cityRoadFeatureIds| to city_roads section to mwm with |dataPath|.
+/// \param cityRoadFeatureIds a vector of road feature ids in cities.
+void SerializeCityRoads(std::string const & dataPath, std::vector<uint64_t> && cityRoadFeatureIds);
+
+/// \brief Builds city_roads in mwm with |dataPath|. This section contains road features
+/// which have at least one point located in at least of on CityBoundary in |table|
+/// \note Before a call of this method, geometry index section should be ready in mwm |dataPath|.
+bool BuildCityRoads(std::string const & dataPath, generator::OsmIdToBoundariesTable & table);
+} // namespace routing
diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt
index f9fe9389cf..3886dcefc2 100644
--- a/generator/generator_tests/CMakeLists.txt
+++ b/generator/generator_tests/CMakeLists.txt
@@ -4,6 +4,8 @@ set(
SRC
altitude_test.cpp
check_mwms.cpp
+ cities_boundaries_checker_tests.cpp
+ city_roads_tests.cpp
coasts_test.cpp
feature_builder_test.cpp
feature_merger_test.cpp
diff --git a/generator/generator_tests/cities_boundaries_checker_tests.cpp b/generator/generator_tests/cities_boundaries_checker_tests.cpp
new file mode 100644
index 0000000000..e89119621e
--- /dev/null
+++ b/generator/generator_tests/cities_boundaries_checker_tests.cpp
@@ -0,0 +1,79 @@
+#include "testing/testing.hpp"
+
+#include "generator/cities_boundaries_checker.hpp"
+
+#include "geometry/latlon.hpp"
+#include "geometry/mercator.hpp"
+
+#include "base/logging.hpp"
+
+namespace
+{
+using namespace generator;
+using namespace indexer;
+
+UNIT_TEST(CitiesBoundariesCheckerTest_Square)
+{
+ auto const checker =
+ CitiesBoundariesChecker({CityBoundary({{0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {0.0, 1.0}})});
+
+ TEST(checker.InCity({0.5, 0.5}), ());
+ TEST(checker.InCity({0.0001, 0.0001}), ());
+
+ TEST(!checker.InCity({2.0, 2.0}), ());
+ TEST(!checker.InCity({20.0, 20.0}), ());
+ TEST(!checker.InCity({-30.0, 30.0}), ());
+ TEST(!checker.InCity({40.0, -40.0}), ());
+}
+
+UNIT_TEST(CitiesBoundariesCheckerTest_NotConvexPolygon)
+{
+ auto const checker =
+ CitiesBoundariesChecker({CityBoundary({{0.0, 0.0}, {1.0, -1.0}, {0.5, 0.0}, {1.0, 1.0}, {0.0, 1.0}})});
+
+ TEST(checker.InCity({0.3, 0.3}), ());
+ TEST(checker.InCity({0.0001, 0.0001}), ());
+
+ TEST(!checker.InCity({2.0, 2.0}), ());
+ TEST(!checker.InCity({20.0, 20.0}), ());
+ TEST(!checker.InCity({-30.0, 30.0}), ());
+ TEST(!checker.InCity({40.0, -40.0}), ());
+}
+
+UNIT_TEST(CitiesBoundariesCheckerTest_IntersectedPolygons)
+{
+ auto const checker = CitiesBoundariesChecker(
+ {CityBoundary({{0.0, 0.0}, {1.0, -1.0}, {0.5, 0.0}, {1.0, 1.0}, {0.0, 1.0}}),
+ CityBoundary({{0.0, 0.0}, {1.0, -1.0}, {0.5, 0.0}, {1.0, 1.0}, {0.0, 1.0}})});
+
+ TEST(checker.InCity({0.3, 0.3}), ());
+ TEST(checker.InCity({0.0001, 0.0001}), ());
+
+ TEST(!checker.InCity({2.0, 2.0}), ());
+ TEST(!checker.InCity({20.0, 20.0}), ());
+ TEST(!checker.InCity({-30.0, 30.0}), ());
+ TEST(!checker.InCity({40.0, -40.0}), ());
+}
+
+UNIT_TEST(CitiesBoundariesCheckerTest_SeveralPolygons)
+{
+ auto const checker = CitiesBoundariesChecker(
+ {CityBoundary({{0.0, 0.0}, {1.0, -1.0}, {0.5, 0.0}, {1.0, 1.0}, {0.0, 1.0}}),
+ CityBoundary({{10.0, 0.0}, {11.0, -1.0}, {10.5, 0.0}, {11.0, 1.0}, {10.0, 1.0}}),
+ CityBoundary({{0.0, 10.0}, {1.0, -11.0}, {0.5, 10.0}, {1.0, 11.0}, {0.0, 11.0}})});
+
+ TEST(checker.InCity({0.3, 0.3}), ());
+ TEST(checker.InCity({0.0001, 0.0001}), ());
+
+ TEST(checker.InCity({10.3, 0.3}), ());
+ TEST(checker.InCity({10.0001, 0.0001}), ());
+
+ TEST(checker.InCity({0.3, 10.4}), ());
+ TEST(checker.InCity({0.0001, 10.0001}), ());
+
+ TEST(!checker.InCity({2.0, 2.0}), ());
+ TEST(!checker.InCity({20.0, 20.0}), ());
+ TEST(!checker.InCity({-30.0, 30.0}), ());
+ TEST(!checker.InCity({40.0, -40.0}), ());
+}
+} // namespace
diff --git a/generator/generator_tests/city_roads_tests.cpp b/generator/generator_tests/city_roads_tests.cpp
new file mode 100644
index 0000000000..9311d795f4
--- /dev/null
+++ b/generator/generator_tests/city_roads_tests.cpp
@@ -0,0 +1,149 @@
+#include "testing/testing.hpp"
+
+#include "generator/generator_tests_support/test_mwm_builder.hpp"
+
+#include "generator/city_roads_generator.hpp"
+
+#include "routing/city_roads_serialization.hpp"
+
+#include "platform/platform_tests_support/scoped_dir.hpp"
+#include "platform/platform_tests_support/scoped_file.hpp"
+
+#include "platform/country_file.hpp"
+#include "platform/local_country_file.hpp"
+#include "platform/platform.hpp"
+
+#include "coding/compressed_bit_vector.hpp"
+#include "coding/file_container.hpp"
+#include "coding/file_name_utils.hpp"
+#include "coding/reader.hpp"
+
+#include "base/assert.hpp"
+#include "base/logging.hpp"
+
+#include <algorithm>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "defines.hpp"
+
+using namespace coding;
+using namespace platform::tests_support;
+using namespace platform;
+using namespace routing;
+using namespace std;
+
+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";
+
+void BuildEmptyMwm(LocalCountryFile & country)
+{
+ generator::tests_support::TestMwmBuilder builder(country, feature::DataHeader::country);
+}
+
+unique_ptr<CompressedBitVector> LoadCityRoads(string const & mwmFilePath)
+{
+ FilesContainerR const cont(mwmFilePath);
+ if (!cont.IsExist(CITY_ROADS_FILE_TAG))
+ return nullptr;
+
+ try
+ {
+ FilesContainerR::TReader const reader = cont.GetReader(CITY_ROADS_FILE_TAG);
+ ReaderSource<FilesContainerR::TReader> src(reader);
+
+ CityRoadsHeader header;
+ header.Deserialize(src);
+ TEST_EQUAL(header.m_version, 0, ());
+
+ return CompressedBitVectorBuilder::DeserializeFromSource(src);
+ }
+ catch (Reader::OpenException const & e)
+ {
+ TEST(false, ("Error while reading", CITY_ROADS_FILE_TAG, "section.", e.Msg()));
+ return nullptr;
+ }
+}
+
+/// \brief Builds mwm with city_roads section, read the section and compare original feature ids
+/// and read ones.
+/// \cityRoadFeatureIds a vector of feature ids which should be saved to city_roads
+/// section and then read from it.
+void TestCityRoadsBuilding(vector<uint64_t> && cityRoadFeatureIds)
+{
+ string const writableDir = GetPlatform().WritableDir();
+
+ // Building empty mwm.
+ LocalCountryFile country(my::JoinPath(writableDir, kTestDir), CountryFile(kTestMwm),
+ 0 /* version */);
+ ScopedDir const scopedDir(kTestDir);
+ string const mwmRelativePath = my::JoinPath(kTestDir, kTestMwm + DATA_FILE_EXTENSION);
+ ScopedFile const scopedMwm(mwmRelativePath, ScopedFile::Mode::Create);
+ BuildEmptyMwm(country);
+
+ // Adding city_roads section to mwm.
+ string const mwmFullPath = my::JoinPath(writableDir, mwmRelativePath);
+ vector<uint64_t> originalCityRoadFeatureIds = cityRoadFeatureIds;
+ SerializeCityRoads(mwmFullPath, move(cityRoadFeatureIds));
+
+ // Loading city_roads section.
+ auto const loadedCityRoadFeatureIds = LoadCityRoads(mwmFullPath);
+
+ // Comparing loading form mwm and expected feature ids.
+ if (originalCityRoadFeatureIds.empty())
+ {
+ TEST(!loadedCityRoadFeatureIds, ());
+ return;
+ }
+
+ TEST(loadedCityRoadFeatureIds, ());
+ sort(originalCityRoadFeatureIds.begin(), originalCityRoadFeatureIds.end());
+ size_t const kMaxRoadFeatureId = originalCityRoadFeatureIds.back();
+ for (uint64_t fid = 0; fid < kMaxRoadFeatureId; ++fid)
+ {
+ bool const isCityRoad =
+ binary_search(originalCityRoadFeatureIds.cbegin(), originalCityRoadFeatureIds.cend(), fid);
+ TEST_EQUAL(loadedCityRoadFeatureIds->GetBit(fid), isCityRoad, (fid));
+ }
+}
+
+UNIT_TEST(CityRoadsGenerationTest_Empty)
+{
+ TestCityRoadsBuilding(vector<uint64_t>({}));
+}
+
+UNIT_TEST(CityRoadsGenerationTest_FromZero)
+{
+ TestCityRoadsBuilding(vector<uint64_t>({0, 1, 10}));
+}
+
+UNIT_TEST(CityRoadsGenerationTest_CommonCase)
+{
+ TestCityRoadsBuilding(vector<uint64_t>({100, 203, 204, 1008, 1009}));
+}
+
+UNIT_TEST(CityRoadsGenerationTest_BigNumbers)
+{
+ TestCityRoadsBuilding(
+ vector<uint64_t>({1000, 1203, 11004, 11008, 11009, 11010, 11011, 11012, 11013, 11014, 11015,
+ 11016, 11017, 11018, 11019, 11020, 11021, 11022, 11023, 11024, 11025}));
+}
+
+UNIT_TEST(CityRoadsGenerationTest_UnsortedIds)
+{
+ TestCityRoadsBuilding(vector<uint64_t>({100, 1, 101, 2, 204, 1008, 1009}));
+}
+
+UNIT_TEST(CityRoadsGenerationTest_UnsortedIds2)
+{
+ TestCityRoadsBuilding(
+ vector<uint64_t>({1000, 1203, 1, 11004, 11, 11009, 11010, 1011, 11012, 11013, 11, 4, 11015,
+ 11016, 11017, 11018, 11019, 11020, 11021, 11022, 11023, 11024, 11025, 2}));
+}
+} // namespace
diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp
index 3aab65be69..138a51203d 100644
--- a/generator/generator_tool/generator_tool.cpp
+++ b/generator/generator_tool/generator_tool.cpp
@@ -5,6 +5,7 @@
#include "generator/centers_table_builder.hpp"
#include "generator/check_model.hpp"
#include "generator/cities_boundaries_builder.hpp"
+#include "generator/city_roads_generator.hpp"
#include "generator/dumper.hpp"
#include "generator/emitter_factory.hpp"
#include "generator/feature_generator.hpp"
@@ -128,6 +129,9 @@ DEFINE_string(srtm_path, "",
"about roads.");
DEFINE_string(transit_path, "", "Path to directory with transit graphs in json.");
DEFINE_bool(generate_cameras, false, "Generate section with speed cameras info.");
+DEFINE_bool(
+ make_city_roads, false,
+ "Calculates which features lie inside cities and makes a section with ids of these features.");
// Sponsored-related.
DEFINE_string(booking_data, "", "Path to booking data in .tsv format.");
@@ -233,8 +237,8 @@ int main(int argc, char ** argv)
FLAGS_calc_statistics || FLAGS_type_statistics || FLAGS_dump_types || FLAGS_dump_prefixes ||
FLAGS_dump_feature_names != "" || FLAGS_check_mwm || FLAGS_srtm_path != "" ||
FLAGS_make_routing_index || FLAGS_make_cross_mwm || FLAGS_make_transit_cross_mwm ||
- FLAGS_generate_traffic_keys || FLAGS_transit_path != "" || FLAGS_ugc_data != "" ||
- FLAGS_popular_places_data != "")
+ FLAGS_make_city_roads || FLAGS_generate_traffic_keys || FLAGS_transit_path != "" ||
+ FLAGS_ugc_data != "" || FLAGS_popular_places_data != "")
{
classificator::Load();
classif().SortClassificator();
@@ -468,6 +472,17 @@ int main(int argc, char ** argv)
routing::BuildRoutingIndex(datFile, country, *countryParentGetter);
}
+ if (FLAGS_make_city_roads)
+ {
+ CHECK(!FLAGS_cities_boundaries_data.empty(), ());
+ LOG(LINFO, ("Generating cities boundaries roads for", datFile));
+ generator::OsmIdToBoundariesTable table;
+ if (!generator::DeserializeBoundariesTable(FLAGS_cities_boundaries_data, table))
+ LOG(LCRITICAL, ("Deserializing boundaries table error."));
+ if (!routing::BuildCityRoads(datFile, table))
+ LOG(LCRITICAL, ("Generating city roads error."));
+ }
+
if (FLAGS_make_cross_mwm || FLAGS_make_transit_cross_mwm)
{
if (!countryParentGetter)
diff --git a/geometry/bounding_box.hpp b/geometry/bounding_box.hpp
index 2b704d0557..b865c3cfd4 100644
--- a/geometry/bounding_box.hpp
+++ b/geometry/bounding_box.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "geometry/point2d.hpp"
+#include "geometry/rect2d.hpp"
#include "base/visitor.hpp"
@@ -27,6 +28,8 @@ public:
PointD Min() const { return m_min; }
PointD Max() const { return m_max; }
+ m2::RectD ToRect() const { return {Min(), Max()}; }
+
std::vector<m2::PointD> Points() const
{
std::vector<m2::PointD> points(4);
diff --git a/routing/CMakeLists.txt b/routing/CMakeLists.txt
index ce32054ff0..67170c58ea 100644
--- a/routing/CMakeLists.txt
+++ b/routing/CMakeLists.txt
@@ -20,6 +20,7 @@ set(
checkpoint_predictor.hpp
checkpoints.cpp
checkpoints.hpp
+ city_roads_serialization.hpp
coding.hpp
cross_mwm_connector.cpp
cross_mwm_connector.hpp
diff --git a/routing/city_roads_serialization.hpp b/routing/city_roads_serialization.hpp
new file mode 100644
index 0000000000..22d72a1f26
--- /dev/null
+++ b/routing/city_roads_serialization.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "coding/compressed_bit_vector.hpp"
+#include "coding/reader.hpp"
+#include "coding/write_to_sink.hpp"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+namespace routing
+{
+struct CityRoadsHeader
+{
+ template <class Sink>
+ void Serialize(Sink & sink) const
+ {
+ WriteToSink(sink, m_version);
+ WriteToSink(sink, m_reserved);
+ }
+
+ template <class Source>
+ void Deserialize(Source & src)
+ {
+ m_version = ReadPrimitiveFromSource<uint16_t>(src);
+ m_reserved = ReadPrimitiveFromSource<uint16_t>(src);
+ }
+
+ uint16_t m_version = 0;
+ uint16_t m_reserved = 0;
+};
+
+static_assert(sizeof(CityRoadsHeader) == 4, "Wrong header size of city_roads section.");
+
+class CityRoadsSerializer
+{
+public:
+ template <class Sink>
+ static void Serialize(coding::CompressedBitVector const & cityRoadFeatureIds, Sink & sink)
+ {
+ cityRoadFeatureIds.Serialize(sink);
+ }
+
+ template <class Source>
+ static std::unique_ptr<coding::CompressedBitVector> Deserialize(Source & src)
+ {
+ return coding::CompressedBitVectorBuilder::DeserializeFromSource(src);
+ }
+};
+} // namespace routing
diff --git a/tools/unix/generate_mwm.sh b/tools/unix/generate_mwm.sh
index e89d460508..178bd1e610 100755
--- a/tools/unix/generate_mwm.sh
+++ b/tools/unix/generate_mwm.sh
@@ -71,10 +71,11 @@ else
INTDIR=$(mktemp -d)
fi
trap "rm -rf \"${INTDIR}\"" EXIT SIGINT SIGTERM
+CITIES_BOUNDARIES_DATA="${CITIES_BOUNDARIES_DATA:-$INTDIR/cities_boundaries.bin}"
# Create MWM file
INTDIR_FLAG="--intermediate_data_path=$INTDIR/ --node_storage=map"
-GENERATE_EVERYTHING='--generate_features=true --generate_geometry=true --generate_index=true --generate_search_index=true'
+GENERATE_EVERYTHING="--generate_features --generate_geometry --generate_index --generate_search_index --dump_cities_boundaries --cities_boundaries_data=$CITIES_BOUNDARIES_DATA"
[ -n "${HOTELS-}" ] && GENERATE_EVERYTHING="$GENERATE_EVERYTHING --booking_data=$HOTELS"
COASTS="${COASTS-WorldCoasts.geom}"
if [ -f "$COASTS" ]; then
@@ -110,6 +111,7 @@ if [ "$SOURCE_TYPE" == "o5m" ]; then
$GENERATOR_TOOL $INTDIR_FLAG --osm_file_type=o5m --osm_file_name="$SOURCE_FILE" --preprocess=true || fail "Preprocessing failed"
$GENERATOR_TOOL $INTDIR_FLAG --osm_file_type=o5m --osm_file_name="$SOURCE_FILE" --data_path="$TARGET" --user_resource_path="$DATA_PATH" $GENERATE_EVERYTHING --output="$BASE_NAME"
+ $GENERATOR_TOOL $INTDIR_FLAG --data_path="$TARGET" --user_resource_path="$DATA_PATH" --cities_boundaries_data="$CITIES_BOUNDARIES_DATA" --make_city_roads --output="$BASE_NAME"
$GENERATOR_TOOL $INTDIR_FLAG --data_path="$TARGET" --user_resource_path="$DATA_PATH" ${CROSS_MWM-} ${GENERATE_CAMERA_SECTION-} --make_routing_index --generate_traffic_keys --output="$BASE_NAME"
else
echo "Unsupported source type: $SOURCE_TYPE" >&2
diff --git a/tools/unix/generate_planet.sh b/tools/unix/generate_planet.sh
index b6b0469dd6..ab6dbcdc86 100755
--- a/tools/unix/generate_planet.sh
+++ b/tools/unix/generate_planet.sh
@@ -511,7 +511,7 @@ if [ "$MODE" == "mwm" ]; then
fi
if [ -z "$NO_REGIONS" ]; then
- PARAMS_WITH_SEARCH="$PARAMS -generate_search_index"
+ PARAMS_WITH_SEARCH="$PARAMS --generate_search_index --cities_boundaries_data=$CITIES_BOUNDARIES_DATA --make_city_roads"
[ -n "${SRTM_PATH-}" -a -d "${SRTM_PATH-}" ] && PARAMS_WITH_SEARCH="$PARAMS_WITH_SEARCH --srtm_path=$SRTM_PATH"
[ -f "$UGC_FILE" ] && PARAMS_WITH_SEARCH="$PARAMS_WITH_SEARCH --ugc_data=$UGC_FILE"
[ -f "$POPULAR_PLACES_FILE" ] && PARAMS_WITH_SEARCH="$PARAMS_WITH_SEARCH --popular_places_data=$POPULAR_PLACES_FILE"
diff --git a/xcode/generator/generator.xcodeproj/project.pbxproj b/xcode/generator/generator.xcodeproj/project.pbxproj
index 0026e1d2d3..74d5fb2e05 100644
--- a/xcode/generator/generator.xcodeproj/project.pbxproj
+++ b/xcode/generator/generator.xcodeproj/project.pbxproj
@@ -55,8 +55,12 @@
441DB3FD2119D72300D2F324 /* camera_info_collector.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 441DB3FA2119D72300D2F324 /* camera_info_collector.hpp */; };
441DB3FE2119D72300D2F324 /* camera_info_collector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 441DB3FB2119D72300D2F324 /* camera_info_collector.cpp */; };
44AA0AEB2133EA7800F72321 /* camera_node_processor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 44AA0AEA2133EA7700F72321 /* camera_node_processor.cpp */; };
+ 56829A462134222300A09A28 /* city_roads_generator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56829A422134222100A09A28 /* city_roads_generator.hpp */; };
+ 56829A482134222300A09A28 /* city_roads_generator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56829A442134222300A09A28 /* city_roads_generator.cpp */; };
568762601F6A9B18002C22A6 /* transit_generator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5687625E1F6A9B18002C22A6 /* transit_generator.cpp */; };
568762611F6A9B18002C22A6 /* transit_generator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 5687625F1F6A9B18002C22A6 /* transit_generator.hpp */; };
+ 56E0C4E4213FD56F00541E0F /* cities_boundaries_checker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56E0C4E2213FD56E00541E0F /* cities_boundaries_checker.cpp */; };
+ 56E0C4E5213FD56F00541E0F /* cities_boundaries_checker.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56E0C4E3213FD56E00541E0F /* cities_boundaries_checker.hpp */; };
670B84BC1A8CDB0000CE4492 /* osm_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670B84BA1A8CDB0000CE4492 /* osm_source.cpp */; };
670B84BD1A8CDB0000CE4492 /* osm_source.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 670B84BB1A8CDB0000CE4492 /* osm_source.hpp */; };
670E7BB31EF9812B00A8E9ED /* metalines_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 670E7BA91EF9812B00A8E9ED /* metalines_builder.cpp */; };
@@ -204,8 +208,16 @@
4003E3992112FB29007721B0 /* factory_utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = factory_utils.hpp; sourceTree = "<group>"; };
4003E39A2112FB29007721B0 /* sponsored_object_base.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sponsored_object_base.hpp; sourceTree = "<group>"; };
4003E39B2112FB29007721B0 /* emitter_factory.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = emitter_factory.hpp; sourceTree = "<group>"; };
+ 4003E39C2112FB2A007721B0 /* emitter_planet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitter_planet.cpp; sourceTree = "<group>"; };
+ 4003E39D2112FB2A007721B0 /* emitter_restaurants.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = emitter_restaurants.hpp; sourceTree = "<group>"; };
+ 4003E39F2112FB2A007721B0 /* emitter_restaurants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitter_restaurants.cpp; sourceTree = "<group>"; };
4003E3A02112FB2A007721B0 /* emitter_booking.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = emitter_booking.hpp; sourceTree = "<group>"; };
4003E3A12112FB2A007721B0 /* emitter_interface.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = emitter_interface.hpp; sourceTree = "<group>"; };
+ 4003E3A22112FB2A007721B0 /* emitter_region.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = emitter_region.cpp; sourceTree = "<group>"; };
+ 4003E3A32112FB2B007721B0 /* popular_places_section_builder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = popular_places_section_builder.cpp; sourceTree = "<group>"; };
+ 4003E3A42112FB2B007721B0 /* ways_merger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ways_merger.cpp; sourceTree = "<group>"; };
+ 4003E3A52112FB2B007721B0 /* popular_places_section_builder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = popular_places_section_builder.hpp; sourceTree = "<group>"; };
+ 4003E3A62112FB2B007721B0 /* emitter_planet.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = emitter_planet.hpp; sourceTree = "<group>"; };
4003E3A82112FB2B007721B0 /* place.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = place.hpp; sourceTree = "<group>"; };
40492BC32021DC53008E093A /* locality_sorter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = locality_sorter.hpp; sourceTree = "<group>"; };
40492BC42021DC53008E093A /* feature_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = feature_helpers.cpp; sourceTree = "<group>"; };
@@ -216,8 +228,12 @@
441DB3FA2119D72300D2F324 /* camera_info_collector.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = camera_info_collector.hpp; sourceTree = "<group>"; };
441DB3FB2119D72300D2F324 /* camera_info_collector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = camera_info_collector.cpp; sourceTree = "<group>"; };
44AA0AEA2133EA7700F72321 /* camera_node_processor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = camera_node_processor.cpp; sourceTree = "<group>"; };
+ 56829A422134222100A09A28 /* city_roads_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = city_roads_generator.hpp; sourceTree = "<group>"; };
+ 56829A442134222300A09A28 /* city_roads_generator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = city_roads_generator.cpp; sourceTree = "<group>"; };
5687625E1F6A9B18002C22A6 /* transit_generator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = transit_generator.cpp; sourceTree = "<group>"; };
5687625F1F6A9B18002C22A6 /* transit_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = transit_generator.hpp; sourceTree = "<group>"; };
+ 56E0C4E2213FD56E00541E0F /* cities_boundaries_checker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cities_boundaries_checker.cpp; sourceTree = "<group>"; };
+ 56E0C4E3213FD56E00541E0F /* cities_boundaries_checker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cities_boundaries_checker.hpp; sourceTree = "<group>"; };
670B84BA1A8CDB0000CE4492 /* osm_source.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = osm_source.cpp; sourceTree = "<group>"; };
670B84BB1A8CDB0000CE4492 /* osm_source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = osm_source.hpp; sourceTree = "<group>"; };
670E7BA91EF9812B00A8E9ED /* metalines_builder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = metalines_builder.cpp; sourceTree = "<group>"; };
@@ -346,6 +362,27 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 56829A38212EA6F600A09A28 /* Recovered References */ = {
+ isa = PBXGroup;
+ children = (
+ 4003E39F2112FB2A007721B0 /* emitter_restaurants.cpp */,
+ 4003E39C2112FB2A007721B0 /* emitter_planet.cpp */,
+ 4003E3A32112FB2B007721B0 /* popular_places_section_builder.cpp */,
+ 4003E3A22112FB2A007721B0 /* emitter_region.cpp */,
+ 4003E3A42112FB2B007721B0 /* ways_merger.cpp */,
+ 4003E3A02112FB2A007721B0 /* emitter_booking.hpp */,
+ 4003E39D2112FB2A007721B0 /* emitter_restaurants.hpp */,
+ 4003E39A2112FB29007721B0 /* sponsored_object_base.hpp */,
+ 4003E3A62112FB2B007721B0 /* emitter_planet.hpp */,
+ 4003E39B2112FB29007721B0 /* emitter_factory.hpp */,
+ 4003E3A82112FB2B007721B0 /* place.hpp */,
+ 4003E3A12112FB2A007721B0 /* emitter_interface.hpp */,
+ 4003E3992112FB29007721B0 /* factory_utils.hpp */,
+ 4003E3A52112FB2B007721B0 /* popular_places_section_builder.hpp */,
+ );
+ name = "Recovered References";
+ sourceTree = "<group>";
+ };
675340121A3F2A1B00A0A8C3 = {
isa = PBXGroup;
children = (
@@ -354,7 +391,7 @@
6753401D1A3F2A1B00A0A8C3 /* generator */,
67BC92D71D1A9E6A00A4A378 /* generator_tests_support */,
6753401C1A3F2A1B00A0A8C3 /* Products */,
- E162BD1C213E8E6B007ADEF1 /* Recovered References */,
+ 56829A38212EA6F600A09A28 /* Recovered References */,
);
sourceTree = "<group>";
};
@@ -370,6 +407,8 @@
6753401D1A3F2A1B00A0A8C3 /* generator */ = {
isa = PBXGroup;
children = (
+ 56E0C4E2213FD56E00541E0F /* cities_boundaries_checker.cpp */,
+ 56E0C4E3213FD56E00541E0F /* cities_boundaries_checker.hpp */,
E162BD4C213EAF2C007ADEF1 /* translator_planet.cpp */,
E162BD4F213EAF2C007ADEF1 /* translator_planet.hpp */,
E162BD4E213EAF2C007ADEF1 /* ways_merger.cpp */,
@@ -392,6 +431,8 @@
441DB3FB2119D72300D2F324 /* camera_info_collector.cpp */,
441DB3FA2119D72300D2F324 /* camera_info_collector.hpp */,
441DB3F92119D72200D2F324 /* camera_node_processor.hpp */,
+ 56829A442134222300A09A28 /* city_roads_generator.cpp */,
+ 56829A422134222100A09A28 /* city_roads_generator.hpp */,
E1EC1469211C5FE000B53061 /* sponsored_object_base.hpp */,
E1EC1465211C5FC800B53061 /* holes.cpp */,
E1EC1466211C5FC900B53061 /* holes.hpp */,
@@ -534,19 +575,6 @@
path = ../../generator/generator_tests_support;
sourceTree = "<group>";
};
- E162BD1C213E8E6B007ADEF1 /* Recovered References */ = {
- isa = PBXGroup;
- children = (
- 4003E3A02112FB2A007721B0 /* emitter_booking.hpp */,
- 4003E39A2112FB29007721B0 /* sponsored_object_base.hpp */,
- 4003E39B2112FB29007721B0 /* emitter_factory.hpp */,
- 4003E3A82112FB2B007721B0 /* place.hpp */,
- 4003E3A12112FB2A007721B0 /* emitter_interface.hpp */,
- 4003E3992112FB29007721B0 /* factory_utils.hpp */,
- );
- name = "Recovered References";
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -557,6 +585,7 @@
40492BC82021DC53008E093A /* locality_sorter.hpp in Headers */,
34F558881DBF4C9600A4FC11 /* opentable_dataset.hpp in Headers */,
E162BD3D213EAEF6007ADEF1 /* emitter_restaurants.hpp in Headers */,
+ 56E0C4E5213FD56F00541E0F /* cities_boundaries_checker.hpp in Headers */,
E1EC1463211C5FBD00B53061 /* place.hpp in Headers */,
6753406B1A3F2A7400A0A8C3 /* feature_emitter_iface.hpp in Headers */,
E1EC1464211C5FBD00B53061 /* relation_tags.hpp in Headers */,
@@ -617,6 +646,7 @@
6753406D1A3F2A7400A0A8C3 /* feature_generator.hpp in Headers */,
675340681A3F2A7400A0A8C3 /* dumper.hpp in Headers */,
670E7BB81EF9812B00A8E9ED /* routing_helpers.hpp in Headers */,
+ 56829A462134222300A09A28 /* city_roads_generator.hpp in Headers */,
4003E3AC2112FB2B007721B0 /* emitter_factory.hpp in Headers */,
3D74EF081F86841C0081202C /* ugc_section_builder.hpp in Headers */,
675340711A3F2A7400A0A8C3 /* feature_sorter.hpp in Headers */,
@@ -728,6 +758,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 56E0C4E4213FD56F00541E0F /* cities_boundaries_checker.cpp in Sources */,
39B2B9781FB468CC00AB85A1 /* cities_boundaries_builder.cpp in Sources */,
670E7BCA1EF9C29A00A8E9ED /* ugc_translator.cpp in Sources */,
6753406C1A3F2A7400A0A8C3 /* feature_generator.cpp in Sources */,
@@ -786,6 +817,7 @@
E162BD22213E8F09007ADEF1 /* region_info_collector.cpp in Sources */,
34F558791DBF4C7800A4FC11 /* booking_quality_check.cpp in Sources */,
6753407E1A3F2A7400A0A8C3 /* osm2type.cpp in Sources */,
+ 56829A482134222300A09A28 /* city_roads_generator.cpp in Sources */,
568762601F6A9B18002C22A6 /* transit_generator.cpp in Sources */,
675340601A3F2A7400A0A8C3 /* check_model.cpp in Sources */,
675340851A3F2A7400A0A8C3 /* tesselator.cpp in Sources */,
diff --git a/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj b/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj
index a635a13938..89910fca75 100644
--- a/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj
+++ b/xcode/generator_tool/generator_tool.xcodeproj/project.pbxproj
@@ -35,6 +35,8 @@
562147291F6AA37E002D2214 /* libmwm_diff.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 562147281F6AA37E002D2214 /* libmwm_diff.a */; };
562D42941FD8460500A995F3 /* libugc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 562D42951FD8460500A995F3 /* libugc.a */; };
562D42961FD8463700A995F3 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 670E7BC61EF992F600A8E9ED /* libsqlite3.tbd */; };
+ 56829A4C2134238800A09A28 /* cities_boundaries_checker_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56829A4A2134238700A09A28 /* cities_boundaries_checker_tests.cpp */; };
+ 56829A4D2134238800A09A28 /* city_roads_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56829A4B2134238800A09A28 /* city_roads_tests.cpp */; };
56EE14CD1FE803EA0036F20C /* libtransit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56EE14CE1FE803EA0036F20C /* libtransit.a */; };
56EE14CF1FE803FE0036F20C /* libtransit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56EE14D01FE803FE0036F20C /* libtransit.a */; };
670E7BBC1EF9832200A8E9ED /* libicu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 670E7BBB1EF9832200A8E9ED /* libicu.a */; };
@@ -218,6 +220,8 @@
562147261F6AA36A002D2214 /* libbsdiff.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbsdiff.a; path = ../bsdiff/build/Debug/libbsdiff.a; sourceTree = "<group>"; };
562147281F6AA37E002D2214 /* libmwm_diff.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmwm_diff.a; path = "../../../../Library/Developer/Xcode/DerivedData/omim-gsfdicnjgjjbizhdmwedavcucpok/Build/Products/Debug/libmwm_diff.a"; sourceTree = "<group>"; };
562D42951FD8460500A995F3 /* libugc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libugc.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 56829A4A2134238700A09A28 /* cities_boundaries_checker_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cities_boundaries_checker_tests.cpp; sourceTree = "<group>"; };
+ 56829A4B2134238800A09A28 /* city_roads_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = city_roads_tests.cpp; sourceTree = "<group>"; };
56EE14CE1FE803EA0036F20C /* libtransit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libtransit.a; sourceTree = BUILT_PRODUCTS_DIR; };
56EE14D01FE803FE0036F20C /* libtransit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libtransit.a; sourceTree = BUILT_PRODUCTS_DIR; };
670E7BBB1EF9832200A8E9ED /* libicu.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libicu.a; path = "../../../../Library/Developer/Xcode/DerivedData/omim-gzleizqujktwggdwiejzkgjrsgvp/Build/Products/Debug/libicu.a"; sourceTree = "<group>"; };
@@ -488,6 +492,8 @@
isa = PBXGroup;
children = (
4491F490213D46380011834F /* speed_cameras_test.cpp */,
+ 56829A4A2134238700A09A28 /* cities_boundaries_checker_tests.cpp */,
+ 56829A4B2134238800A09A28 /* city_roads_tests.cpp */,
671ED3BC20D4098100D4317E /* altitude_test.cpp */,
679624B31D102D3300AE4E3C /* booking_test.cpp */,
6726C1E31A4C28D5005EEA39 /* check_mwms.cpp */,
@@ -729,9 +735,11 @@
67AB92D01B75156400AB5194 /* coasts_test.cpp in Sources */,
670F291B1BA6CE4F00F2ABF4 /* check_mwms.cpp in Sources */,
67AB92D91B75158300AB5194 /* osm_o5m_source_test.cpp in Sources */,
+ 56829A4D2134238800A09A28 /* city_roads_tests.cpp in Sources */,
67AB92D61B75157700AB5194 /* tesselator_test.cpp in Sources */,
671ED3C420D4098100D4317E /* road_access_test.cpp in Sources */,
4491F494213D6B470011834F /* speed_cameras_test.cpp in Sources */,
+ 56829A4C2134238800A09A28 /* cities_boundaries_checker_tests.cpp in Sources */,
6726C2411A4C2D9F005EEA39 /* testingmain.cpp in Sources */,
670E7BC51EF9860100A8E9ED /* ugc_test.cpp in Sources */,
4491F495213D6B7C0011834F /* booking_test.cpp in Sources */,
diff --git a/xcode/routing/routing.xcodeproj/project.pbxproj b/xcode/routing/routing.xcodeproj/project.pbxproj
index ac2fe9b2ff..aae0529ad6 100644
--- a/xcode/routing/routing.xcodeproj/project.pbxproj
+++ b/xcode/routing/routing.xcodeproj/project.pbxproj
@@ -89,6 +89,7 @@
56290B87206A3232003892E0 /* routing_algorithm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56290B85206A3231003892E0 /* routing_algorithm.cpp */; };
56290B88206A3232003892E0 /* routing_algorithm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56290B86206A3231003892E0 /* routing_algorithm.hpp */; };
562BDE2020D14860008EFF6F /* routing_callbacks.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 562BDE1F20D14860008EFF6F /* routing_callbacks.hpp */; };
+ 56332AD52134243800B85DF8 /* city_roads_serialization.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56332AD42134243800B85DF8 /* city_roads_serialization.hpp */; };
56555E561D897C90009D786D /* libalohalitics.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6742ACE61C68A23B009CB89E /* libalohalitics.a */; };
56555E581D897C9D009D786D /* liboauthcpp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6742ACFA1C68A2D7009CB89E /* liboauthcpp.a */; };
56555E591D897D28009D786D /* testingmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6742ACDE1C68A13F009CB89E /* testingmain.cpp */; };
@@ -369,6 +370,7 @@
56290B85206A3231003892E0 /* routing_algorithm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = routing_algorithm.cpp; sourceTree = "<group>"; };
56290B86206A3231003892E0 /* routing_algorithm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_algorithm.hpp; sourceTree = "<group>"; };
562BDE1F20D14860008EFF6F /* routing_callbacks.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_callbacks.hpp; sourceTree = "<group>"; };
+ 56332AD42134243800B85DF8 /* city_roads_serialization.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = city_roads_serialization.hpp; sourceTree = "<group>"; };
5661A5CD20DE51C500C6B1D1 /* tools.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tools.hpp; sourceTree = "<group>"; };
567059591F3AF96D0062672D /* checkpoint_predictor_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = checkpoint_predictor_test.cpp; sourceTree = "<group>"; };
5670595B1F3AF97F0062672D /* checkpoint_predictor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = checkpoint_predictor.cpp; sourceTree = "<group>"; };
@@ -783,6 +785,7 @@
children = (
44E5574B2136EED000B01439 /* speed_camera_ser_des.cpp */,
44E557492136EEC800B01439 /* speed_camera_ser_des.hpp */,
+ 56332AD42134243800B85DF8 /* city_roads_serialization.hpp */,
562BDE1F20D14860008EFF6F /* routing_callbacks.hpp */,
56FA20461FBF23A90045DE78 /* cross_mwm_ids.hpp */,
40BEC0801F99FFD600E06CA4 /* transit_info.hpp */,
@@ -986,6 +989,7 @@
56EA2FD51D8FD8590083F01A /* routing_helpers.hpp in Headers */,
0C15B8021F02A61B0058E253 /* checkpoints.hpp in Headers */,
0C5F5D211E798B0400307B98 /* cross_mwm_connector_serialization.hpp in Headers */,
+ 56332AD52134243800B85DF8 /* city_roads_serialization.hpp in Headers */,
0C0DF9221DE898B70055A22F /* index_graph_starter.hpp in Headers */,
56290B88206A3232003892E0 /* routing_algorithm.hpp in Headers */,
40A111CE1F2F6776005E6AD5 /* route_weight.hpp in Headers */,