[generator] Add logic to replace OSM tag 'name' with 'name:full' for highway elements when 'name' and 'name:prefix' match with 'name:full'

Signed-off-by: daxgar <daxgar@noreply.codeberg.org>
This commit is contained in:
daxgar
2026-01-15 18:17:49 -07:00
committed by x7z4w
parent 9cd7b49f08
commit 2cd5a0a9df
5 changed files with 128 additions and 0 deletions

View File

@@ -9,6 +9,7 @@ CoMaps contributors:
Bastian Greshake Tzovaras
clover sage
daxgar
Harry Bond <me@hbond.xyz>
NoelClick
thesupertechie

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;