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
23
24using namespace KOSMIndoorMap;
25
26static void filterByBbox(OSM::DataSet &dataSet, OSM::BoundingBox bbox)
27{
28 dataSet.relations.erase(std::remove_if(dataSet.relations.begin(), dataSet.relations.end(), [bbox](const auto &rel) {
29 return !OSM::intersects(rel.bbox, bbox);
30 }), dataSet.relations.end());
31 dataSet.ways.erase(std::remove_if(dataSet.ways.begin(), dataSet.ways.end(), [bbox](const auto &way) {
32 return !OSM::intersects(way.bbox, bbox);
33 }), dataSet.ways.end());
34 dataSet.nodes.erase(std::remove_if(dataSet.nodes.begin(), dataSet.nodes.end(), [bbox](const auto &nd) {
35 return !OSM::contains(bbox, nd.coordinate);
36 }), dataSet.nodes.end());
37}
38
39template <typename Elem>
40static bool containsElement(const std::vector<Elem> &elems, OSM::Id id)
41{
42 const auto it = std::lower_bound(elems.begin(), elems.end(), id, [](const Elem &lhs, OSM::Id rhs) { return lhs.id < rhs; });
43 return it != elems.end() && (*it).id == id;
44}
45
46static void purgeDanglingReferences(OSM::DataSet &dataSet)
47{
48 for (auto &rel : dataSet.relations) {
49 rel.members.erase(std::remove_if(rel.members.begin(), rel.members.end(), [&dataSet](const auto &mem) {
50 switch (mem.type()) {
51 case OSM::Type::Null:
52 Q_UNREACHABLE();
53 case OSM::Type::Node:
54 return !containsElement(dataSet.nodes, mem.id);
55 case OSM::Type::Way:
56 return !containsElement(dataSet.ways, mem.id);
57 case OSM::Type::Relation:
58 return !containsElement(dataSet.relations, mem.id);
59 }
60 return false;
61 }), rel.members.end());
62 }
63}
64
65int main(int argc, char **argv)
66{
67 QCoreApplication app(argc, argv);
68 QCommandLineParser parser;
69 parser.addHelpOption();
70 QCommandLineOption bboxOpt({QStringLiteral("b"), QStringLiteral("bbox")}, QStringLiteral("bounding box to download"), QStringLiteral("minlat,minlon,maxlat,maxlon"));
71 parser.addOption(bboxOpt);
72 QCommandLineOption clipOpt({QStringLiteral("c"), QStringLiteral("clip")}, QStringLiteral("clip to bounding box"));
73 parser.addOption(clipOpt);
74 QCommandLineOption outOpt({QStringLiteral("o"), QStringLiteral("out")}, QStringLiteral("output file"), QStringLiteral("file"));
75 parser.addOption(outOpt);
76 QCommandLineOption pointOpt({QStringLiteral("p"), QStringLiteral("point")}, QStringLiteral("download area around point"), QStringLiteral("lat,lon"));
77 parser.addOption(pointOpt);
78 QCommandLineOption tileOpt({QStringLiteral("t"), QStringLiteral("tile")}, QStringLiteral("download tile"), QStringLiteral("z/x/y"));
79 parser.addOption(tileOpt);
80 parser.process(app);
81
82 if ((!parser.isSet(bboxOpt) && !parser.isSet(pointOpt) && !parser.isSet(tileOpt)) || !parser.isSet(outOpt)) {
83 parser.showHelp(1);
84 return 1;
85 }
86
88 MapLoader loader;
89 if (parser.isSet(bboxOpt)) {
90 const auto coords = QStringView(parser.value(bboxOpt)).split(QLatin1Char(','));
91 if (coords.size() == 4) {
92 bbox.min = OSM::Coordinate(coords[0].toDouble(), coords[1].toDouble());
93 bbox.max = OSM::Coordinate(coords[2].toDouble(), coords[3].toDouble());
94 }
95 if (!bbox.isValid()) {
96 qCritical() << "Invalid bounding box!";
97 return 1;
98 }
99 }
100
101 if (parser.isSet(pointOpt)) {
102 const auto coords = QStringView(parser.value(pointOpt)).split(QLatin1Char(','));
103 if (coords.size() != 2) {
104 qCritical() << "Invalid coordinate!";
105 return 1;
106 }
107 OSM::Coordinate coord{coords[0].toDouble(), coords[1].toDouble()};
108 loader.loadForCoordinate(coord.latF(), coord.lonF());
109 } else if (parser.isSet(tileOpt)) {
110 const auto coords = QStringView(parser.value(tileOpt)).split(QLatin1Char('/'));
111 if (coords.size() != 3) {
112 qCritical() << "Invalid tile!";
113 return 1;
114 }
115 Tile t(coords[1].toUInt(), coords[2].toUInt(), coords[0].toUInt());
116 loader.loadForTile(t);
117 } else if (parser.isSet(bboxOpt)) {
118 loader.loadForBoundingBox(bbox);
119 }
120
123 auto data = loader.takeData();
124
125 if (parser.isSet(clipOpt) && parser.isSet(bboxOpt)) {
126 filterByBbox(data.dataSet(), bbox);
127 purgeDanglingReferences(data.dataSet());
128 }
129
130 QFile f(parser.value(outOpt));
131 if (!f.open(QFile::WriteOnly)) {
132 qCritical() << f.errorString();
133 return 1;
134 }
135 auto writer = OSM::IO::writerForFileName(f.fileName());
136 if (!writer) {
137 qCritical() << "no file writer for requested format:" << f.fileName();
138 return 1;
139 }
140 writer->write(data.dataSet(), &f);
141 return 0;
142}
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.
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:343
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:60
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 Fri Jul 26 2024 11:57:47 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.