Skip to content

Commit cd7d5fa

Browse files
committed
Add osmium_tags_filter example showing use of tags filter
1 parent b4901a3 commit cd7d5fa

3 files changed

Lines changed: 171 additions & 0 deletions

File tree

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ set(EXAMPLES
2525
read
2626
read_with_progress
2727
road_length
28+
tags_filter
2829
tiles
2930
CACHE STRING "Example programs"
3031
)

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ them.
2929

3030
* `osmium_area_test`
3131
* `osmium_create_pois`
32+
* `osmium_tags_filter`
3233

3334
## Even more advanced examples
3435

examples/osmium_tags_filter.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
3+
EXAMPLE osmium_filter
4+
5+
Filter OSM files
6+
7+
DEMONSTRATES USE OF:
8+
* file input and output
9+
* file types
10+
* Osmium buffers
11+
* Tags filter
12+
13+
SIMPLER EXAMPLES you might want to understand first:
14+
* osmium_convert
15+
16+
LICENSE
17+
The code in this example file is released into the Public Domain.
18+
19+
*/
20+
21+
#include <cstdlib> // for std::exit
22+
#include <cstring> // for std::strcmp
23+
#include <exception> // for std::exception
24+
#include <iostream> // for std::cout, std::cerr
25+
#include <string> // for std::string
26+
27+
// Allow any format of input files (XML, PBF, ...)
28+
#include <osmium/io/any_input.hpp>
29+
30+
// Allow any format of output files (XML, PBF, ...)
31+
#include <osmium/io/any_output.hpp>
32+
33+
#include <osmium/tags/tags_filter.hpp>
34+
#include <osmium/tags/taglist.hpp>
35+
36+
void print_help() {
37+
std::cout << "osmium_filter [OPTIONS] [INFILE [OUTFILE]]\n\n" \
38+
<< "If INFILE or OUTFILE is not given stdin/stdout is assumed.\n" \
39+
<< "File format is autodetected from file name suffix.\n" \
40+
<< "Use -f and -t options to force file format.\n" \
41+
<< "\nFile types:\n" \
42+
<< " osm normal OSM file\n" \
43+
<< " osc OSM change file\n" \
44+
<< " osh OSM file with history information\n" \
45+
<< "\nFile format:\n" \
46+
<< " (default) XML encoding\n" \
47+
<< " pbf binary PBF encoding\n" \
48+
<< " opl OPL encoding\n" \
49+
<< "\nFile compression\n" \
50+
<< " gz compressed with gzip\n" \
51+
<< " bz2 compressed with bzip2\n" \
52+
<< "\nOptions:\n" \
53+
<< " -h, --help This help message\n" \
54+
<< " -f, --from-format=FORMAT Input format\n" \
55+
<< " -t, --to-format=FORMAT Output format\n";
56+
}
57+
58+
void print_usage(const char* prgname) {
59+
std::cerr << "Usage: " << prgname << " [OPTIONS] [INFILE [OUTFILE]]\n";
60+
std::exit(0);
61+
}
62+
63+
int main(int argc, char* argv[]) {
64+
if (argc == 1) {
65+
print_usage(argv[0]);
66+
}
67+
68+
if (argc > 1 && (!std::strcmp(argv[1], "-h") ||
69+
!std::strcmp(argv[1], "--help"))) {
70+
print_help();
71+
std::exit(0);
72+
}
73+
74+
// Input and output format are empty by default. Later this will mean that
75+
// the format should be taken from the input and output file suffix,
76+
// respectively.
77+
std::string input_format;
78+
std::string output_format;
79+
80+
std::string input_file_name;
81+
std::string output_file_name;
82+
83+
for (int i = 1; i < argc; ++i) {
84+
if (!std::strcmp(argv[i], "-f") || !std::strcmp(argv[i], "--from-format")) {
85+
++i;
86+
if (i < argc) {
87+
input_format = argv[i];
88+
} else {
89+
print_usage(argv[0]);
90+
}
91+
} else if (!std::strncmp(argv[i], "--from-format=", 14)) {
92+
input_format = argv[i] + 14;
93+
} else if (!std::strcmp(argv[i], "-t") || !std::strcmp(argv[i], "--to-format")) {
94+
++i;
95+
if (i < argc) {
96+
output_format = argv[i];
97+
} else {
98+
print_usage(argv[0]);
99+
}
100+
} else if (!std::strncmp(argv[i], "--to-format=", 12)) {
101+
output_format = argv[i] + 12;
102+
} else if (input_file_name.empty()) {
103+
input_file_name = argv[i];
104+
} else if (output_file_name.empty()) {
105+
output_file_name = argv[i];
106+
} else {
107+
print_usage(argv[0]);
108+
}
109+
}
110+
111+
// This declares the input and output files using either the suffix of
112+
// the file names or the format in the 2nd argument. It does not yet open
113+
// the files.
114+
const osmium::io::File input_file{input_file_name, input_format};
115+
const osmium::io::File output_file{output_file_name, output_format};
116+
117+
// Input and output files can be OSM data files (without history) or
118+
// OSM history files. History files are detected if they use the '.osh'
119+
// file suffix.
120+
if ( input_file.has_multiple_object_versions() &&
121+
!output_file.has_multiple_object_versions()) {
122+
std::cerr << "Warning! You are converting from an OSM file with (potentially) several versions of the same object to one that is not marked as such.\n";
123+
}
124+
125+
try {
126+
// Initialize Reader
127+
osmium::io::Reader reader{input_file};
128+
129+
// Get header from input file and change the "generator" setting to
130+
// ourselves.
131+
osmium::io::Header header = reader.header();
132+
header.set("generator", "osmium_convert");
133+
134+
// Initialize Writer using the header from above and tell it that it
135+
// is allowed to overwrite a possibly existing file.
136+
osmium::io::Writer writer{output_file, header, osmium::io::overwrite::allow};
137+
138+
// Match highway=primary or highway=secondary
139+
osmium::TagsFilter filter1{false};
140+
filter1.add_rule(true, "highway", "primary");
141+
filter1.add_rule(true, "highway", "secondary");
142+
143+
// Match oneway=yes
144+
osmium::TagsFilter filter2{false};
145+
filter2.add_rule(true, "oneway", "yes");
146+
147+
// Get all object matching both filters
148+
while (osmium::memory::Buffer buffer = reader.read()) { // NOLINT(bugprone-use-after-move) Bug in clang-tidy https://bugs.llvm.org/show_bug.cgi?id=36516
149+
for (const auto& object : buffer.select<osmium::OSMObject>()) {
150+
if (osmium::tags::match_any_of(object.tags(), filter1) &&
151+
osmium::tags::match_any_of(object.tags(), filter2)) {
152+
writer(object);
153+
}
154+
}
155+
}
156+
157+
// Explicitly close the writer and reader. Will throw an exception if
158+
// there is a problem. If you wait for the destructor to close the writer
159+
// and reader, you will not notice the problem, because destructors must
160+
// not throw.
161+
writer.close();
162+
reader.close();
163+
} catch (const std::exception& e) {
164+
// All exceptions used by the Osmium library derive from std::exception.
165+
std::cerr << e.what() << '\n';
166+
std::exit(1);
167+
}
168+
}
169+

0 commit comments

Comments
 (0)