7#include "platformmodel.h"
8#include "platformfinder_p.h"
11#include <QRegularExpression>
17static constexpr auto TOP_PARENT = std::numeric_limits<quintptr>::max();
19PlatformModel::PlatformModel(
QObject* parent) :
22 m_matchTimer.setSingleShot(
true);
23 m_matchTimer.setInterval(0);
27 connect(
this, &PlatformModel::arrivalPlatformChanged, &m_matchTimer, qOverload<>(&
QTimer::start));
28 connect(
this, &PlatformModel::departurePlatformChanged, &m_matchTimer, qOverload<>(&
QTimer::start));
31PlatformModel::~PlatformModel() =
default;
33MapData PlatformModel::mapData()
const
38void PlatformModel::setMapData(
const MapData &data)
46 m_platformLabels.clear();
47 m_sectionsLabels.clear();
48 m_arrivalPlatformRow = -1;
49 m_departurePlatformRow = -1;
52 if (!m_data.isEmpty()) {
53 PlatformFinder finder;
54 m_platforms = finder.find(m_data);
56 m_tagKeys.arrival = m_data.dataSet().
makeTagKey(
"mx:arrival");
57 m_tagKeys.departure = m_data.dataSet().
makeTagKey(
"mx:departure");
62 Q_EMIT platformIndexChanged();
65bool PlatformModel::isEmpty()
const
67 return rowCount() == 0;
70int PlatformModel::columnCount(
const QModelIndex& parent)
const
76int PlatformModel::rowCount(
const QModelIndex &parent)
const
79 return parent.internalId() == TOP_PARENT ? m_platforms[
parent.row()].sections().size() : 0;
82 return m_platforms.size();
92 const auto &platform = m_platforms[index.
row()];
95 return platform.name();
97 return QPointF(platform.position().lonF(), platform.position().latF());
101 return platform.level();
102 case TransportModeRole:
103 return platform.mode();
105 return platform.lines();
106 case ArrivalPlatformRole:
107 return index.
row() == m_arrivalPlatformRow;
108 case DeparturePlatformRole:
109 return index.
row() == m_departurePlatformRow;
112 const auto &platform = m_platforms[index.
internalId()];
113 const auto §ion = platform.sections()[index.
row()];
116 return section.name();
118 return QPointF(section.position().center().lonF(), section.position().center().latF());
122 return platform.level();
148 n.insert(CoordinateRole,
"coordinate");
149 n.insert(ElementRole,
"osmElement");
150 n.insert(LevelRole,
"level");
151 n.insert(TransportModeRole,
"mode");
152 n.insert(LinesRole,
"lines");
153 n.insert(ArrivalPlatformRole,
"isArrivalPlatform");
154 n.insert(DeparturePlatformRole,
"isDeparturePlatform");
160 return m_arrivalPlatform;
163void PlatformModel::setArrivalPlatform(
const Platform &platform)
165 m_arrivalPlatform = platform;
166 Q_EMIT arrivalPlatformChanged();
171 m_arrivalPlatform.setName(name);
172 m_arrivalPlatform.setMode(mode);
173 Q_EMIT arrivalPlatformChanged();
176Platform PlatformModel::departurePlatform()
const
178 return m_departurePlatform;
181void PlatformModel::setDeparturePlatform(
const Platform &platform)
183 m_departurePlatform = platform;
184 Q_EMIT departurePlatformChanged();
189 m_departurePlatform.setName(name);
190 m_departurePlatform.setMode(mode);
191 Q_EMIT departurePlatformChanged();
196 return m_arrivalPlatformRow;
199int PlatformModel::departurePlatformRow()
const
201 return m_departurePlatformRow;
204void PlatformModel::matchPlatforms()
206 setPlatformTag(m_arrivalPlatformRow, m_tagKeys.arrival,
false);
207 applySectionSelection(m_arrivalPlatformRow, m_tagKeys.arrival, {});
208 m_arrivalPlatformRow = matchPlatform(m_arrivalPlatform);
209 setPlatformTag(m_arrivalPlatformRow, m_tagKeys.arrival,
true);
210 setPlatformTag(m_departurePlatformRow, m_tagKeys.departure,
false);
211 applySectionSelection(m_departurePlatformRow, m_tagKeys.departure, {});
212 m_departurePlatformRow = matchPlatform(m_departurePlatform);
213 setPlatformTag(m_departurePlatformRow, m_tagKeys.departure,
true);
214 Q_EMIT platformIndexChanged();
216 if (m_arrivalPlatformRow >= 0) {
217 const auto idx = index(m_arrivalPlatformRow, 0);
219 applySectionSelection(m_arrivalPlatformRow, m_tagKeys.arrival, effectiveArrivalSections());
222 if (m_departurePlatformRow >= 0) {
223 const auto idx = index(m_departurePlatformRow, 0);
225 applySectionSelection(m_departurePlatformRow, m_tagKeys.departure, effectiveDepartureSections());
230static bool isPossiblySamePlatformName(
const QString &name,
const QString &platform)
233 if (name.size() > platform.
size()) {
235 const auto match = exp.match(name);
236 return match.hasMatch() &&
match.captured(1) == platform;
242int PlatformModel::matchPlatform(
const Platform &platform)
const
244 if (!platform.ifopt().
isEmpty()) {
245 const auto it = std::find_if(m_platforms.begin(), m_platforms.end(), [platform](
const auto &p) {
246 return p.ifopt() == platform.ifopt();
248 if (it != m_platforms.end()) {
249 return std::distance(m_platforms.begin(), it);
253 if (platform.name().
isEmpty()) {
259 for (
const auto &p : m_platforms) {
260 if (p.name() == platform.name() && p.mode() == platform.mode()) {
270 for (
const auto &p : m_platforms) {
271 if (p.mode() == platform.mode() && isPossiblySamePlatformName(platform.name(), p.name())) {
280void PlatformModel::createLabels()
282 const auto platformTag = m_data.dataSet().
makeTagKey(
"mx:platform");
283 const auto sectionTag = m_data.dataSet().
makeTagKey(
"mx:platform_section");
285 m_platformLabels.reserve(m_platforms.size());
286 m_sectionsLabels.resize(m_platforms.size());
287 for (std::size_t i = 0; i < m_platforms.size(); ++i) {
288 const auto &p = m_platforms[i];
293 node->coordinate = p.position();
297 m_sectionsLabels[i].reserve(p.sections().size());
298 for (
const auto &sec : p.sections()) {
301 node->coordinate = sec.position().center();
308void PlatformModel::setPlatformTag(
int idx,
OSM::TagKey key,
bool enabled)
314 m_platformLabels[idx].setTagValue(key, enabled ?
"1" :
"0");
319 while (!p.
empty() && (p[0].isDigit() || p[0].isSpace())) {
325QStringView PlatformModel::effectiveArrivalSections()
const
328 return stripPlatform(m_arrivalPlatform.name());
331QStringView PlatformModel::effectiveDepartureSections()
const
334 return stripPlatform(m_departurePlatform.name());
337static std::vector<QChar> parseSectionSet(
QStringView sections)
339 std::vector<QChar> result;
341 for (
const auto &r : ranges) {
343 result.push_back(r[0]);
346 if (r.size() == 3 && r[1] ==
QLatin1Char(
'-') && r[0] < r[2]) {
347 for (
QChar c = r[0]; c <= r[2]; c =
QChar(c.unicode() + 1)) {
352 qDebug() <<
"failed to parse platform section expression:" << r;
359 if (platformIdx < 0) {
363 const auto sectionSet = parseSectionSet(sections);
365 std::size_t totalSelected = 0;
366 for (std::size_t i = 0; i < m_platforms[platformIdx].sections().size(); ++i) {
367 if (std::any_of(sectionSet.begin(), sectionSet.end(), [
this, i, platformIdx](
const QChar s) {
368 return s == m_platforms[platformIdx].sections()[i].name();
370 m_sectionsLabels[platformIdx][i].setTagValue(key,
"1");
373 m_sectionsLabels[platformIdx][i].setTagValue(key,
"0");
378 if (totalSelected == m_sectionsLabels[platformIdx].size()) {
379 for (
auto &s : m_sectionsLabels[platformIdx]) {
380 s.setTagValue(key,
"0");
385#include "moc_platformmodel.cpp"
Raw OSM map data, separated by levels.
Id nextInternalId() const
Create a unique id for internal use (ie.
TagKey makeTagKey(const char *keyName, StringMemory keyMemOpt=StringMemory::Transient)
Create a tag key for the given tag name.
A reference to any of OSM::Node/OSM::Way/OSM::Relation.
A std::unique_ptr-like object for OSM element types.
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
OSM-based multi-floor indoor maps for buildings.
void setTagValue(Elem &elem, TagKey key, QByteArray &&value)
Inserts a new tag, or updates an existing one.
QModelIndex createIndex(int row, int column, const void *ptr) const const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
virtual QHash< int, QByteArray > roleNames() const const
quintptr internalId() const const
bool isValid() const const
QObject * parent() const const
bool isEmpty() const const
qsizetype size() const const
QStringView mid(qsizetype start, qsizetype length) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QVariant fromValue(T &&value)