Compare commits

...

5 Commits

Author SHA1 Message Date
map-per
21c9a58173 fix: don't return reference to object that goes out of scope
Signed-off-by: map-per <map-per@gmx.de>
2025-12-17 15:22:06 +01:00
map-per
8007c0df53 review fixes
Signed-off-by: map-per <map-per@gmx.de>
2025-12-17 15:05:09 +01:00
map-per
02ac1d8977 fix vending=public_transport_tickets in editor.config
Signed-off-by: map-per <map-per@gmx.de>
2025-12-17 15:05:08 +01:00
Yannik Bloscheck
3c2e77f59e [iOS] Added new editor files to their Xcode projects
Signed-off-by: Yannik Bloscheck <git@yannikbloscheck.com>
2025-12-17 15:05:08 +01:00
map-per
c1760bbc37 [editor] Support complex POI types in the editor (#2855)
Signed-off-by: map-per <map-per@gmx.de>
2025-12-17 15:05:08 +01:00
12 changed files with 505 additions and 98 deletions

View File

@@ -0,0 +1 @@
../../../../../data/mapcss-mapping.csv
1 ../../../../../data/mapcss-mapping.csv

View File

@@ -394,32 +394,25 @@
<type id="amenity-pharmacy" group="shop">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-buddhist" can_add="no">
<type id="amenity-place_of_worship-buddhist">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-christian" can_add="no">
<type id="amenity-place_of_worship-christian">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-hindu" can_add="no">
<type id="amenity-place_of_worship-hindu">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-jewish" can_add="no">
<type id="amenity-place_of_worship-jewish">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-muslim" can_add="no">
<type id="amenity-place_of_worship-muslim">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-shinto" can_add="no">
<type id="amenity-place_of_worship-shinto">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="amenity-place_of_worship-taoist" can_add="no">
<type id="amenity-place_of_worship-taoist">
<include group="poi_internet" />
</type>
<type id="amenity-place_of_worship">
@@ -705,6 +698,9 @@
<type id="leisure-resort">
<include group="poi_internet" />
</type>
<type id="leisure-sports_centre-sport-swimming">
<include group="poi_internet" />
</type>
<type id="leisure-sports_centre">
<include group="poi_internet" />
</type>
@@ -1115,6 +1111,7 @@
<type id="tourism-artwork">
<include field="name" />
</type>
<!-- Not addable because OSM category is too broad and due to vandalism problems -->
<type id="tourism-attraction" can_add="no">
<include group="poi_internet" />
<!-- <include field="wikipedia" />-->
@@ -1144,26 +1141,22 @@
<include group="poi_internet" />
<include field="self_service" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="tourism-information-office" can_add="no">
<type id="tourism-information-office">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="tourism-information-visitor_centre" can_add="no">
<type id="tourism-information-visitor_centre">
<include group="poi_internet" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="tourism-information-board" can_add="no">
<type id="tourism-information-board">
<include field="name" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="tourism-information-map" can_add="no">
<type id="tourism-information-map">
<include field="name" />
</type>
<!-- Can not be added because it is a complex type -->
<type id="tourism-information-guidepost" can_add="no">
<type id="tourism-information-guidepost">
</type>
<type id="tourism-information">
<!-- Too generic to add -->
<type id="tourism-information" can_add="no">
<include group="poi" />
</type>
<type id="amenity-ranger_station">
@@ -1509,67 +1502,50 @@
<type id="leisure-escape_game">
<include group="poi_internet" />
</type>
<!-- Uncomment this after our editor core supports complex types
<type id="amenity-vending_machine-parking_tickets">
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-public_transport_tickets">
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-cigarettes">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="cigarettes" />
<include field="operator" />
</type>
<type id="amenity-vending_machine-coffee">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="coffee" />
<include field="operator" />
</type>
<type id="amenity-vending_machine-condoms">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="condoms" />
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-drinks">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="drinks" />
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-excrement_bags">
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-coffee">
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-condoms">
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-food">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="food" />
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-newspapers">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="newspapers" />
<include field="operator" />
<include field="level" />
</type>
<type id="amenity-vending_machine-sweets">
<tag k="amenity" v="vending_machine" />
<tag k="vending" v="sweets" />
<include field="operator" />
<include field="level" />
</type>
<type id="shop-car_repair-tyres">
<tag k="shop" v="car_repair" />
<tag k="service" v="tyres" />
<include group="poi_internet" />
<type id="amenity-vending_machine">
<include field="operator" />
<include field="level" />
</type>
<type id="leisure-sports_centre-climbing">
<tag k="leisure" v="sports_centre" />
<tag k="sport" v="climbing" />
<include group="poi_internet" />
</type>
<type id="leisure-sports_centre-shooting">
<tag k="leisure" v="sports_centre" />
<tag k="sport" v="shooting" />
<include group="poi_internet" />
</type>
<type id="leisure-sports_centre-swimming">
<tag k="leisure" v="sports_centre" />
<tag k="sport" v="swimming" />
<include group="poi_internet" />
</type>
<type id="leisure-sports_centre-yoga">
<tag k="leisure" v="sports_centre" />
<tag k="sport" v="yoga" />
<include group="poi_internet" />
</type-->
<!-- Not addable as mapping as a node is uncommon -->
<type id="natural-beach" can_add="no">
<include field="name" />

View File

@@ -5,7 +5,7 @@
# highway|bus_stop;[highway=bus_stop];;name;int_name;22;
# It contains:
# - type name: "highway|bus_stop" ("|" is converted to "-" internally)
# - mapcss selectors for tags: "[highway=bus_stop]", multiple selectors are separated with commas
# - mapcss selectors for tags: "[highway=bus_stop]", multiple selectors are separated with commas, best practice tagging for OSM editor is listed first
# - "x" for a deprecated type or an empty cell otherwise
# - primary title tag (usually "name")
# - secondary title tag (usually "int_name")
@@ -626,7 +626,7 @@ highway|trunk_link|tunnel;[highway=trunk_link][tunnel?];;name;int_name;503;
drinking_water|yes;[drinking_water=yes],[drinking_water=treated],[drinking_water:refill=yes];;;;504;
drinking_water|no;505;
amenity|sailing_school;[amenity=sailing_school],[education=sailing_school];;name;int_name;506;
amenity|flight_school;[amenity=sailing_school],[education=flight_school];;name;int_name;507;
amenity|flight_school;[amenity=flight_school],[education=flight_school];;name;int_name;507;
amenity|prep_school;[amenity=prep_school],[education=prep_school];;name;int_name;508;
amenity|car_pooling;509;
social_facility|soup_kitchen;510;
Can't render this file because it contains an unexpected character in line 7 and column 16.

View File

@@ -40,6 +40,7 @@
27AF18562E1DB63000CD41E2 /* PowerSavingMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27AF18552E1DB62F00CD41E2 /* PowerSavingMode.swift */; };
27AF18582E1DB63A00CD41E2 /* Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27AF18572E1DB63900CD41E2 /* Appearance.swift */; };
27AF185A2E1DB64500CD41E2 /* AnnouncingSpeedTrapsWhileVoiceRouting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27AF18592E1DB64400CD41E2 /* AnnouncingSpeedTrapsWhileVoiceRouting.swift */; };
27FDBF212EEEFC830045621D /* mapcss-mapping.csv in Resources */ = {isa = PBXBuildFile; fileRef = 27FDBF202EEEFC830045621D /* mapcss-mapping.csv */; };
3304306D21D4EAFB00317CA3 /* SearchCategoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3304306C21D4EAFB00317CA3 /* SearchCategoryCell.swift */; };
33046832219C57180041F3A8 /* CategorySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33046831219C57180041F3A8 /* CategorySettingsViewController.swift */; };
337F98A621D37B7400C8AC27 /* SearchTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 337F98A521D37B7400C8AC27 /* SearchTabViewController.swift */; };
@@ -789,6 +790,7 @@
27AF18552E1DB62F00CD41E2 /* PowerSavingMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerSavingMode.swift; sourceTree = "<group>"; };
27AF18572E1DB63900CD41E2 /* Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Appearance.swift; sourceTree = "<group>"; };
27AF18592E1DB64400CD41E2 /* AnnouncingSpeedTrapsWhileVoiceRouting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncingSpeedTrapsWhileVoiceRouting.swift; sourceTree = "<group>"; };
27FDBF202EEEFC830045621D /* mapcss-mapping.csv */ = {isa = PBXFileReference; lastKnownFileType = text; name = "mapcss-mapping.csv"; path = "/Users/yannikbloscheck/Apps/CoMaps/Code/data/mapcss-mapping.csv"; sourceTree = "<absolute>"; };
28A0AB4B0D9B1048005BE974 /* Maps_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Maps_Prefix.pch; sourceTree = "<group>"; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
29B97316FDCFA39411CA2CEA /* main.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; indentWidth = 2; path = main.mm; sourceTree = "<group>"; tabWidth = 2; };
30034C5C2B3F0B74005D961A /* az */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = az; path = az.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -3948,6 +3950,7 @@
6B9978341C89A316003B8AA0 /* editor.config */,
978D4A30199A11E600D72CA7 /* faq.html */,
BB7626B41E8559980031D71C /* icudt75l.dat */,
27FDBF202EEEFC830045621D /* mapcss-mapping.csv */,
F623DA6A1C9C2731006A3436 /* opening_hours_how_to_edit.html */,
FA85F632145DDDC20090E1A0 /* packed_polygons.bin */,
451950391B7A3E070085DA05 /* patterns.txt */,
@@ -4201,6 +4204,7 @@
34F73F9F1E082FF800AC1FD6 /* Localizable.strings in Resources */,
340E1EF21E2F614400CE49BF /* Main.storyboard in Resources */,
F6E2FE521E097BA00083EBEC /* MWMActionBarButton.xib in Resources */,
27FDBF212EEEFC830045621D /* mapcss-mapping.csv in Resources */,
EDBD68072B625724005DD151 /* LocationServicesDisabledAlert.xib in Resources */,
993DF0CA23F6BD0600AC231A /* ElevationDetailsViewController.xib in Resources */,
F623DA6F1C9C2E62006A3436 /* MWMAddPlaceNavigationBar.xib in Resources */,

View File

@@ -18,6 +18,8 @@ set(SRC
edits_migration.hpp
feature_matcher.cpp
feature_matcher.hpp
feature_type_to_osm.cpp
feature_type_to_osm.hpp
new_feature_categories.cpp
new_feature_categories.hpp
opening_hours_ui.cpp

View File

@@ -5,6 +5,7 @@ set(SRC
editor_config_test.cpp
editor_notes_test.cpp
feature_matcher_test.cpp
feature_type_to_osm_test.cpp
match_by_geometry_test.cpp
new_feature_categories_test.cpp
opening_hours_ui_test.cpp

View File

@@ -0,0 +1,224 @@
#include "testing/testing.hpp"
#include "editor/feature_type_to_osm.hpp"
#include "indexer/classificator.hpp"
#include "indexer/classificator_loader.hpp"
using namespace editor;
UNIT_TEST(simpleType)
{
std::string data =
"amenity|restaurant;61;\n"
"amenity|bicycle_parking;1071;\n";
classificator::Load();
TypeToOSMTranslator translator(false);
std::stringstream s(data);
translator.LoadFromStream(s);
uint32_t type = classif().GetTypeByReadableObjectName("amenity-restaurant");
std::vector<OSMTag> result = translator.OsmTagsFromType(type);
TEST_EQUAL(result.size(), 1, ());
TEST_EQUAL(result[0].key, "amenity", ());
TEST_EQUAL(result[0].value, "restaurant", ());
}
UNIT_TEST(simpleTypeWithTags)
{
std::string data =
"building;[building];;addr:housenumber;name;1;\n"
"amenity|school;[amenity=school],[education=school];;name;int_name;36;\n"
"amenity|doctors;[amenity=doctors][healthcare=doctor],[amenity=doctors],[healthcare=doctor];;name;int_name;207;\n";
classificator::Load();
TypeToOSMTranslator translator(false);
std::stringstream s(data);
translator.LoadFromStream(s);
uint32_t buildingType = classif().GetTypeByReadableObjectName("building");
std::vector<OSMTag> buildingResult = translator.OsmTagsFromType(buildingType);
TEST_EQUAL(buildingResult.size(), 1, ());
TEST_EQUAL(buildingResult[0].key, "building", ());
TEST_EQUAL(buildingResult[0].value, "yes", ());
uint32_t schoolType = classif().GetTypeByReadableObjectName("amenity-school");
std::vector<OSMTag> schoolResult = translator.OsmTagsFromType(schoolType);
TEST_EQUAL(schoolResult.size(), 1, ());
TEST_EQUAL(schoolResult[0].key, "amenity", ());
TEST_EQUAL(schoolResult[0].value, "school", ());
uint32_t doctorType = classif().GetTypeByReadableObjectName("amenity-doctors");
std::vector<OSMTag> doctorResult = translator.OsmTagsFromType(doctorType);
TEST_EQUAL(doctorResult.size(), 2, ());
TEST_EQUAL(doctorResult[0].key, "amenity", ());
TEST_EQUAL(doctorResult[0].value, "doctors", ());
TEST_EQUAL(doctorResult[1].key, "healthcare", ());
TEST_EQUAL(doctorResult[1].value, "doctor", ());
}
UNIT_TEST(complexType)
{
std::string data =
"building;[building];;addr:housenumber;name;1;\n"
" # comment that should be ignored\n"
"\n"
"amenity|restaurant;61;\n"
"tourism|information|office;[tourism=information][information=office];;name;int_name;313;\n"
"historic|castle|fortress;[historic=castle][castle_type=fortress],[historic=fortress];;name;int_name;1144;\n"
"#comment\n"
"amenity|place_of_worship|christian|mormon;[amenity=place_of_worship][religion=christian][denomination=mormon];;name;int_name;1572;\n";
classificator::Load();
TypeToOSMTranslator translator(false);
std::stringstream s(data);
translator.LoadFromStream(s);
uint32_t officeType = classif().GetTypeByReadableObjectName("tourism-information-office");
std::vector<OSMTag> officeResult = translator.OsmTagsFromType(officeType);
TEST_EQUAL(officeResult.size(), 2, ());
TEST_EQUAL(officeResult[0].key, "tourism", ());
TEST_EQUAL(officeResult[0].value, "information", ());
TEST_EQUAL(officeResult[1].key, "information", ());
TEST_EQUAL(officeResult[1].value, "office", ());
uint32_t fortressType = classif().GetTypeByReadableObjectName("historic-castle-fortress");
std::vector<OSMTag> fortressResult = translator.OsmTagsFromType(fortressType);
TEST_EQUAL(fortressResult.size(), 2, ());
TEST_EQUAL(fortressResult[0].key, "historic", ());
TEST_EQUAL(fortressResult[0].value, "castle", ());
TEST_EQUAL(fortressResult[1].key, "castle_type", ());
TEST_EQUAL(fortressResult[1].value, "fortress", ());
uint32_t mormonType = classif().GetTypeByReadableObjectName("amenity-place_of_worship-christian-mormon");
std::vector<OSMTag> mormonResult = translator.OsmTagsFromType(mormonType);
TEST_EQUAL(mormonResult.size(), 3, ());
TEST_EQUAL(mormonResult[0].key, "amenity", ());
TEST_EQUAL(mormonResult[0].value, "place_of_worship", ());
TEST_EQUAL(mormonResult[1].key, "religion", ());
TEST_EQUAL(mormonResult[1].value, "christian", ());
TEST_EQUAL(mormonResult[2].key, "denomination", ());
TEST_EQUAL(mormonResult[2].value, "mormon", ());
}
UNIT_TEST(mandatorySelector)
{
std::string data =
"amenity|parking|fee;[amenity=parking][fee];;name;int_name;125;\n"
"highway|track|bridge;[highway=track][bridge?];;name;int_name;193;\n"
"shop;[shop?];;name;int_name;943;\n"
"disusedbusiness;[disused:shop?],[disused:amenity=restaurant],[disused:amenity=fast_food],[disused:amenity=cafe],[disused:amenity=pub],[disused:amenity=bar];;;;1237;\n";
classificator::Load();
TypeToOSMTranslator translator(false);
std::stringstream s(data);
translator.LoadFromStream(s);
uint32_t parkingType = classif().GetTypeByReadableObjectName("amenity-parking-fee");
std::vector<OSMTag> parkingResult = translator.OsmTagsFromType(parkingType);
TEST_EQUAL(parkingResult.size(), 2, ());
TEST_EQUAL(parkingResult[0].key, "amenity", ());
TEST_EQUAL(parkingResult[0].value, "parking", ());
TEST_EQUAL(parkingResult[1].key, "fee", ());
TEST_EQUAL(parkingResult[1].value, "yes", ());
uint32_t trackType = classif().GetTypeByReadableObjectName("highway-track-bridge");
std::vector<OSMTag> trackResult = translator.OsmTagsFromType(trackType);
TEST_EQUAL(trackResult.size(), 2, ());
TEST_EQUAL(trackResult[0].key, "highway", ());
TEST_EQUAL(trackResult[0].value, "track", ());
TEST_EQUAL(trackResult[1].key, "bridge", ());
TEST_EQUAL(trackResult[1].value, "yes", ());
uint32_t shopType = classif().GetTypeByReadableObjectName("shop");
std::vector<OSMTag> shopResult = translator.OsmTagsFromType(shopType);
TEST_EQUAL(shopResult.size(), 1, ());
TEST_EQUAL(shopResult[0].key, "shop", ());
TEST_EQUAL(shopResult[0].value, "yes", ());
uint32_t disusedType = classif().GetTypeByReadableObjectName("disusedbusiness");
std::vector<OSMTag> disusedResult = translator.OsmTagsFromType(disusedType);
TEST_EQUAL(disusedResult.size(), 1, ());
TEST_EQUAL(disusedResult[0].key, "disused:shop", ());
TEST_EQUAL(disusedResult[0].value, "yes", ());
}
UNIT_TEST(forbiddenSelector)
{
std::string data =
"amenity|lounger;[amenity=lounger][!seasonal];;name;int_name;153;\n"
"amenity|charging_station|motorcar|small;[amenity=charging_station][motorcar?][!capacity],[amenity=charging_station][motorcar?][capacity=1],[amenity=charging_station][motorcar?][capacity=2];;name;int_name;201;\n";
classificator::Load();
TypeToOSMTranslator translator(false);
std::stringstream s(data);
translator.LoadFromStream(s);
uint32_t loungerType = classif().GetTypeByReadableObjectName("amenity-lounger");
std::vector<OSMTag> loungerResult = translator.OsmTagsFromType(loungerType);
TEST_EQUAL(loungerResult.size(), 1, ());
TEST_EQUAL(loungerResult[0].key, "amenity", ());
TEST_EQUAL(loungerResult[0].value, "lounger", ());
uint32_t chargingType = classif().GetTypeByReadableObjectName("amenity-charging_station-motorcar-small");
std::vector<OSMTag> chargingResult = translator.OsmTagsFromType(chargingType);
TEST_EQUAL(chargingResult.size(), 2, ());
TEST_EQUAL(chargingResult[0].key, "amenity", ());
TEST_EQUAL(chargingResult[0].value, "charging_station", ());
TEST_EQUAL(chargingResult[1].key, "motorcar", ());
TEST_EQUAL(chargingResult[1].value, "yes", ());
}
UNIT_TEST(ignoreComments)
{
std::string data =
"building;[building];;addr:housenumber;name;1;\n"
" # comment that should be ignored\n"
"\n"
"deprecated:waterway|riverbank:05.2024;52;x\n"
"amenity|restaurant;61;\n"
"moved:amenity|telephone:05.2024;122;amenity|telephone\n"
"natural|lake;564;natural|water|lake\n"; // moved type, should be ignored
classificator::Load();
TypeToOSMTranslator translator(false);
std::stringstream s(data);
translator.LoadFromStream(s);
}
UNIT_TEST(loadConfigFile)
{
TypeToOSMTranslator translator(false);
translator.LoadConfigFile();
size_t size = translator.GetStorage().size();
LOG(LINFO, ("Size of feature type storage:", size));
ASSERT(size > 1300, ());
ASSERT(size < 1700, ());
}
UNIT_TEST(testWithRealFile)
{
classificator::Load();
uint32_t restaurantType = classif().GetTypeByReadableObjectName("amenity-restaurant");
std::vector<OSMTag> restaurantResult = GetOSMTranslator().OsmTagsFromType(restaurantType);
TEST_EQUAL(restaurantResult.size(), 1, ());
TEST_EQUAL(restaurantResult[0].key, "amenity", ());
TEST_EQUAL(restaurantResult[0].value, "restaurant", ());
uint32_t officeType = classif().GetTypeByReadableObjectName("tourism-information-office");
std::vector<OSMTag> officeResult = GetOSMTranslator().OsmTagsFromType(officeType);
TEST_EQUAL(officeResult.size(), 2, ());
TEST_EQUAL(officeResult[0].key, "tourism", ());
TEST_EQUAL(officeResult[0].value, "information", ());
TEST_EQUAL(officeResult[1].key, "information", ());
TEST_EQUAL(officeResult[1].value, "office", ());
}

View File

@@ -0,0 +1,166 @@
#include "editor/feature_type_to_osm.hpp"
#include "base/assert.hpp"
#include "coding/reader_streambuf.hpp"
#include "indexer/classificator.hpp"
#include "platform/platform.hpp"
#include <string>
namespace editor
{
TypeToOSMTranslator::TypeToOSMTranslator(bool initialize)
{
if (initialize)
LoadConfigFile();
}
void TypeToOSMTranslator::LoadConfigFile()
{
Platform & p = GetPlatform();
std::unique_ptr<ModelReader> reader = p.GetReader("mapcss-mapping.csv");
ReaderStreamBuf buffer(std::move(reader));
std::istream s(&buffer);
LoadFromStream(s);
}
void TypeToOSMTranslator::LoadFromStream(std::istream & s)
{
m_storage.clear();
std::string line;
while (s.good())
{
getline(s, line);
strings::Trim(line);
// skip empty lines, comments, deprecated and moved types
if (line.empty() || line.front() == '#' || line.starts_with("deprecated") || line.starts_with("moved") ||
line.back() != ';')
continue;
std::vector<std::string_view> const rowTokens = strings::Tokenize(line, ";");
if (rowTokens.size() < 2)
{
ASSERT(false, ("Invalid feature type definition:", line));
continue;
}
// Get internal feature type
std::vector<std::string_view> const featureTypeTokens = strings::Tokenize(rowTokens[0], "|");
uint32_t const type = classif().GetTypeByPathSafe(featureTypeTokens);
ASSERT(type != IndexAndTypeMapping::INVALID_TYPE, ("Feature with invalid type:", line));
if (rowTokens.size() == 2)
{
// Derive OSM tags from type name
ASSERT(featureTypeTokens.size() <= 2, ("OSM tags can not be inferred from name:", line));
OSMTag osmTag;
// e.g. "amenity-restaurant"
if (featureTypeTokens.size() >= 2)
{
osmTag.key = featureTypeTokens[0];
osmTag.value = featureTypeTokens[1];
}
// e.g. "building"
else if (featureTypeTokens.size() == 1)
{
osmTag.key = featureTypeTokens[0];
osmTag.value = "yes";
}
m_storage.insert({type, {osmTag}});
}
else
{
// OSM tags are listed in the feature type entry
std::vector<std::string_view> const osmTagTokens = strings::Tokenize(rowTokens[1], ",");
// First entry is the best practice way to tag a feature
std::string_view const osmTagList = osmTagTokens[0];
// Process OSM tag list (e.g. "[tourism=information][information=office]")
std::vector<OSMTag> osmTags;
size_t pos = 0;
while ((pos = osmTagList.find('[', pos)) != std::string::npos)
{
size_t end = osmTagList.find(']', pos);
if (end == std::string::npos)
{
ASSERT(false, ("Bracket not closed in OSM tag:", line));
break;
}
std::string_view keyValuePair = osmTagList.substr(pos + 1, end - pos - 1);
if (keyValuePair.empty())
{
ASSERT(false, ("Key value pair is empty:", line));
break;
}
size_t equalSign = keyValuePair.find('=');
if (equalSign != std::string::npos)
{
// Tags in key=value format
OSMTag osmTag;
osmTag.key = keyValuePair.substr(0, equalSign);
osmTag.value = keyValuePair.substr(equalSign + 1);
// mapcss-mapping.csv uses 'not' instead of 'no' as a workaround for the rendering engine
if (osmTag.value == "not")
osmTag.value = "no";
osmTags.push_back(osmTag);
}
else if (keyValuePair.front() == '!')
{
// Tags with "forbidden" selector '!' are skipped
}
else
{
// Tags with optional "mandatory" selector '?'
if (keyValuePair.back() == '?')
keyValuePair.remove_suffix(1);
OSMTag osmTag;
osmTag.key = keyValuePair;
osmTag.value = "yes";
osmTags.push_back(osmTag);
}
pos = end + 1;
}
ASSERT(!osmTags.empty(), ("No OSM tags found for feature:", line));
m_storage.insert({type, osmTags});
}
}
}
std::vector<OSMTag> const & TypeToOSMTranslator::OsmTagsFromType(uint32_t type) const
{
auto it = m_storage.find(type);
if (it == m_storage.end())
{
ASSERT(false, ("OSM tags for type", type, "could not be found"));
return kEmptyResult;
}
return it->second;
}
TypeToOSMTranslator const & GetOSMTranslator()
{
static TypeToOSMTranslator translator;
return translator;
}
} // namespace editor

View File

@@ -0,0 +1,36 @@
#pragma once
#include <cstdint>
#include <unordered_map>
#include <vector>
namespace editor
{
struct OSMTag
{
std::string key;
std::string value;
};
class TypeToOSMTranslator
{
public:
std::vector<OSMTag> static constexpr kEmptyResult = {};
TypeToOSMTranslator() : TypeToOSMTranslator(true) {}
explicit TypeToOSMTranslator(bool initialize);
void LoadConfigFile();
void LoadFromStream(std::istream & s);
std::vector<OSMTag> const & OsmTagsFromType(uint32_t type) const;
std::unordered_map<uint32_t, std::vector<OSMTag>> const & GetStorage() const { return m_storage; }
private:
std::unordered_map<uint32_t, std::vector<OSMTag>> m_storage;
};
TypeToOSMTranslator const & GetOSMTranslator();
} // namespace editor

View File

@@ -1,4 +1,6 @@
#include "editor/xml_feature.hpp"
#include "editor/feature_type_to_osm.hpp"
#include "editor/keys_to_remove.hpp"
#include "indexer/classificator.hpp"
@@ -640,36 +642,16 @@ void XMLFeature::RemoveTag(string_view key)
void XMLFeature::SetOSMTagsForType(uint32_t type)
{
if (ftypes::IsRecyclingCentreChecker::Instance()(type))
{
SetTagValue("amenity", "recycling");
SetTagValue("recycling_type", "centre");
}
else if (ftypes::IsRecyclingContainerChecker::Instance()(type))
{
SetTagValue("amenity", "recycling");
SetTagValue("recycling_type", "container");
}
else if (ftypes::IsAddressChecker::Instance()(type))
if (ftypes::IsAddressChecker::Instance()(type))
{
// Addresses don't have a category tag
return;
}
else
{
string const strType = classif().GetReadableObjectName(type);
strings::SimpleTokenizer iter(strType, "-");
string_view const k = *iter;
if (++iter)
{
// Main type is stored as "k=amenity v=restaurant"
SetTagValue(k, *iter);
}
else {
// Main type is stored as "k=building v=yes"
SetTagValue(k, kYes);
}
}
std::vector<OSMTag> const & osmTags = GetOSMTranslator().OsmTagsFromType(type);
for (auto const & osmTag : osmTags)
SetTagValue(osmTag.key, osmTag.value);
}
void XMLFeature::UpdateOSMTag(std::string_view key, std::string_view value)

View File

@@ -126,6 +126,7 @@ copy_resources(
patterns.txt
transit_colors.txt
types.txt
mapcss-mapping.csv
World.mwm
WorldCoasts.mwm
)

View File

@@ -8,6 +8,9 @@
/* Begin PBXBuildFile section */
271DC2172EC60C0C00442D94 /* keys_to_remove.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 271DC2162EC60C0C00442D94 /* keys_to_remove.hpp */; };
27FDBF1B2EEEFC3F0045621D /* feature_type_to_osm_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FDBF1A2EEEFC3F0045621D /* feature_type_to_osm_test.cpp */; };
27FDBF1E2EEEFC5A0045621D /* feature_type_to_osm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FDBF1D2EEEFC5A0045621D /* feature_type_to_osm.cpp */; };
27FDBF1F2EEEFC5A0045621D /* feature_type_to_osm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 27FDBF1C2EEEFC5A0045621D /* feature_type_to_osm.hpp */; };
340C20DE1C3E4DFD00111D22 /* osm_auth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 340C20DC1C3E4DFD00111D22 /* osm_auth.cpp */; };
340C20DF1C3E4DFD00111D22 /* osm_auth.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 340C20DD1C3E4DFD00111D22 /* osm_auth.hpp */; };
340DC8291C4E71E500EAA2CC /* changeset_wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 340DC8271C4E71E500EAA2CC /* changeset_wrapper.cpp */; };
@@ -77,6 +80,10 @@
/* Begin PBXFileReference section */
270C9C212E16AABF00ABA688 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = module.modulemap; path = ../../libs/editor/module.modulemap; sourceTree = SOURCE_ROOT; };
271DC2162EC60C0C00442D94 /* keys_to_remove.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = keys_to_remove.hpp; sourceTree = "<group>"; };
27998A9E2EEEFE09001EAFD0 /* mapcss-mapping.csv */ = {isa = PBXFileReference; lastKnownFileType = text; name = "mapcss-mapping.csv"; path = "../../data/mapcss-mapping.csv"; sourceTree = SOURCE_ROOT; };
27FDBF1A2EEEFC3F0045621D /* feature_type_to_osm_test.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = feature_type_to_osm_test.cpp; sourceTree = "<group>"; };
27FDBF1C2EEEFC5A0045621D /* feature_type_to_osm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = feature_type_to_osm.hpp; sourceTree = "<group>"; };
27FDBF1D2EEEFC5A0045621D /* feature_type_to_osm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = feature_type_to_osm.cpp; sourceTree = "<group>"; };
340C20DC1C3E4DFD00111D22 /* osm_auth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = osm_auth.cpp; sourceTree = "<group>"; };
340C20DD1C3E4DFD00111D22 /* osm_auth.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = osm_auth.hpp; sourceTree = "<group>"; };
340DC8271C4E71E500EAA2CC /* changeset_wrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = changeset_wrapper.cpp; sourceTree = "<group>"; };
@@ -199,6 +206,7 @@
isa = PBXGroup;
children = (
3496AC041DC204B700C5DDBA /* editor.config */,
27998A9E2EEEFE09001EAFD0 /* mapcss-mapping.csv */,
270C9C212E16AABF00ABA688 /* module.modulemap */,
34F5586E1DBF49B200A4FC11 /* common-debug.xcconfig */,
34F5586F1DBF49B200A4FC11 /* common-release.xcconfig */,
@@ -242,6 +250,8 @@
6715560420BEC331002BA3B4 /* edits_migration.hpp */,
3D052486200F62ED00F24998 /* feature_matcher.cpp */,
3D052485200F62ED00F24998 /* feature_matcher.hpp */,
27FDBF1D2EEEFC5A0045621D /* feature_type_to_osm.cpp */,
27FDBF1C2EEEFC5A0045621D /* feature_type_to_osm.hpp */,
271DC2162EC60C0C00442D94 /* keys_to_remove.hpp */,
6715565220BF0F86002BA3B4 /* new_feature_categories.cpp */,
6715565320BF0F87002BA3B4 /* new_feature_categories.hpp */,
@@ -270,6 +280,7 @@
3496ABD21DC2034900C5DDBA /* editor_config_test.cpp */,
3496ABD31DC2034900C5DDBA /* editor_notes_test.cpp */,
3D052489200F630000F24998 /* feature_matcher_test.cpp */,
27FDBF1A2EEEFC3F0045621D /* feature_type_to_osm_test.cpp */,
3D05248A200F630000F24998 /* match_by_geometry_test.cpp */,
6715560920BEF0A4002BA3B4 /* new_feature_categories_test.cpp */,
3496ABD41DC2034900C5DDBA /* opening_hours_ui_test.cpp */,
@@ -338,6 +349,7 @@
34527C521C89B1770015050E /* editor_config.hpp in Headers */,
675B562820D2706000A521D2 /* editable_feature_source.hpp in Headers */,
6715565520BF0F87002BA3B4 /* new_feature_categories.hpp in Headers */,
27FDBF1F2EEEFC5A0045621D /* feature_type_to_osm.hpp in Headers */,
6715560820BEC332002BA3B4 /* edits_migration.hpp in Headers */,
3D052487200F62EE00F24998 /* feature_matcher.hpp in Headers */,
271DC2172EC60C0C00442D94 /* keys_to_remove.hpp in Headers */,
@@ -470,6 +482,7 @@
340C20DE1C3E4DFD00111D22 /* osm_auth.cpp in Sources */,
6715560720BEC332002BA3B4 /* osm_editor.cpp in Sources */,
3D052488200F62EE00F24998 /* feature_matcher.cpp in Sources */,
27FDBF1E2EEEFC5A0045621D /* feature_type_to_osm.cpp in Sources */,
3D489BEF1D4F67E10052AA38 /* editor_storage.cpp in Sources */,
3411387A1C15AE42002E3B3E /* ui2oh.cpp in Sources */,
340DC8291C4E71E500EAA2CC /* changeset_wrapper.cpp in Sources */,
@@ -488,6 +501,7 @@
buildActionMask = 2147483647;
files = (
3496ABE11DC2035800C5DDBA /* config_loader_test.cpp in Sources */,
27FDBF1B2EEEFC3F0045621D /* feature_type_to_osm_test.cpp in Sources */,
671555E820BDC5D3002BA3B4 /* osm_editor_test.cpp in Sources */,
3496ABE21DC2035800C5DDBA /* editor_config_test.cpp in Sources */,
FACB76B826B89DF700810C9C /* feature_matcher_test.cpp in Sources */,