diff --git a/CONTRIBUTORS b/CONTRIBUTORS index c2899d4d4..632ca329f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -9,6 +9,7 @@ CoMaps contributors: Bastian Greshake Tzovaras clover sage +daxgar Harry Bond NoelClick thesupertechie diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt index 65780e830..1d625b61b 100644 --- a/generator/generator_tests/CMakeLists.txt +++ b/generator/generator_tests/CMakeLists.txt @@ -26,6 +26,7 @@ set(SRC gen_mwm_info_tests.cpp # hierarchy_entry_tests.cpp # hierarchy_tests.cpp + highway_full_name_tests.cpp intermediate_data_test.cpp maxspeeds_tests.cpp merge_collectors_tests.cpp diff --git a/generator/generator_tests/highway_full_name_tests.cpp b/generator/generator_tests/highway_full_name_tests.cpp new file mode 100644 index 000000000..12ae39d50 --- /dev/null +++ b/generator/generator_tests/highway_full_name_tests.cpp @@ -0,0 +1,87 @@ +#include "testing/testing.hpp" + +#include "generator/generator_tests/common.hpp" + +namespace highway_full_name_tests +{ + +UNIT_TEST(HighwayFullNameTest_NotHighway) +{ + OsmElement notRoad = + MakeOsmElement(0 /* id */, {{"name", "300 East"}, {"name:prefix", "North"}, {"name:full", "North 300 East"}}, + OsmElement::EntityType::Way); + + TEST_EQUAL(notRoad.GetTag("name"), "300 East", ()); + TEST_EQUAL(notRoad.GetTag("name:prefix"), "North", ()); + TEST_EQUAL(notRoad.GetTag("name:full"), "North 300 East", ()); +} + +UNIT_TEST(HighwayFullNameTest_ReplaceName) +{ + OsmElement road1 = MakeOsmElement( + 1 /* id */, + {{"highway", "residential"}, {"name", "300 East"}, {"name:prefix", "North"}, {"name:full", "North 300 East"}}, + OsmElement::EntityType::Way); + + TEST_EQUAL(road1.GetTag("name"), "North 300 East", ()); +} + +UNIT_TEST(HighwayFullNameTest_MissingName) +{ + OsmElement road2 = MakeOsmElement( + 2 /* id */, {{"highway", "residential"}, {"name:prefix", "North"}, {"name:full", "North 300 East"}}, + OsmElement::EntityType::Way); + + TEST(!road2.HasTag("name"), ()); +} + +UNIT_TEST(HighwayFullNameTest_MissingNamePrefix) +{ + OsmElement road3 = + MakeOsmElement(3 /* id */, {{"highway", "residential"}, {"name", "300 East"}, {"name:full", "North 300 East"}}, + OsmElement::EntityType::Way); + + TEST_EQUAL(road3.GetTag("name"), "300 East", ()); + TEST(!road3.HasTag("name:prefix"), ()); +} + +UNIT_TEST(HighwayFullNameTest_MissingNameFull) +{ + OsmElement road4 = + MakeOsmElement(4 /* id */, {{"highway", "residential"}, {"name", "300 East"}, {"name:prefix", "North"}}, + OsmElement::EntityType::Way); + + TEST_EQUAL(road4.GetTag("name"), "300 East", ()); + TEST(!road4.HasTag("name:full"), ()); +} + +UNIT_TEST(HighwayFullNameTest_OnlyName) +{ + OsmElement road5 = + MakeOsmElement(5 /* id */, {{"highway", "residential"}, {"name", "300 East"}}, OsmElement::EntityType::Way); + + TEST_EQUAL(road5.GetTag("name"), "300 East", ()); + TEST(!road5.HasTag("name:prefix"), ()); + TEST(!road5.HasTag("name:full"), ()); +} + +UNIT_TEST(HighwayFullNameTest_OnlyFullName) +{ + OsmElement road6 = MakeOsmElement(6 /* id */, {{"highway", "residential"}, {"name:full", "North 300 East"}}, + OsmElement::EntityType::Way); + + TEST_EQUAL(road6.GetTag("name:full"), "North 300 East", ()); + TEST(!road6.HasTag("name"), ()); + TEST(!road6.HasTag("name:prefix"), ()); +} + +UNIT_TEST(HighwayFullNameTest_NotMatching) +{ + OsmElement road7 = MakeOsmElement( + 7 /* id */, + {{"highway", "residential"}, {"name", "300 East"}, {"name:prefix", "South"}, {"name:full", "North 300 East"}}, + OsmElement::EntityType::Way); + + TEST_EQUAL(road7.GetTag("name"), "300 East", ()); +} +} // namespace highway_full_name_tests diff --git a/generator/osm_element.cpp b/generator/osm_element.cpp index 27872da3c..a3fdbff56 100644 --- a/generator/osm_element.cpp +++ b/generator/osm_element.cpp @@ -52,6 +52,36 @@ void OsmElement::AddTag(std::string_view key, std::string_view value) return; m_tags.emplace_back(key, value); + + // Determine if all of these keys are set, + // without having to repeatedly look them up in the tags list + if (key == "name") + m_setKeys |= NAME; + else if (key == "name:prefix") + m_setKeys |= NAME_PREFIX; + else if (key == "name:full") + m_setKeys |= NAME_FULL; + else if (key == "highway") + m_setKeys |= HIGHWAY; + else + return; // Only run the following code if one of the above keys was added + + // If a highway has a name, a full name, and a name prefix, + // and the full name is equal to the name prefix joined with a space before the name, + // then replace the name with the full name + // See https://codeberg.org/comaps/comaps/issues/3193 + if (m_setKeys & NAME && m_setKeys & NAME_PREFIX && m_setKeys & NAME_FULL && m_setKeys & HIGHWAY) + { + std::string name = GetTag("name"); + std::string namePrefix = GetTag("name:prefix"); + std::string nameFull = GetTag("name:full"); + + if ((namePrefix + " " + name) == nameFull) + UpdateTag("name", nameFull); + else + LOG(LDEBUG, ("Highway name tags don't match. name:prefix:", namePrefix, "name:", name, "name:full:", nameFull, + "in OSM Element:", m_id)); + } } bool OsmElement::HasTag(std::string_view const & key) const diff --git a/generator/osm_element.hpp b/generator/osm_element.hpp index f8d59c6cc..63c591725 100644 --- a/generator/osm_element.hpp +++ b/generator/osm_element.hpp @@ -21,6 +21,14 @@ struct OsmElement Osm = 0x736F, // "os" }; + enum SetKeys + { + NAME = 0x1 << 0, + NAME_PREFIX = 0x1 << 1, + NAME_FULL = 0x1 << 2, + HIGHWAY = 0x1 << 3, + }; + struct Member { Member() = default; @@ -126,6 +134,7 @@ struct OsmElement std::string GetTag(std::string const & key) const; EntityType m_type = EntityType::Unknown; + uint8_t m_setKeys = 0; uint64_t m_id = 0; double m_lon = 0; double m_lat = 0;