[feature] Added RouteRelation and linked it with FeatureType.

Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
This commit is contained in:
Viktor Govako
2025-06-25 23:58:19 -03:00
committed by Konstantin Pastbin
parent 315bba2a22
commit b85c11ea5a
26 changed files with 336 additions and 63 deletions

View File

@@ -244,6 +244,7 @@ std::unique_ptr<FeatureType> FeatureType::CreateFromMapObject(osm::MapObject con
ft->m_parsed.m_types = true;
ft->m_header = CalculateHeader(emo.GetTypes().Size(), headerGeomType, ft->m_params);
ft->m_parsed.m_header2 = true;
ft->m_parsed.m_relations = true;
ft->m_id = emo.GetID();
return ft;
@@ -305,7 +306,17 @@ void FeatureType::ParseCommon()
if (GetGeomType() == GeomType::Point)
{
m_center = serial::LoadPoint(source, m_loadInfo->GetDefGeometryCodingParams());
uint64_t decoded = ReadVarUint<uint64_t>(source);
if (m_loadInfo->m_version >= DatSectionHeader::Version::V1)
{
m_hasRelations = (decoded & 0x1) == 1;
decoded >>= 1;
}
auto const & cp = m_loadInfo->GetDefGeometryCodingParams();
m_center = PointUToPointD(coding::DecodePointDeltaFromUint(decoded, cp.GetBasePoint()), cp.GetCoordBits());
m_limitRect.Add(m_center);
}
@@ -329,13 +340,7 @@ int8_t FeatureType::GetLayer()
return m_params.layer;
}
// TODO: there is a room to store more information in Header2 (geometry header),
// but it needs a mwm version change.
// 1st bit - inner / outer flag
// 4 more bits - inner points/triangles count or outer geom offsets mask
// (but actually its enough to store number of the first existing geom level only - 2 bits)
// 3-5 more bits are spare
// One of them could be used for a closed line flag to avoid storing identical first + last points.
// TODO: One of the free bits could be used for a closed line flag to avoid storing identical first + last points.
void FeatureType::ParseHeader2()
{
if (m_parsed.m_header2)
@@ -347,7 +352,10 @@ void FeatureType::ParseHeader2()
auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE);
if (headerGeomType != HeaderGeomType::Line && headerGeomType != HeaderGeomType::Area)
{
m_offsets.m_relations = m_offsets.m_header2;
return;
}
BitSource bitSource(m_data.data() + m_offsets.m_header2);
uint8_t elemsCount = bitSource.Read(4);
@@ -362,13 +370,15 @@ void FeatureType::ParseHeader2()
}
else
{
ASSERT_EQUAL(m_loadInfo->m_version, DatSectionHeader::Version::V1, ());
ASSERT(m_loadInfo->m_version >= DatSectionHeader::Version::V1, ());
bool const isOuter = (bitSource.Read(1) == 1);
if (isOuter)
{
geomScalesMask = elemsCount;
elemsCount = 0;
}
m_hasRelations = (bitSource.Read(1) == 1);
}
ArrayByteSource src(bitSource.RoundPtr());
@@ -426,6 +436,23 @@ void FeatureType::ParseHeader2()
}
}
m_offsets.m_relations = CalcOffset(src, m_data.data());
}
void FeatureType::ParseRelations()
{
if (m_parsed.m_relations)
return;
ParseHeader2();
ArrayByteSource src(m_data.data() + m_offsets.m_relations);
if (m_hasRelations)
ReadVarUInt32SortedShortArray(src, m_relationIDs);
m_parsed.m_relations = true;
// Size of the whole header incl. inner geometry / triangles.
m_innerStats.m_size = CalcOffset(src, m_data.data());
}
@@ -442,7 +469,7 @@ void FeatureType::ResetGeometry()
if (GetGeomType() != GeomType::Point)
m_limitRect = m2::RectD();
m_parsed.m_header2 = m_parsed.m_points = m_parsed.m_triangles = false;
m_parsed.m_relations = m_parsed.m_header2 = m_parsed.m_points = m_parsed.m_triangles = false;
m_offsets.m_pts.clear();
m_offsets.m_trg.clear();
m_ptsSimpMask = 0;
@@ -501,9 +528,9 @@ void FeatureType::ParseGeometry(int scale)
FeatureType::GeomStat FeatureType::GetOuterGeometryStats()
{
CHECK(m_loadInfo && m_parsed.m_header2 && !m_parsed.m_points, ("Call geometry stats first and once!"));
CHECK(m_loadInfo && m_parsed.m_relations && !m_parsed.m_points, ());
size_t const scalesCount = m_loadInfo->GetScalesCount();
ASSERT_LESS_OR_EQUAL(scalesCount, DataHeader::kMaxScalesCount, ("MWM has too many geometry scales!"));
ASSERT_LESS_OR_EQUAL(scalesCount, DataHeader::kMaxScalesCount, ());
FeatureType::GeomStat res;
auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE);
@@ -576,10 +603,9 @@ void FeatureType::ParseTriangles(int scale)
FeatureType::GeomStat FeatureType::GetOuterTrianglesStats()
{
CHECK(m_loadInfo && m_parsed.m_header2 && !m_parsed.m_triangles, ("Call geometry stats first and once!"));
CHECK(m_loadInfo && m_parsed.m_relations && !m_parsed.m_triangles, ());
int const scalesCount = m_loadInfo->GetScalesCount();
ASSERT_LESS_OR_EQUAL(scalesCount, static_cast<int>(DataHeader::kMaxScalesCount),
("MWM has too many geometry scales!"));
ASSERT_LESS_OR_EQUAL(scalesCount, static_cast<int>(DataHeader::kMaxScalesCount), ());
FeatureType::GeomStat res;
auto const headerGeomType = static_cast<HeaderGeomType>(Header(m_data) & HEADER_MASK_GEOMTYPE);
@@ -868,3 +894,16 @@ bool FeatureType::HasMetadata(feature::Metadata::EType type)
return base::FindIf(m_metaIds, [&type](auto const & v) { return v.first == type; }) != m_metaIds.end();
}
FeatureType::RelationIDsV const & FeatureType::GetRelations()
{
ParseRelations();
return m_relationIDs;
}
/// @pre id is from m_relationIDs.
feature::RouteRelationBase FeatureType::ReadRelation(uint32_t id)
{
ParseRelations();
return m_loadInfo->ReadRelation(id);
}