7#include "localization.h"
11#include <style/mapcssdeclaration_p.h>
12#include <style/mapcssstate_p.h>
14#include <KOSMIndoorMap/MapCSSParser>
15#include <KOSMIndoorMap/MapCSSResult>
17#include <KLocalizedString>
27RoomModel::RoomModel(
QObject *parent)
29 , m_langs(
OSM::Languages::fromQLocale(
QLocale()))
31 connect(
this, &RoomModel::timeChanged,
this, [
this]() {
39RoomModel::~RoomModel() =
default;
41MapData RoomModel::mapData()
const
46void RoomModel::setMapData(
const MapData &data)
52 if (m_style.isEmpty()) {
54 m_style = p.parse(QStringLiteral(
":/org.kde.kosmindoormap/assets/quick/room-model.mapcss"));
56 qWarning() << p.errorMessage();
65 if (!m_data.isEmpty()) {
66 m_style.compile(m_data.dataSet());
72int RoomModel::rowCount(
const QModelIndex &parent)
const
79 return (
int)m_rooms.size();
82QVariant RoomModel::data(
const QModelIndex &index,
int role)
const
88 const auto &room = m_rooms[
index.row()];
97 const auto types = room.element.tagValue(
"room",
"amenity").split(
';');
99 for (
const auto &type : types) {
108 return QLocale().createSeparatedList(l);
112 const auto center = room.element.center();
120 return QString::fromUtf8(room.buildingElement.tagValue(m_langs,
"name",
"local_ref",
"ref"));
123 auto s =
QString::fromUtf8(room.levelElement.tagValue(m_langs,
"name",
"level:ref"));
128 if ((room.level / 10) == 0) {
129 return i18n(
"Ground floor");
131 return i18n(
"Floor %1", room.level / 10);
147QHash<int, QByteArray> RoomModel::roleNames()
const
153 r.insert(CoordinateRole,
"coordinate");
164 return (
int)m_buildings.size();
169 return rowCount() == 0;
172void RoomModel::ensurePopulated()
const
174 if (m_rooms.empty() && !m_data.isEmpty()) {
177 const_cast<RoomModel*
>(
this)->populateModel();
181void RoomModel::populateModel()
184 const auto buildingKey = m_data.dataSet().tagKey(
"building");
185 const auto nameKey = m_data.dataSet().tagKey(
"name");
186 const auto refKey = m_data.dataSet().tagKey(
"ref");
188 for (
auto it = m_data.levelMap().begin(); it != m_data.levelMap().end(); ++it) {
189 for (
const auto &e : (*it).second) {
190 if (e.type() == OSM::Type::Node || !OSM::contains(m_data.boundingBox(), e.center())) {
193 if (e.hasTag(buildingKey) && (e.hasTag(nameKey) || e.hasTag(refKey))) {
195 building.element = e;
197 m_buildings.push_back(std::move(building));
203 const auto indoorKey = m_data.dataSet().tagKey(
"indoor");
204 for (
auto it = m_data.levelMap().begin(); it != m_data.levelMap().end(); ++it) {
205 for (
const auto &e : (*it).second) {
206 if (e.type() == OSM::Type::Node || !OSM::contains(m_data.boundingBox(), e.center())) {
209 if (e.tagValue(indoorKey) ==
"level") {
215 for (
auto &building : m_buildings) {
217 if (OSM::intersects(e.boundingBox(), building.element.boundingBox())) {
218 building.levels.push_back(level);
227 MapCSSResult filterResult;
228 OpeningHoursCache ohCache;
229 ohCache.setMapData(mapData());
230 ohCache.setTimeRange(m_beginTime, m_endTime);
232 for (
auto it = m_data.levelMap().begin(); it != m_data.levelMap().end(); ++it) {
233 for (
const auto &e : (*it).second) {
234 if (e.type() == OSM::Type::Node || !OSM::contains(m_data.boundingBox(), e.center())) {
238 MapCSSState filterState;
239 filterState.element = e;
240 filterState.openingHours = &ohCache;
241 m_style.initializeState(filterState);
242 m_style.evaluate(filterState, filterResult);
244 const auto &res = filterResult[{}];
251 room.level = (*it).first.numericLevel();
254 for (
auto &building :m_buildings) {
256 if (OSM::intersects(e.boundingBox(), building.element.boundingBox())) {
257 room.buildingElement = building.element;
258 ++building.roomCount;
261 for (
const auto &level : building.levels) {
262 if (
level.level == room.level) {
263 room.levelElement =
level.element;
272 const auto name = filterResult[{}].resolvedTagValue(m_langs,
"name", filterState);
276 m_rooms.push_back(std::move(room));
284 std::sort(m_rooms.begin(), m_rooms.end(), [](
const auto &lhs,
const auto &rhs) {
285 if (lhs.element == rhs.element) {
286 return std::abs(lhs.level) < std::abs(rhs.level);
288 return lhs.element < rhs.element;
290 m_rooms.erase(std::unique(m_rooms.begin(), m_rooms.end(), [](
const auto &lhs,
const auto &rhs) {
291 return lhs.element == rhs.element;
298 std::sort(m_rooms.begin(), m_rooms.end(), [](
const auto &lhs,
const auto &rhs) {
299 return lhs.buildingElement < rhs.buildingElement;
303 m_buildings.erase(std::remove_if(m_buildings.begin(), m_buildings.end(), [](
const auto &b) { return b.roomCount == 0; }), m_buildings.end());
305 qCDebug(Log) << m_buildings.size() <<
"buildings found";
306 qCDebug(Log) << m_rooms.size() <<
"rooms found";
312 if (name.isEmpty()) {
317 for (
auto it = m_rooms.begin(); it != m_rooms.end(); ++it) {
320 return (
int)std::distance(m_rooms.begin(), it);
327#include "moc_roommodel.cpp"
bool hasError() const
Returns true if an error occured during parsing and the returned style is invalid.
Raw OSM map data, separated by levels.
Q_INVOKABLE int findRoom(const QString &name) const
Tries to identify the given room name or number and returns the row index if found.
int buildingCount
Number of buildings found in the model data.
bool isEmpty
Returns true if there are no rooms in the current map data.
@ TypeNameRole
Type of the room as translated human readable text, if set.
@ NumberRole
room number, if set
@ LevelRole
numeric level for positioning rather than for display
@ ElementRole
OSM element for this room.
@ LevelShortNameRole
Name of the floor the room is on (short form, if available)
@ NameRole
room name, if set
@ LevelLongNameRole
Name of the floor the room is on (long form, if available)
@ BuildingNameRole
Name of the building the room is in.
QString i18n(const char *text, const TYPE &arg...)
QString amenityType(const char *value, Localization::TranslationOption opt=Localization::ReturnUnknownKey)
Translated name for an amenity tag value (after list splitting).
OSM-based multi-floor indoor maps for buildings.
QStringView level(QStringView ifopt)
Low-level types and functions to work with raw OSM data as efficiently as possible.
bool checkIndex(const QModelIndex &index, CheckIndexOptions options) const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual QModelIndex parent(const QModelIndex &index) const const=0
virtual QHash< int, QByteArray > roleNames() const const
void push_back(parameter_type value)
QString fromUtf8(QByteArrayView str)
QString number(double n, char format, int precision)
QChar first() const const
QTextStream & center(QTextStream &stream)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QVariant fromValue(T &&value)