7#include <config-kosmindoormap.h>
9#include "levelparser_p.h"
12#include "style/mapcssdeclaration_p.h"
13#include "style/mapcssresult.h"
14#include "style/mapcssstate_p.h"
16#include <KOSMIndoorMap/MapCSSParser>
17#include <KOSMIndoorMap/MapCSSProperty>
18#include <KOSMIndoorMap/MapCSSStyle>
21#include <osm/geomath.h>
28MapLevel::MapLevel(
int level)
33MapLevel::~MapLevel() =
default;
35bool MapLevel::operator<(
const MapLevel &other)
const
37 return m_level > other.m_level;
40bool MapLevel::operator==(
const MapLevel &other)
const
42 return m_level == other.m_level;
45bool MapLevel::hasName()
const
58void MapLevel::setName(
const QString &name)
63bool MapLevel::isFullLevel()
const
65 return m_level % 10 == 0;
70 return m_level < 0 ? (m_level - (10 + m_level % 10)) : (m_level - m_level % 10);
73int MapLevel::fullLevelAbove()
const
75 return m_level < 0 ? (m_level - m_level % 10) : (m_level + (10 - m_level % 10));
78int MapLevel::numericLevel()
const
92 std::map<MapLevel, std::vector<OSM::Element>> m_levelMap;
93 std::map<MapLevel, std::size_t> m_dependentElementCounts;
101 : d(
std::make_shared<MapDataPrivate>())
105MapData::MapData(
const MapData&) =
default;
106MapData::MapData(
MapData&&) =
default;
107MapData::~MapData() =
default;
117bool MapData::isEmpty()
const
119 return !d || d->m_levelMap.empty();
122bool MapData::operator==(
const MapData &other)
const
134 d->m_dataSet = std::move(dataSet);
136 d->m_levelRefTag = d->m_dataSet.tagKey(
"level:ref");
137 d->m_nameTag = d->m_dataSet.tagKey(
"name");
139 d->m_levelMap.clear();
156const std::map<MapLevel, std::vector<OSM::Element>>& MapData::levelMap()
const
158 return d->m_levelMap;
161void MapData::processElements()
163 const auto levelTag = d->m_dataSet.tagKey(
"level");
164 const auto repeatOnTag = d->m_dataSet.tagKey(
"repeat_on");
165 const auto buildingLevelsTag = d->m_dataSet.tagKey(
"building:levels");
166 const auto buildingMinLevelTag = d->m_dataSet.tagKey(
"building:min_level");
167 const auto buildingLevelsUndergroundTag = d->m_dataSet.tagKey(
"building:levels:underground");
168 const auto maxLevelTag = d->m_dataSet.tagKey(
"max_level");
169 const auto minLevelTag = d->m_dataSet.tagKey(
"min_level");
170 const auto countryTag = d->m_dataSet.tagKey(
"addr:country");
174 auto filter = p.parse(QStringLiteral(
":/org.kde.kosmindoormap/assets/css/input-filter.mapcss"));
176 qWarning() << p.errorMessage();
178 filter.compile(d->m_dataSet);
182 OSM::for_each(d->m_dataSet, [&](
auto e) {
189 if (d->m_regionCode.isEmpty()) {
190 const auto countryCode = e.tagValue(countryTag);
191 if (countryCode.size() == 2 && std::isupper(static_cast<unsigned char>(countryCode[0])) && std::isupper(static_cast<unsigned char>(countryCode[1]))) {
192 d->m_regionCode = QString::fromUtf8(countryCode);
197 bool isDependentElement =
false;
199 MapCSSState filterState;
200 filterState.element = e;
201 filter.evaluate(std::move(filterState), filterResult);
203 if (prop->doubleValue() == 0.0) {
204 qDebug() <<
"input filter dropped" << e.url();
210 if (prop->doubleValue() < 1.0) {
211 isDependentElement = true;
217 e.recomputeBoundingBox(d->m_dataSet);
218 d->m_bbox = OSM::unite(e.boundingBox(), d->m_bbox);
223 const auto buildingLevels = e.tagValue(buildingLevelsTag, maxLevelTag).toInt();
224 if (buildingLevels > 0) {
225 const auto startLevel = e.tagValue(buildingMinLevelTag, levelTag, minLevelTag).toInt();
227 for (
auto i = startLevel; i < startLevel + buildingLevels; ++i) {
228 addElement(i * 10, e,
true);
231 const auto undergroundLevels = e.tagValue(buildingLevelsUndergroundTag).toUInt();
232 for (
auto i = undergroundLevels; i > 0; --i) {
233 addElement(-i * 10, e,
true);
235 if (buildingLevels > 0 || undergroundLevels > 0) {
240 auto level = e.tagValue(levelTag);
242 level = e.tagValue(repeatOnTag);
245 LevelParser::parse(std::move(level), e, [
this, isDependentElement](
int level,
OSM::Element e) {
246 addElement(level, e, isDependentElement);
252 d->m_levelMap[
MapLevel{}].push_back(e);
253 if (isDependentElement) {
254 d->m_dependentElementCounts[
MapLevel{}]++;
259void MapData::addElement(
int level,
OSM::Element e,
bool isDependentElement)
262 auto it = d->m_levelMap.find(l);
263 if (it == d->m_levelMap.end()) {
264 l.setName(levelName(e));
265 d->m_levelMap[l] = {e};
267 if (!(*it).first.hasName()) {
269 const_cast<MapLevel&
>((*it).first).setName(levelName(e));
271 (*it).second.push_back(e);
273 if (isDependentElement) {
274 d->m_dependentElementCounts[l]++;
278static bool isPlausibleLevelName(
const QByteArray &s)
285 const auto n = e.tagValue(d->m_levelRefTag);
286 if (isPlausibleLevelName(n)) {
290 if (e.type() == OSM::Type::Relation) {
291 const auto isLevelRel = std::all_of(e.relation()->members.begin(), e.relation()->members.end(), [](
const auto &mem) {
292 return std::strcmp(mem.role().name(),
"shell") == 0 || std::strcmp(mem.role().name(),
"buildingpart") == 0;
295 const auto n = e.tagValue(d->m_nameTag);
296 if (isPlausibleLevelName(n)) {
305void MapData::filterLevels()
309 for (
auto it = d->m_levelMap.begin(); it != d->m_levelMap.end();) {
310 if ((*it).first.numericLevel() != 0 && d->m_dependentElementCounts[(*it).first] == (*it).second.size()) {
311 it = d->m_levelMap.erase(it);
316 d->m_dependentElementCounts.clear();
321 return QPointF(d->m_bbox.center().lonF(), d->m_bbox.center().latF());
331 return d->m_regionCode;
334void MapData::setRegionCode(
const QString ®ionCode)
336 d->m_regionCode = regionCode;
341 return d->m_timeZone;
344void MapData::setTimeZone(
const QTimeZone &tz)
349QString MapData::timeZoneId()
const
354#include "moc_mapdata.cpp"
Result of MapCSS stylesheet evaluation for all layer selectors.
Raw OSM map data, separated by levels.
float radius
Radius from the bounding box center encompassing the entire bounding box, in meters.
QPointF center
Center position of the bounding box for QML usage (longitude/latitude, in degree).
int fullLevelBelow() const
In case this is not a full level, this returns the numeric values of the full levels above/below.
A set of nodes, ways and relations.
A reference to any of OSM::Node/OSM::Way/OSM::Relation.
OSM-based multi-floor indoor maps for buildings.
QStringView level(QStringView ifopt)
KOSM_EXPORT double distance(double lat1, double lon1, double lat2, double lon2)
Distance between two coordinates.
bool contains(QByteArrayView bv) const const
bool isEmpty() const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
bool isEmpty() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)