From 1d10e25761e5aa4d9ed32700517f20b7134e8340 Mon Sep 17 00:00:00 2001 From: Yannik Bloscheck Date: Sat, 10 Jan 2026 18:26:57 +0100 Subject: [PATCH] Adding general support for subtypes (and switching charging stations to using it) Signed-off-by: Yannik Bloscheck --- android/sdk/src/main/assets/subtypes.csv | 1 + data/subtypes.csv | 2 + generator/osm2type.cpp | 12 +- iphone/Maps/Maps.xcodeproj/project.pbxproj | 4 + libs/indexer/CMakeLists.txt | 2 + libs/indexer/feature_data.cpp | 23 +--- libs/indexer/feature_visibility.cpp | 4 + libs/indexer/ftypes_matcher.cpp | 6 - libs/indexer/ftypes_matcher.hpp | 8 -- libs/indexer/ftypes_subtypes.cpp | 94 ++++++++++++++ libs/indexer/ftypes_subtypes.hpp | 122 ++++++++++++++++++ libs/indexer/map_object.cpp | 4 +- .../indexer/indexer.xcodeproj/project.pbxproj | 12 ++ 13 files changed, 258 insertions(+), 36 deletions(-) create mode 120000 android/sdk/src/main/assets/subtypes.csv create mode 100644 data/subtypes.csv create mode 100644 libs/indexer/ftypes_subtypes.cpp create mode 100644 libs/indexer/ftypes_subtypes.hpp diff --git a/android/sdk/src/main/assets/subtypes.csv b/android/sdk/src/main/assets/subtypes.csv new file mode 120000 index 000000000..cfe9a20db --- /dev/null +++ b/android/sdk/src/main/assets/subtypes.csv @@ -0,0 +1 @@ +../../../../../data/subtypes.csv \ No newline at end of file diff --git a/data/subtypes.csv b/data/subtypes.csv new file mode 100644 index 000000000..9aa1d4fd9 --- /dev/null +++ b/data/subtypes.csv @@ -0,0 +1,2 @@ +Types;Related Subtypes +amenity|charging_station;amenity|charging_station|motorcar,amenity|charging_station|motorcycle,amenity|charging_station|bicycle,amenity|charging_station|small,amenity|charging_station|carless \ No newline at end of file diff --git a/generator/osm2type.cpp b/generator/osm2type.cpp index 182059ff7..364713ad9 100644 --- a/generator/osm2type.cpp +++ b/generator/osm2type.cpp @@ -11,6 +11,7 @@ #include "indexer/classificator.hpp" #include "indexer/feature_impl.hpp" #include "indexer/ftypes_matcher.hpp" +#include "indexer/ftypes_subtypes.hpp" #include "platform/platform.hpp" @@ -351,9 +352,11 @@ private: // - both amenity-charging_station-motorcar and amenity-charging_station-bicycle are left; void LeaveLongestTypes(std::vector & matchedTypes) { - auto const isChargingStation = [](auto const & lhs, auto const & rhs) + // Prevents types, that either have subtypes or are subtypes, from being removed + auto subtypes = ftypes::Subtypes::Instance(); + auto const hasSubtypeRelatedTypes = [subtypes](auto const & lhs, auto const & rhs) { - return lhs.size() > 1 && rhs.size() > 1 && lhs.at(1) == "charging_station" && rhs.at(1) == "charging_station" && lhs.at(0) == "amenity" && rhs.at(0) == "amenity"; + return subtypes.IsPathOfTypeWithSubtypesOrSubtype(lhs) || subtypes.IsPathOfTypeWithSubtypesOrSubtype(rhs); }; auto const equalPrefix = [](auto const & lhs, auto const & rhs) @@ -374,9 +377,10 @@ void LeaveLongestTypes(std::vector & matchedTypes) return lhs < rhs; }; - auto const isEqual = [&equalPrefix, &isChargingStation](auto const & lhs, auto const & rhs) + // `true` means it will be deleted, because being equal means it isn't unique + auto const isEqual = [&equalPrefix, &hasSubtypeRelatedTypes](auto const & lhs, auto const & rhs) { - if (isChargingStation(lhs, rhs)) + if (hasSubtypeRelatedTypes(lhs, rhs)) return false; if (equalPrefix(lhs, rhs)) diff --git a/iphone/Maps/Maps.xcodeproj/project.pbxproj b/iphone/Maps/Maps.xcodeproj/project.pbxproj index 7657604cc..04cd96cd6 100644 --- a/iphone/Maps/Maps.xcodeproj/project.pbxproj +++ b/iphone/Maps/Maps.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 270C9C282E16AB6F00ABA688 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 270C9C252E16AB6300ABA688 /* Profile.swift */; }; 27176A862E65B0150015F25F /* Icon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 27176A852E65B0150015F25F /* Icon.icon */; }; 27176A8A2E65B01B0015F25F /* Debug Icon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 27176A892E65B01B0015F25F /* Debug Icon.icon */; }; + 272CA4492F127221005A3F5B /* subtypes.csv in Resources */ = {isa = PBXBuildFile; fileRef = 272CA4482F127221005A3F5B /* subtypes.csv */; }; 272F1F392E0EE09000FA52EF /* ExistingProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272F1F382E0EE08A00FA52EF /* ExistingProfileView.swift */; }; 272F1F3B2E0EE0A300FA52EF /* NoExistingProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272F1F3A2E0EE09500FA52EF /* NoExistingProfileView.swift */; }; 272F1F3D2E0EE0C800FA52EF /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272F1F3C2E0EE0C400FA52EF /* ProfileView.swift */; }; @@ -764,6 +765,7 @@ 270C9C252E16AB6300ABA688 /* Profile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Profile.swift; sourceTree = ""; }; 27176A852E65B0150015F25F /* Icon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = Icon.icon; sourceTree = ""; }; 27176A892E65B01B0015F25F /* Debug Icon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = "Debug Icon.icon"; sourceTree = ""; }; + 272CA4482F127221005A3F5B /* subtypes.csv */ = {isa = PBXFileReference; lastKnownFileType = text; name = subtypes.csv; path = ../../data/subtypes.csv; sourceTree = SOURCE_ROOT; }; 272F1F382E0EE08A00FA52EF /* ExistingProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExistingProfileView.swift; sourceTree = ""; }; 272F1F3A2E0EE09500FA52EF /* NoExistingProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoExistingProfileView.swift; sourceTree = ""; }; 272F1F3C2E0EE0C400FA52EF /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; @@ -3954,6 +3956,7 @@ F623DA6A1C9C2731006A3436 /* opening_hours_how_to_edit.html */, FA85F632145DDDC20090E1A0 /* packed_polygons.bin */, 451950391B7A3E070085DA05 /* patterns.txt */, + 272CA4482F127221005A3F5B /* subtypes.csv */, FAAEA7D0161BD26600CCD661 /* synonyms.txt */, BB25B1A51FB32767007276FA /* transit_colors.txt */, FA64D9A813F975AD00350ECF /* types.txt */, @@ -4281,6 +4284,7 @@ 34AB66681FC5AA330078E451 /* TransportTransitPedestrian.xib in Resources */, F6D67CDE2062BBA60032FD38 /* MWMBCCreateCategoryAlert.xib in Resources */, 3490D2E31CE9DD2500D0B838 /* MWMSideButtonsView.xib in Resources */, + 272CA4492F127221005A3F5B /* subtypes.csv in Resources */, F6E2FE2E1E097BA00083EBEC /* MWMStreetEditorEditTableViewCell.xib in Resources */, 3463BA691DE81DB90082417F /* MWMTrafficButtonViewController.xib in Resources */, F623DA6C1C9C2731006A3436 /* opening_hours_how_to_edit.html in Resources */, diff --git a/libs/indexer/CMakeLists.txt b/libs/indexer/CMakeLists.txt index b5e53f119..64390a383 100644 --- a/libs/indexer/CMakeLists.txt +++ b/libs/indexer/CMakeLists.txt @@ -88,6 +88,8 @@ set(SRC ftraits.hpp ftypes_matcher.cpp ftypes_matcher.hpp + ftypes_subtypes.cpp + ftypes_subtypes.hpp house_to_street_iface.hpp index_builder.cpp index_builder.hpp diff --git a/libs/indexer/feature_data.cpp b/libs/indexer/feature_data.cpp index 8d22bf1cc..b51956a63 100644 --- a/libs/indexer/feature_data.cpp +++ b/libs/indexer/feature_data.cpp @@ -3,6 +3,7 @@ #include "indexer/classificator.hpp" #include "indexer/feature.hpp" #include "indexer/ftypes_matcher.hpp" +#include "indexer/ftypes_subtypes.hpp" #include "base/assert.hpp" #include "base/macros.hpp" @@ -191,25 +192,13 @@ void TypesHolder::SortBySpec() auto const getPriority = [&cl](uint32_t type) { return cl.GetObject(type)->GetMaxOverlaysPriority(); }; auto const & checker = UselessTypesChecker::Instance(); - auto const & isChargingStationChecker = ftypes::IsCharingStationChecker::Instance(); - auto const & isChargingStationSmallChecker = ftypes::IsCharingStationSmallChecker::Instance(); + auto const & subtypes = ftypes::Subtypes::Instance(); - std::stable_sort(begin(), end(), [&checker, &getPriority, &isChargingStationChecker, &isChargingStationSmallChecker](uint32_t t1, uint32_t t2) + std::stable_sort(begin(), end(), [&checker, &getPriority, &subtypes](uint32_t t1, uint32_t t2) { - if (isChargingStationChecker(t1) && isChargingStationChecker(t2)) - { - if (isChargingStationSmallChecker(t1) && !isChargingStationSmallChecker(t2)) - return false; - else if (!isChargingStationSmallChecker(t1) && isChargingStationSmallChecker(t2)) - return true; - - uint8_t const t1Level = ftype::GetLevel(t1); - uint8_t const t2Level = ftype::GetLevel(t2); - if (t1Level == 2 && t2Level != 2) - return true; - else if (t1Level != 2 && t2Level == 2) - return false; - } + std::optional const comaprisonResultBasedOnTypeRelation = subtypes.ComaprisonResultBasedOnTypeRelation(t1, t2); + if (comaprisonResultBasedOnTypeRelation.has_value()) + return comaprisonResultBasedOnTypeRelation.value(); int const p1 = getPriority(t1); int const p2 = getPriority(t2); diff --git a/libs/indexer/feature_visibility.cpp b/libs/indexer/feature_visibility.cpp index fff888730..ad309f24f 100644 --- a/libs/indexer/feature_visibility.cpp +++ b/libs/indexer/feature_visibility.cpp @@ -5,6 +5,7 @@ #include "indexer/feature.hpp" #include "indexer/feature_data.hpp" #include "indexer/ftypes_matcher.hpp" +#include "indexer/ftypes_subtypes.hpp" #include "indexer/scales.hpp" #include "base/assert.hpp" @@ -135,6 +136,9 @@ bool TypeAlwaysExists(uint32_t type, GeomType geomType = GeomType::Undefined) if (IsUsefulStandaloneType(type, geomType)) return true; + if (ftypes::Subtypes::Instance().IsTypeWithSubtypesOrSubtype(type)) + return true; + uint8_t const typeLevel = ftype::GetLevel(type); ftype::TruncValue(type, 1); diff --git a/libs/indexer/ftypes_matcher.cpp b/libs/indexer/ftypes_matcher.cpp index bec8dfc88..63aab23f2 100644 --- a/libs/indexer/ftypes_matcher.cpp +++ b/libs/indexer/ftypes_matcher.cpp @@ -753,12 +753,6 @@ IsDirectionalChecker::IsDirectionalChecker() : ftypes::BaseChecker(1 /* level */ m_types.push_back(c.GetTypeByPath({"lateral"})); } -IsCharingStationChecker::IsCharingStationChecker() : ftypes::BaseChecker(2 /* level */) -{ - Classificator const & c = classif(); - m_types.push_back(c.GetTypeByPath({"amenity", "charging_station"})); -} - IsCharingStationCarChecker::IsCharingStationCarChecker() : ftypes::BaseChecker(3 /* level */) { Classificator const & c = classif(); diff --git a/libs/indexer/ftypes_matcher.hpp b/libs/indexer/ftypes_matcher.hpp index ed036a26f..f36dac6ed 100644 --- a/libs/indexer/ftypes_matcher.hpp +++ b/libs/indexer/ftypes_matcher.hpp @@ -519,14 +519,6 @@ public: DECLARE_CHECKER_INSTANCE(IsDirectionalChecker); }; -class IsCharingStationChecker : public ftypes::BaseChecker -{ - IsCharingStationChecker(); - -public: - DECLARE_CHECKER_INSTANCE(IsCharingStationChecker); -}; - class IsCharingStationCarChecker : public ftypes::BaseChecker { IsCharingStationCarChecker(); diff --git a/libs/indexer/ftypes_subtypes.cpp b/libs/indexer/ftypes_subtypes.cpp new file mode 100644 index 000000000..0643d62fb --- /dev/null +++ b/libs/indexer/ftypes_subtypes.cpp @@ -0,0 +1,94 @@ +#include "indexer/ftypes_subtypes.hpp" + +#include "base/assert.hpp" +#include "coding/csv_reader.hpp" +#include "indexer/classificator.hpp" +#include "platform/platform.hpp" + +namespace ftypes +{ + /// Constructor + Subtypes::Subtypes() + { + auto const & classificator = classif(); + + // Get the actual path to the CSV file. + Platform & platform = GetPlatform(); + string const filePath = platform.ReadPathForFile("subtypes.csv"); + + // Load the CSV file and go through the lines of it one by one. + for (auto const & columns : coding::CSVRunner(coding::CSVReader(filePath, true, ';'))) + { + // Skip empty lines. + if (columns.empty()) + continue; + + // There only should be two columns. + if (columns.size() != 2) + { + ASSERT(false, ("Parsing of subtypes file: Invalid columns \"", columns, "\"")); + break; + } + + // Parse the column. The first column has the type definitions(s) and the second one has the associated subtype definitions(s). + vector types; + vector subtypes; + for (int columnIndex = 0; columnIndex < 2; columnIndex++) { + string_view const column = columns[columnIndex]; + + // Separate the different type definitions by the `,`. There needs to be at least one. + vector const typeDefinitions = strings::Tokenize(column, ","); + if (typeDefinitions.size() < 1) + { + ASSERT(columnIndex != 0, ("Parsing of subtypes file: Invalid or missing types definition \"", column, "\"")); + ASSERT(columnIndex == 0, ("Parsing of subtypes file: Invalid or missing subtypes definition \"", column, "\"")); + break; + } + + // Parse the type definitions and convert them to actual types. Invalid types are getting skipped. + vector typesInColumn; + for (auto typeDefinition : typeDefinitions) + { + vector const typePath = strings::Tokenize(typeDefinition, "|"); + uint32_t const type = classificator.GetTypeByPathSafe(typePath); + if (type != IndexAndTypeMapping::INVALID_TYPE) + { + typesInColumn.push_back(type); + + vector typesAndSubtypesPath(typePath.begin(), typePath.end()); + if (find(m_typesAndSubtypesPaths.begin(), m_typesAndSubtypesPaths.end(), typesAndSubtypesPath) == m_typesAndSubtypesPaths.end()) + m_typesAndSubtypesPaths.push_back(typesAndSubtypesPath); + } + else + { + ASSERT(columnIndex != 0, ("Parsing of subtypes file: Invalid type \"", typeDefinition, "\"")); + ASSERT(columnIndex == 0, ("Parsing of subtypes file: Invalid subtype \"", typeDefinition, "\"")); + } + } + + if (columnIndex == 0) + types = typesInColumn; + else + subtypes = typesInColumn; + } + + for (auto type : types) + { + m_types.insert(type); + m_typesWithSubtypes[type] = subtypes; + } + + for (auto subtype : subtypes) + { + m_subtypes.insert(subtype); + } + } + } + + /// Static instance + Subtypes const & Subtypes::Instance() + { + static Subtypes instance; + return instance; + } +} // namespace ftypes diff --git a/libs/indexer/ftypes_subtypes.hpp b/libs/indexer/ftypes_subtypes.hpp new file mode 100644 index 000000000..b50032600 --- /dev/null +++ b/libs/indexer/ftypes_subtypes.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include + +namespace ftypes +{ + using namespace std; + + class Subtypes + { + public: + /// Static instance + static Subtypes const & Instance(); + + /** + * Checks if the given type is a type with subtypes or a subtype + * @param type The type to check + * @return `true` if it is a type with subtypes or a subtype, otherwise `false` + */ + bool IsTypeWithSubtypesOrSubtype(uint32_t const type) const + { + return IsTypeWithSubtypes(type) || IsSubtype(type); + } + + /** + * Checks if the given type is a type with subtypes + * @param type The type to check + * @return `true` if it is a type with subtypes, otherwise `false` + */ + bool IsTypeWithSubtypes(uint32_t const type) const + { + return find(m_types.begin(), m_types.end(), type) != m_types.end(); + } + + /** + * Checks if the given type is a subtype + * @param type The type to check + * @return `true` if it is a subtype, otherwise `false` + */ + bool IsSubtype(uint32_t const type) const + { + return find(m_subtypes.begin(), m_subtypes.end(), type) != m_subtypes.end(); + } + + /** + * Checks if the given type is a subtype of a given parent type + * @param type The type to check + * @param parentType The possible parent type + * @return `true` if it is a subtype of the parent type, otherwise `false` + */ + bool IsSubtypeOfParentType(uint32_t const type, uint32_t const parentType) const + { + auto position = m_typesWithSubtypes.find(parentType); + if (position != m_typesWithSubtypes.end()) { + vector subtypes = position->second; + return find(subtypes.begin(), subtypes.end(), type) != subtypes.end(); + } + + return false; + } + + /** + * Compares to given types based on their type relation + * @param firstType The first type to compare + * @param secondType The type to compare + * @return `true` if the first type is a subtype but the second one isn't, `false` if it is the other way around + */ + optional ComaprisonResultBasedOnTypeRelation(uint32_t const firstType, uint32_t const secondType) const + { + bool const firstTypeIsSubtype = IsSubtype(firstType); + bool const secondTypeIsSubtype = IsSubtype(secondType); + if (!firstTypeIsSubtype && !secondTypeIsSubtype) + return {}; + else if (firstTypeIsSubtype && !secondTypeIsSubtype) + return false; + else if (!firstTypeIsSubtype && secondTypeIsSubtype) + return true; + + // If they got to here, both are subtypes. So use the order of the subtypes for the comparison. + for (auto [types, subtypes] : m_typesWithSubtypes) + { + for (auto const subtype : subtypes) + { + if (subtype == firstType) + return true; + else if (subtype == secondType) + return false; + } + } + + return {}; + } + + /** + * Checks if the given type path belongs to a type with subtypes or a subtype + * @param typePath The type path to check + * @return `true` if it is a type with subtypes or a subtype, otherwise `false` + */ + bool IsPathOfTypeWithSubtypesOrSubtype(vector const typePath) const + { + return find(m_typesAndSubtypesPaths.begin(), m_typesAndSubtypesPaths.end(), typePath) != m_typesAndSubtypesPaths.end(); + } + + private: + /// Constructor + Subtypes(); + + /// Types, which have subtypes, as unordered set for faster check performance + unordered_set m_types; + + /// Subypes as unordered set for faster check performance + unordered_set m_subtypes; + + /// Types with their associated subtypes + map> m_typesWithSubtypes; + + /// Paths of types, which have subtypes, and subtypes for the generator + vector> m_typesAndSubtypesPaths; + }; +} // namespace ftypes diff --git a/libs/indexer/map_object.cpp b/libs/indexer/map_object.cpp index 87c0aa990..63e21e324 100644 --- a/libs/indexer/map_object.cpp +++ b/libs/indexer/map_object.cpp @@ -3,6 +3,7 @@ #include "indexer/feature.hpp" #include "indexer/feature_algo.hpp" #include "indexer/ftypes_matcher.hpp" +#include "indexer/ftypes_subtypes.hpp" #include "indexer/road_shields_parser.hpp" #include "geometry/mercator.hpp" @@ -119,6 +120,7 @@ std::string MapObject::GetLocalizedAllTypes(bool withMainType) const copy.SortBySpec(); auto const & isPoi = ftypes::IsPoiChecker::Instance(); + auto const & subtypes = ftypes::Subtypes::Instance(); auto const & isDirectional = ftypes::IsDirectionalChecker::Instance(); auto const & amenityChecker = ftypes::IsAmenityChecker::Instance(); auto const & charingStationCarChecker = ftypes::IsCharingStationCarChecker::Instance(); @@ -141,7 +143,7 @@ std::string MapObject::GetLocalizedAllTypes(bool withMainType) const } // Ignore types that are not POI - if (!isMainType && !isPoi(type) && !isDirectional(type)) + if (!isMainType && !isPoi(type) && !subtypes.IsTypeWithSubtypesOrSubtype(type) && !isDirectional(type)) continue; // Ignore general amenity diff --git a/xcode/indexer/indexer.xcodeproj/project.pbxproj b/xcode/indexer/indexer.xcodeproj/project.pbxproj index 6acd3593f..d305b0d15 100644 --- a/xcode/indexer/indexer.xcodeproj/project.pbxproj +++ b/xcode/indexer/indexer.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 272CA4462F126795005A3F5B /* ftypes_subtypes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 272CA4442F126795005A3F5B /* ftypes_subtypes.hpp */; }; + 272CA4472F126795005A3F5B /* ftypes_subtypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 272CA4452F126795005A3F5B /* ftypes_subtypes.cpp */; }; + 272CA44D2F12723B005A3F5B /* subtypes.csv in Resources */ = {isa = PBXBuildFile; fileRef = 272CA44C2F12723B005A3F5B /* subtypes.csv */; }; 27BCD5272E93E625002C50F0 /* feature_charge_sockets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27BCD5262E93E625002C50F0 /* feature_charge_sockets.cpp */; }; 27BCD5282E93E625002C50F0 /* feature_charge_sockets.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 27BCD5252E93E625002C50F0 /* feature_charge_sockets.hpp */; }; 27BCD52A2E93E670002C50F0 /* feature_charge_sockets_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27BCD5292E93E670002C50F0 /* feature_charge_sockets_test.cpp */; }; @@ -230,6 +233,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 272CA4442F126795005A3F5B /* ftypes_subtypes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ftypes_subtypes.hpp; sourceTree = ""; }; + 272CA4452F126795005A3F5B /* ftypes_subtypes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ftypes_subtypes.cpp; sourceTree = ""; }; + 272CA44C2F12723B005A3F5B /* subtypes.csv */ = {isa = PBXFileReference; lastKnownFileType = text; name = subtypes.csv; path = ../../data/subtypes.csv; sourceTree = ""; }; 27BCD5252E93E625002C50F0 /* feature_charge_sockets.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = feature_charge_sockets.hpp; sourceTree = ""; }; 27BCD5262E93E625002C50F0 /* feature_charge_sockets.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = feature_charge_sockets.cpp; sourceTree = ""; }; 27BCD5292E93E670002C50F0 /* feature_charge_sockets_test.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = feature_charge_sockets_test.cpp; sourceTree = ""; }; @@ -499,6 +505,7 @@ 3496AB9C1DC1FA5200C5DDBA /* drules_proto.bin */, 3496ABA21DC1FA7200C5DDBA /* editor.config */, 3496ABAE1DC1FAC900C5DDBA /* minsk-pass.mwm */, + 272CA44C2F12723B005A3F5B /* subtypes.csv */, 3496AB961DC1FA2000C5DDBA /* types.txt */, ); name = Resources; @@ -689,6 +696,8 @@ 3D74ABBB1EA67C1E0063A898 /* ftypes_mapping.hpp */, 675340D51A3F540F00A0A8C3 /* ftypes_matcher.cpp */, 675340D61A3F540F00A0A8C3 /* ftypes_matcher.hpp */, + 272CA4452F126795005A3F5B /* ftypes_subtypes.cpp */, + 272CA4442F126795005A3F5B /* ftypes_subtypes.hpp */, 675340DB1A3F540F00A0A8C3 /* index_builder.cpp */, 675340DC1A3F540F00A0A8C3 /* index_builder.hpp */, 675340DF1A3F540F00A0A8C3 /* interval_index_builder.hpp */, @@ -815,6 +824,7 @@ 675341411A3F540F00A0A8C3 /* scales.hpp in Headers */, 675341321A3F540F00A0A8C3 /* interval_index_builder.hpp in Headers */, 40009062201F5CB000963E18 /* cell_value_pair.hpp in Headers */, + 272CA4462F126795005A3F5B /* ftypes_subtypes.hpp in Headers */, 347F337C1C454242009758CC /* rank_table.hpp in Headers */, 40D62CEF23F2E8BE009A20F5 /* dat_section_header.hpp in Headers */, F61F83071E4B187500B37B7A /* road_shields_parser.hpp in Headers */, @@ -935,6 +945,7 @@ 3496ABA31DC1FA7200C5DDBA /* editor.config in Resources */, 3496AB9D1DC1FA5200C5DDBA /* drules_proto_clear.bin in Resources */, 3496AB9E1DC1FA5200C5DDBA /* drules_proto_dark.bin in Resources */, + 272CA44D2F12723B005A3F5B /* subtypes.csv in Resources */, FA67C84F26BB36D700B33DCA /* categories_brands.txt in Resources */, FA67C84626BB356800B33DCA /* categories_cuisines.txt in Resources */, 3496ABA11DC1FA5200C5DDBA /* drules_proto.bin in Resources */, @@ -1027,6 +1038,7 @@ 4043C0B924ACBA3300545FD8 /* transliteration_loader.cpp in Sources */, 6753411C1A3F540F00A0A8C3 /* shared_load_info.cpp in Sources */, 67BC92F41D21476500A4A378 /* string_slice.cpp in Sources */, + 272CA4472F126795005A3F5B /* ftypes_subtypes.cpp in Sources */, BBB7060F23E46E0100A7F29A /* isolines_info.cpp in Sources */, 408FE47724FEB95600F5D06D /* metadata_serdes.cpp in Sources */, 34583BCB1C88552100F94664 /* map_object.cpp in Sources */,