KOSMIndoorMap

osm-download-data.cpp
1/*
2 SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include <KOSMIndoorMap/MapData>
8#include <KOSMIndoorMap/MapLoader>
9#include <loader/tilecache_p.h>
10
11#include <osm/datatypes.h>
12#include <osm/io.h>
13
14#include <QCommandLineParser>
15#include <QCoreApplication>
16#include <QDebug>
17#include <QFile>
18#include <QtPlugin>
19
20#if HAVE_OSM_PBF_SUPPORT
21Q_IMPORT_PLUGIN(OSM_PbfIOPlugin)
22#endif
23Q_IMPORT_PLUGIN(OSM_XmlIOPlugin)
24
25using namespace KOSMIndoorMap;
26
27static void filterByBbox(OSM::DataSet &dataSet, OSM::BoundingBox bbox)
28{
29 dataSet.relations.erase(std::remove_if(dataSet.relations.begin(), dataSet.relations.end(), [bbox](const auto &rel) {
30 return !OSM::intersects(rel.bbox, bbox);
31 }), dataSet.relations.end());
32 dataSet.ways.erase(std::remove_if(dataSet.ways.begin(), dataSet.ways.end(), [bbox](const auto &way) {
33 return !OSM::intersects(way.bbox, bbox);
34 }), dataSet.ways.end());
35 dataSet.nodes.erase(std::remove_if(dataSet.nodes.begin(), dataSet.nodes.end(), [bbox](const auto &nd) {
36 return !OSM::contains(bbox, nd.coordinate);
37 }), dataSet.nodes.end());
38}
39
40template <typename Elem>
41static bool containsElement(const std::vector<Elem> &elems, OSM::Id id)
42{
43 const auto it = std::lower_bound(elems.begin(), elems.end(), id, [](const Elem &lhs, OSM::Id rhs) { return lhs.id < rhs; });
44 return it != elems.end() && (*it).id == id;
45}
46
47static void purgeDanglingReferences(OSM::DataSet &dataSet)
48{
49 for (auto &rel : dataSet.relations) {
50 rel.members.erase(std::remove_if(rel.members.begin(), rel.members.end(), [&dataSet](const auto &mem) {
51 switch (mem.type()) {
52 case OSM::Type::Null:
53 Q_UNREACHABLE();
54 case OSM::Type::Node:
55 return !containsElement(dataSet.nodes, mem.id);
56 case OSM::Type::Way:
57 return !containsElement(dataSet.ways, mem.id);
58 case OSM::Type::Relation:
59 return !containsElement(dataSet.relations, mem.id);
60 }
61 return false;
62 }), rel.members.end());
63 }
64}
65
66int main(int argc, char **argv)
67{
68 QCoreApplication app(argc, argv);
69 QCommandLineParser parser;
70 parser.addHelpOption();
71 QCommandLineOption bboxOpt({QStringLiteral("b"), QStringLiteral("bbox")}, QStringLiteral("bounding box to download"), QStringLiteral("minlat,minlon,maxlat,maxlon"));
72 parser.addOption(bboxOpt);
73 QCommandLineOption clipOpt({QStringLiteral("c"), QStringLiteral("clip")}, QStringLiteral("clip to bounding box"));
74 parser.addOption(clipOpt);
75 QCommandLineOption outOpt({QStringLiteral("o"), QStringLiteral("out")}, QStringLiteral("output file"), QStringLiteral("file"));
76 parser.addOption(outOpt);
77 QCommandLineOption pointOpt({QStringLiteral("p"), QStringLiteral("point")}, QStringLiteral("download area around point"), QStringLiteral("lat,lon"));
78 parser.addOption(pointOpt);
79 QCommandLineOption tileOpt({QStringLiteral("t"), QStringLiteral("tile")}, QStringLiteral("download tile"), QStringLiteral("z/x/y"));
80 parser.addOption(tileOpt);
81 parser.process(app);
82
83 if ((!parser.isSet(bboxOpt) && !parser.isSet(pointOpt) && !parser.isSet(tileOpt)) || !parser.isSet(outOpt)) {
84 parser.showHelp(1);
85 return 1;
86 }
87
89 MapLoader loader;
90 if (parser.isSet(bboxOpt)) {
91 const auto coords = QStringView(parser.value(bboxOpt)).split(QLatin1Char(','));
92 if (coords.size() == 4) {
93 bbox.min = OSM::Coordinate(coords[0].toDouble(), coords[1].toDouble());
94 bbox.max = OSM::Coordinate(coords[2].toDouble(), coords[3].toDouble());
95 }
96 if (!bbox.isValid()) {
97 qCritical() << "Invalid bounding box!";
98 return 1;
99 }
100 }
101
102 if (parser.isSet(pointOpt)) {
103 const auto coords = QStringView(parser.value(pointOpt)).split(QLatin1Char(','));
104 if (coords.size() != 2) {
105 qCritical() << "Invalid coordinate!";
106 return 1;
107 }
108 OSM::Coordinate coord{coords[0].toDouble(), coords[1].toDouble()};
109 loader.loadForCoordinate(coord.latF(), coord.lonF());
110 } else if (parser.isSet(tileOpt)) {
111 const auto coords = QStringView(parser.value(tileOpt)).split(QLatin1Char('/'));
112 if (coords.size() != 3) {
113 qCritical() << "Invalid tile!";
114 return 1;
115 }
116 Tile t(coords[1].toUInt(), coords[2].toUInt(), coords[0].toUInt());
117 loader.loadForTile(t);
118 } else if (parser.isSet(bboxOpt)) {
119 loader.loadForBoundingBox(bbox);
120 }
121
124 auto data = loader.takeData();
125
126 if (parser.isSet(clipOpt) && parser.isSet(bboxOpt)) {
127 filterByBbox(data.dataSet(), bbox);
128 purgeDanglingReferences(data.dataSet());
129 }
130
131 QFile f(parser.value(outOpt));
132 if (!f.open(QFile::WriteOnly)) {
133 qCritical() << f.errorString();
134 return 1;
135 }
136 auto writer = OSM::IO::writerForFileName(f.fileName());
137 if (!writer) {
138 qCritical() << "no file writer for requested format:" << f.fileName();
139 return 1;
140 }
141 writer->write(data.dataSet(), &f);
142 return 0;
143}
Loader for OSM data for a single station or airport.
Definition maploader.h:29
void done()
Emitted when the requested data has been loaded.
void loadForBoundingBox(OSM::BoundingBox box)
Load map data for the given bounding box, without applying the boundary search.
Q_INVOKABLE void loadForCoordinate(double lat, double lon)
Load map for the given coordinates.
Definition maploader.cpp:97
MapData && takeData()
Take out the completely loaded result.
void loadForTile(Tile tile)
Load map data for the given tile.
Bounding box, ie.
Definition datatypes.h:95
Coordinate, stored as 1e7 * degree to avoid floating point precision issues, and offset to unsigned v...
Definition datatypes.h:37
A set of nodes, ways and relations.
Definition datatypes.h:340
OSM-based multi-floor indoor maps for buildings.
KOSM_EXPORT std::unique_ptr< AbstractWriter > writerForFileName(QStringView fileName)
Returns a suitable writer for the given file name.
Definition io.cpp:58
int64_t Id
OSM element identifier.
Definition datatypes.h:30
QCommandLineOption addHelpOption()
bool addOption(const QCommandLineOption &option)
bool isSet(const QCommandLineOption &option) const const
void process(const QCoreApplication &app)
void showHelp(int exitCode)
QString value(const QCommandLineOption &option) const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:20:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.