262 lines
9.7 KiB
C++
262 lines
9.7 KiB
C++
|
#ifndef OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
|
||
|
#define OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
|
||
|
|
||
|
/*
|
||
|
|
||
|
This file is part of Osmium (http://osmcode.org/libosmium).
|
||
|
|
||
|
Copyright 2013-2016 Jochen Topf <jochen@topf.org> and others (see README).
|
||
|
|
||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||
|
|
||
|
Permission is hereby granted, free of charge, to any person or organization
|
||
|
obtaining a copy of the software and accompanying documentation covered by
|
||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||
|
do so, all subject to the following:
|
||
|
|
||
|
The copyright notices in the Software and this entire statement, including
|
||
|
the above license grant, this restriction and the following disclaimer,
|
||
|
must be included in all copies of the Software, in whole or in part, and
|
||
|
all derivative works of the Software, unless such copies or derivative
|
||
|
works are solely in the form of machine-executable object code generated by
|
||
|
a source language processor.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include <cinttypes>
|
||
|
#include <cstddef>
|
||
|
#include <cstdint>
|
||
|
#include <cstdio>
|
||
|
#include <future>
|
||
|
#include <iterator>
|
||
|
#include <memory>
|
||
|
#include <string>
|
||
|
#include <thread>
|
||
|
#include <utility>
|
||
|
|
||
|
#include <osmium/io/detail/output_format.hpp>
|
||
|
#include <osmium/io/file_format.hpp>
|
||
|
#include <osmium/memory/buffer.hpp>
|
||
|
#include <osmium/memory/collection.hpp>
|
||
|
#include <osmium/osm/box.hpp>
|
||
|
#include <osmium/osm/changeset.hpp>
|
||
|
#include <osmium/osm/item_type.hpp>
|
||
|
#include <osmium/osm/location.hpp>
|
||
|
#include <osmium/osm/node.hpp>
|
||
|
#include <osmium/osm/object.hpp>
|
||
|
#include <osmium/osm/relation.hpp>
|
||
|
#include <osmium/osm/tag.hpp>
|
||
|
#include <osmium/osm/timestamp.hpp>
|
||
|
#include <osmium/osm/way.hpp>
|
||
|
#include <osmium/thread/pool.hpp>
|
||
|
#include <osmium/visitor.hpp>
|
||
|
|
||
|
namespace osmium {
|
||
|
|
||
|
namespace io {
|
||
|
|
||
|
class File;
|
||
|
|
||
|
namespace detail {
|
||
|
|
||
|
struct opl_output_options {
|
||
|
|
||
|
/// Should metadata of objects be added?
|
||
|
bool add_metadata;
|
||
|
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Writes out one buffer with OSM data in OPL format.
|
||
|
*/
|
||
|
class OPLOutputBlock : public OutputBlock {
|
||
|
|
||
|
opl_output_options m_options;
|
||
|
|
||
|
void append_encoded_string(const char* data) {
|
||
|
osmium::io::detail::append_utf8_encoded_string(*m_out, data);
|
||
|
}
|
||
|
|
||
|
void write_meta(const osmium::OSMObject& object) {
|
||
|
output_formatted("%" PRId64, object.id());
|
||
|
if (m_options.add_metadata) {
|
||
|
output_formatted(" v%d d", object.version());
|
||
|
*m_out += (object.visible() ? 'V' : 'D');
|
||
|
output_formatted(" c%d t", object.changeset());
|
||
|
*m_out += object.timestamp().to_iso();
|
||
|
output_formatted(" i%d u", object.uid());
|
||
|
append_encoded_string(object.user());
|
||
|
}
|
||
|
*m_out += " T";
|
||
|
bool first = true;
|
||
|
for (const auto& tag : object.tags()) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
*m_out += ',';
|
||
|
}
|
||
|
append_encoded_string(tag.key());
|
||
|
*m_out += '=';
|
||
|
append_encoded_string(tag.value());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void write_location(const osmium::Location& location, const char x, const char y) {
|
||
|
if (location) {
|
||
|
output_formatted(" %c%.7f %c%.7f", x, location.lon_without_check(), y, location.lat_without_check());
|
||
|
} else {
|
||
|
*m_out += ' ';
|
||
|
*m_out += x;
|
||
|
*m_out += ' ';
|
||
|
*m_out += y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
|
||
|
OPLOutputBlock(osmium::memory::Buffer&& buffer, const opl_output_options& options) :
|
||
|
OutputBlock(std::move(buffer)),
|
||
|
m_options(options) {
|
||
|
}
|
||
|
|
||
|
OPLOutputBlock(const OPLOutputBlock&) = default;
|
||
|
OPLOutputBlock& operator=(const OPLOutputBlock&) = default;
|
||
|
|
||
|
OPLOutputBlock(OPLOutputBlock&&) = default;
|
||
|
OPLOutputBlock& operator=(OPLOutputBlock&&) = default;
|
||
|
|
||
|
~OPLOutputBlock() noexcept = default;
|
||
|
|
||
|
std::string operator()() {
|
||
|
osmium::apply(m_input_buffer->cbegin(), m_input_buffer->cend(), *this);
|
||
|
|
||
|
std::string out;
|
||
|
using std::swap;
|
||
|
swap(out, *m_out);
|
||
|
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
void node(const osmium::Node& node) {
|
||
|
*m_out += 'n';
|
||
|
write_meta(node);
|
||
|
write_location(node.location(), 'x', 'y');
|
||
|
*m_out += '\n';
|
||
|
}
|
||
|
|
||
|
void way(const osmium::Way& way) {
|
||
|
*m_out += 'w';
|
||
|
write_meta(way);
|
||
|
|
||
|
*m_out += " N";
|
||
|
bool first = true;
|
||
|
for (const auto& node_ref : way.nodes()) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
*m_out += ',';
|
||
|
}
|
||
|
output_formatted("n%" PRId64, node_ref.ref());
|
||
|
}
|
||
|
*m_out += '\n';
|
||
|
}
|
||
|
|
||
|
void relation(const osmium::Relation& relation) {
|
||
|
*m_out += 'r';
|
||
|
write_meta(relation);
|
||
|
|
||
|
*m_out += " M";
|
||
|
bool first = true;
|
||
|
for (const auto& member : relation.members()) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
*m_out += ',';
|
||
|
}
|
||
|
*m_out += item_type_to_char(member.type());
|
||
|
output_formatted("%" PRId64 "@", member.ref());
|
||
|
append_encoded_string(member.role());
|
||
|
}
|
||
|
*m_out += '\n';
|
||
|
}
|
||
|
|
||
|
void changeset(const osmium::Changeset& changeset) {
|
||
|
output_formatted("c%d k%d s", changeset.id(), changeset.num_changes());
|
||
|
*m_out += changeset.created_at().to_iso();
|
||
|
*m_out += " e";
|
||
|
*m_out += changeset.closed_at().to_iso();
|
||
|
output_formatted(" d%d i%d u", changeset.num_comments(), changeset.uid());
|
||
|
append_encoded_string(changeset.user());
|
||
|
write_location(changeset.bounds().bottom_left(), 'x', 'y');
|
||
|
write_location(changeset.bounds().top_right(), 'X', 'Y');
|
||
|
*m_out += " T";
|
||
|
bool first = true;
|
||
|
for (const auto& tag : changeset.tags()) {
|
||
|
if (first) {
|
||
|
first = false;
|
||
|
} else {
|
||
|
*m_out += ',';
|
||
|
}
|
||
|
append_encoded_string(tag.key());
|
||
|
*m_out += '=';
|
||
|
append_encoded_string(tag.value());
|
||
|
}
|
||
|
|
||
|
*m_out += '\n';
|
||
|
}
|
||
|
|
||
|
}; // class OPLOutputBlock
|
||
|
|
||
|
class OPLOutputFormat : public osmium::io::detail::OutputFormat {
|
||
|
|
||
|
opl_output_options m_options;
|
||
|
|
||
|
public:
|
||
|
|
||
|
OPLOutputFormat(const osmium::io::File& file, future_string_queue_type& output_queue) :
|
||
|
OutputFormat(output_queue),
|
||
|
m_options() {
|
||
|
m_options.add_metadata = file.is_not_false("add_metadata");
|
||
|
}
|
||
|
|
||
|
OPLOutputFormat(const OPLOutputFormat&) = delete;
|
||
|
OPLOutputFormat& operator=(const OPLOutputFormat&) = delete;
|
||
|
|
||
|
~OPLOutputFormat() noexcept final = default;
|
||
|
|
||
|
void write_buffer(osmium::memory::Buffer&& buffer) final {
|
||
|
m_output_queue.push(osmium::thread::Pool::instance().submit(OPLOutputBlock{std::move(buffer), m_options}));
|
||
|
}
|
||
|
|
||
|
}; // class OPLOutputFormat
|
||
|
|
||
|
// we want the register_output_format() function to run, setting
|
||
|
// the variable is only a side-effect, it will never be used
|
||
|
const bool registered_opl_output = osmium::io::detail::OutputFormatFactory::instance().register_output_format(osmium::io::file_format::opl,
|
||
|
[](const osmium::io::File& file, future_string_queue_type& output_queue) {
|
||
|
return new osmium::io::detail::OPLOutputFormat(file, output_queue);
|
||
|
});
|
||
|
|
||
|
// dummy function to silence the unused variable warning from above
|
||
|
inline bool get_registered_opl_output() noexcept {
|
||
|
return registered_opl_output;
|
||
|
}
|
||
|
|
||
|
} // namespace detail
|
||
|
|
||
|
} // namespace io
|
||
|
|
||
|
} // namespace osmium
|
||
|
|
||
|
#endif // OSMIUM_IO_DETAIL_OPL_OUTPUT_FORMAT_HPP
|