co-maps/libs/indexer/route_relation.hpp
2025-11-22 13:58:55 +01:00

167 lines
3.5 KiB
C++

#pragma once
#include "coding/read_write_utils.hpp"
#include "coding/string_utf8_multilang.hpp"
#include "base/buffer_vector.hpp"
#include "drape/color.hpp"
#include <array>
#include <string>
namespace feature
{
class RouteRelationBase // like RelationType (FeatureType)
{
public:
enum class Type : uint8_t
{
Foot = 0,
Hiking,
Bicycle,
MTB,
Bus,
Train,
Tram,
Trolleybus,
};
enum IdxAndFlags : uint8_t
{
CycleNetworkIdx = 0,
OperatorIdx = 1,
OfficialRefIdx = 2,
FromIdx = 3,
ToIdx = 4,
WikipediaIdx = 5,
CountIdx = 6,
HasColor = 0x40,
HasName = 0x80,
};
static constexpr dp::Color kEmptyColor = dp::Color::Transparent();
void SetParam(std::string_view s, IdxAndFlags idx) { m_params[idx] = s; }
std::string_view GetParam(IdxAndFlags idx) const { return m_params[idx]; }
Type GetType() const { return m_type; }
dp::Color GetColor() const { return m_color; }
std::string const & GetRef() const { return m_ref; }
std::string const & GetNetwork() const { return m_network; }
RouteRelationBase() = default;
/// @todo Can optimize by storing color as an index in a palette (1 byte).
template <class TSink>
void Write(TSink & sink) const
{
WriteToSink(sink, uint8_t(m_type));
uint8_t flags = 0;
if (m_color != kEmptyColor)
flags |= HasColor;
if (!m_name.IsEmpty())
flags |= HasName;
for (int i = 0; i < CountIdx; ++i)
if (!m_params[i].empty())
flags |= (1 << i);
WriteToSink(sink, flags);
if (flags & HasColor)
WriteToSink(sink, m_color.GetRGBA());
if (flags & HasName)
m_name.WriteNonEmpty(sink);
rw::Write(sink, m_network);
rw::Write(sink, m_ref);
for (int i = 0; i < CountIdx; ++i)
if (!m_params[i].empty())
rw::WriteNonEmpty(sink, m_params[i]);
}
template <class TSource>
void Read(TSource & src)
{
m_type = static_cast<Type>(ReadPrimitiveFromSource<uint8_t>(src));
uint8_t const flags = ReadPrimitiveFromSource<uint8_t>(src);
if (flags & HasColor)
m_color = dp::Color::FromRGBA(ReadPrimitiveFromSource<uint32_t>(src));
if (flags & HasName)
m_name.ReadNonEmpty(src);
rw::Read(src, m_network);
rw::Read(src, m_ref);
for (int i = 0; i < CountIdx; ++i)
if (flags & (1 << i))
rw::ReadNonEmpty(src, m_params[i]);
}
protected:
StringUtf8Multilang m_name;
std::string m_network, m_ref;
std::array<std::string, CountIdx> m_params;
dp::Color m_color = kEmptyColor;
Type m_type; // from route or route_master tag
friend class RelationBuilder;
};
using ShortArray = buffer_vector<uint32_t, 2>;
class RouteRelation : public RouteRelationBase
{
public:
enum Flags : uint8_t
{
HasRelationMembers = 0x1,
HasParents = 0x2,
};
RouteRelation() = default;
/// @todo Use RecordReader + buffers?
template <class TSource>
void Read(TSource & src)
{
RouteRelationBase::Read(src);
uint32_t const sz = ReadVarUint<uint32_t>(src);
m_ftMembers.reserve(sz);
uint32_t prev = 0;
for (size_t i = 0; i < sz; ++i)
{
m_ftMembers.push_back(prev + ReadVarUint<uint32_t>(src));
prev = m_ftMembers.back();
}
uint8_t const flags = ReadPrimitiveFromSource<uint8_t>(src);
if (flags & HasRelationMembers)
ReadVarUInt32SortedShortArray(src, m_relMembers);
if (flags & HasParents)
ReadVarUInt32SortedShortArray(src, m_relParents);
}
private:
std::vector<uint32_t> m_ftMembers;
ShortArray m_relMembers;
ShortArray m_relParents;
};
} // namespace feature