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.initializeState(filterState);
202 filter.evaluate(filterState, filterResult);
204 if (prop->doubleValue() == 0.0) {
205 qDebug() <<
"input filter dropped" << e.url();
211 if (prop->doubleValue() < 1.0) {
212 isDependentElement =
true;
218 e.recomputeBoundingBox(d->m_dataSet);
219 d->m_bbox = OSM::unite(e.boundingBox(), d->m_bbox);
224 const auto buildingLevels = e.tagValue(buildingLevelsTag, maxLevelTag).toInt();
225 if (buildingLevels > 0) {
226 const auto startLevel = e.tagValue(buildingMinLevelTag, levelTag, minLevelTag).toInt();
228 for (
auto i = startLevel; i < startLevel + buildingLevels; ++i) {
229 addElement(i * 10, e,
true);
232 const auto undergroundLevels = e.tagValue(buildingLevelsUndergroundTag).toUInt();
233 for (
auto i = undergroundLevels; i > 0; --i) {
234 addElement(-i * 10, e,
true);
236 if (buildingLevels > 0 || undergroundLevels > 0) {
241 auto level = e.tagValue(levelTag);
242 auto repeatOn = e.tagValue(repeatOnTag);
245 d->m_levelMap[MapLevel{}].push_back(e);
246 if (isDependentElement) {
247 d->m_dependentElementCounts[
MapLevel{}]++;
250 LevelParser::parse(std::move(level), e, [
this, isDependentElement](
int level,
OSM::Element e) {
251 addElement(level, e, isDependentElement);
253 LevelParser::parse(std::move(repeatOn), e, [
this, isDependentElement](
int level,
OSM::Element e) {
254 addElement(level, e, isDependentElement);
260void MapData::addElement(
int level,
OSM::Element e,
bool isDependentElement)
263 auto it = d->m_levelMap.find(l);
264 if (it == d->m_levelMap.end()) {
265 l.setName(levelName(e));
266 d->m_levelMap[l] = {e};
268 if (!(*it).first.hasName()) {
270 const_cast<MapLevel&
>((*it).first).setName(levelName(e));
272 (*it).second.push_back(e);
274 if (isDependentElement) {
275 d->m_dependentElementCounts[l]++;
279static bool isPlausibleLevelName(
const QByteArray &s)
286 const auto n = e.tagValue(d->m_levelRefTag);
287 if (isPlausibleLevelName(n)) {
291 if (e.type() == OSM::Type::Relation) {
292 const auto isLevelRel = std::all_of(e.relation()->members.begin(), e.relation()->members.end(), [](
const auto &mem) {
293 return std::strcmp(mem.role().name(),
"shell") == 0 || std::strcmp(mem.role().name(),
"buildingpart") == 0;
296 const auto n = e.tagValue(d->m_nameTag);
297 if (isPlausibleLevelName(n)) {
306void MapData::filterLevels()
310 for (
auto it = d->m_levelMap.begin(); it != d->m_levelMap.end();) {
311 if ((*it).first.numericLevel() != 0 && d->m_dependentElementCounts[(*it).first] == (*it).second.size()) {
312 it = d->m_levelMap.erase(it);
317 d->m_dependentElementCounts.clear();
322 return QPointF(d->m_bbox.center().lonF(), d->m_bbox.center().latF());
332 return d->m_regionCode;
335void MapData::setRegionCode(
const QString ®ionCode)
337 d->m_regionCode = regionCode;
342 return d->m_timeZone;
345void MapData::setTimeZone(
const QTimeZone &tz)
350QString MapData::timeZoneId()
const
355#include "moc_mapdata.cpp"
bool hasError() const
Returns true if an error occured during parsing and the returned style is invalid.
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)