Merge commit '879f7eb04200d7d2c28af565229bf6e3d54274fd' into retry/libosmium
This commit is contained in:
+81
-10
@@ -110,8 +110,12 @@ namespace gdalcpp {
|
||||
namespace detail {
|
||||
|
||||
struct init_wrapper {
|
||||
#if GDAL_VERSION_MAJOR >= 2
|
||||
init_wrapper() { GDALAllRegister(); }
|
||||
#else
|
||||
init_wrapper() { OGRRegisterAll(); }
|
||||
~init_wrapper() { OGRCleanupAll(); }
|
||||
#endif
|
||||
};
|
||||
|
||||
struct init_library {
|
||||
@@ -237,6 +241,8 @@ namespace gdalcpp {
|
||||
detail::Options m_options;
|
||||
SRS m_srs;
|
||||
std::unique_ptr<gdal_dataset_type, gdal_dataset_deleter> m_dataset;
|
||||
uint64_t m_edit_count = 0;
|
||||
uint64_t m_max_edit_count = 0;
|
||||
|
||||
public:
|
||||
|
||||
@@ -255,6 +261,15 @@ namespace gdalcpp {
|
||||
}
|
||||
}
|
||||
|
||||
~Dataset() {
|
||||
try {
|
||||
if (m_edit_count > 0) {
|
||||
commit_transaction();
|
||||
}
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& driver_name() const {
|
||||
return m_driver_name;
|
||||
}
|
||||
@@ -282,10 +297,14 @@ namespace gdalcpp {
|
||||
exec(sql.c_str());
|
||||
}
|
||||
|
||||
|
||||
Dataset& start_transaction() {
|
||||
#if GDAL_VERSION_MAJOR >= 2
|
||||
m_dataset->StartTransaction();
|
||||
#else
|
||||
OGRLayer* layer = m_dataset->GetLayer(0);
|
||||
if (layer) {
|
||||
layer->StartTransaction();
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
@@ -293,7 +312,38 @@ namespace gdalcpp {
|
||||
Dataset& commit_transaction() {
|
||||
#if GDAL_VERSION_MAJOR >= 2
|
||||
m_dataset->CommitTransaction();
|
||||
#else
|
||||
OGRLayer* layer = m_dataset->GetLayer(0);
|
||||
if (layer) {
|
||||
layer->CommitTransaction();
|
||||
}
|
||||
#endif
|
||||
m_edit_count = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void prepare_edit() {
|
||||
if (m_max_edit_count != 0 && m_edit_count == 0) {
|
||||
start_transaction();
|
||||
}
|
||||
}
|
||||
|
||||
void finalize_edit() {
|
||||
if (m_max_edit_count != 0 && ++m_edit_count > m_max_edit_count) {
|
||||
commit_transaction();
|
||||
}
|
||||
}
|
||||
|
||||
Dataset& enable_auto_transactions(uint64_t edits = 100000) {
|
||||
m_max_edit_count = edits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Dataset& disable_auto_transactions() {
|
||||
if (m_max_edit_count != 0 && m_edit_count > 0) {
|
||||
commit_transaction();
|
||||
}
|
||||
m_max_edit_count = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -346,19 +396,32 @@ namespace gdalcpp {
|
||||
return *this;
|
||||
}
|
||||
|
||||
void create_feature(OGRFeature* feature) {
|
||||
dataset().prepare_edit();
|
||||
OGRErr result = m_layer->CreateFeature(feature);
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("creating feature in layer '") + name() + "' failed", result, dataset().driver_name(), dataset().dataset_name());
|
||||
}
|
||||
dataset().finalize_edit();
|
||||
}
|
||||
|
||||
Layer& start_transaction() {
|
||||
#if GDAL_VERSION_MAJOR < 2
|
||||
OGRErr result = m_layer->StartTransaction();
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("starting transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
Layer& commit_transaction() {
|
||||
#if GDAL_VERSION_MAJOR < 2
|
||||
OGRErr result = m_layer->CommitTransaction();
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("committing transaction on layer '") + name() + "' failed", result, m_dataset.driver_name(), m_dataset.dataset_name(), name());
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -366,36 +429,44 @@ namespace gdalcpp {
|
||||
|
||||
class Feature {
|
||||
|
||||
struct ogr_feature_deleter {
|
||||
|
||||
void operator()(OGRFeature* feature) {
|
||||
OGRFeature::DestroyFeature(feature);
|
||||
}
|
||||
|
||||
}; // struct ogr_feature_deleter
|
||||
|
||||
Layer& m_layer;
|
||||
OGRFeature m_feature;
|
||||
std::unique_ptr<OGRFeature, ogr_feature_deleter> m_feature;
|
||||
|
||||
public:
|
||||
|
||||
Feature(Layer& layer, std::unique_ptr<OGRGeometry>&& geometry) :
|
||||
m_layer(layer),
|
||||
m_feature(m_layer.get().GetLayerDefn()) {
|
||||
OGRErr result = m_feature.SetGeometryDirectly(geometry.release());
|
||||
m_feature(OGRFeature::CreateFeature(m_layer.get().GetLayerDefn())) {
|
||||
if (!m_feature) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
OGRErr result = m_feature->SetGeometryDirectly(geometry.release());
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("setting feature geometry in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
|
||||
}
|
||||
}
|
||||
|
||||
void add_to_layer() {
|
||||
OGRErr result = m_layer.get().CreateFeature(&m_feature);
|
||||
if (result != OGRERR_NONE) {
|
||||
throw gdal_error(std::string("creating feature in layer '") + m_layer.name() + "' failed", result, m_layer.dataset().driver_name(), m_layer.dataset().dataset_name());
|
||||
}
|
||||
m_layer.create_feature(m_feature.get());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Feature& set_field(int n, T&& arg) {
|
||||
m_feature.SetField(n, std::forward<T>(arg));
|
||||
m_feature->SetField(n, std::forward<T>(arg));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Feature& set_field(const char* name, T&& arg) {
|
||||
m_feature.SetField(name, std::forward<T>(arg));
|
||||
m_feature->SetField(name, std::forward<T>(arg));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
+1281
-479
File diff suppressed because it is too large
Load Diff
@@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/area/detail/vector.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
|
||||
@@ -53,108 +54,178 @@ namespace osmium {
|
||||
*/
|
||||
namespace detail {
|
||||
|
||||
class ProtoRing;
|
||||
|
||||
enum class role_type : uint8_t {
|
||||
unknown = 0,
|
||||
outer = 1,
|
||||
inner = 2,
|
||||
empty = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* This helper class for the Assembler class models a segment.
|
||||
* Segments are the connection between
|
||||
* two nodes and they all have their smaller coordinate at the
|
||||
* beginning of the segment. Smaller, in this case, means smaller x
|
||||
* coordinate, and if they are the same smaller y coordinate.
|
||||
* This helper class for the Assembler class models a segment,
|
||||
* the connection between two nodes.
|
||||
*
|
||||
* Internally segments have their smaller coordinate at the
|
||||
* beginning of the segment. Smaller, in this case, means smaller
|
||||
* x coordinate, and, if they are the same, smaller y coordinate.
|
||||
*/
|
||||
class NodeRefSegment {
|
||||
|
||||
// First node in order described above.
|
||||
osmium::NodeRef m_first;
|
||||
|
||||
// Second node in order described above.
|
||||
osmium::NodeRef m_second;
|
||||
|
||||
/// Role of the member this segment was from.
|
||||
const char* m_role;
|
||||
|
||||
/// Way this segment was from.
|
||||
// Way this segment was from.
|
||||
const osmium::Way* m_way;
|
||||
|
||||
// The ring this segment is part of. Initially nullptr, this
|
||||
// will be filled in once we know which ring the segment is in.
|
||||
ProtoRing* m_ring;
|
||||
|
||||
// The role of this segment from the member role.
|
||||
role_type m_role;
|
||||
|
||||
// Nodes have to be reversed to get the intended order.
|
||||
bool m_reverse = false;
|
||||
|
||||
// We found the right direction for this segment in the ring.
|
||||
// (This depends on whether it is an inner or outer ring.)
|
||||
bool m_direction_done = false;
|
||||
|
||||
public:
|
||||
|
||||
void swap_locations() {
|
||||
using std::swap;
|
||||
swap(m_first, m_second);
|
||||
}
|
||||
|
||||
explicit NodeRefSegment() noexcept :
|
||||
NodeRefSegment() noexcept :
|
||||
m_first(),
|
||||
m_second(),
|
||||
m_role(nullptr),
|
||||
m_way(nullptr) {
|
||||
m_way(nullptr),
|
||||
m_ring(nullptr),
|
||||
m_role(role_type::unknown) {
|
||||
}
|
||||
|
||||
explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
|
||||
NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, role_type role = role_type::unknown, const osmium::Way* way = nullptr) noexcept :
|
||||
m_first(nr1),
|
||||
m_second(nr2),
|
||||
m_role(role),
|
||||
m_way(way) {
|
||||
m_way(way),
|
||||
m_ring(nullptr),
|
||||
m_role(role) {
|
||||
if (nr2.location() < nr1.location()) {
|
||||
swap_locations();
|
||||
using std::swap;
|
||||
swap(m_first, m_second);
|
||||
}
|
||||
}
|
||||
|
||||
NodeRefSegment(const NodeRefSegment&) = default;
|
||||
NodeRefSegment(NodeRefSegment&&) = default;
|
||||
/**
|
||||
* The ring this segment is a part of. nullptr if we don't
|
||||
* have the ring yet.
|
||||
*/
|
||||
ProtoRing* ring() const noexcept {
|
||||
return m_ring;
|
||||
}
|
||||
|
||||
NodeRefSegment& operator=(const NodeRefSegment&) = default;
|
||||
NodeRefSegment& operator=(NodeRefSegment&&) = default;
|
||||
/**
|
||||
* Returns true if the segment has already been placed in a
|
||||
* ring.
|
||||
*/
|
||||
bool is_done() const noexcept {
|
||||
return m_ring != nullptr;
|
||||
}
|
||||
|
||||
~NodeRefSegment() = default;
|
||||
void set_ring(ProtoRing* ring) noexcept {
|
||||
assert(ring);
|
||||
m_ring = ring;
|
||||
}
|
||||
|
||||
/// Return first NodeRef of Segment according to sorting order (bottom left to top right).
|
||||
bool is_reverse() const noexcept {
|
||||
return m_reverse;
|
||||
}
|
||||
|
||||
void reverse() noexcept {
|
||||
m_reverse = !m_reverse;
|
||||
}
|
||||
|
||||
bool is_direction_done() const noexcept {
|
||||
return m_direction_done;
|
||||
}
|
||||
|
||||
void mark_direction_done() noexcept {
|
||||
m_direction_done = true;
|
||||
}
|
||||
|
||||
void mark_direction_not_done() noexcept {
|
||||
m_direction_done = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return first NodeRef of Segment according to sorting
|
||||
* order (bottom left to top right).
|
||||
*/
|
||||
const osmium::NodeRef& first() const noexcept {
|
||||
return m_first;
|
||||
}
|
||||
|
||||
/// Return second NodeRef of Segment according to sorting order (bottom left to top right).
|
||||
/**
|
||||
* Return second NodeRef of Segment according to sorting
|
||||
* order (bottom left to top right).
|
||||
*/
|
||||
const osmium::NodeRef& second() const noexcept {
|
||||
return m_second;
|
||||
}
|
||||
|
||||
bool to_left_of(const osmium::Location& location) const {
|
||||
// std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
|
||||
/**
|
||||
* Return real first NodeRef of Segment.
|
||||
*/
|
||||
const osmium::NodeRef& start() const noexcept {
|
||||
return m_reverse ? m_second : m_first;
|
||||
}
|
||||
|
||||
if (first().location() == location || second().location() == location) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::pair<osmium::Location, osmium::Location> mm = std::minmax(first().location(), second().location(), [](const osmium::Location a, const osmium::Location b) {
|
||||
return a.y() < b.y();
|
||||
});
|
||||
|
||||
if (mm.first.y() >= location.y() || mm.second.y() < location.y() || first().location().x() > location.x()) {
|
||||
// std::cerr << " false\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t ax = mm.first.x();
|
||||
int64_t bx = mm.second.x();
|
||||
int64_t lx = location.x();
|
||||
int64_t ay = mm.first.y();
|
||||
int64_t by = mm.second.y();
|
||||
int64_t ly = location.y();
|
||||
return ((bx - ax)*(ly - ay) - (by - ay)*(lx - ax)) <= 0;
|
||||
/**
|
||||
* Return real second NodeRef of Segment.
|
||||
*/
|
||||
const osmium::NodeRef& stop() const noexcept {
|
||||
return m_reverse ? m_first : m_second;
|
||||
}
|
||||
|
||||
bool role_outer() const noexcept {
|
||||
return !strcmp(m_role, "outer");
|
||||
return m_role == role_type::outer;
|
||||
}
|
||||
|
||||
bool role_inner() const noexcept {
|
||||
return !strcmp(m_role, "inner");
|
||||
return m_role == role_type::inner;
|
||||
}
|
||||
|
||||
bool role_empty() const noexcept {
|
||||
return m_role == role_type::empty;
|
||||
}
|
||||
|
||||
const char* role_name() const noexcept {
|
||||
static const char* names[] = { "unknown", "outer", "inner", "empty" };
|
||||
return names[int(m_role)];
|
||||
}
|
||||
|
||||
const osmium::Way* way() const noexcept {
|
||||
return m_way;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "determinant" of this segment. Used for calculating
|
||||
* the winding order or a ring.
|
||||
*/
|
||||
int64_t det() const noexcept {
|
||||
const vec a{start()};
|
||||
const vec b{stop()};
|
||||
return a * b;
|
||||
}
|
||||
|
||||
}; // class NodeRefSegment
|
||||
|
||||
/// NodeRefSegments are equal if both their locations are equal
|
||||
inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
|
||||
return lhs.first().location() == rhs.first().location() &&
|
||||
lhs.second().location() == rhs.second().location();
|
||||
}
|
||||
|
||||
inline bool operator!=(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
@@ -162,12 +233,33 @@ namespace osmium {
|
||||
}
|
||||
|
||||
/**
|
||||
* NodeRefSegments are "smaller" if they are to the left and down of another
|
||||
* segment. The first() location is checked first() and only if they have the
|
||||
* same first() location the second() location is taken into account.
|
||||
* A NodeRefSegment is "smaller" if the first point is to the
|
||||
* left and down of the first point of the second segment.
|
||||
* If both first points are the same, the segment with the higher
|
||||
* slope comes first. If the slope is the same, the shorter
|
||||
* segment comes first.
|
||||
*/
|
||||
inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
|
||||
if (lhs.first().location() == rhs.first().location()) {
|
||||
const vec p0{lhs.first().location()};
|
||||
const vec p1{lhs.second().location()};
|
||||
const vec q0{rhs.first().location()};
|
||||
const vec q1{rhs.second().location()};
|
||||
const vec p = p1 - p0;
|
||||
const vec q = q1 - q0;
|
||||
|
||||
if (p.x == 0 && q.x == 0) {
|
||||
return p.y < q.y;
|
||||
}
|
||||
|
||||
const auto a = p.y * q.x;
|
||||
const auto b = q.y * p.x;
|
||||
if (a == b) {
|
||||
return p.x < q.x;
|
||||
}
|
||||
return a > b;
|
||||
}
|
||||
return lhs.first().location() < rhs.first().location();
|
||||
}
|
||||
|
||||
inline bool operator>(const NodeRefSegment& lhs, const NodeRefSegment& rhs) noexcept {
|
||||
@@ -184,7 +276,10 @@ namespace osmium {
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const NodeRefSegment& segment) {
|
||||
return out << segment.first() << "--" << segment.second();
|
||||
return out << segment.start() << "--" << segment.stop()
|
||||
<< "[" << (segment.is_reverse() ? 'R' : '_')
|
||||
<< (segment.is_done() ? 'd' : '_')
|
||||
<< (segment.is_direction_done() ? 'D' : '_') << "]";
|
||||
}
|
||||
|
||||
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
|
||||
@@ -194,7 +289,7 @@ namespace osmium {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
|
||||
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
|
||||
const std::pair<int32_t, int32_t> m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
|
||||
const std::pair<int32_t, int32_t> m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
|
||||
if (m1.first > m2.second || m2.first > m1.second) {
|
||||
@@ -210,55 +305,94 @@ namespace osmium {
|
||||
* might be slightly different than the numerically correct
|
||||
* location.
|
||||
*
|
||||
* This function uses integer arithmentic as much as possible and
|
||||
* This function uses integer arithmetic as much as possible and
|
||||
* will not work if the segments are longer than about half the
|
||||
* planet. This shouldn't happen with real data, so it isn't a big
|
||||
* problem.
|
||||
*
|
||||
* If the segments touch in one of their endpoints, it doesn't
|
||||
* count as an intersection.
|
||||
* If the segments touch in one or both of their endpoints, it
|
||||
* doesn't count as an intersection.
|
||||
*
|
||||
* If the segments intersect not in a single point but in multiple
|
||||
* points, ie if they overlap, this is NOT detected.
|
||||
* points, ie if they are collinear and overlap, the smallest
|
||||
* of the endpoints that is in the overlapping section is returned.
|
||||
*
|
||||
* @returns Undefined osmium::Location if there is no intersection
|
||||
* or a defined Location if the segments intersect.
|
||||
*/
|
||||
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) {
|
||||
if (s1.first().location() == s2.first().location() ||
|
||||
s1.first().location() == s2.second().location() ||
|
||||
s1.second().location() == s2.first().location() ||
|
||||
s1.second().location() == s2.second().location()) {
|
||||
inline osmium::Location calculate_intersection(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
|
||||
// See http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
|
||||
// for some hints about how the algorithm works.
|
||||
const vec p0{s1.first()};
|
||||
const vec p1{s1.second()};
|
||||
const vec q0{s2.first()};
|
||||
const vec q1{s2.second()};
|
||||
|
||||
if ((p0 == q0 && p1 == q1) ||
|
||||
(p0 == q1 && p1 == q0)) {
|
||||
// segments are the same
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
int64_t s1ax = s1.first().x();
|
||||
int64_t s1ay = s1.first().y();
|
||||
int64_t s1bx = s1.second().x();
|
||||
int64_t s1by = s1.second().y();
|
||||
int64_t s2ax = s2.first().x();
|
||||
int64_t s2ay = s2.first().y();
|
||||
int64_t s2bx = s2.second().x();
|
||||
int64_t s2by = s2.second().y();
|
||||
|
||||
int64_t d = (s2by - s2ay) * (s1bx - s1ax) -
|
||||
(s2bx - s2ax) * (s1by - s1ay);
|
||||
const vec pd = p1 - p0;
|
||||
const int64_t d = pd * (q1 - q0);
|
||||
|
||||
if (d != 0) {
|
||||
int64_t na = (s2bx - s2ax) * (s1ay - s2ay) -
|
||||
(s2by - s2ay) * (s1ax - s2ax);
|
||||
// segments are not collinear
|
||||
|
||||
int64_t nb = (s1bx - s1ax) * (s1ay - s2ay) -
|
||||
(s1by - s1ay) * (s1ax - s2ax);
|
||||
if (p0 == q0 || p0 == q1 || p1 == q0 || p1 == q1) {
|
||||
// touching at an end point
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
// intersection in a point
|
||||
|
||||
const int64_t na = (q1.x - q0.x) * (p0.y - q0.y) -
|
||||
(q1.y - q0.y) * (p0.x - q0.x);
|
||||
|
||||
const int64_t nb = (p1.x - p0.x) * (p0.y - q0.y) -
|
||||
(p1.y - p0.y) * (p0.x - q0.x);
|
||||
|
||||
if ((d > 0 && na >= 0 && na <= d && nb >= 0 && nb <= d) ||
|
||||
(d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {
|
||||
const double ua = double(na) / d;
|
||||
const vec i = p0 + ua * (p1 - p0);
|
||||
return osmium::Location(int32_t(i.x), int32_t(i.y));
|
||||
}
|
||||
|
||||
double ua = double(na) / d;
|
||||
int32_t ix = int32_t(s1ax + ua*(s1bx - s1ax));
|
||||
int32_t iy = int32_t(s1ay + ua*(s1by - s1ay));
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
return osmium::Location(ix, iy);
|
||||
// segments are collinear
|
||||
|
||||
if (pd * (q0 - p0) == 0) {
|
||||
// segments are on the same line
|
||||
|
||||
struct seg_loc {
|
||||
int segment;
|
||||
osmium::Location location;
|
||||
};
|
||||
|
||||
seg_loc sl[4];
|
||||
sl[0] = {0, s1.first().location() };
|
||||
sl[1] = {0, s1.second().location()};
|
||||
sl[2] = {1, s2.first().location() };
|
||||
sl[3] = {1, s2.second().location()};
|
||||
|
||||
std::sort(sl, sl+4, [](const seg_loc& a, const seg_loc& b) {
|
||||
return a.location < b.location;
|
||||
});
|
||||
|
||||
if (sl[1].location == sl[2].location) {
|
||||
return osmium::Location();
|
||||
}
|
||||
|
||||
if (sl[0].segment != sl[1].segment) {
|
||||
if (sl[0].location == sl[1].location) {
|
||||
return sl[2].location;
|
||||
} else {
|
||||
return sl[1].location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+99
-157
@@ -34,10 +34,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@@ -47,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Way;
|
||||
|
||||
namespace area {
|
||||
|
||||
namespace detail {
|
||||
@@ -58,214 +59,155 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::vector<NodeRefSegment> segments_type;
|
||||
using segments_type = std::vector<NodeRefSegment*>;
|
||||
|
||||
private:
|
||||
|
||||
// segments in this ring
|
||||
// Segments in this ring.
|
||||
segments_type m_segments;
|
||||
|
||||
bool m_outer {true};
|
||||
|
||||
// if this is an outer ring, these point to it's inner rings (if any)
|
||||
// If this is an outer ring, these point to it's inner rings
|
||||
// (if any).
|
||||
std::vector<ProtoRing*> m_inner;
|
||||
|
||||
// The smallest segment. Will be kept current whenever a new
|
||||
// segment is added to the ring.
|
||||
NodeRefSegment* m_min_segment;
|
||||
|
||||
// If this is an inner ring, points to the outer ring.
|
||||
ProtoRing* m_outer_ring;
|
||||
|
||||
int64_t m_sum;
|
||||
|
||||
public:
|
||||
|
||||
explicit ProtoRing(const NodeRefSegment& segment) noexcept :
|
||||
m_segments() {
|
||||
explicit ProtoRing(NodeRefSegment* segment) noexcept :
|
||||
m_segments(),
|
||||
m_inner(),
|
||||
m_min_segment(segment),
|
||||
m_outer_ring(nullptr),
|
||||
m_sum(0) {
|
||||
add_segment_back(segment);
|
||||
}
|
||||
|
||||
explicit ProtoRing(segments_type::const_iterator sbegin, segments_type::const_iterator send) :
|
||||
m_segments(static_cast<size_t>(std::distance(sbegin, send))) {
|
||||
std::copy(sbegin, send, m_segments.begin());
|
||||
void add_segment_back(NodeRefSegment* segment) {
|
||||
assert(segment);
|
||||
if (*segment < *m_min_segment) {
|
||||
m_min_segment = segment;
|
||||
}
|
||||
m_segments.push_back(segment);
|
||||
segment->set_ring(this);
|
||||
m_sum += segment->det();
|
||||
}
|
||||
|
||||
bool outer() const noexcept {
|
||||
return m_outer;
|
||||
NodeRefSegment* min_segment() const noexcept {
|
||||
return m_min_segment;
|
||||
}
|
||||
|
||||
void set_inner() noexcept {
|
||||
m_outer = false;
|
||||
ProtoRing* outer_ring() const noexcept {
|
||||
return m_outer_ring;
|
||||
}
|
||||
|
||||
segments_type& segments() noexcept {
|
||||
return m_segments;
|
||||
void set_outer_ring(ProtoRing* outer_ring) noexcept {
|
||||
assert(outer_ring);
|
||||
assert(m_inner.empty());
|
||||
m_outer_ring = outer_ring;
|
||||
}
|
||||
|
||||
const std::vector<ProtoRing*>& inner_rings() const noexcept {
|
||||
return m_inner;
|
||||
}
|
||||
|
||||
void add_inner_ring(ProtoRing* ring) {
|
||||
assert(ring);
|
||||
assert(!m_outer_ring);
|
||||
m_inner.push_back(ring);
|
||||
}
|
||||
|
||||
bool is_outer() const noexcept {
|
||||
return !m_outer_ring;
|
||||
}
|
||||
|
||||
const segments_type& segments() const noexcept {
|
||||
return m_segments;
|
||||
}
|
||||
|
||||
void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
|
||||
m_segments.erase(sbegin, send);
|
||||
const NodeRef& get_node_ref_start() const noexcept {
|
||||
return m_segments.front()->start();
|
||||
}
|
||||
|
||||
void add_segment_front(const NodeRefSegment& segment) {
|
||||
m_segments.insert(m_segments.begin(), segment);
|
||||
const NodeRef& get_node_ref_stop() const noexcept {
|
||||
return m_segments.back()->stop();
|
||||
}
|
||||
|
||||
void add_segment_back(const NodeRefSegment& segment) {
|
||||
m_segments.push_back(segment);
|
||||
bool closed() const noexcept {
|
||||
return get_node_ref_start().location() == get_node_ref_stop().location();
|
||||
}
|
||||
|
||||
const NodeRefSegment& get_segment_front() const {
|
||||
return m_segments.front();
|
||||
void reverse() {
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
|
||||
segment->reverse();
|
||||
});
|
||||
std::reverse(m_segments.begin(), m_segments.end());
|
||||
m_sum = -m_sum;
|
||||
}
|
||||
|
||||
NodeRefSegment& get_segment_front() {
|
||||
return m_segments.front();
|
||||
void mark_direction_done() {
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
|
||||
segment->mark_direction_done();
|
||||
});
|
||||
}
|
||||
|
||||
const NodeRef& get_node_ref_front() const {
|
||||
return get_segment_front().first();
|
||||
bool is_cw() const noexcept {
|
||||
return m_sum <= 0;
|
||||
}
|
||||
|
||||
const NodeRefSegment& get_segment_back() const {
|
||||
return m_segments.back();
|
||||
int64_t sum() const noexcept {
|
||||
return m_sum;
|
||||
}
|
||||
|
||||
NodeRefSegment& get_segment_back() {
|
||||
return m_segments.back();
|
||||
}
|
||||
|
||||
const NodeRef& get_node_ref_back() const {
|
||||
return get_segment_back().second();
|
||||
}
|
||||
|
||||
bool closed() const {
|
||||
return m_segments.front().first().location() == m_segments.back().second().location();
|
||||
}
|
||||
|
||||
int64_t sum() const {
|
||||
int64_t sum = 0;
|
||||
|
||||
for (const auto& segment : m_segments) {
|
||||
sum += static_cast<int64_t>(segment.first().location().x()) * static_cast<int64_t>(segment.second().location().y()) -
|
||||
static_cast<int64_t>(segment.second().location().x()) * static_cast<int64_t>(segment.first().location().y());
|
||||
void fix_direction() noexcept {
|
||||
if (is_cw() == is_outer()) {
|
||||
reverse();
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
bool is_cw() const {
|
||||
return sum() <= 0;
|
||||
void reset() {
|
||||
m_inner.clear();
|
||||
m_outer_ring = nullptr;
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment* segment) {
|
||||
segment->mark_direction_not_done();
|
||||
});
|
||||
}
|
||||
|
||||
int64_t area() const {
|
||||
return std::abs(sum()) / 2;
|
||||
void get_ways(std::set<const osmium::Way*>& ways) const {
|
||||
for (const auto& segment : m_segments) {
|
||||
ways.insert(segment->way());
|
||||
}
|
||||
}
|
||||
|
||||
void swap_segments(ProtoRing& other) {
|
||||
using std::swap;
|
||||
swap(m_segments, other.m_segments);
|
||||
void join_forward(ProtoRing& other) {
|
||||
for (NodeRefSegment* segment : other.m_segments) {
|
||||
add_segment_back(segment);
|
||||
}
|
||||
}
|
||||
|
||||
void add_inner_ring(ProtoRing* ring) {
|
||||
m_inner.push_back(ring);
|
||||
}
|
||||
|
||||
const std::vector<ProtoRing*>& inner_rings() const {
|
||||
return m_inner;
|
||||
void join_backward(ProtoRing& other) {
|
||||
for (auto it = other.m_segments.rbegin(); it != other.m_segments.rend(); ++it) {
|
||||
(*it)->reverse();
|
||||
add_segment_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void print(std::ostream& out) const {
|
||||
out << "[";
|
||||
bool first = true;
|
||||
if (!m_segments.empty()) {
|
||||
out << m_segments.front()->start().ref();
|
||||
}
|
||||
for (const auto& segment : m_segments) {
|
||||
if (first) {
|
||||
out << segment.first().ref();
|
||||
}
|
||||
out << ',' << segment.second().ref();
|
||||
first = false;
|
||||
out << ',' << segment->stop().ref();
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
void reverse() {
|
||||
std::for_each(m_segments.begin(), m_segments.end(), [](NodeRefSegment& segment) {
|
||||
segment.swap_locations();
|
||||
});
|
||||
std::reverse(m_segments.begin(), m_segments.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge other ring to end of this ring.
|
||||
*/
|
||||
void merge_ring(const ProtoRing& other, bool debug) {
|
||||
if (debug) {
|
||||
std::cerr << " MERGE rings ";
|
||||
print(std::cerr);
|
||||
std::cerr << " to ";
|
||||
other.print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
m_segments.insert(m_segments.end(), other.m_segments.begin(), other.m_segments.end());
|
||||
if (debug) {
|
||||
std::cerr << " result ring: ";
|
||||
print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void merge_ring_reverse(const ProtoRing& other, bool debug) {
|
||||
if (debug) {
|
||||
std::cerr << " MERGE rings (reverse) ";
|
||||
print(std::cerr);
|
||||
std::cerr << " to ";
|
||||
other.print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
size_t n = m_segments.size();
|
||||
m_segments.resize(n + other.m_segments.size());
|
||||
std::transform(other.m_segments.rbegin(), other.m_segments.rend(), m_segments.begin() + static_cast<segments_type::difference_type>(n), [](NodeRefSegment segment) {
|
||||
segment.swap_locations();
|
||||
return segment;
|
||||
});
|
||||
if (debug) {
|
||||
std::cerr << " result ring: ";
|
||||
print(std::cerr);
|
||||
std::cerr << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
const NodeRef& min_node() const {
|
||||
auto it = std::min_element(m_segments.begin(), m_segments.end());
|
||||
if (location_less()(it->first(), it->second())) {
|
||||
return it->first();
|
||||
} else {
|
||||
return it->second();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_in(ProtoRing* outer) {
|
||||
osmium::Location testpoint = segments().front().first().location();
|
||||
bool is_in = false;
|
||||
|
||||
for (size_t i = 0, j = outer->segments().size()-1; i < outer->segments().size(); j = i++) {
|
||||
if (((outer->segments()[i].first().location().y() > testpoint.y()) != (outer->segments()[j].first().location().y() > testpoint.y())) &&
|
||||
(testpoint.x() < (outer->segments()[j].first().location().x() - outer->segments()[i].first().location().x()) * (testpoint.y() - outer->segments()[i].first().location().y()) / (outer->segments()[j].first().location().y() - outer->segments()[i].first().location().y()) + outer->segments()[i].first().location().x()) ) {
|
||||
is_in = !is_in;
|
||||
}
|
||||
}
|
||||
|
||||
return is_in;
|
||||
}
|
||||
|
||||
void get_ways(std::set<const osmium::Way*>& ways) {
|
||||
for (const auto& segment : m_segments) {
|
||||
ways.insert(segment.way());
|
||||
}
|
||||
}
|
||||
|
||||
bool contains(const NodeRefSegment& segment) const {
|
||||
for (const auto& s : m_segments) {
|
||||
if (s == segment || (s.first() == segment.second() && s.second() == segment.first())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
out << "]-" << (is_outer() ? "OUTER" : "INNER");
|
||||
}
|
||||
|
||||
}; // class ProtoRing
|
||||
|
||||
+139
-34
@@ -35,12 +35,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/area/detail/node_ref_segment.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
@@ -52,6 +56,24 @@ namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Iterate over all relation members and the vector of ways at the
|
||||
* same time and call given function with the relation member and
|
||||
* way as parameter. This takes into account that there might be
|
||||
* non-way members in the relation.
|
||||
*/
|
||||
template <typename F>
|
||||
inline void for_each_member(const osmium::Relation& relation, const std::vector<const osmium::Way*>& ways, F&& func) {
|
||||
auto way_it = ways.cbegin();
|
||||
for (const osmium::RelationMember& member : relation.members()) {
|
||||
if (member.type() == osmium::item_type::way) {
|
||||
assert(way_it != ways.cend());
|
||||
func(member, **way_it);
|
||||
++way_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper class for the area assembler. It models
|
||||
* a list of segments.
|
||||
@@ -64,6 +86,51 @@ namespace osmium {
|
||||
|
||||
bool m_debug;
|
||||
|
||||
static role_type parse_role(const char* role) noexcept {
|
||||
if (role[0] == '\0') {
|
||||
return role_type::empty;
|
||||
} else if (!std::strcmp(role, "outer")) {
|
||||
return role_type::outer;
|
||||
} else if (!std::strcmp(role, "inner")) {
|
||||
return role_type::inner;
|
||||
}
|
||||
return role_type::unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the number of segments in all the ways together.
|
||||
*/
|
||||
static size_t get_num_segments(const std::vector<const osmium::Way*>& members) noexcept {
|
||||
return std::accumulate(members.cbegin(), members.cend(), 0, [](size_t sum, const osmium::Way* way) {
|
||||
if (way->nodes().empty()) {
|
||||
return sum;
|
||||
} else {
|
||||
return sum + way->nodes().size() - 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint32_t extract_segments_from_way_impl(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way, role_type role) {
|
||||
uint32_t duplicate_nodes = 0;
|
||||
|
||||
osmium::NodeRef previous_nr;
|
||||
for (const osmium::NodeRef& nr : way.nodes()) {
|
||||
if (previous_nr.location()) {
|
||||
if (previous_nr.location() != nr.location()) {
|
||||
m_segments.emplace_back(previous_nr, nr, role, &way);
|
||||
} else {
|
||||
++duplicate_nodes;
|
||||
if (problem_reporter) {
|
||||
problem_reporter->report_duplicate_node(previous_nr.ref(), nr.ref(), nr.location());
|
||||
}
|
||||
}
|
||||
}
|
||||
previous_nr = nr;
|
||||
}
|
||||
|
||||
return duplicate_nodes;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit SegmentList(bool debug) noexcept :
|
||||
@@ -84,12 +151,31 @@ namespace osmium {
|
||||
return m_segments.size();
|
||||
}
|
||||
|
||||
/// Is the segment list empty?
|
||||
bool empty() const noexcept {
|
||||
return m_segments.empty();
|
||||
}
|
||||
|
||||
typedef slist_type::const_iterator const_iterator;
|
||||
typedef slist_type::iterator iterator;
|
||||
using const_iterator = slist_type::const_iterator;
|
||||
using iterator = slist_type::iterator;
|
||||
|
||||
NodeRefSegment& front() {
|
||||
return m_segments.front();
|
||||
}
|
||||
|
||||
NodeRefSegment& back() {
|
||||
return m_segments.back();
|
||||
}
|
||||
|
||||
const NodeRefSegment& operator[](size_t n) const noexcept {
|
||||
assert(n < m_segments.size());
|
||||
return m_segments[n];
|
||||
}
|
||||
|
||||
NodeRefSegment& operator[](size_t n) noexcept {
|
||||
assert(n < m_segments.size());
|
||||
return m_segments[n];
|
||||
}
|
||||
|
||||
iterator begin() noexcept {
|
||||
return m_segments.begin();
|
||||
@@ -115,11 +201,6 @@ namespace osmium {
|
||||
m_debug = debug;
|
||||
}
|
||||
|
||||
/// Clear the list of segments. All segments are removed.
|
||||
void clear() {
|
||||
m_segments.clear();
|
||||
}
|
||||
|
||||
/// Sort the list of segments.
|
||||
void sort() {
|
||||
std::sort(m_segments.begin(), m_segments.end());
|
||||
@@ -128,32 +209,37 @@ namespace osmium {
|
||||
/**
|
||||
* Extract segments from given way and add them to the list.
|
||||
*
|
||||
* Segments connecting two nodes with the same location (ie same
|
||||
* node or different node with same location) are removed.
|
||||
*
|
||||
* XXX should two nodes with same location be reported?
|
||||
* Segments connecting two nodes with the same location (ie
|
||||
* same node or different nodes with same location) are
|
||||
* removed after reporting the duplicate node.
|
||||
*/
|
||||
void extract_segments_from_way(const osmium::Way& way, const char* role) {
|
||||
osmium::NodeRef last_nr;
|
||||
for (const osmium::NodeRef& nr : way.nodes()) {
|
||||
if (last_nr.location() && last_nr.location() != nr.location()) {
|
||||
m_segments.emplace_back(last_nr, nr, role, &way);
|
||||
}
|
||||
last_nr = nr;
|
||||
uint32_t extract_segments_from_way(osmium::area::ProblemReporter* problem_reporter, const osmium::Way& way) {
|
||||
if (way.nodes().empty()) {
|
||||
return 0;
|
||||
}
|
||||
m_segments.reserve(way.nodes().size() - 1);
|
||||
return extract_segments_from_way_impl(problem_reporter, way, role_type::outer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all segments from all ways that make up this
|
||||
* multipolygon relation and add them to the list.
|
||||
*/
|
||||
void extract_segments_from_ways(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer) {
|
||||
auto member_it = relation.members().begin();
|
||||
for (size_t offset : members) {
|
||||
const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
|
||||
extract_segments_from_way(way, member_it->role());
|
||||
++member_it;
|
||||
uint32_t extract_segments_from_ways(osmium::area::ProblemReporter* problem_reporter, const osmium::Relation& relation, const std::vector<const osmium::Way*>& members) {
|
||||
assert(relation.members().size() >= members.size());
|
||||
|
||||
const size_t num_segments = get_num_segments(members);
|
||||
if (problem_reporter) {
|
||||
problem_reporter->set_nodes(num_segments);
|
||||
}
|
||||
m_segments.reserve(num_segments);
|
||||
|
||||
uint32_t duplicate_nodes = 0;
|
||||
for_each_member(relation, members, [this, &problem_reporter, &duplicate_nodes](const osmium::RelationMember& member, const osmium::Way& way) {
|
||||
duplicate_nodes += extract_segments_from_way_impl(problem_reporter, way, parse_role(member.role()));
|
||||
});
|
||||
|
||||
return duplicate_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,17 +248,35 @@ namespace osmium {
|
||||
* same segment. So if there are three, for instance, two will
|
||||
* be removed and one will be left.
|
||||
*/
|
||||
void erase_duplicate_segments() {
|
||||
uint32_t erase_duplicate_segments(osmium::area::ProblemReporter* problem_reporter) {
|
||||
uint32_t duplicate_segments = 0;
|
||||
|
||||
while (true) {
|
||||
auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
|
||||
if (it == m_segments.end()) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (m_debug) {
|
||||
std::cerr << " erase duplicate segment: " << *it << "\n";
|
||||
}
|
||||
|
||||
// Only count and report duplicate segments if they
|
||||
// belong to the same way or if they don't both have
|
||||
// the role "inner". Those cases are definitely wrong.
|
||||
// If the duplicate segments belong to different
|
||||
// "inner" ways, they could be touching inner rings
|
||||
// which are perfectly okay. Note that for this check
|
||||
// the role has to be correct in the member data.
|
||||
if (it->way() == std::next(it)->way() || !it->role_inner() || !std::next(it)->role_inner()) {
|
||||
++duplicate_segments;
|
||||
if (problem_reporter) {
|
||||
problem_reporter->report_duplicate_segment(it->first(), it->second());
|
||||
}
|
||||
}
|
||||
m_segments.erase(it, it+2);
|
||||
}
|
||||
|
||||
return duplicate_segments;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,14 +286,14 @@ namespace osmium {
|
||||
* reported to this object.
|
||||
* @returns true if there are intersections.
|
||||
*/
|
||||
bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
|
||||
uint32_t find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
|
||||
if (m_segments.empty()) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool found_intersections = false;
|
||||
uint32_t found_intersections = 0;
|
||||
|
||||
for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
|
||||
for (auto it1 = m_segments.cbegin(); it1 != m_segments.cend()-1; ++it1) {
|
||||
const NodeRefSegment& s1 = *it1;
|
||||
for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
|
||||
const NodeRefSegment& s2 = *it2;
|
||||
@@ -203,12 +307,13 @@ namespace osmium {
|
||||
if (y_range_overlap(s1, s2)) {
|
||||
osmium::Location intersection = calculate_intersection(s1, s2);
|
||||
if (intersection) {
|
||||
found_intersections = true;
|
||||
++found_intersections;
|
||||
if (m_debug) {
|
||||
std::cerr << " segments " << s1 << " and " << s2 << " intersecting at " << intersection << "\n";
|
||||
}
|
||||
if (problem_reporter) {
|
||||
problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(), s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
|
||||
problem_reporter->report_intersection(s1.way()->id(), s1.first().location(), s1.second().location(),
|
||||
s2.way()->id(), s2.first().location(), s2.second().location(), intersection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#ifndef OSMIUM_AREA_DETAIL_VECTOR_HPP
|
||||
#define OSMIUM_AREA_DETAIL_VECTOR_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 <cstdint>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace area {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* This helper class models a 2D vector in the mathematical sense.
|
||||
* It uses 64 bit integers internally which has enough precision
|
||||
* for most operations with inputs based on 32 bit locations.
|
||||
*/
|
||||
struct vec {
|
||||
|
||||
int64_t x;
|
||||
int64_t y;
|
||||
|
||||
constexpr vec(int64_t a, int64_t b) noexcept :
|
||||
x(a),
|
||||
y(b) {
|
||||
}
|
||||
|
||||
constexpr explicit vec(const osmium::Location& l) noexcept :
|
||||
x(l.x()),
|
||||
y(l.y()) {
|
||||
}
|
||||
|
||||
constexpr explicit vec(const osmium::NodeRef& nr) noexcept :
|
||||
x(nr.x()),
|
||||
y(nr.y()) {
|
||||
}
|
||||
|
||||
}; // struct vec
|
||||
|
||||
// addition
|
||||
constexpr inline vec operator+(const vec& a, const vec& b) noexcept {
|
||||
return vec{a.x + b.x, a.y + b.y};
|
||||
}
|
||||
|
||||
// subtraction
|
||||
constexpr inline vec operator-(const vec& a, const vec& b) noexcept {
|
||||
return vec{a.x - b.x, a.y - b.y};
|
||||
}
|
||||
|
||||
// cross product
|
||||
constexpr inline int64_t operator*(const vec& a, const vec& b) noexcept {
|
||||
return a.x * b.y - a.y * b.x;
|
||||
}
|
||||
|
||||
// scale vector
|
||||
constexpr inline vec operator*(double s, const vec& v) noexcept {
|
||||
return vec{int64_t(s * v.x), int64_t(s * v.y)};
|
||||
}
|
||||
|
||||
// scale vector
|
||||
constexpr inline vec operator*(const vec& v, double s) noexcept {
|
||||
return vec{int64_t(s * v.x), int64_t(s * v.y)};
|
||||
}
|
||||
|
||||
// equality
|
||||
constexpr inline bool operator==(const vec& a, const vec& b) noexcept {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
// inequality
|
||||
constexpr inline bool operator!=(const vec& a, const vec& b) noexcept {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const vec& v) {
|
||||
return out << '(' << v.x << ',' << v.y << ')';
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace area
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_AREA_DETAIL_VECTOR_HPP
|
||||
@@ -34,11 +34,11 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/area/stats.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
@@ -47,7 +47,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/relations/collector.hpp>
|
||||
#include <osmium/relations/detail/member_meta.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -74,13 +73,15 @@ namespace osmium {
|
||||
template <typename TAssembler>
|
||||
class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
|
||||
|
||||
typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
|
||||
using collector_type = osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false>;
|
||||
|
||||
typedef typename TAssembler::config_type assembler_config_type;
|
||||
using assembler_config_type = typename TAssembler::config_type;
|
||||
const assembler_config_type m_assembler_config;
|
||||
|
||||
osmium::memory::Buffer m_output_buffer;
|
||||
|
||||
osmium::area::area_stats m_stats;
|
||||
|
||||
static constexpr size_t initial_output_buffer_size = 1024 * 1024;
|
||||
static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
|
||||
|
||||
@@ -107,6 +108,10 @@ namespace osmium {
|
||||
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
|
||||
}
|
||||
|
||||
const osmium::area::area_stats& stats() const noexcept {
|
||||
return m_stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* We are interested in all relations tagged with type=multipolygon
|
||||
* or type=boundary.
|
||||
@@ -121,7 +126,7 @@ namespace osmium {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
|
||||
if ((!std::strcmp(type, "multipolygon")) || (!std::strcmp(type, "boundary"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -155,26 +160,32 @@ namespace osmium {
|
||||
// way is closed and has enough nodes, build simple multipolygon
|
||||
TAssembler assembler(m_assembler_config);
|
||||
assembler(way, m_output_buffer);
|
||||
m_stats += assembler.stats();
|
||||
possibly_flush_output_buffer();
|
||||
}
|
||||
} catch (osmium::invalid_location&) {
|
||||
} catch (const osmium::invalid_location&) {
|
||||
// XXX ignore
|
||||
}
|
||||
}
|
||||
|
||||
void complete_relation(osmium::relations::RelationMeta& relation_meta) {
|
||||
const osmium::Relation& relation = this->get_relation(relation_meta);
|
||||
std::vector<size_t> offsets;
|
||||
const osmium::memory::Buffer& buffer = this->members_buffer();
|
||||
|
||||
std::vector<const osmium::Way*> ways;
|
||||
for (const auto& member : relation.members()) {
|
||||
if (member.ref() != 0) {
|
||||
offsets.push_back(this->get_offset(member.type(), member.ref()));
|
||||
const size_t offset = this->get_offset(member.type(), member.ref());
|
||||
ways.push_back(&buffer.get<const osmium::Way>(offset));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
TAssembler assembler(m_assembler_config);
|
||||
assembler(relation, offsets, this->members_buffer(), m_output_buffer);
|
||||
assembler(relation, ways, m_output_buffer);
|
||||
m_stats += assembler.stats();
|
||||
possibly_flush_output_buffer();
|
||||
} catch (osmium::invalid_location&) {
|
||||
} catch (const osmium::invalid_location&) {
|
||||
// XXX ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,17 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class NodeRef;
|
||||
class Way;
|
||||
|
||||
namespace area {
|
||||
|
||||
/**
|
||||
@@ -62,6 +67,9 @@ namespace osmium {
|
||||
// ID of the relation/way we are currently working on
|
||||
osmium::object_id_type m_object_id;
|
||||
|
||||
// Number of nodes in the area
|
||||
size_t m_nodes;
|
||||
|
||||
public:
|
||||
|
||||
ProblemReporter() = default;
|
||||
@@ -79,6 +87,10 @@ namespace osmium {
|
||||
m_object_id = object_id;
|
||||
}
|
||||
|
||||
void set_nodes(size_t nodes) noexcept {
|
||||
m_nodes = nodes;
|
||||
}
|
||||
|
||||
// Disable "unused-parameter" warning, so that the compiler will not complain.
|
||||
// We can't remove the parameter names, because then doxygen will complain.
|
||||
#pragma GCC diagnostic push
|
||||
@@ -87,13 +99,23 @@ namespace osmium {
|
||||
/**
|
||||
* Report a duplicate node, ie. two nodes with the same location.
|
||||
*
|
||||
* @param node_id1 ID of the first node.
|
||||
* @param node_id2 ID of the second node.
|
||||
* @param location Location of both nodes.
|
||||
* @param node_id1 ID of the first node.
|
||||
* @param node_id2 ID of the second node.
|
||||
* @param location Location of both nodes.
|
||||
*/
|
||||
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a node/location where rings touch. This is often wrong,
|
||||
* but not necessarily so.
|
||||
*
|
||||
* @param node_id ID of the node.
|
||||
* @param location Location of the node.
|
||||
*/
|
||||
virtual void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an intersection between two segments.
|
||||
*
|
||||
@@ -109,21 +131,33 @@ namespace osmium {
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a duplicate segments. Two or more segments are directly
|
||||
* on top of each other. This can be a problem, if there is a
|
||||
* spike for instance, or it could be okay, if there are touching
|
||||
* inner rings.
|
||||
*
|
||||
* @param nr1 NodeRef of one end of the segment.
|
||||
* @param nr2 NodeRef of the other end of the segment.
|
||||
*/
|
||||
virtual void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an open ring.
|
||||
*
|
||||
* @param end1 Location of the first open end.
|
||||
* @param end2 Location of the second open end.
|
||||
* @param nr NodeRef of one end of the ring.
|
||||
* @param way Optional pointer to way the end node is in.
|
||||
*/
|
||||
virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
|
||||
virtual void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a segment that should have role "outer", but has a different role.
|
||||
*
|
||||
* @param way_id ID of the way this segment is in.
|
||||
* @param seg_start Start of the segment with the wrong role.
|
||||
* @param seg_end End of the segment with the wrong role.
|
||||
* @param way_id ID of the way this segment is in.
|
||||
* @param seg_start Start of the segment with the wrong role.
|
||||
* @param seg_end End of the segment with the wrong role.
|
||||
*/
|
||||
virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
|
||||
}
|
||||
@@ -138,6 +172,32 @@ namespace osmium {
|
||||
virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a way that is in multiple rings.
|
||||
*
|
||||
* @param way The way.
|
||||
*/
|
||||
virtual void report_way_in_multiple_rings(const osmium::Way& way) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a way with role inner that has the same tags as the
|
||||
* relation or outer ways.
|
||||
*
|
||||
* @param way The way.
|
||||
*/
|
||||
virtual void report_inner_with_same_tags(const osmium::Way& way) {
|
||||
}
|
||||
|
||||
/**
|
||||
* In addition to reporting specific problems, this is used to
|
||||
* report all ways belonging to areas having problems.
|
||||
*
|
||||
* @param way The way
|
||||
*/
|
||||
virtual void report_way(const osmium::Way& way) {
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
}; // class ProblemReporter
|
||||
|
||||
@@ -42,6 +42,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class NodeRef;
|
||||
class Way;
|
||||
|
||||
namespace area {
|
||||
|
||||
class ProblemReporterException : public ProblemReporterStream {
|
||||
@@ -62,6 +65,12 @@ namespace osmium {
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_touching_ring(node_id, location);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
m_sstream.str();
|
||||
@@ -69,9 +78,15 @@ namespace osmium {
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
|
||||
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_ring_not_closed(end1, end2);
|
||||
ProblemReporterStream::report_duplicate_segment(nr1, nr2);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_ring_not_closed(nr, way);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
@@ -87,6 +102,18 @@ namespace osmium {
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_way_in_multiple_rings(const osmium::Way& way) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_way_in_multiple_rings(way);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
void report_inner_with_same_tags(const osmium::Way& way) override {
|
||||
m_sstream.str();
|
||||
ProblemReporterStream::report_inner_with_same_tags(way);
|
||||
throw std::runtime_error(m_sstream.str());
|
||||
}
|
||||
|
||||
}; // class ProblemReporterException
|
||||
|
||||
} // namespace area
|
||||
|
||||
+117
-26
@@ -49,8 +49,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/geom/factory.hpp>
|
||||
#include <osmium/geom/ogr.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/node_ref_list.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -66,26 +70,34 @@ namespace osmium {
|
||||
|
||||
gdalcpp::Layer m_layer_perror;
|
||||
gdalcpp::Layer m_layer_lerror;
|
||||
gdalcpp::Layer m_layer_ways;
|
||||
|
||||
void set_object(gdalcpp::Feature& feature) {
|
||||
const char t[2] = { osmium::item_type_to_char(m_object_type), '\0' };
|
||||
feature.set_field("obj_type", t);
|
||||
feature.set_field("obj_id", int32_t(m_object_id));
|
||||
feature.set_field("nodes", int32_t(m_nodes));
|
||||
}
|
||||
|
||||
void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
|
||||
gdalcpp::Feature feature(m_layer_perror, m_ogr_factory.create_point(location));
|
||||
feature.set_field("id1", static_cast<double>(id1));
|
||||
feature.set_field("id2", static_cast<double>(id2));
|
||||
feature.set_field("problem_type", problem_type);
|
||||
set_object(feature);
|
||||
feature.set_field("id1", double(id1));
|
||||
feature.set_field("id2", double(id2));
|
||||
feature.set_field("problem", problem_type);
|
||||
feature.add_to_layer();
|
||||
}
|
||||
|
||||
void write_line(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location loc1, osmium::Location loc2) {
|
||||
std::unique_ptr<OGRPoint> ogr_point1 = m_ogr_factory.create_point(loc1);
|
||||
std::unique_ptr<OGRPoint> ogr_point2 = m_ogr_factory.create_point(loc2);
|
||||
std::unique_ptr<OGRLineString> ogr_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
|
||||
ogr_linestring->addPoint(ogr_point1.get());
|
||||
ogr_linestring->addPoint(ogr_point2.get());
|
||||
auto ogr_linestring = std::unique_ptr<OGRLineString>{new OGRLineString{}};
|
||||
ogr_linestring->addPoint(loc1.lon(), loc1.lat());
|
||||
ogr_linestring->addPoint(loc2.lon(), loc2.lat());
|
||||
|
||||
gdalcpp::Feature feature(m_layer_lerror, std::move(ogr_linestring));
|
||||
set_object(feature);
|
||||
feature.set_field("id1", static_cast<double>(id1));
|
||||
feature.set_field("id2", static_cast<double>(id2));
|
||||
feature.set_field("problem_type", problem_type);
|
||||
feature.set_field("problem", problem_type);
|
||||
feature.add_to_layer();
|
||||
}
|
||||
|
||||
@@ -93,15 +105,36 @@ namespace osmium {
|
||||
|
||||
explicit ProblemReporterOGR(gdalcpp::Dataset& dataset) :
|
||||
m_layer_perror(dataset, "perrors", wkbPoint),
|
||||
m_layer_lerror(dataset, "lerrors", wkbLineString) {
|
||||
m_layer_lerror(dataset, "lerrors", wkbLineString),
|
||||
m_layer_ways(dataset, "ways", wkbLineString) {
|
||||
|
||||
m_layer_perror.add_field("id1", OFTReal, 10);
|
||||
m_layer_perror.add_field("id2", OFTReal, 10);
|
||||
m_layer_perror.add_field("problem_type", OFTString, 30);
|
||||
// 64bit integers are not supported in GDAL < 2, so we
|
||||
// are using a workaround here in fields where we expect
|
||||
// node IDs, we use real numbers.
|
||||
m_layer_perror
|
||||
.add_field("obj_type", OFTString, 1)
|
||||
.add_field("obj_id", OFTInteger, 10)
|
||||
.add_field("nodes", OFTInteger, 8)
|
||||
.add_field("id1", OFTReal, 12, 1)
|
||||
.add_field("id2", OFTReal, 12, 1)
|
||||
.add_field("problem", OFTString, 30)
|
||||
;
|
||||
|
||||
m_layer_lerror.add_field("id1", OFTReal, 10);
|
||||
m_layer_lerror.add_field("id2", OFTReal, 10);
|
||||
m_layer_lerror.add_field("problem_type", OFTString, 30);
|
||||
m_layer_lerror
|
||||
.add_field("obj_type", OFTString, 1)
|
||||
.add_field("obj_id", OFTInteger, 10)
|
||||
.add_field("nodes", OFTInteger, 8)
|
||||
.add_field("id1", OFTReal, 12, 1)
|
||||
.add_field("id2", OFTReal, 12, 1)
|
||||
.add_field("problem", OFTString, 30)
|
||||
;
|
||||
|
||||
m_layer_ways
|
||||
.add_field("obj_type", OFTString, 1)
|
||||
.add_field("obj_id", OFTInteger, 10)
|
||||
.add_field("way_id", OFTInteger, 10)
|
||||
.add_field("nodes", OFTInteger, 8)
|
||||
;
|
||||
}
|
||||
|
||||
~ProblemReporterOGR() override = default;
|
||||
@@ -110,24 +143,82 @@ namespace osmium {
|
||||
write_point("duplicate_node", node_id1, node_id2, location);
|
||||
}
|
||||
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
write_point("intersection", m_object_id, 0, intersection);
|
||||
write_line("intersection", m_object_id, way1_id, way1_seg_start, way1_seg_end);
|
||||
write_line("intersection", m_object_id, way2_id, way2_seg_start, way2_seg_end);
|
||||
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
|
||||
write_point("touching_ring", node_id, 0, location);
|
||||
}
|
||||
|
||||
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
|
||||
write_point("ring_not_closed", m_object_id, 0, end1);
|
||||
write_point("ring_not_closed", m_object_id, 0, end2);
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
write_point("intersection", way1_id, way2_id, intersection);
|
||||
write_line("intersection", way1_id, way2_id, way1_seg_start, way1_seg_end);
|
||||
write_line("intersection", way2_id, way1_id, way2_seg_start, way2_seg_end);
|
||||
}
|
||||
|
||||
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
|
||||
write_line("duplicate_segment", nr1.ref(), nr2.ref(), nr1.location(), nr2.location());
|
||||
}
|
||||
|
||||
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
|
||||
write_point("ring_not_closed", nr.ref(), way ? way->id() : 0, nr.location());
|
||||
}
|
||||
|
||||
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
|
||||
write_line("role_should_be_outer", m_object_id, way_id, seg_start, seg_end);
|
||||
write_line("role_should_be_outer", way_id, 0, seg_start, seg_end);
|
||||
}
|
||||
|
||||
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
|
||||
write_line("role_should_be_inner", m_object_id, way_id, seg_start, seg_end);
|
||||
write_line("role_should_be_inner", way_id, 0, seg_start, seg_end);
|
||||
}
|
||||
|
||||
void report_way_in_multiple_rings(const osmium::Way& way) override {
|
||||
if (way.nodes().size() < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way));
|
||||
set_object(feature);
|
||||
feature.set_field("id1", int32_t(way.id()));
|
||||
feature.set_field("id2", 0);
|
||||
feature.set_field("problem", "way_in_multiple_rings");
|
||||
feature.add_to_layer();
|
||||
} catch (const osmium::geometry_error&) {
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
void report_inner_with_same_tags(const osmium::Way& way) override {
|
||||
if (way.nodes().size() < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
gdalcpp::Feature feature(m_layer_lerror, m_ogr_factory.create_linestring(way));
|
||||
set_object(feature);
|
||||
feature.set_field("id1", int32_t(way.id()));
|
||||
feature.set_field("id2", 0);
|
||||
feature.set_field("problem", "inner_with_same_tags");
|
||||
feature.add_to_layer();
|
||||
} catch (const osmium::geometry_error&) {
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
void report_way(const osmium::Way& way) override {
|
||||
if (way.nodes().empty()) {
|
||||
return;
|
||||
}
|
||||
if (way.nodes().size() == 1) {
|
||||
const auto& first_nr = way.nodes()[0];
|
||||
write_point("single_node_in_way", way.id(), first_nr.ref(), first_nr.location());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
gdalcpp::Feature feature(m_layer_ways, m_ogr_factory.create_linestring(way));
|
||||
set_object(feature);
|
||||
feature.set_field("way_id", int32_t(way.id()));
|
||||
feature.add_to_layer();
|
||||
} catch (const osmium::geometry_error&) {
|
||||
// XXX
|
||||
}
|
||||
}
|
||||
|
||||
}; // class ProblemReporterOGR
|
||||
|
||||
@@ -38,7 +38,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/area/problem_reporter.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -57,7 +59,7 @@ namespace osmium {
|
||||
~ProblemReporterStream() override = default;
|
||||
|
||||
void header(const char* msg) {
|
||||
*m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
|
||||
*m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << " (with " << m_nodes << " nodes): ";
|
||||
}
|
||||
|
||||
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
|
||||
@@ -65,6 +67,11 @@ namespace osmium {
|
||||
*m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " location=" << location << "\n";
|
||||
}
|
||||
|
||||
void report_touching_ring(osmium::object_id_type node_id, osmium::Location location) override {
|
||||
header("touching ring");
|
||||
*m_out << "node_id=" << node_id << " location=" << location << "\n";
|
||||
}
|
||||
|
||||
void report_intersection(osmium::object_id_type way1_id, osmium::Location way1_seg_start, osmium::Location way1_seg_end,
|
||||
osmium::object_id_type way2_id, osmium::Location way2_seg_start, osmium::Location way2_seg_end, osmium::Location intersection) override {
|
||||
header("intersection");
|
||||
@@ -72,9 +79,19 @@ namespace osmium {
|
||||
<< " way2_id=" << way2_id << " way2_seg_start=" << way2_seg_start << " way2_seg_end=" << way2_seg_end << " intersection=" << intersection << "\n";
|
||||
}
|
||||
|
||||
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
|
||||
void report_duplicate_segment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) override {
|
||||
header("duplicate segment");
|
||||
*m_out << "node_id1=" << nr1.ref() << " location1=" << nr1.location()
|
||||
<< " node_id2=" << nr2.ref() << " location2=" << nr2.location() << "\n";
|
||||
}
|
||||
|
||||
void report_ring_not_closed(const osmium::NodeRef& nr, const osmium::Way* way = nullptr) override {
|
||||
header("ring not closed");
|
||||
*m_out << "end1=" << end1 << " end2=" << end2 << "\n";
|
||||
*m_out << "node_id=" << nr.ref() << " location=" << nr.location();
|
||||
if (way) {
|
||||
*m_out << " on way " << way->id();
|
||||
}
|
||||
*m_out << "\n";
|
||||
}
|
||||
|
||||
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
|
||||
@@ -87,6 +104,16 @@ namespace osmium {
|
||||
*m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
|
||||
}
|
||||
|
||||
void report_way_in_multiple_rings(const osmium::Way& way) override {
|
||||
header("way in multiple rings");
|
||||
*m_out << "way_id=" << way.id() << '\n';
|
||||
}
|
||||
|
||||
void report_inner_with_same_tags(const osmium::Way& way) override {
|
||||
header("inner way with same tags as relation or outer");
|
||||
*m_out << "way_id=" << way.id() << '\n';
|
||||
}
|
||||
|
||||
}; // class ProblemReporterStream
|
||||
|
||||
} // namespace area
|
||||
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
#ifndef OSMIUM_AREA_STATS_HPP
|
||||
#define OSMIUM_AREA_STATS_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 <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace area {
|
||||
|
||||
/**
|
||||
* These statistics are generated by the area assembler code. They
|
||||
* tell the user of the assembler a lot about the objects this area
|
||||
* is made out of, what happened during the assembly, and what errors
|
||||
* there were.
|
||||
*/
|
||||
struct area_stats {
|
||||
uint64_t area_really_complex_case = 0; ///< Most difficult case with rings touching in multiple points
|
||||
uint64_t area_simple_case = 0; ///< Simple case, no touching rings
|
||||
uint64_t area_touching_rings_case = 0; ///< More difficult case with touching rings
|
||||
uint64_t duplicate_nodes = 0; ///< Consecutive identical nodes or consecutive nodes with same location
|
||||
uint64_t duplicate_segments = 0; ///< Segments duplicated (going back and forth)
|
||||
uint64_t from_relations = 0; ///< Area created from multipolygon relation
|
||||
uint64_t from_ways = 0; ///< Area created from way
|
||||
uint64_t inner_rings = 0; ///< Number of inner rings
|
||||
uint64_t inner_with_same_tags = 0; ///< Number of inner ways with same tags as area
|
||||
uint64_t intersections = 0; ///< Number of intersections between segments
|
||||
uint64_t member_ways = 0; ///< Number of ways in the area
|
||||
uint64_t no_tags_on_relation = 0; ///< No tags on relation (old-style multipolygon with tags on outer ways)
|
||||
uint64_t no_way_in_mp_relation = 0; ///< Multipolygon relation with no way members
|
||||
uint64_t nodes = 0; ///< Number of nodes in the area
|
||||
uint64_t open_rings = 0; ///< Number of open rings in the area
|
||||
uint64_t outer_rings = 0; ///< Number of outer rings in the area
|
||||
uint64_t short_ways = 0; ///< Number of ways with less than two nodes
|
||||
uint64_t single_way_in_mp_relation = 0; ///< Multipolygon relation containing a single way
|
||||
uint64_t touching_rings = 0; ///< Rings touching in a node
|
||||
uint64_t ways_in_multiple_rings = 0; ///< Different segments of a way ended up in different rings
|
||||
uint64_t wrong_role = 0; ///< Member has wrong role (not "outer", "inner", or empty)
|
||||
|
||||
area_stats& operator+=(const area_stats& other) noexcept {
|
||||
area_really_complex_case += other.area_really_complex_case;
|
||||
area_simple_case += other.area_simple_case;
|
||||
area_touching_rings_case += other.area_touching_rings_case;
|
||||
duplicate_nodes += other.duplicate_nodes;
|
||||
duplicate_segments += other.duplicate_segments;
|
||||
from_relations += other.from_relations;
|
||||
from_ways += other.from_ways;
|
||||
inner_rings += other.inner_rings;
|
||||
inner_with_same_tags += other.inner_with_same_tags;
|
||||
intersections += other.intersections;
|
||||
member_ways += other.member_ways;
|
||||
no_tags_on_relation += other.no_tags_on_relation;
|
||||
no_way_in_mp_relation += other.no_way_in_mp_relation;
|
||||
nodes += other.nodes;
|
||||
open_rings += other.open_rings;
|
||||
outer_rings += other.outer_rings;
|
||||
short_ways += other.short_ways;
|
||||
single_way_in_mp_relation += other.single_way_in_mp_relation;
|
||||
touching_rings += other.touching_rings;
|
||||
ways_in_multiple_rings += other.ways_in_multiple_rings;
|
||||
wrong_role += other.wrong_role;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}; // struct area_stats
|
||||
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const area_stats& s) {
|
||||
return out << " area_really_complex_case=" << s.area_really_complex_case
|
||||
<< " area_simple_case=" << s.area_simple_case
|
||||
<< " area_touching_rings_case=" << s.area_touching_rings_case
|
||||
<< " duplicate_nodes=" << s.duplicate_nodes
|
||||
<< " duplicate_segments=" << s.duplicate_segments
|
||||
<< " from_relations=" << s.from_relations
|
||||
<< " from_ways=" << s.from_ways
|
||||
<< " inner_rings=" << s.inner_rings
|
||||
<< " inner_with_same_tags=" << s.inner_with_same_tags
|
||||
<< " intersections=" << s.intersections
|
||||
<< " member_ways=" << s.member_ways
|
||||
<< " no_tags_on_relation=" << s.no_tags_on_relation
|
||||
<< " no_way_in_mp_relation=" << s.no_way_in_mp_relation
|
||||
<< " nodes=" << s.nodes
|
||||
<< " open_rings=" << s.open_rings
|
||||
<< " outer_rings=" << s.outer_rings
|
||||
<< " short_ways=" << s.short_ways
|
||||
<< " single_way_in_mp_relation=" << s.single_way_in_mp_relation
|
||||
<< " touching_rings=" << s.touching_rings
|
||||
<< " ways_in_multiple_rings=" << s.ways_in_multiple_rings
|
||||
<< " wrong_role=" << s.wrong_role;
|
||||
}
|
||||
|
||||
} // namespace area
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
#endif // OSMIUM_AREA_STATS_HPP
|
||||
+36
-1
@@ -46,8 +46,15 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/memory/buffer.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/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -261,6 +268,34 @@ namespace osmium {
|
||||
|
||||
}; // class member_type
|
||||
|
||||
class member_type_string {
|
||||
|
||||
osmium::item_type m_type;
|
||||
osmium::object_id_type m_ref;
|
||||
std::string m_role;
|
||||
|
||||
public:
|
||||
|
||||
member_type_string(osmium::item_type type, osmium::object_id_type ref, std::string&& role) :
|
||||
m_type(type),
|
||||
m_ref(ref),
|
||||
m_role(std::move(role)) {
|
||||
}
|
||||
|
||||
osmium::item_type type() const noexcept {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
osmium::object_id_type ref() const noexcept {
|
||||
return m_ref;
|
||||
}
|
||||
|
||||
const char* role() const noexcept {
|
||||
return m_role.c_str();
|
||||
}
|
||||
|
||||
}; // class member_type_string
|
||||
|
||||
class comment_type {
|
||||
|
||||
osmium::Timestamp m_date;
|
||||
|
||||
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
@@ -101,7 +100,7 @@ namespace osmium {
|
||||
*
|
||||
*/
|
||||
void add_padding(bool self = false) {
|
||||
auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
|
||||
const auto padding = osmium::memory::align_bytes - (size() % osmium::memory::align_bytes);
|
||||
if (padding != osmium::memory::align_bytes) {
|
||||
std::fill_n(m_buffer.reserve_space(padding), padding, 0);
|
||||
if (self) {
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_way_node_list() instead.
|
||||
*/
|
||||
OSMIUM_DEPRECATED inline const osmium::WayNodeList& build_way_node_list(osmium::memory::Buffer& buffer, const std::initializer_list<osmium::NodeRef>& nodes) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(buffer);
|
||||
for (const auto& node_ref : nodes) {
|
||||
@@ -72,7 +72,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
inline const osmium::TagList& build_tag_list(osmium::memory::Buffer& buffer, const std::initializer_list<std::pair<const char*, const char*>>& tags) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
for (const auto& p : tags) {
|
||||
@@ -88,7 +88,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
inline const osmium::TagList& build_tag_list_from_map(osmium::memory::Buffer& buffer, const std::map<const char*, const char*>& tags) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
for (const auto& p : tags) {
|
||||
@@ -104,7 +104,7 @@ namespace osmium {
|
||||
* Use osmium::builder::add_tag_list() instead.
|
||||
*/
|
||||
inline const osmium::TagList& build_tag_list_from_func(osmium::memory::Buffer& buffer, std::function<void(osmium::builder::TagListBuilder&)> func) {
|
||||
size_t pos = buffer.committed();
|
||||
const size_t pos = buffer.committed();
|
||||
{
|
||||
osmium::builder::TagListBuilder tl_builder(buffer);
|
||||
func(tl_builder);
|
||||
|
||||
@@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
@@ -44,16 +43,23 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/area.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Node;
|
||||
|
||||
namespace memory {
|
||||
class Buffer;
|
||||
} // namespace memory
|
||||
@@ -186,9 +192,9 @@ namespace osmium {
|
||||
|
||||
}; // class NodeRefListBuilder
|
||||
|
||||
typedef NodeRefListBuilder<WayNodeList> WayNodeListBuilder;
|
||||
typedef NodeRefListBuilder<OuterRing> OuterRingBuilder;
|
||||
typedef NodeRefListBuilder<InnerRing> InnerRingBuilder;
|
||||
using WayNodeListBuilder = NodeRefListBuilder<WayNodeList>;
|
||||
using OuterRingBuilder = NodeRefListBuilder<OuterRing>;
|
||||
using InnerRingBuilder = NodeRefListBuilder<InnerRing>;
|
||||
|
||||
class RelationMemberListBuilder : public ObjectBuilder<RelationMemberList> {
|
||||
|
||||
@@ -353,8 +359,8 @@ namespace osmium {
|
||||
|
||||
}; // class OSMObjectBuilder
|
||||
|
||||
typedef OSMObjectBuilder<osmium::Node> NodeBuilder;
|
||||
typedef OSMObjectBuilder<osmium::Relation> RelationBuilder;
|
||||
using NodeBuilder = OSMObjectBuilder<osmium::Node>;
|
||||
using RelationBuilder = OSMObjectBuilder<osmium::Relation>;
|
||||
|
||||
class WayBuilder : public OSMObjectBuilder<osmium::Way> {
|
||||
|
||||
@@ -398,7 +404,7 @@ namespace osmium {
|
||||
|
||||
}; // class AreaBuilder
|
||||
|
||||
typedef ObjectBuilder<osmium::Changeset> ChangesetBuilder;
|
||||
using ChangesetBuilder = ObjectBuilder<osmium::Changeset>;
|
||||
|
||||
} // namespace builder
|
||||
|
||||
|
||||
+9
-1
@@ -34,8 +34,10 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/osm/diff_object.hpp>
|
||||
|
||||
@@ -49,7 +51,7 @@ namespace osmium {
|
||||
* underlying OSMObjects.
|
||||
*/
|
||||
template <typename TBasicIterator>
|
||||
class DiffIterator : public std::iterator<std::input_iterator_tag, const osmium::DiffObject> {
|
||||
class DiffIterator {
|
||||
|
||||
static_assert(std::is_base_of<osmium::OSMObject, typename TBasicIterator::value_type>::value, "TBasicIterator::value_type must derive from osmium::OSMObject");
|
||||
|
||||
@@ -76,6 +78,12 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = const osmium::DiffObject;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
DiffIterator(TBasicIterator begin, TBasicIterator end) :
|
||||
m_prev(begin),
|
||||
m_curr(begin),
|
||||
|
||||
@@ -36,11 +36,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/fwd.hpp>
|
||||
#include <osmium/handler.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Node;
|
||||
class Way;
|
||||
class Relation;
|
||||
class Area;
|
||||
class Changeset;
|
||||
|
||||
namespace handler {
|
||||
|
||||
namespace detail {
|
||||
@@ -143,7 +148,7 @@ auto _name_##_dispatch(THandler& handler, const osmium::_type_& object, long) ->
|
||||
|
||||
class DynamicHandler : public osmium::handler::Handler {
|
||||
|
||||
typedef std::unique_ptr<osmium::handler::detail::HandlerWrapperBase> impl_ptr;
|
||||
using impl_ptr = std::unique_ptr<osmium::handler::detail::HandlerWrapperBase>;
|
||||
impl_ptr m_impl;
|
||||
|
||||
public:
|
||||
|
||||
@@ -34,11 +34,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/area/assembler.hpp>
|
||||
#include <osmium/area/multipolygon_collector.hpp>
|
||||
#include <osmium/handler/node_locations_for_ways.hpp>
|
||||
#include <osmium/handler/node_locations_for_ways.hpp> // IWYU pragma: keep
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/io/reader.hpp>
|
||||
|
||||
+19
-15
@@ -46,6 +46,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/node_ref_list.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
@@ -148,7 +150,7 @@ namespace osmium {
|
||||
/**
|
||||
* Add all points of an outer or inner ring to a multipolygon.
|
||||
*/
|
||||
void add_points(const osmium::OuterRing& nodes) {
|
||||
void add_points(const osmium::NodeRefList& nodes) {
|
||||
osmium::Location last_location;
|
||||
for (const osmium::NodeRef& node_ref : nodes) {
|
||||
if (last_location != node_ref.location()) {
|
||||
@@ -169,7 +171,7 @@ namespace osmium {
|
||||
template <typename... TArgs>
|
||||
explicit GeometryFactory<TGeomImpl, TProjection>(TArgs&&... args) :
|
||||
m_projection(),
|
||||
m_impl(std::forward<TArgs>(args)...) {
|
||||
m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,15 +181,16 @@ namespace osmium {
|
||||
template <typename... TArgs>
|
||||
explicit GeometryFactory<TGeomImpl, TProjection>(TProjection&& projection, TArgs&&... args) :
|
||||
m_projection(std::move(projection)),
|
||||
m_impl(std::forward<TArgs>(args)...) {
|
||||
m_impl(m_projection.epsg(), std::forward<TArgs>(args)...) {
|
||||
}
|
||||
|
||||
typedef TProjection projection_type;
|
||||
typedef typename TGeomImpl::point_type point_type;
|
||||
typedef typename TGeomImpl::linestring_type linestring_type;
|
||||
typedef typename TGeomImpl::polygon_type polygon_type;
|
||||
typedef typename TGeomImpl::multipolygon_type multipolygon_type;
|
||||
typedef typename TGeomImpl::ring_type ring_type;
|
||||
using projection_type = TProjection;
|
||||
|
||||
using point_type = typename TGeomImpl::point_type;
|
||||
using linestring_type = typename TGeomImpl::linestring_type;
|
||||
using polygon_type = typename TGeomImpl::polygon_type;
|
||||
using multipolygon_type = typename TGeomImpl::multipolygon_type;
|
||||
using ring_type = typename TGeomImpl::ring_type;
|
||||
|
||||
int epsg() const {
|
||||
return m_projection.epsg();
|
||||
@@ -280,13 +283,13 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (num_points < 2) {
|
||||
throw osmium::geometry_error("need at least two points for linestring");
|
||||
throw osmium::geometry_error{"need at least two points for linestring"};
|
||||
}
|
||||
|
||||
return linestring_finish(num_points);
|
||||
}
|
||||
|
||||
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
|
||||
linestring_type create_linestring(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
|
||||
try {
|
||||
return create_linestring(way.nodes(), un, dir);
|
||||
} catch (osmium::geometry_error& e) {
|
||||
@@ -354,13 +357,13 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (num_points < 4) {
|
||||
throw osmium::geometry_error("need at least four points for polygon");
|
||||
throw osmium::geometry_error{"need at least four points for polygon"};
|
||||
}
|
||||
|
||||
return polygon_finish(num_points);
|
||||
}
|
||||
|
||||
polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir=direction::forward) {
|
||||
polygon_type create_polygon(const osmium::Way& way, use_nodes un=use_nodes::unique, direction dir = direction::forward) {
|
||||
try {
|
||||
return create_polygon(way.nodes(), un, dir);
|
||||
} catch (osmium::geometry_error& e) {
|
||||
@@ -378,8 +381,8 @@ namespace osmium {
|
||||
m_impl.multipolygon_start();
|
||||
|
||||
for (auto it = area.cbegin(); it != area.cend(); ++it) {
|
||||
const osmium::OuterRing& ring = static_cast<const osmium::OuterRing&>(*it);
|
||||
if (it->type() == osmium::item_type::outer_ring) {
|
||||
auto& ring = static_cast<const osmium::OuterRing&>(*it);
|
||||
if (num_polygons > 0) {
|
||||
m_impl.multipolygon_polygon_finish();
|
||||
}
|
||||
@@ -390,6 +393,7 @@ namespace osmium {
|
||||
++num_rings;
|
||||
++num_polygons;
|
||||
} else if (it->type() == osmium::item_type::inner_ring) {
|
||||
auto& ring = static_cast<const osmium::InnerRing&>(*it);
|
||||
m_impl.multipolygon_inner_ring_start();
|
||||
add_points(ring);
|
||||
m_impl.multipolygon_inner_ring_finish();
|
||||
@@ -399,7 +403,7 @@ namespace osmium {
|
||||
|
||||
// if there are no rings, this area is invalid
|
||||
if (num_rings == 0) {
|
||||
throw osmium::geometry_error("area contains no rings");
|
||||
throw osmium::geometry_error{"invalid area"};
|
||||
}
|
||||
|
||||
m_impl.multipolygon_polygon_finish();
|
||||
|
||||
+7
-6
@@ -34,6 +34,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
@@ -53,13 +54,13 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::string point_type;
|
||||
typedef std::string linestring_type;
|
||||
typedef std::string polygon_type;
|
||||
typedef std::string multipolygon_type;
|
||||
typedef std::string ring_type;
|
||||
using point_type = std::string;
|
||||
using linestring_type = std::string;
|
||||
using polygon_type = std::string;
|
||||
using multipolygon_type = std::string;
|
||||
using ring_type = std::string;
|
||||
|
||||
GeoJSONFactoryImpl(int precision = 7) :
|
||||
GeoJSONFactoryImpl(int /* srid */, int precision = 7) :
|
||||
m_precision(precision) {
|
||||
}
|
||||
|
||||
|
||||
+37
-20
@@ -42,9 +42,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
* @attention If you include this file, you'll need to link with `libgeos`.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <geos/geom/Coordinate.h>
|
||||
#include <geos/geom/CoordinateSequence.h>
|
||||
@@ -59,11 +64,13 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <osmium/geom/factory.hpp>
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
// MSVC doesn't support throw_with_nested yet
|
||||
#ifdef _MSC_VER
|
||||
# define THROW throw
|
||||
#else
|
||||
# include <exception>
|
||||
# define THROW std::throw_with_nested
|
||||
#endif
|
||||
|
||||
@@ -71,8 +78,8 @@ namespace osmium {
|
||||
|
||||
struct geos_geometry_error : public geometry_error {
|
||||
|
||||
geos_geometry_error(const char* message) :
|
||||
geometry_error(std::string("geometry creation failed in GEOS library: ") + message) {
|
||||
explicit geos_geometry_error(const char* message) :
|
||||
geometry_error(std::string{"geometry creation failed in GEOS library: "} + message) {
|
||||
}
|
||||
|
||||
}; // struct geos_geometry_error
|
||||
@@ -93,19 +100,29 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::unique_ptr<geos::geom::Point> point_type;
|
||||
typedef std::unique_ptr<geos::geom::LineString> linestring_type;
|
||||
typedef std::unique_ptr<geos::geom::Polygon> polygon_type;
|
||||
typedef std::unique_ptr<geos::geom::MultiPolygon> multipolygon_type;
|
||||
typedef std::unique_ptr<geos::geom::LinearRing> ring_type;
|
||||
using point_type = std::unique_ptr<geos::geom::Point>;
|
||||
using linestring_type = std::unique_ptr<geos::geom::LineString>;
|
||||
using polygon_type = std::unique_ptr<geos::geom::Polygon>;
|
||||
using multipolygon_type = std::unique_ptr<geos::geom::MultiPolygon>;
|
||||
using ring_type = std::unique_ptr<geos::geom::LinearRing>;
|
||||
|
||||
explicit GEOSFactoryImpl(geos::geom::GeometryFactory& geos_factory) :
|
||||
explicit GEOSFactoryImpl(int /* srid */, geos::geom::GeometryFactory& geos_factory) :
|
||||
m_precision_model(nullptr),
|
||||
m_our_geos_factory(nullptr),
|
||||
m_geos_factory(&geos_factory) {
|
||||
}
|
||||
|
||||
explicit GEOSFactoryImpl(int srid = -1) :
|
||||
/**
|
||||
* @deprecated Do not set SRID explicitly. It will be set to the
|
||||
* correct value automatically.
|
||||
*/
|
||||
OSMIUM_DEPRECATED explicit GEOSFactoryImpl(int /* srid */, int srid) :
|
||||
m_precision_model(new geos::geom::PrecisionModel),
|
||||
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
|
||||
m_geos_factory(m_our_geos_factory.get()) {
|
||||
}
|
||||
|
||||
explicit GEOSFactoryImpl(int srid) :
|
||||
m_precision_model(new geos::geom::PrecisionModel),
|
||||
m_our_geos_factory(new geos::geom::GeometryFactory(m_precision_model.get(), srid)),
|
||||
m_geos_factory(m_our_geos_factory.get()) {
|
||||
@@ -116,7 +133,7 @@ namespace osmium {
|
||||
point_type make_point(const osmium::geom::Coordinates& xy) const {
|
||||
try {
|
||||
return point_type(m_geos_factory->createPoint(geos::geom::Coordinate(xy.x, xy.y)));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -126,7 +143,7 @@ namespace osmium {
|
||||
void linestring_start() {
|
||||
try {
|
||||
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -134,7 +151,7 @@ namespace osmium {
|
||||
void linestring_add_location(const osmium::geom::Coordinates& xy) {
|
||||
try {
|
||||
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -142,7 +159,7 @@ namespace osmium {
|
||||
linestring_type linestring_finish(size_t /* num_points */) {
|
||||
try {
|
||||
return linestring_type(m_geos_factory->createLineString(m_coordinate_sequence.release()));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -166,7 +183,7 @@ namespace osmium {
|
||||
});
|
||||
m_polygons.emplace_back(m_geos_factory->createPolygon(m_rings[0].release(), inner_rings));
|
||||
m_rings.clear();
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -174,7 +191,7 @@ namespace osmium {
|
||||
void multipolygon_outer_ring_start() {
|
||||
try {
|
||||
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -182,7 +199,7 @@ namespace osmium {
|
||||
void multipolygon_outer_ring_finish() {
|
||||
try {
|
||||
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -190,7 +207,7 @@ namespace osmium {
|
||||
void multipolygon_inner_ring_start() {
|
||||
try {
|
||||
m_coordinate_sequence.reset(m_geos_factory->getCoordinateSequenceFactory()->create(static_cast<size_t>(0), 2));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -198,7 +215,7 @@ namespace osmium {
|
||||
void multipolygon_inner_ring_finish() {
|
||||
try {
|
||||
m_rings.emplace_back(m_geos_factory->createLinearRing(m_coordinate_sequence.release()));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -206,7 +223,7 @@ namespace osmium {
|
||||
void multipolygon_add_location(const osmium::geom::Coordinates& xy) {
|
||||
try {
|
||||
m_coordinate_sequence->add(geos::geom::Coordinate(xy.x, xy.y));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
@@ -219,7 +236,7 @@ namespace osmium {
|
||||
});
|
||||
m_polygons.clear();
|
||||
return multipolygon_type(m_geos_factory->createMultiPolygon(polygons));
|
||||
} catch (geos::util::GEOSException& e) {
|
||||
} catch (const geos::util::GEOSException& e) {
|
||||
THROW(osmium::geos_geometry_error(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ namespace osmium {
|
||||
namespace haversine {
|
||||
|
||||
/// @brief Earth's quadratic mean radius for WGS84
|
||||
constexpr double EARTH_RADIUS_IN_METERS = 6372797.560856;
|
||||
constexpr const double EARTH_RADIUS_IN_METERS = 6372797.560856;
|
||||
|
||||
/**
|
||||
* Calculate distance in meters between two sets of coordinates.
|
||||
|
||||
+20
-18
@@ -62,33 +62,34 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::unique_ptr<OGRPoint> point_type;
|
||||
typedef std::unique_ptr<OGRLineString> linestring_type;
|
||||
typedef std::unique_ptr<OGRPolygon> polygon_type;
|
||||
typedef std::unique_ptr<OGRMultiPolygon> multipolygon_type;
|
||||
typedef std::unique_ptr<OGRLinearRing> ring_type;
|
||||
using point_type = std::unique_ptr<OGRPoint>;
|
||||
using linestring_type = std::unique_ptr<OGRLineString>;
|
||||
using polygon_type = std::unique_ptr<OGRPolygon>;
|
||||
using multipolygon_type = std::unique_ptr<OGRMultiPolygon>;
|
||||
using ring_type = std::unique_ptr<OGRLinearRing>;
|
||||
|
||||
private:
|
||||
|
||||
linestring_type m_linestring;
|
||||
multipolygon_type m_multipolygon;
|
||||
polygon_type m_polygon;
|
||||
ring_type m_ring;
|
||||
linestring_type m_linestring{nullptr};
|
||||
multipolygon_type m_multipolygon{nullptr};
|
||||
polygon_type m_polygon{nullptr};
|
||||
ring_type m_ring{nullptr};
|
||||
|
||||
public:
|
||||
|
||||
OGRFactoryImpl() = default;
|
||||
explicit OGRFactoryImpl(int /* srid */) {
|
||||
}
|
||||
|
||||
/* Point */
|
||||
|
||||
point_type make_point(const osmium::geom::Coordinates& xy) const {
|
||||
return point_type(new OGRPoint(xy.x, xy.y));
|
||||
return point_type{new OGRPoint{xy.x, xy.y}};
|
||||
}
|
||||
|
||||
/* LineString */
|
||||
|
||||
void linestring_start() {
|
||||
m_linestring = std::unique_ptr<OGRLineString>(new OGRLineString());
|
||||
m_linestring.reset(new OGRLineString{});
|
||||
}
|
||||
|
||||
void linestring_add_location(const osmium::geom::Coordinates& xy) {
|
||||
@@ -97,13 +98,14 @@ namespace osmium {
|
||||
}
|
||||
|
||||
linestring_type linestring_finish(size_t /* num_points */) {
|
||||
assert(!!m_linestring);
|
||||
return std::move(m_linestring);
|
||||
}
|
||||
|
||||
/* Polygon */
|
||||
|
||||
void polygon_start() {
|
||||
m_ring = std::unique_ptr<OGRLinearRing>(new OGRLinearRing());
|
||||
m_ring.reset(new OGRLinearRing{});
|
||||
}
|
||||
|
||||
void polygon_add_location(const osmium::geom::Coordinates& xy) {
|
||||
@@ -112,7 +114,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
polygon_type polygon_finish(size_t /* num_points */) {
|
||||
std::unique_ptr<OGRPolygon> polygon = std::unique_ptr<OGRPolygon>(new OGRPolygon());
|
||||
auto polygon = std::unique_ptr<OGRPolygon>{new OGRPolygon{}};
|
||||
polygon->addRingDirectly(m_ring.release());
|
||||
return polygon;
|
||||
}
|
||||
@@ -120,11 +122,11 @@ namespace osmium {
|
||||
/* MultiPolygon */
|
||||
|
||||
void multipolygon_start() {
|
||||
m_multipolygon.reset(new OGRMultiPolygon());
|
||||
m_multipolygon.reset(new OGRMultiPolygon{});
|
||||
}
|
||||
|
||||
void multipolygon_polygon_start() {
|
||||
m_polygon.reset(new OGRPolygon());
|
||||
m_polygon.reset(new OGRPolygon{});
|
||||
}
|
||||
|
||||
void multipolygon_polygon_finish() {
|
||||
@@ -134,7 +136,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void multipolygon_outer_ring_start() {
|
||||
m_ring.reset(new OGRLinearRing());
|
||||
m_ring.reset(new OGRLinearRing{});
|
||||
}
|
||||
|
||||
void multipolygon_outer_ring_finish() {
|
||||
@@ -144,7 +146,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void multipolygon_inner_ring_start() {
|
||||
m_ring.reset(new OGRLinearRing());
|
||||
m_ring.reset(new OGRLinearRing{});
|
||||
}
|
||||
|
||||
void multipolygon_inner_ring_finish() {
|
||||
|
||||
+16
-6
@@ -70,15 +70,19 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
CRS(const std::string& crs) :
|
||||
explicit CRS(const std::string& crs) :
|
||||
m_crs(pj_init_plus(crs.c_str()), ProjCRSDeleter()) {
|
||||
if (!m_crs) {
|
||||
throw osmium::projection_error(std::string("creation of CRS failed: ") + pj_strerrno(*pj_get_errno_ref()));
|
||||
throw osmium::projection_error(std::string{"creation of CRS failed: "} + pj_strerrno(*pj_get_errno_ref()));
|
||||
}
|
||||
}
|
||||
|
||||
CRS(int epsg) :
|
||||
CRS(std::string("+init=epsg:") + std::to_string(epsg)) {
|
||||
explicit CRS(const char* crs) :
|
||||
CRS(std::string{crs}) {
|
||||
}
|
||||
|
||||
explicit CRS(int epsg) :
|
||||
CRS(std::string{"+init=epsg:"} + std::to_string(epsg)) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,13 +131,19 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
Projection(const std::string& proj_string) :
|
||||
explicit Projection(const std::string& proj_string) :
|
||||
m_epsg(-1),
|
||||
m_proj_string(proj_string),
|
||||
m_crs_user(proj_string) {
|
||||
}
|
||||
|
||||
Projection(int epsg) :
|
||||
explicit Projection(const char* proj_string) :
|
||||
m_epsg(-1),
|
||||
m_proj_string(proj_string),
|
||||
m_crs_user(proj_string) {
|
||||
}
|
||||
|
||||
explicit Projection(int epsg) :
|
||||
m_epsg(epsg),
|
||||
m_proj_string(std::string("+init=epsg:") + std::to_string(epsg)),
|
||||
m_crs_user(epsg) {
|
||||
|
||||
@@ -33,6 +33,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
#include <osmium/geom/factory.hpp>
|
||||
|
||||
@@ -53,13 +55,13 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef void point_type;
|
||||
typedef void linestring_type;
|
||||
typedef void polygon_type;
|
||||
typedef void multipolygon_type;
|
||||
typedef void ring_type;
|
||||
using point_type = void;
|
||||
using linestring_type = void;
|
||||
using polygon_type = void;
|
||||
using multipolygon_type = void;
|
||||
using ring_type = void;
|
||||
|
||||
RapidGeoJSONFactoryImpl(TWriter& writer) :
|
||||
RapidGeoJSONFactoryImpl(int /* srid */, TWriter& writer) :
|
||||
m_writer(&writer) {
|
||||
}
|
||||
|
||||
|
||||
+44
-1
@@ -33,9 +33,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
#include <osmium/geom/coordinates.hpp>
|
||||
#include <osmium/geom/mercator_projection.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -57,24 +60,64 @@ namespace osmium {
|
||||
*/
|
||||
struct Tile {
|
||||
|
||||
/// x coordinate
|
||||
uint32_t x;
|
||||
|
||||
/// y coordinate
|
||||
uint32_t y;
|
||||
|
||||
/// Zoom level
|
||||
uint32_t z;
|
||||
|
||||
/**
|
||||
* Create a tile with the given zoom level and x any y tile
|
||||
* coordinates.
|
||||
*
|
||||
* The values are not checked for validity.
|
||||
*
|
||||
* @pre @code zoom <= 30 && x < 2^zoom && y < 2^zoom @endcode
|
||||
*/
|
||||
explicit Tile(uint32_t zoom, uint32_t tx, uint32_t ty) noexcept : x(tx), y(ty), z(zoom) {
|
||||
assert(zoom <= 30u);
|
||||
assert(x < (1u << zoom));
|
||||
assert(y < (1u << zoom));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tile with the given zoom level that contains the given
|
||||
* location.
|
||||
*
|
||||
* The values are not checked for validity.
|
||||
*
|
||||
* @pre @code location.valid() && zoom <= 30 @endcode
|
||||
*/
|
||||
explicit Tile(uint32_t zoom, const osmium::Location& location) :
|
||||
z(zoom) {
|
||||
osmium::geom::Coordinates c = lonlat_to_mercator(location);
|
||||
assert(zoom <= 30u);
|
||||
assert(location.valid());
|
||||
const osmium::geom::Coordinates c = lonlat_to_mercator(location);
|
||||
const int32_t n = 1 << zoom;
|
||||
const double scale = detail::max_coordinate_epsg3857 * 2 / n;
|
||||
x = uint32_t(detail::restrict_to_range<int32_t>(int32_t((c.x + detail::max_coordinate_epsg3857) / scale), 0, n-1));
|
||||
y = uint32_t(detail::restrict_to_range<int32_t>(int32_t((detail::max_coordinate_epsg3857 - c.y) / scale), 0, n-1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this tile is valid. For a tile to be valid the
|
||||
* zoom level must be between 0 and 30 and the coordinates must
|
||||
* each be between 0 and 2^zoom-1.
|
||||
*/
|
||||
bool valid() const noexcept {
|
||||
if (z > 30) {
|
||||
return false;
|
||||
}
|
||||
const uint32_t max = 1 << z;
|
||||
return x < max && y < max;
|
||||
}
|
||||
|
||||
}; // struct Tile
|
||||
|
||||
/// Tiles are equal if all their attributes are equal.
|
||||
inline bool operator==(const Tile& a, const Tile& b) {
|
||||
return a.z == b.z && a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
+2
-2
@@ -44,11 +44,11 @@ namespace osmium {
|
||||
*/
|
||||
struct projection_error : public std::runtime_error {
|
||||
|
||||
projection_error(const std::string& what) :
|
||||
explicit projection_error(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
projection_error(const char* what) :
|
||||
explicit projection_error(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
|
||||
+15
-15
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
@@ -60,14 +61,13 @@ namespace osmium {
|
||||
|
||||
template <typename T>
|
||||
inline void str_push(std::string& str, T data) {
|
||||
size_t size = str.size();
|
||||
str.resize(size + sizeof(T));
|
||||
std::copy_n(reinterpret_cast<char*>(&data), sizeof(T), &str[size]);
|
||||
str.append(reinterpret_cast<const char*>(&data), sizeof(T));
|
||||
}
|
||||
|
||||
inline std::string convert_to_hex(const std::string& str) {
|
||||
static const char* lookup_hex = "0123456789ABCDEF";
|
||||
std::string out;
|
||||
out.reserve(str.size() * 2);
|
||||
|
||||
for (char c : str) {
|
||||
out += lookup_hex[(c >> 4) & 0xf];
|
||||
@@ -79,9 +79,6 @@ namespace osmium {
|
||||
|
||||
class WKBFactoryImpl {
|
||||
|
||||
/// OSM data always uses SRID 4326 (WGS84).
|
||||
static constexpr uint32_t srid = 4326;
|
||||
|
||||
/**
|
||||
* Type of WKB geometry.
|
||||
* These definitions are from
|
||||
@@ -112,6 +109,7 @@ namespace osmium {
|
||||
|
||||
std::string m_data;
|
||||
uint32_t m_points {0};
|
||||
int m_srid;
|
||||
wkb_type m_wkb_type;
|
||||
out_type m_out_type;
|
||||
|
||||
@@ -130,11 +128,11 @@ namespace osmium {
|
||||
#endif
|
||||
if (m_wkb_type == wkb_type::ewkb) {
|
||||
str_push(str, type | wkbSRID);
|
||||
str_push(str, srid);
|
||||
str_push(str, m_srid);
|
||||
} else {
|
||||
str_push(str, type);
|
||||
}
|
||||
size_t offset = str.size();
|
||||
const size_t offset = str.size();
|
||||
if (add_length) {
|
||||
str_push(str, static_cast<uint32_t>(0));
|
||||
}
|
||||
@@ -142,18 +140,20 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void set_size(const size_t offset, const size_t size) {
|
||||
*reinterpret_cast<uint32_t*>(&m_data[offset]) = static_cast_with_assert<uint32_t>(size);
|
||||
uint32_t s = static_cast_with_assert<uint32_t>(size);
|
||||
std::copy_n(reinterpret_cast<char*>(&s), sizeof(uint32_t), &m_data[offset]);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef std::string point_type;
|
||||
typedef std::string linestring_type;
|
||||
typedef std::string polygon_type;
|
||||
typedef std::string multipolygon_type;
|
||||
typedef std::string ring_type;
|
||||
using point_type = std::string;
|
||||
using linestring_type = std::string;
|
||||
using polygon_type = std::string;
|
||||
using multipolygon_type = std::string;
|
||||
using ring_type = std::string;
|
||||
|
||||
explicit WKBFactoryImpl(wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
|
||||
explicit WKBFactoryImpl(int srid, wkb_type wtype = wkb_type::wkb, out_type otype = out_type::binary) :
|
||||
m_srid(srid),
|
||||
m_wkb_type(wtype),
|
||||
m_out_type(otype) {
|
||||
}
|
||||
|
||||
+27
-10
@@ -45,29 +45,44 @@ namespace osmium {
|
||||
|
||||
namespace geom {
|
||||
|
||||
enum class wkt_type : bool {
|
||||
wkt = false,
|
||||
ewkt = true
|
||||
}; // enum class wkt_type
|
||||
|
||||
namespace detail {
|
||||
|
||||
class WKTFactoryImpl {
|
||||
|
||||
std::string m_srid_prefix;
|
||||
std::string m_str;
|
||||
int m_precision;
|
||||
wkt_type m_wkt_type;
|
||||
|
||||
public:
|
||||
|
||||
typedef std::string point_type;
|
||||
typedef std::string linestring_type;
|
||||
typedef std::string polygon_type;
|
||||
typedef std::string multipolygon_type;
|
||||
typedef std::string ring_type;
|
||||
using point_type = std::string;
|
||||
using linestring_type = std::string;
|
||||
using polygon_type = std::string;
|
||||
using multipolygon_type = std::string;
|
||||
using ring_type = std::string;
|
||||
|
||||
WKTFactoryImpl(int precision = 7) :
|
||||
m_precision(precision) {
|
||||
WKTFactoryImpl(int srid, int precision = 7, wkt_type wtype = wkt_type::wkt) :
|
||||
m_srid_prefix(),
|
||||
m_precision(precision),
|
||||
m_wkt_type(wtype) {
|
||||
if (m_wkt_type == wkt_type::ewkt) {
|
||||
m_srid_prefix = "SRID=";
|
||||
m_srid_prefix += std::to_string(srid);
|
||||
m_srid_prefix += ';';
|
||||
}
|
||||
}
|
||||
|
||||
/* Point */
|
||||
|
||||
point_type make_point(const osmium::geom::Coordinates& xy) const {
|
||||
std::string str {"POINT"};
|
||||
std::string str {m_srid_prefix};
|
||||
str += "POINT";
|
||||
xy.append_to_string(str, '(', ' ', ')', m_precision);
|
||||
return str;
|
||||
}
|
||||
@@ -75,7 +90,8 @@ namespace osmium {
|
||||
/* LineString */
|
||||
|
||||
void linestring_start() {
|
||||
m_str = "LINESTRING(";
|
||||
m_str = m_srid_prefix;
|
||||
m_str += "LINESTRING(";
|
||||
}
|
||||
|
||||
void linestring_add_location(const osmium::geom::Coordinates& xy) {
|
||||
@@ -97,7 +113,8 @@ namespace osmium {
|
||||
/* MultiPolygon */
|
||||
|
||||
void multipolygon_start() {
|
||||
m_str = "MULTIPOLYGON(";
|
||||
m_str = m_srid_prefix;
|
||||
m_str += "MULTIPOLYGON(";
|
||||
}
|
||||
|
||||
void multipolygon_polygon_start() {
|
||||
|
||||
+41
-15
@@ -33,56 +33,82 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/fwd.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Area;
|
||||
class Changeset;
|
||||
class ChangesetDiscussion;
|
||||
class InnerRing;
|
||||
class Node;
|
||||
class OSMObject;
|
||||
class OuterRing;
|
||||
class Relation;
|
||||
class RelationMemberList;
|
||||
class TagList;
|
||||
class Way;
|
||||
class WayNodeList;
|
||||
|
||||
/**
|
||||
* @brief Osmium handlers provide callbacks for OSM objects
|
||||
*/
|
||||
namespace handler {
|
||||
|
||||
/**
|
||||
* Handler base class. Never used directly. Derive your own class from
|
||||
* this class and "overwrite" the functions. Your functions must be
|
||||
* named the same, but don't have to be const or noexcept or take
|
||||
* their argument as const.
|
||||
*
|
||||
* Usually you will overwrite the node(), way(), and relation()
|
||||
* functions. If your program supports multipolygons, also the area()
|
||||
* function. You can also use the osm_object() function which is
|
||||
* called for all OSM objects (nodes, ways, relations, and areas)
|
||||
* right before each of their specific callbacks is called.
|
||||
*
|
||||
* If you are working with changesets, implement the changeset()
|
||||
* function.
|
||||
*/
|
||||
class Handler {
|
||||
|
||||
public:
|
||||
|
||||
void osm_object(const osmium::OSMObject&) const {
|
||||
void osm_object(const osmium::OSMObject&) const noexcept {
|
||||
}
|
||||
|
||||
void node(const osmium::Node&) const {
|
||||
void node(const osmium::Node&) const noexcept {
|
||||
}
|
||||
|
||||
void way(const osmium::Way&) const {
|
||||
void way(const osmium::Way&) const noexcept {
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation&) const {
|
||||
void relation(const osmium::Relation&) const noexcept {
|
||||
}
|
||||
|
||||
void area(const osmium::Area&) const {
|
||||
void area(const osmium::Area&) const noexcept {
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset&) const {
|
||||
void changeset(const osmium::Changeset&) const noexcept {
|
||||
}
|
||||
|
||||
void tag_list(const osmium::TagList&) const {
|
||||
void tag_list(const osmium::TagList&) const noexcept {
|
||||
}
|
||||
|
||||
void way_node_list(const osmium::WayNodeList&) const {
|
||||
void way_node_list(const osmium::WayNodeList&) const noexcept {
|
||||
}
|
||||
|
||||
void relation_member_list(const osmium::RelationMemberList&) const {
|
||||
void relation_member_list(const osmium::RelationMemberList&) const noexcept {
|
||||
}
|
||||
|
||||
void outer_ring(const osmium::OuterRing&) const {
|
||||
void outer_ring(const osmium::OuterRing&) const noexcept {
|
||||
}
|
||||
|
||||
void inner_ring(const osmium::InnerRing&) const {
|
||||
void inner_ring(const osmium::InnerRing&) const noexcept {
|
||||
}
|
||||
|
||||
void changeset_discussion(const osmium::ChangesetDiscussion&) const {
|
||||
void changeset_discussion(const osmium::ChangesetDiscussion&) const noexcept {
|
||||
}
|
||||
|
||||
void flush() const {
|
||||
void flush() const noexcept {
|
||||
}
|
||||
|
||||
}; // class Handler
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ namespace osmium {
|
||||
template <typename... THandler>
|
||||
class ChainHandler : public osmium::handler::Handler {
|
||||
|
||||
typedef std::tuple<THandler&...> handlers_type;
|
||||
using handlers_type = std::tuple<THandler&...>;
|
||||
handlers_type m_handlers;
|
||||
|
||||
template <int N, int SIZE, typename THandlers>
|
||||
|
||||
@@ -51,11 +51,11 @@ namespace osmium {
|
||||
*/
|
||||
struct out_of_order_error : public std::runtime_error {
|
||||
|
||||
out_of_order_error(const std::string& what) :
|
||||
explicit out_of_order_error(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
out_of_order_error(const char* what) :
|
||||
explicit out_of_order_error(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace osmium {
|
||||
*/
|
||||
class DiskStore : public osmium::handler::Handler {
|
||||
|
||||
typedef osmium::index::map::Map<unsigned_object_id_type, size_t> offset_index_type;
|
||||
using offset_index_type = osmium::index::map::Map<unsigned_object_id_type, size_t>;
|
||||
|
||||
size_t m_offset = 0;
|
||||
int m_data_fd;
|
||||
|
||||
@@ -33,6 +33,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
@@ -50,7 +51,7 @@ namespace osmium {
|
||||
|
||||
namespace handler {
|
||||
|
||||
typedef osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location> dummy_type;
|
||||
using dummy_type = osmium::index::map::Dummy<osmium::unsigned_object_id_type, osmium::Location>;
|
||||
|
||||
/**
|
||||
* Handler to retrieve locations from nodes and add them to ways.
|
||||
@@ -69,8 +70,8 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef TStoragePosIDs index_pos_type;
|
||||
typedef TStorageNegIDs index_neg_type;
|
||||
using index_pos_type = TStoragePosIDs;
|
||||
using index_neg_type = TStorageNegIDs;
|
||||
|
||||
private:
|
||||
|
||||
@@ -80,6 +81,8 @@ namespace osmium {
|
||||
/// Object that handles the actual storage of the node locations (with negative IDs).
|
||||
TStorageNegIDs& m_storage_neg;
|
||||
|
||||
osmium::unsigned_object_id_type m_last_id{0};
|
||||
|
||||
bool m_ignore_errors {false};
|
||||
|
||||
bool m_must_sort {false};
|
||||
@@ -115,7 +118,11 @@ namespace osmium {
|
||||
* Store the location of the node in the storage.
|
||||
*/
|
||||
void node(const osmium::Node& node) {
|
||||
m_must_sort = true;
|
||||
if (node.positive_id() < m_last_id) {
|
||||
m_must_sort = true;
|
||||
}
|
||||
m_last_id = node.positive_id();
|
||||
|
||||
const osmium::object_id_type id = node.id();
|
||||
if (id >= 0) {
|
||||
m_storage_pos.set(static_cast<osmium::unsigned_object_id_type>( id), node.location());
|
||||
@@ -144,6 +151,7 @@ namespace osmium {
|
||||
m_storage_pos.sort();
|
||||
m_storage_neg.sort();
|
||||
m_must_sort = false;
|
||||
m_last_id = std::numeric_limits<osmium::unsigned_object_id_type>::max();
|
||||
}
|
||||
bool error = false;
|
||||
for (auto& node_ref : way.nodes()) {
|
||||
@@ -152,7 +160,7 @@ namespace osmium {
|
||||
if (!node_ref.location()) {
|
||||
error = true;
|
||||
}
|
||||
} catch (osmium::not_found&) {
|
||||
} catch (const osmium::not_found&) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace osmium {
|
||||
*/
|
||||
class ObjectRelations : public osmium::handler::Handler {
|
||||
|
||||
typedef osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type> index_type;
|
||||
using index_type = osmium::index::multimap::Multimap<unsigned_object_id_type, unsigned_object_id_type>;
|
||||
|
||||
index_type& m_index_n2w;
|
||||
index_type& m_index_n2r;
|
||||
|
||||
@@ -54,9 +54,9 @@ namespace osmium {
|
||||
}
|
||||
assert(config.size() > 1);
|
||||
const std::string& filename = config[1];
|
||||
int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
|
||||
const int fd = ::open(filename.c_str(), O_CREAT | O_RDWR, 0644);
|
||||
if (fd == -1) {
|
||||
throw std::runtime_error(std::string("can't open file '") + filename + "': " + strerror(errno));
|
||||
throw std::runtime_error(std::string("can't open file '") + filename + "': " + std::strerror(errno));
|
||||
}
|
||||
return new T(fd);
|
||||
}
|
||||
|
||||
@@ -33,10 +33,13 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <new> // IWYU pragma: keep
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osmium/index/index.hpp>
|
||||
#include <osmium/util/memory_mapping.hpp>
|
||||
|
||||
namespace osmium {
|
||||
@@ -63,22 +66,26 @@ namespace osmium {
|
||||
mmap_vector_base(int fd, size_t capacity, size_t size = 0) :
|
||||
m_size(size),
|
||||
m_mapping(capacity, osmium::util::MemoryMapping::mapping_mode::write_shared, fd) {
|
||||
assert(size <= capacity);
|
||||
std::fill(data() + size, data() + capacity, osmium::index::empty_value<T>());
|
||||
shrink_to_fit();
|
||||
}
|
||||
|
||||
explicit mmap_vector_base(size_t capacity = mmap_vector_size_increment) :
|
||||
m_size(0),
|
||||
m_mapping(capacity) {
|
||||
std::fill_n(data(), capacity, osmium::index::empty_value<T>());
|
||||
}
|
||||
|
||||
~mmap_vector_base() noexcept = default;
|
||||
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
using value_type = T;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const value_type*;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
|
||||
void close() {
|
||||
m_mapping.unmap();
|
||||
@@ -105,6 +112,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
T& operator[](size_t n) {
|
||||
assert(n < m_size);
|
||||
return data()[n];
|
||||
}
|
||||
|
||||
@@ -120,20 +128,21 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void shrink_to_fit() {
|
||||
// XXX do something here
|
||||
while (m_size > 0 && data()[m_size - 1] == osmium::index::empty_value<T>()) {
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
|
||||
void push_back(const T& value) {
|
||||
if (m_size >= capacity()) {
|
||||
resize(m_size+1);
|
||||
}
|
||||
data()[m_size] = value;
|
||||
++m_size;
|
||||
resize(m_size+1);
|
||||
data()[m_size-1] = value;
|
||||
}
|
||||
|
||||
void reserve(size_t new_capacity) {
|
||||
if (new_capacity > capacity()) {
|
||||
const size_t old_capacity = capacity();
|
||||
m_mapping.resize(new_capacity);
|
||||
std::fill(data() + old_capacity, data() + new_capacity, osmium::index::empty_value<T>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,9 +150,6 @@ namespace osmium {
|
||||
if (new_size > capacity()) {
|
||||
reserve(new_size + osmium::detail::mmap_vector_size_increment);
|
||||
}
|
||||
if (new_size > size()) {
|
||||
new (data() + size()) T[new_size - size()];
|
||||
}
|
||||
m_size = new_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,11 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/index/detail/mmap_vector_base.hpp>
|
||||
#include <osmium/index/detail/tmpfile.hpp>
|
||||
#include <osmium/util/file.hpp>
|
||||
@@ -48,6 +53,16 @@ namespace osmium {
|
||||
template <typename T>
|
||||
class mmap_vector_file : public mmap_vector_base<T> {
|
||||
|
||||
size_t filesize(int fd) const {
|
||||
const size_t size = osmium::util::file_size(fd);
|
||||
|
||||
if (size % sizeof(T) != 0) {
|
||||
throw std::runtime_error("Index file has wrong size (must be multiple of " + std::to_string(sizeof(T)) + ").");
|
||||
}
|
||||
|
||||
return size / sizeof(T);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
mmap_vector_file() :
|
||||
@@ -59,8 +74,8 @@ namespace osmium {
|
||||
explicit mmap_vector_file(int fd) :
|
||||
mmap_vector_base<T>(
|
||||
fd,
|
||||
osmium::util::file_size(fd) / sizeof(T),
|
||||
osmium::util::file_size(fd) / sizeof(T)) {
|
||||
std::max(osmium::detail::mmap_vector_size_increment, filesize(fd)),
|
||||
filesize(fd)) {
|
||||
}
|
||||
|
||||
~mmap_vector_file() noexcept = default;
|
||||
|
||||
@@ -55,10 +55,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef TValue element_type;
|
||||
typedef TVector vector_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
using element_type = TValue;
|
||||
using vector_type = TVector;
|
||||
using iterator = typename vector_type::iterator;
|
||||
using const_iterator = typename vector_type::const_iterator;
|
||||
|
||||
VectorBasedDenseMap() :
|
||||
m_vector() {
|
||||
@@ -88,7 +88,7 @@ namespace osmium {
|
||||
not_found_error(id);
|
||||
}
|
||||
return value;
|
||||
} catch (std::out_of_range&) {
|
||||
} catch (const std::out_of_range&) {
|
||||
not_found_error(id);
|
||||
}
|
||||
}
|
||||
@@ -146,10 +146,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
typedef TVector<element_type> vector_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
using vector_type = TVector<element_type>;
|
||||
using iterator = typename vector_type::iterator;
|
||||
using const_iterator = typename vector_type::const_iterator;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -52,10 +52,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
typedef TVector<element_type> vector_type;
|
||||
typedef typename vector_type::iterator iterator;
|
||||
typedef typename vector_type::const_iterator const_iterator;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
using vector_type = TVector<element_type>;
|
||||
using iterator = typename vector_type::iterator;
|
||||
using const_iterator = typename vector_type::const_iterator;
|
||||
|
||||
private:
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void remove(const TId id, const TValue value) {
|
||||
auto r = get_all(id);
|
||||
const auto r = get_all(id);
|
||||
for (auto it = r.first; it != r.second; ++it) {
|
||||
if (it->second == value) {
|
||||
it->second = 0;
|
||||
|
||||
+2
-2
@@ -49,11 +49,11 @@ namespace osmium {
|
||||
*/
|
||||
struct not_found : public std::runtime_error {
|
||||
|
||||
not_found(const std::string& what) :
|
||||
explicit not_found(const std::string& what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
not_found(const char* what) :
|
||||
explicit not_found(const char* what) :
|
||||
std::runtime_error(what) {
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -98,10 +98,10 @@ namespace osmium {
|
||||
public:
|
||||
|
||||
/// The "key" type, usually osmium::unsigned_object_id_type.
|
||||
typedef TId key_type;
|
||||
using key_type = TId;
|
||||
|
||||
/// The "value" type, usually a Location or size_t.
|
||||
typedef TValue value_type;
|
||||
using value_type = TValue;
|
||||
|
||||
Map() = default;
|
||||
|
||||
@@ -171,10 +171,10 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef TId id_type;
|
||||
typedef TValue value_type;
|
||||
typedef osmium::index::map::Map<id_type, value_type> map_type;
|
||||
typedef std::function<map_type*(const std::vector<std::string>&)> create_map_func;
|
||||
using id_type = TId;
|
||||
using value_type = TValue;
|
||||
using map_type = osmium::index::map::Map<id_type, value_type>;
|
||||
using create_map_func = std::function<map_type*(const std::vector<std::string>&)>;
|
||||
|
||||
private:
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
bool has_map_type(const std::string& map_type_name) const {
|
||||
return m_callbacks.count(map_type_name);
|
||||
return m_callbacks.count(map_type_name) != 0;
|
||||
}
|
||||
|
||||
std::vector<std::string> map_types() const {
|
||||
|
||||
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <osmium/index/map.hpp>
|
||||
@@ -98,7 +97,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void dump_as_list(const int fd) final {
|
||||
typedef typename std::map<TId, TValue>::value_type t;
|
||||
using t = typename std::map<TId, TValue>::value_type;
|
||||
std::vector<t> v;
|
||||
v.reserve(m_elements.size());
|
||||
std::copy(m_elements.cbegin(), m_elements.cend(), std::back_inserter(v));
|
||||
|
||||
+4
-4
@@ -52,7 +52,7 @@ namespace osmium {
|
||||
|
||||
static_assert(std::is_integral<TId>::value && std::is_unsigned<TId>::value, "TId template parameter for class Multimap must be unsigned integral type");
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
|
||||
Multimap(const Multimap&) = delete;
|
||||
Multimap& operator=(const Multimap&) = delete;
|
||||
@@ -65,10 +65,10 @@ namespace osmium {
|
||||
public:
|
||||
|
||||
/// The "key" type, usually osmium::unsigned_object_id_type.
|
||||
typedef TId key_type;
|
||||
using key_type = TId;
|
||||
|
||||
/// The "value" type, usually a Location or size_t.
|
||||
typedef TValue value_type;
|
||||
using value_type = TValue;
|
||||
|
||||
Multimap() = default;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace osmium {
|
||||
/// Set the field with id to value.
|
||||
virtual void set(const TId id, const TValue value) = 0;
|
||||
|
||||
typedef element_type* iterator;
|
||||
using iterator = element_type*;
|
||||
|
||||
// virtual std::pair<iterator, iterator> get_all(const TId id) const = 0;
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@ namespace osmium {
|
||||
template <typename TId, typename TValue>
|
||||
class HybridIterator {
|
||||
|
||||
typedef SparseMemArray<TId, TValue> main_map_type;
|
||||
typedef SparseMemMultimap<TId, TValue> extra_map_type;
|
||||
using main_map_type = SparseMemArray<TId, TValue>;
|
||||
using extra_map_type = SparseMemMultimap<TId, TValue>;
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
|
||||
typename main_map_type::iterator m_begin_main;
|
||||
typename main_map_type::iterator m_end_main;
|
||||
@@ -120,16 +120,16 @@ namespace osmium {
|
||||
template <typename TId, typename TValue>
|
||||
class Hybrid : public Multimap<TId, TValue> {
|
||||
|
||||
typedef SparseMemArray<TId, TValue> main_map_type;
|
||||
typedef SparseMemMultimap<TId, TValue> extra_map_type;
|
||||
using main_map_type = SparseMemArray<TId, TValue>;
|
||||
using extra_map_type = SparseMemMultimap<TId, TValue>;
|
||||
|
||||
main_map_type m_main;
|
||||
extra_map_type m_extra;
|
||||
|
||||
public:
|
||||
|
||||
typedef HybridIterator<TId, TValue> iterator;
|
||||
typedef const HybridIterator<TId, TValue> const_iterator;
|
||||
using iterator = HybridIterator<TId, TValue>;
|
||||
using const_iterator = const HybridIterator<TId, TValue>;
|
||||
|
||||
Hybrid() :
|
||||
m_main(),
|
||||
|
||||
+5
-6
@@ -63,12 +63,11 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef typename std::multimap<const TId, TValue> collection_type;
|
||||
typedef typename collection_type::iterator iterator;
|
||||
typedef typename collection_type::const_iterator const_iterator;
|
||||
typedef typename collection_type::value_type value_type;
|
||||
|
||||
typedef typename std::pair<TId, TValue> element_type;
|
||||
using collection_type = typename std::multimap<const TId, TValue>;
|
||||
using iterator = typename collection_type::iterator;
|
||||
using const_iterator = typename collection_type::const_iterator;
|
||||
using value_type = typename collection_type::value_type;
|
||||
using element_type = typename std::pair<TId, TValue>;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
+2
-1
@@ -45,8 +45,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <osmium/io/any_compression.hpp> // IWYU pragma: export
|
||||
|
||||
#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/opl_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/pbf_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/xml_input.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/o5m_input.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_ANY_INPUT_HPP
|
||||
|
||||
@@ -43,10 +43,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#include <bzlib.h>
|
||||
|
||||
@@ -55,6 +54,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#endif
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/detail/read_write.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
@@ -109,7 +109,7 @@ namespace osmium {
|
||||
|
||||
explicit Bzip2Compressor(int fd, fsync sync) :
|
||||
Compressor(sync),
|
||||
m_file(fdopen(dup(fd), "wb")),
|
||||
m_file(fdopen(::dup(fd), "wb")),
|
||||
m_bzerror(BZ_OK),
|
||||
m_bzfile(::BZ2_bzWriteOpen(&m_bzerror, m_file, 6, 0, 0)) {
|
||||
if (!m_bzfile) {
|
||||
@@ -165,7 +165,7 @@ namespace osmium {
|
||||
|
||||
explicit Bzip2Decompressor(int fd) :
|
||||
Decompressor(),
|
||||
m_file(fdopen(dup(fd), "rb")),
|
||||
m_file(fdopen(::dup(fd), "rb")),
|
||||
m_bzerror(BZ_OK),
|
||||
m_bzfile(::BZ2_bzReadOpen(&m_bzerror, m_file, 0, 0, nullptr, 0)) {
|
||||
if (!m_bzfile) {
|
||||
@@ -215,6 +215,8 @@ namespace osmium {
|
||||
buffer.resize(static_cast<std::string::size_type>(nread));
|
||||
}
|
||||
|
||||
set_offset(size_t(ftell(m_file)));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
+36
-9
@@ -33,11 +33,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
@@ -54,6 +55,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
#include <osmium/util/file.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -86,6 +88,9 @@ namespace osmium {
|
||||
|
||||
class Decompressor {
|
||||
|
||||
std::atomic<size_t> m_file_size {0};
|
||||
std::atomic<size_t> m_offset {0};
|
||||
|
||||
public:
|
||||
|
||||
static constexpr unsigned int input_buffer_size = 1024 * 1024;
|
||||
@@ -105,6 +110,22 @@ namespace osmium {
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
size_t file_size() const noexcept {
|
||||
return m_file_size;
|
||||
}
|
||||
|
||||
void set_file_size(size_t size) noexcept {
|
||||
m_file_size = size;
|
||||
}
|
||||
|
||||
size_t offset() const noexcept {
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
void set_offset(size_t offset) noexcept {
|
||||
m_offset = offset;
|
||||
}
|
||||
|
||||
}; // class Decompressor
|
||||
|
||||
/**
|
||||
@@ -118,16 +139,16 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::Compressor*(int, fsync)> create_compressor_type;
|
||||
typedef std::function<osmium::io::Decompressor*(int)> create_decompressor_type_fd;
|
||||
typedef std::function<osmium::io::Decompressor*(const char*, size_t)> create_decompressor_type_buffer;
|
||||
using create_compressor_type = std::function<osmium::io::Compressor*(int, fsync)>;
|
||||
using create_decompressor_type_fd = std::function<osmium::io::Decompressor*(int)>;
|
||||
using create_decompressor_type_buffer = std::function<osmium::io::Decompressor*(const char*, size_t)>;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<const osmium::io::file_compression,
|
||||
std::tuple<create_compressor_type,
|
||||
create_decompressor_type_fd,
|
||||
create_decompressor_type_buffer>> compression_map_type;
|
||||
using compression_map_type = std::map<const osmium::io::file_compression,
|
||||
std::tuple<create_compressor_type,
|
||||
create_decompressor_type_fd,
|
||||
create_decompressor_type_buffer>>;
|
||||
|
||||
compression_map_type m_callbacks;
|
||||
|
||||
@@ -182,7 +203,9 @@ namespace osmium {
|
||||
auto it = m_callbacks.find(compression);
|
||||
|
||||
if (it != m_callbacks.end()) {
|
||||
return std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
|
||||
auto p = std::unique_ptr<osmium::io::Decompressor>(std::get<1>(it->second)(fd));
|
||||
p->set_file_size(osmium::util::file_size(fd));
|
||||
return p;
|
||||
}
|
||||
|
||||
error(compression);
|
||||
@@ -241,6 +264,7 @@ namespace osmium {
|
||||
int m_fd;
|
||||
const char *m_buffer;
|
||||
size_t m_buffer_size;
|
||||
size_t m_offset = 0;
|
||||
|
||||
public:
|
||||
|
||||
@@ -284,6 +308,9 @@ namespace osmium {
|
||||
buffer.resize(std::string::size_type(nread));
|
||||
}
|
||||
|
||||
m_offset += buffer.size();
|
||||
set_offset(m_offset);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,29 +34,35 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <future>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/crc.hpp>
|
||||
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/crc.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/util/minmax.hpp>
|
||||
@@ -66,8 +72,6 @@ namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr const char* color_bold = "\x1b[1m";
|
||||
@@ -80,6 +84,10 @@ namespace osmium {
|
||||
constexpr const char* color_magenta = "\x1b[35m";
|
||||
constexpr const char* color_cyan = "\x1b[36m";
|
||||
constexpr const char* color_white = "\x1b[37m";
|
||||
|
||||
constexpr const char* color_backg_red = "\x1b[41m";
|
||||
constexpr const char* color_backg_green = "\x1b[42m";
|
||||
|
||||
constexpr const char* color_reset = "\x1b[0m";
|
||||
|
||||
struct debug_output_options {
|
||||
@@ -90,6 +98,11 @@ namespace osmium {
|
||||
/// Output with ANSI colors?
|
||||
bool use_color;
|
||||
|
||||
/// Add CRC32 checksum to each object?
|
||||
bool add_crc32;
|
||||
|
||||
/// Write in form of a diff file?
|
||||
bool format_as_diff;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -102,16 +115,47 @@ namespace osmium {
|
||||
const char* m_utf8_prefix = "";
|
||||
const char* m_utf8_suffix = "";
|
||||
|
||||
char m_diff_char = '\0';
|
||||
|
||||
void append_encoded_string(const char* data) {
|
||||
append_debug_encoded_string(*m_out, data, m_utf8_prefix, m_utf8_suffix);
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
void output_formatted(const char* format, TArgs&&... args) {
|
||||
append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
void write_color(const char* color) {
|
||||
if (m_options.use_color) {
|
||||
*m_out += color;
|
||||
}
|
||||
}
|
||||
|
||||
void write_diff() {
|
||||
if (!m_diff_char) {
|
||||
return;
|
||||
}
|
||||
if (m_options.use_color) {
|
||||
if (m_diff_char == '-') {
|
||||
*m_out += color_backg_red;
|
||||
*m_out += color_white;
|
||||
*m_out += color_bold;
|
||||
*m_out += '-';
|
||||
*m_out += color_reset;
|
||||
return;
|
||||
} else if (m_diff_char == '+') {
|
||||
*m_out += color_backg_green;
|
||||
*m_out += color_white;
|
||||
*m_out += color_bold;
|
||||
*m_out += '+';
|
||||
*m_out += color_reset;
|
||||
return;
|
||||
}
|
||||
}
|
||||
*m_out += m_diff_char;
|
||||
}
|
||||
|
||||
void write_string(const char* string) {
|
||||
*m_out += '"';
|
||||
write_color(color_blue);
|
||||
@@ -121,6 +165,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_object_type(const char* object_type, bool visible = true) {
|
||||
write_diff();
|
||||
if (visible) {
|
||||
write_color(color_bold);
|
||||
} else {
|
||||
@@ -132,6 +177,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_fieldname(const char* name) {
|
||||
write_diff();
|
||||
*m_out += " ";
|
||||
write_color(color_cyan);
|
||||
*m_out += name;
|
||||
@@ -161,7 +207,9 @@ namespace osmium {
|
||||
void write_timestamp(const osmium::Timestamp& timestamp) {
|
||||
if (timestamp.valid()) {
|
||||
*m_out += timestamp.to_iso();
|
||||
output_formatted(" (%d)", timestamp.seconds_since_epoch());
|
||||
*m_out += " (";
|
||||
output_int(timestamp.seconds_since_epoch());
|
||||
*m_out += ')';
|
||||
} else {
|
||||
write_error("NOT SET");
|
||||
}
|
||||
@@ -169,53 +217,63 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
output_formatted("%" PRId64 "\n", object.id());
|
||||
output_int(object.id());
|
||||
*m_out += '\n';
|
||||
if (m_options.add_metadata) {
|
||||
write_fieldname("version");
|
||||
output_formatted(" %d", object.version());
|
||||
*m_out += " ";
|
||||
output_int(object.version());
|
||||
if (object.visible()) {
|
||||
*m_out += " visible\n";
|
||||
} else {
|
||||
write_error(" deleted\n");
|
||||
}
|
||||
write_fieldname("changeset");
|
||||
output_formatted("%d\n", object.changeset());
|
||||
output_int(object.changeset());
|
||||
*m_out += '\n';
|
||||
write_fieldname("timestamp");
|
||||
write_timestamp(object.timestamp());
|
||||
write_fieldname("user");
|
||||
output_formatted(" %d ", object.uid());
|
||||
*m_out += " ";
|
||||
output_int(object.uid());
|
||||
*m_out += ' ';
|
||||
write_string(object.user());
|
||||
*m_out += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void write_tags(const osmium::TagList& tags, const char* padding="") {
|
||||
if (!tags.empty()) {
|
||||
write_fieldname("tags");
|
||||
*m_out += padding;
|
||||
output_formatted(" %d\n", tags.size());
|
||||
if (tags.empty()) {
|
||||
return;
|
||||
}
|
||||
write_fieldname("tags");
|
||||
*m_out += padding;
|
||||
*m_out += " ";
|
||||
output_int(tags.size());
|
||||
*m_out += '\n';
|
||||
|
||||
osmium::max_op<size_t> max;
|
||||
for (const auto& tag : tags) {
|
||||
max.update(std::strlen(tag.key()));
|
||||
}
|
||||
for (const auto& tag : tags) {
|
||||
*m_out += " ";
|
||||
write_string(tag.key());
|
||||
auto spacing = max() - std::strlen(tag.key());
|
||||
while (spacing--) {
|
||||
*m_out += " ";
|
||||
}
|
||||
*m_out += " = ";
|
||||
write_string(tag.value());
|
||||
*m_out += '\n';
|
||||
osmium::max_op<size_t> max;
|
||||
for (const auto& tag : tags) {
|
||||
max.update(std::strlen(tag.key()));
|
||||
}
|
||||
for (const auto& tag : tags) {
|
||||
write_diff();
|
||||
*m_out += " ";
|
||||
write_string(tag.key());
|
||||
auto spacing = max() - std::strlen(tag.key());
|
||||
while (spacing--) {
|
||||
*m_out += " ";
|
||||
}
|
||||
*m_out += " = ";
|
||||
write_string(tag.value());
|
||||
*m_out += '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void write_location(const osmium::Location& location) {
|
||||
write_fieldname("lon/lat");
|
||||
output_formatted(" %.7f,%.7f", location.lon_without_check(), location.lat_without_check());
|
||||
*m_out += " ";
|
||||
location.as_string_without_check(std::back_inserter(*m_out));
|
||||
if (!location.valid()) {
|
||||
write_error(" INVALID LOCATION!");
|
||||
}
|
||||
@@ -230,13 +288,30 @@ namespace osmium {
|
||||
}
|
||||
const auto& bl = box.bottom_left();
|
||||
const auto& tr = box.top_right();
|
||||
output_formatted("%.7f,%.7f %.7f,%.7f", bl.lon_without_check(), bl.lat_without_check(), tr.lon_without_check(), tr.lat_without_check());
|
||||
bl.as_string(std::back_inserter(*m_out));
|
||||
*m_out += ' ';
|
||||
tr.as_string(std::back_inserter(*m_out));
|
||||
if (!box.valid()) {
|
||||
write_error(" INVALID BOX!");
|
||||
}
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_crc32(const T& object) {
|
||||
write_fieldname("crc32");
|
||||
osmium::CRC<boost::crc_32_type> crc32;
|
||||
crc32.update(object);
|
||||
output_formatted(" %x\n", crc32().checksum());
|
||||
}
|
||||
|
||||
void write_crc32(const osmium::Changeset& object) {
|
||||
write_fieldname("crc32");
|
||||
osmium::CRC<boost::crc_32_type> crc32;
|
||||
crc32.update(object);
|
||||
output_formatted(" %x\n", crc32().checksum());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
DebugOutputBlock(osmium::memory::Buffer&& buffer, const debug_output_options& options) :
|
||||
@@ -265,6 +340,8 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
m_diff_char = m_options.format_as_diff ? node.diff_as_char() : '\0';
|
||||
|
||||
write_object_type("node", node.visible());
|
||||
write_meta(node);
|
||||
|
||||
@@ -274,17 +351,24 @@ namespace osmium {
|
||||
|
||||
write_tags(node.tags());
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(node);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
m_diff_char = m_options.format_as_diff ? way.diff_as_char() : '\0';
|
||||
|
||||
write_object_type("way", way.visible());
|
||||
write_meta(way);
|
||||
write_tags(way.tags());
|
||||
|
||||
write_fieldname("nodes");
|
||||
|
||||
output_formatted(" %d", way.nodes().size());
|
||||
*m_out += " ";
|
||||
output_int(way.nodes().size());
|
||||
if (way.nodes().size() < 2) {
|
||||
write_error(" LESS THAN 2 NODES!\n");
|
||||
} else if (way.nodes().size() > 2000) {
|
||||
@@ -295,32 +379,45 @@ namespace osmium {
|
||||
*m_out += " (open)\n";
|
||||
}
|
||||
|
||||
int width = int(log10(way.nodes().size())) + 1;
|
||||
const int width = int(std::log10(way.nodes().size())) + 1;
|
||||
int n = 0;
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
write_diff();
|
||||
write_counter(width, n++);
|
||||
output_formatted("%10" PRId64, node_ref.ref());
|
||||
if (node_ref.location().valid()) {
|
||||
output_formatted(" (%.7f,%.7f)", node_ref.location().lon_without_check(), node_ref.location().lat_without_check());
|
||||
*m_out += " (";
|
||||
node_ref.location().as_string(std::back_inserter(*m_out));
|
||||
*m_out += ')';
|
||||
}
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(way);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
static const char* short_typename[] = { "node", "way ", "rel " };
|
||||
|
||||
m_diff_char = m_options.format_as_diff ? relation.diff_as_char() : '\0';
|
||||
|
||||
write_object_type("relation", relation.visible());
|
||||
write_meta(relation);
|
||||
write_tags(relation.tags());
|
||||
|
||||
write_fieldname("members");
|
||||
output_formatted(" %d\n", relation.members().size());
|
||||
*m_out += " ";
|
||||
output_int(relation.members().size());
|
||||
*m_out += '\n';
|
||||
|
||||
int width = int(log10(relation.members().size())) + 1;
|
||||
const int width = int(std::log10(relation.members().size())) + 1;
|
||||
int n = 0;
|
||||
for (const auto& member : relation.members()) {
|
||||
write_diff();
|
||||
write_counter(width, n++);
|
||||
*m_out += short_typename[item_type_to_nwr_index(member.type())];
|
||||
output_formatted(" %10" PRId64 " ", member.ref());
|
||||
@@ -328,15 +425,20 @@ namespace osmium {
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(relation);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void changeset(const osmium::Changeset& changeset) {
|
||||
write_object_type("changeset");
|
||||
output_formatted("%d\n", changeset.id());
|
||||
output_int(changeset.id());
|
||||
*m_out += '\n';
|
||||
|
||||
write_fieldname("num changes");
|
||||
output_formatted("%d", changeset.num_changes());
|
||||
output_int(changeset.num_changes());
|
||||
if (changeset.num_changes() == 0) {
|
||||
write_error(" NO CHANGES!");
|
||||
}
|
||||
@@ -355,7 +457,9 @@ namespace osmium {
|
||||
}
|
||||
|
||||
write_fieldname("user");
|
||||
output_formatted(" %d ", changeset.uid());
|
||||
*m_out += " ";
|
||||
output_int(changeset.uid());
|
||||
*m_out += ' ';
|
||||
write_string(changeset.user());
|
||||
*m_out += '\n';
|
||||
|
||||
@@ -364,9 +468,11 @@ namespace osmium {
|
||||
|
||||
if (changeset.num_comments() > 0) {
|
||||
write_fieldname("comments");
|
||||
output_formatted(" %d\n", changeset.num_comments());
|
||||
*m_out += " ";
|
||||
output_int(changeset.num_comments());
|
||||
*m_out += '\n';
|
||||
|
||||
int width = int(log10(changeset.num_comments())) + 1;
|
||||
const int width = int(std::log10(changeset.num_comments())) + 1;
|
||||
int n = 0;
|
||||
for (const auto& comment : changeset.discussion()) {
|
||||
write_counter(width, n++);
|
||||
@@ -376,7 +482,8 @@ namespace osmium {
|
||||
output_formatted(" %*s", width, "");
|
||||
|
||||
write_comment_field("user");
|
||||
output_formatted("%d ", comment.uid());
|
||||
output_int(comment.uid());
|
||||
*m_out += ' ';
|
||||
write_string(comment.user());
|
||||
output_formatted("\n %*s", width, "");
|
||||
|
||||
@@ -386,6 +493,10 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_options.add_crc32) {
|
||||
write_crc32(changeset);
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
@@ -412,8 +523,10 @@ namespace osmium {
|
||||
DebugOutputFormat(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");
|
||||
m_options.use_color = file.is_true("color");
|
||||
m_options.add_metadata = file.is_not_false("add_metadata");
|
||||
m_options.use_color = file.is_true("color");
|
||||
m_options.add_crc32 = file.is_true("add_crc32");
|
||||
m_options.format_as_diff = file.is_true("diff");
|
||||
}
|
||||
|
||||
DebugOutputFormat(const DebugOutputFormat&) = delete;
|
||||
@@ -422,6 +535,10 @@ namespace osmium {
|
||||
~DebugOutputFormat() noexcept final = default;
|
||||
|
||||
void write_header(const osmium::io::Header& header) final {
|
||||
if (m_options.format_as_diff) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string out;
|
||||
|
||||
if (m_options.use_color) {
|
||||
@@ -439,9 +556,9 @@ namespace osmium {
|
||||
out += '\n';
|
||||
for (const auto& box : header.boxes()) {
|
||||
out += " ";
|
||||
box.bottom_left().as_string(std::back_inserter(out), ',');
|
||||
out += " ";
|
||||
box.top_right().as_string(std::back_inserter(out), ',');
|
||||
box.bottom_left().as_string(std::back_inserter(out));
|
||||
out += ' ';
|
||||
box.top_right().as_string(std::back_inserter(out));
|
||||
out += '\n';
|
||||
}
|
||||
write_fieldname(out, "options");
|
||||
|
||||
@@ -38,11 +38,11 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
@@ -154,18 +154,14 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<
|
||||
std::unique_ptr<Parser>(
|
||||
future_string_queue_type&,
|
||||
future_buffer_queue_type&,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities
|
||||
)
|
||||
> create_parser_type;
|
||||
using create_parser_type = std::function<std::unique_ptr<Parser>(future_string_queue_type&,
|
||||
future_buffer_queue_type&,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities)>;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<osmium::io::file_format, create_parser_type> map_type;
|
||||
using map_type = std::map<osmium::io::file_format, create_parser_type>;
|
||||
|
||||
map_type m_callbacks;
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/exception.hpp>
|
||||
#include <protozero/varint.hpp>
|
||||
|
||||
#include <osmium/builder/builder.hpp>
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
@@ -52,19 +52,26 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/entity_bits.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/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/delta.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
* Exception thrown when the o5m deocder failed. The exception contains
|
||||
* (if available) information about the place where the error happened
|
||||
@@ -529,7 +536,7 @@ namespace osmium {
|
||||
uint64_t length = 0;
|
||||
try {
|
||||
length = protozero::decode_varint(&m_data, m_end);
|
||||
} catch (protozero::end_of_buffer_exception&) {
|
||||
} catch (const protozero::end_of_buffer_exception&) {
|
||||
throw o5m_error("premature end of file");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
|
||||
#define OSMIUM_IO_DETAIL_OPL_INPUT_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 <cstdlib>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/opl_parser_functions.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class OPLParser : public Parser {
|
||||
|
||||
osmium::memory::Buffer m_buffer{1024*1024};
|
||||
const char* m_data = nullptr;
|
||||
uint64_t m_line_count = 0;
|
||||
|
||||
void maybe_flush() {
|
||||
if (m_buffer.committed() > 800*1024) {
|
||||
osmium::memory::Buffer buffer{1024*1024};
|
||||
using std::swap;
|
||||
swap(m_buffer, buffer);
|
||||
send_to_output_queue(std::move(buffer));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void parse_line() {
|
||||
if (opl_parse_line(m_line_count, m_data, m_buffer, read_types())) {
|
||||
maybe_flush();
|
||||
}
|
||||
++m_line_count;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
OPLParser(future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_types) :
|
||||
Parser(input_queue, output_queue, header_promise, read_types) {
|
||||
set_header_value(osmium::io::Header{});
|
||||
}
|
||||
|
||||
~OPLParser() noexcept final = default;
|
||||
|
||||
void run() final {
|
||||
osmium::thread::set_thread_name("_osmium_opl_in");
|
||||
|
||||
std::string rest;
|
||||
while (!input_done()) {
|
||||
std::string input = get_input();
|
||||
std::string::size_type ppos = 0;
|
||||
|
||||
if (!rest.empty()) {
|
||||
ppos = input.find('\n');
|
||||
if (ppos == std::string::npos) {
|
||||
rest.append(input);
|
||||
continue;
|
||||
}
|
||||
rest.append(input.substr(0, ppos));
|
||||
m_data = rest.data();
|
||||
parse_line();
|
||||
rest.clear();
|
||||
}
|
||||
|
||||
std::string::size_type pos = input.find('\n', ppos);
|
||||
while (pos != std::string::npos) {
|
||||
m_data = &input[ppos];
|
||||
input[pos] = '\0';
|
||||
parse_line();
|
||||
ppos = pos + 1;
|
||||
if (ppos >= input.size()) {
|
||||
break;
|
||||
}
|
||||
pos = input.find('\n', ppos);
|
||||
}
|
||||
rest = input.substr(ppos);
|
||||
}
|
||||
|
||||
if (m_buffer.committed() > 0) {
|
||||
send_to_output_queue(std::move(m_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
}; // class OPLParser
|
||||
|
||||
// we want the register_parser() function to run, setting
|
||||
// the variable is only a side-effect, it will never be used
|
||||
const bool registered_opl_parser = ParserFactory::instance().register_parser(
|
||||
file_format::opl,
|
||||
[](future_string_queue_type& input_queue,
|
||||
future_buffer_queue_type& output_queue,
|
||||
std::promise<osmium::io::Header>& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
return std::unique_ptr<Parser>(new OPLParser(input_queue, output_queue, header_promise, read_which_entities));
|
||||
});
|
||||
|
||||
// dummy function to silence the unused variable warning from above
|
||||
inline bool get_registered_opl_parser() noexcept {
|
||||
return registered_opl_parser;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_OPL_INPUT_FORMAT_HPP
|
||||
@@ -33,26 +33,26 @@ 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/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.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/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
@@ -65,8 +65,6 @@ namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
class File;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct opl_output_options {
|
||||
@@ -74,6 +72,12 @@ namespace osmium {
|
||||
/// Should metadata of objects be added?
|
||||
bool add_metadata;
|
||||
|
||||
/// Should node locations be added to ways?
|
||||
bool locations_on_ways;
|
||||
|
||||
/// Write in form of a diff file?
|
||||
bool format_as_diff;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -87,38 +91,71 @@ namespace osmium {
|
||||
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());
|
||||
}
|
||||
void write_field_int(char c, int64_t value) {
|
||||
*m_out += c;
|
||||
output_int(value);
|
||||
}
|
||||
|
||||
void write_field_timestamp(char c, const osmium::Timestamp& timestamp) {
|
||||
*m_out += c;
|
||||
*m_out += timestamp.to_iso();
|
||||
}
|
||||
|
||||
void write_tags(const osmium::TagList& tags) {
|
||||
*m_out += " T";
|
||||
bool first = true;
|
||||
for (const auto& tag : object.tags()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
*m_out += ',';
|
||||
}
|
||||
append_encoded_string(tag.key());
|
||||
|
||||
if (tags.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = tags.begin();
|
||||
append_encoded_string(it->key());
|
||||
*m_out += '=';
|
||||
append_encoded_string(it->value());
|
||||
|
||||
for (++it; it != tags.end(); ++it) {
|
||||
*m_out += ',';
|
||||
append_encoded_string(it->key());
|
||||
*m_out += '=';
|
||||
append_encoded_string(tag.value());
|
||||
append_encoded_string(it->value());
|
||||
}
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
output_int(object.id());
|
||||
if (m_options.add_metadata) {
|
||||
*m_out += ' ';
|
||||
write_field_int('v', object.version());
|
||||
*m_out += " d";
|
||||
*m_out += (object.visible() ? 'V' : 'D');
|
||||
*m_out += ' ';
|
||||
write_field_int('c', object.changeset());
|
||||
*m_out += ' ';
|
||||
write_field_timestamp('t', object.timestamp());
|
||||
*m_out += ' ';
|
||||
write_field_int('i', object.uid());
|
||||
*m_out += " u";
|
||||
append_encoded_string(object.user());
|
||||
}
|
||||
write_tags(object.tags());
|
||||
}
|
||||
|
||||
void write_location(const osmium::Location& location, const char x, const char y) {
|
||||
*m_out += ' ';
|
||||
*m_out += x;
|
||||
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;
|
||||
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.x());
|
||||
}
|
||||
*m_out += ' ';
|
||||
*m_out += y;
|
||||
if (location) {
|
||||
osmium::detail::append_location_coordinate_to_string(std::back_inserter(*m_out), location.y());
|
||||
}
|
||||
}
|
||||
|
||||
void write_diff(const osmium::OSMObject& object) {
|
||||
if (m_options.format_as_diff) {
|
||||
*m_out += object.diff_as_char();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,70 +185,93 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void node(const osmium::Node& node) {
|
||||
write_diff(node);
|
||||
*m_out += 'n';
|
||||
write_meta(node);
|
||||
write_location(node.location(), 'x', 'y');
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void write_field_ref(const osmium::NodeRef& node_ref) {
|
||||
write_field_int('n', node_ref.ref());
|
||||
*m_out += 'x';
|
||||
if (node_ref.location()) {
|
||||
node_ref.location().as_string(std::back_inserter(*m_out), 'y');
|
||||
} else {
|
||||
*m_out += 'y';
|
||||
}
|
||||
}
|
||||
|
||||
void way(const osmium::Way& way) {
|
||||
write_diff(way);
|
||||
*m_out += 'w';
|
||||
write_meta(way);
|
||||
|
||||
*m_out += " N";
|
||||
bool first = true;
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
|
||||
if (!way.nodes().empty()) {
|
||||
auto it = way.nodes().begin();
|
||||
if (m_options.locations_on_ways) {
|
||||
write_field_ref(*it);
|
||||
for (++it; it != way.nodes().end(); ++it) {
|
||||
*m_out += ',';
|
||||
write_field_ref(*it);
|
||||
}
|
||||
} else {
|
||||
*m_out += ',';
|
||||
write_field_int('n', it->ref());
|
||||
for (++it; it != way.nodes().end(); ++it) {
|
||||
*m_out += ',';
|
||||
write_field_int('n', it->ref());
|
||||
}
|
||||
}
|
||||
output_formatted("n%" PRId64, node_ref.ref());
|
||||
}
|
||||
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
void relation_member(const osmium::RelationMember& member) {
|
||||
*m_out += item_type_to_char(member.type());
|
||||
output_int(member.ref());
|
||||
*m_out += '@';
|
||||
append_encoded_string(member.role());
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
write_diff(relation);
|
||||
*m_out += 'r';
|
||||
write_meta(relation);
|
||||
|
||||
*m_out += " M";
|
||||
bool first = true;
|
||||
for (const auto& member : relation.members()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
|
||||
if (!relation.members().empty()) {
|
||||
auto it = relation.members().begin();
|
||||
relation_member(*it);
|
||||
for (++it; it != relation.members().end(); ++it) {
|
||||
*m_out += ',';
|
||||
relation_member(*it);
|
||||
}
|
||||
*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());
|
||||
write_field_int('c', changeset.id());
|
||||
*m_out += ' ';
|
||||
write_field_int('k', changeset.num_changes());
|
||||
*m_out += ' ';
|
||||
write_field_timestamp('s', changeset.created_at());
|
||||
*m_out += ' ';
|
||||
write_field_timestamp('e', changeset.closed_at());
|
||||
*m_out += ' ';
|
||||
write_field_int('d', changeset.num_comments());
|
||||
*m_out += ' ';
|
||||
write_field_int('i', changeset.uid());
|
||||
*m_out += " u";
|
||||
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());
|
||||
}
|
||||
|
||||
write_tags(changeset.tags());
|
||||
*m_out += '\n';
|
||||
}
|
||||
|
||||
@@ -226,7 +286,9 @@ namespace osmium {
|
||||
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");
|
||||
m_options.add_metadata = file.is_not_false("add_metadata");
|
||||
m_options.locations_on_ways = file.is_true("locations_on_ways");
|
||||
m_options.format_as_diff = file.is_true("diff");
|
||||
}
|
||||
|
||||
OPLOutputFormat(const OPLOutputFormat&) = delete;
|
||||
|
||||
@@ -0,0 +1,747 @@
|
||||
#ifndef OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
|
||||
#define OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_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 <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <utf8.h>
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
/**
|
||||
* Exception thrown when there was a problem with parsing the OPL format
|
||||
* of a file.
|
||||
*/
|
||||
struct opl_error : public io_error {
|
||||
|
||||
uint64_t line = 0;
|
||||
uint64_t column = 0;
|
||||
const char* data;
|
||||
std::string msg;
|
||||
|
||||
explicit opl_error(const std::string& what, const char* d = nullptr) :
|
||||
io_error(std::string("OPL error: ") + what),
|
||||
data(d),
|
||||
msg("OPL error: ") {
|
||||
msg.append(what);
|
||||
}
|
||||
|
||||
explicit opl_error(const char* what, const char* d = nullptr) :
|
||||
io_error(std::string("OPL error: ") + what),
|
||||
data(d),
|
||||
msg("OPL error: ") {
|
||||
msg.append(what);
|
||||
}
|
||||
|
||||
void set_pos(uint64_t l, uint64_t col) {
|
||||
line = l;
|
||||
column = col;
|
||||
msg.append(" on line ");
|
||||
msg.append(std::to_string(line));
|
||||
msg.append(" column ");
|
||||
msg.append(std::to_string(column));
|
||||
}
|
||||
|
||||
const char* what() const noexcept override {
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
}; // struct opl_error
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Consume consecutive space and tab characters. There must be
|
||||
* at least one.
|
||||
*/
|
||||
inline void opl_parse_space(const char** s) {
|
||||
if (**s != ' ' && **s != '\t') {
|
||||
throw opl_error{"expected space or tab character", *s};
|
||||
}
|
||||
do {
|
||||
++*s;
|
||||
} while (**s == ' ' || **s == '\t');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether s points to something else than the end of the
|
||||
* string or a space or tab.
|
||||
*/
|
||||
inline bool opl_non_empty(const char *s) {
|
||||
return *s != '\0' && *s != ' ' && *s != '\t';
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip to the next space or tab character or the end of the
|
||||
* string.
|
||||
*/
|
||||
inline const char* opl_skip_section(const char** s) noexcept {
|
||||
while (opl_non_empty(*s)) {
|
||||
++*s;
|
||||
}
|
||||
return *s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse OPL-escaped strings with hex code with a '%' at the end.
|
||||
* Appends resulting unicode character to the result string.
|
||||
*
|
||||
* Returns a pointer to next character that needs to be consumed.
|
||||
*/
|
||||
inline void opl_parse_escaped(const char** data, std::string& result) {
|
||||
const char* s = *data;
|
||||
uint32_t value = 0;
|
||||
const int max_length = sizeof(value) * 2 /* hex chars per byte */;
|
||||
int length = 0;
|
||||
while (++length <= max_length) {
|
||||
if (*s == '\0') {
|
||||
throw opl_error{"eol", s};
|
||||
}
|
||||
if (*s == '%') {
|
||||
++s;
|
||||
utf8::utf32to8(&value, &value + 1, std::back_inserter(result));
|
||||
*data = s;
|
||||
return;
|
||||
}
|
||||
value <<= 4;
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
value += *s - '0';
|
||||
} else if (*s >= 'a' && *s <= 'f') {
|
||||
value += *s - 'a' + 10;
|
||||
} else if (*s >= 'A' && *s <= 'F') {
|
||||
value += *s - 'A' + 10;
|
||||
} else {
|
||||
throw opl_error{"not a hex char", s};
|
||||
}
|
||||
++s;
|
||||
}
|
||||
throw opl_error{"hex escape too long", s};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string up to end of string or next space, tab, comma, or
|
||||
* equal sign.
|
||||
*
|
||||
* Appends characters to the result string.
|
||||
*
|
||||
* Returns a pointer to next character that needs to be consumed.
|
||||
*/
|
||||
inline void opl_parse_string(const char** data, std::string& result) {
|
||||
const char* s = *data;
|
||||
while (true) {
|
||||
if (*s == '\0' || *s == ' ' || *s == '\t' || *s == ',' || *s == '=') {
|
||||
break;
|
||||
} else if (*s == '%') {
|
||||
++s;
|
||||
opl_parse_escaped(&s, result);
|
||||
} else {
|
||||
result += *s;
|
||||
++s;
|
||||
}
|
||||
}
|
||||
*data = s;
|
||||
}
|
||||
|
||||
// Arbitrary limit how long integers can get
|
||||
constexpr const int max_int_len = 16;
|
||||
|
||||
template <typename T>
|
||||
inline T opl_parse_int(const char** s) {
|
||||
if (**s == '\0') {
|
||||
throw opl_error{"expected integer", *s};
|
||||
}
|
||||
const bool negative = (**s == '-');
|
||||
if (negative) {
|
||||
++*s;
|
||||
}
|
||||
|
||||
int64_t value = 0;
|
||||
|
||||
int n = max_int_len;
|
||||
while (**s >= '0' && **s <= '9') {
|
||||
if (--n == 0) {
|
||||
throw opl_error{"integer too long", *s};
|
||||
}
|
||||
value *= 10;
|
||||
value += **s - '0';
|
||||
++*s;
|
||||
}
|
||||
|
||||
if (n == max_int_len) {
|
||||
throw opl_error{"expected integer", *s};
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
value = -value;
|
||||
if (value < std::numeric_limits<T>::min()) {
|
||||
throw opl_error{"integer too long", *s};
|
||||
}
|
||||
} else {
|
||||
if (value > std::numeric_limits<T>::max()) {
|
||||
throw opl_error{"integer too long", *s};
|
||||
}
|
||||
}
|
||||
|
||||
return T(value);
|
||||
}
|
||||
|
||||
inline osmium::object_id_type opl_parse_id(const char** s) {
|
||||
return opl_parse_int<osmium::object_id_type>(s);
|
||||
}
|
||||
|
||||
inline osmium::changeset_id_type opl_parse_changeset_id(const char** s) {
|
||||
return opl_parse_int<osmium::changeset_id_type>(s);
|
||||
}
|
||||
|
||||
inline osmium::object_version_type opl_parse_version(const char** s) {
|
||||
return opl_parse_int<osmium::object_version_type>(s);
|
||||
}
|
||||
|
||||
inline bool opl_parse_visible(const char** data) {
|
||||
if (**data == 'V') {
|
||||
++*data;
|
||||
return true;
|
||||
}
|
||||
if (**data == 'D') {
|
||||
++*data;
|
||||
return false;
|
||||
}
|
||||
throw opl_error{"invalid visible flag", *data};
|
||||
}
|
||||
|
||||
inline osmium::user_id_type opl_parse_uid(const char** s) {
|
||||
return opl_parse_int<osmium::user_id_type>(s);
|
||||
}
|
||||
|
||||
inline osmium::Timestamp opl_parse_timestamp(const char** s) {
|
||||
try {
|
||||
if (**s == '\0' || **s == ' ' || **s == '\t') {
|
||||
return osmium::Timestamp{};
|
||||
}
|
||||
osmium::Timestamp timestamp{*s};
|
||||
*s += 20;
|
||||
return timestamp;
|
||||
} catch (const std::invalid_argument&) {
|
||||
throw opl_error{"can not parse timestamp", *s};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if data points to given character and consume it.
|
||||
* Throw error otherwise.
|
||||
*/
|
||||
inline void opl_parse_char(const char** data, char c) {
|
||||
if (**data == c) {
|
||||
++*data;
|
||||
return;
|
||||
}
|
||||
std::string msg = "expected '";
|
||||
msg += c;
|
||||
msg += "'";
|
||||
throw opl_error{msg, *data};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a list of tags in the format 'key=value,key=value,...'
|
||||
*
|
||||
* Tags will be added to the buffer using a TagListBuilder.
|
||||
*/
|
||||
inline void opl_parse_tags(const char* s, osmium::memory::Buffer& buffer, osmium::builder::Builder* parent_builder = nullptr) {
|
||||
osmium::builder::TagListBuilder builder{buffer, parent_builder};
|
||||
std::string key;
|
||||
std::string value;
|
||||
while (true) {
|
||||
opl_parse_string(&s, key);
|
||||
opl_parse_char(&s, '=');
|
||||
opl_parse_string(&s, value);
|
||||
builder.add_tag(key, value);
|
||||
if (*s == ' ' || *s == '\t' || *s == '\0') {
|
||||
break;
|
||||
}
|
||||
opl_parse_char(&s, ',');
|
||||
key.clear();
|
||||
value.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a number of nodes in the format "nID,nID,nID..."
|
||||
*
|
||||
* Nodes will be added to the buffer using a WayNodeListBuilder.
|
||||
*/
|
||||
inline void opl_parse_way_nodes(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::WayBuilder* parent_builder = nullptr) {
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
osmium::builder::WayNodeListBuilder builder{buffer, parent_builder};
|
||||
|
||||
while (s < e) {
|
||||
opl_parse_char(&s, 'n');
|
||||
if (s == e) {
|
||||
throw opl_error{"expected integer", s};
|
||||
}
|
||||
|
||||
const osmium::object_id_type ref = opl_parse_id(&s);
|
||||
if (s == e) {
|
||||
builder.add_node_ref(ref);
|
||||
return;
|
||||
}
|
||||
|
||||
osmium::Location location;
|
||||
if (*s == 'x') {
|
||||
++s;
|
||||
location.set_lon_partial(&s);
|
||||
if (*s == 'y') {
|
||||
++s;
|
||||
location.set_lat_partial(&s);
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_node_ref(ref, location);
|
||||
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
|
||||
opl_parse_char(&s, ',');
|
||||
}
|
||||
}
|
||||
|
||||
inline void opl_parse_node(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::NodeBuilder builder{buffer};
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.set_id(opl_parse_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
std::string user;
|
||||
osmium::Location location;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
node.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
node.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
node.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
node.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
node.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
if (opl_non_empty(*data)) {
|
||||
location.set_lon_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (opl_non_empty(*data)) {
|
||||
location.set_lat_partial(data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
}
|
||||
|
||||
if (location.valid()) {
|
||||
node.set_location(location);
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline void opl_parse_way(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::WayBuilder builder{buffer};
|
||||
osmium::Way& way = builder.object();
|
||||
|
||||
way.set_id(opl_parse_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
const char* nodes_begin = nullptr;
|
||||
const char* nodes_end = nullptr;
|
||||
|
||||
std::string user;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
way.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
way.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
way.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
way.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
way.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
nodes_begin = *data;
|
||||
nodes_end = opl_skip_section(data);
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
opl_parse_way_nodes(nodes_begin, nodes_end, buffer, &builder);
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline void opl_parse_relation_members(const char* s, const char* e, osmium::memory::Buffer& buffer, osmium::builder::RelationBuilder* parent_builder = nullptr) {
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
osmium::builder::RelationMemberListBuilder builder{buffer, parent_builder};
|
||||
|
||||
while (s < e) {
|
||||
osmium::item_type type = osmium::char_to_item_type(*s);
|
||||
if (type != osmium::item_type::node &&
|
||||
type != osmium::item_type::way &&
|
||||
type != osmium::item_type::relation) {
|
||||
throw opl_error{"unknown object type", s};
|
||||
}
|
||||
++s;
|
||||
|
||||
if (s == e) {
|
||||
throw opl_error{"expected integer", s};
|
||||
}
|
||||
osmium::object_id_type ref = opl_parse_id(&s);
|
||||
opl_parse_char(&s, '@');
|
||||
if (s == e) {
|
||||
builder.add_member(type, ref, "");
|
||||
return;
|
||||
}
|
||||
std::string role;
|
||||
opl_parse_string(&s, role);
|
||||
builder.add_member(type, ref, role);
|
||||
|
||||
if (s == e) {
|
||||
return;
|
||||
}
|
||||
opl_parse_char(&s, ',');
|
||||
}
|
||||
}
|
||||
|
||||
inline void opl_parse_relation(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::RelationBuilder builder{buffer};
|
||||
osmium::Relation& relation = builder.object();
|
||||
|
||||
relation.set_id(opl_parse_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
const char* members_begin = nullptr;
|
||||
const char* members_end = nullptr;
|
||||
|
||||
std::string user;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'v':
|
||||
relation.set_version(opl_parse_version(data));
|
||||
break;
|
||||
case 'd':
|
||||
relation.set_visible(opl_parse_visible(data));
|
||||
break;
|
||||
case 'c':
|
||||
relation.set_changeset(opl_parse_changeset_id(data));
|
||||
break;
|
||||
case 't':
|
||||
relation.set_timestamp(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'i':
|
||||
relation.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
members_begin = *data;
|
||||
members_end = opl_skip_section(data);
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
if (members_begin != members_end) {
|
||||
opl_parse_relation_members(members_begin, members_end, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline void opl_parse_changeset(const char** data, osmium::memory::Buffer& buffer) {
|
||||
osmium::builder::ChangesetBuilder builder{buffer};
|
||||
osmium::Changeset& changeset = builder.object();
|
||||
|
||||
changeset.set_id(opl_parse_changeset_id(data));
|
||||
|
||||
const char* tags_begin = nullptr;
|
||||
|
||||
osmium::Location location1;
|
||||
osmium::Location location2;
|
||||
std::string user;
|
||||
while (**data) {
|
||||
opl_parse_space(data);
|
||||
const char c = **data;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
}
|
||||
++(*data);
|
||||
switch (c) {
|
||||
case 'k':
|
||||
changeset.set_num_changes(opl_parse_int<osmium::num_changes_type>(data));
|
||||
break;
|
||||
case 's':
|
||||
changeset.set_created_at(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'e':
|
||||
changeset.set_closed_at(opl_parse_timestamp(data));
|
||||
break;
|
||||
case 'd':
|
||||
changeset.set_num_comments(opl_parse_int<osmium::num_comments_type>(data));
|
||||
break;
|
||||
case 'i':
|
||||
changeset.set_uid(opl_parse_uid(data));
|
||||
break;
|
||||
case 'u':
|
||||
opl_parse_string(data, user);
|
||||
break;
|
||||
case 'x':
|
||||
if (opl_non_empty(*data)) {
|
||||
location1.set_lon_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (opl_non_empty(*data)) {
|
||||
location1.set_lat_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
if (opl_non_empty(*data)) {
|
||||
location2.set_lon_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'Y':
|
||||
if (opl_non_empty(*data)) {
|
||||
location2.set_lat_partial(data);
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
if (opl_non_empty(*data)) {
|
||||
tags_begin = *data;
|
||||
opl_skip_section(data);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
--(*data);
|
||||
throw opl_error{"unknown attribute", *data};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (location1.valid() && location2.valid()) {
|
||||
changeset.bounds().extend(location1);
|
||||
changeset.bounds().extend(location2);
|
||||
}
|
||||
|
||||
builder.add_user(user);
|
||||
|
||||
if (tags_begin) {
|
||||
opl_parse_tags(tags_begin, buffer, &builder);
|
||||
}
|
||||
|
||||
buffer.commit();
|
||||
}
|
||||
|
||||
inline bool opl_parse_line(uint64_t line_count,
|
||||
const char* data,
|
||||
osmium::memory::Buffer& buffer,
|
||||
osmium::osm_entity_bits::type read_types = osmium::osm_entity_bits::all) {
|
||||
const char* start_of_line = data;
|
||||
try {
|
||||
switch (*data) {
|
||||
case '\0':
|
||||
// ignore empty lines
|
||||
break;
|
||||
case '#':
|
||||
// ignore lines starting with #
|
||||
break;
|
||||
case 'n':
|
||||
if (read_types & osmium::osm_entity_bits::node) {
|
||||
++data;
|
||||
opl_parse_node(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
if (read_types & osmium::osm_entity_bits::way) {
|
||||
++data;
|
||||
opl_parse_way(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (read_types & osmium::osm_entity_bits::relation) {
|
||||
++data;
|
||||
opl_parse_relation(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (read_types & osmium::osm_entity_bits::changeset) {
|
||||
++data;
|
||||
opl_parse_changeset(&data, buffer);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw opl_error{"unknown type", data};
|
||||
}
|
||||
} catch (opl_error& e) {
|
||||
e.set_pos(line_count, e.data ? e.data - start_of_line : 0);
|
||||
throw;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace io
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
|
||||
#endif // OSMIUM_IO_DETAIL_OPL_PARSER_FUNCTIONS_HPP
|
||||
@@ -33,16 +33,16 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
@@ -70,9 +70,28 @@ namespace osmium {
|
||||
m_out(std::make_shared<std::string>()) {
|
||||
}
|
||||
|
||||
template <typename... TArgs>
|
||||
void output_formatted(const char* format, TArgs&&... args) {
|
||||
append_printf_formatted_string(*m_out, format, std::forward<TArgs>(args)...);
|
||||
// Simple function to convert integer to string. This is much
|
||||
// faster than using sprintf, but could be further optimized.
|
||||
// See https://github.com/miloyip/itoa-benchmark .
|
||||
void output_int(int64_t value) {
|
||||
if (value < 0) {
|
||||
*m_out += '-';
|
||||
value = -value;
|
||||
}
|
||||
|
||||
char temp[20];
|
||||
char *t = temp;
|
||||
do {
|
||||
*t++ = char(value % 10) + '0';
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
const auto old_size = m_out->size();
|
||||
m_out->resize(old_size + (t - temp));
|
||||
char* data = &(*m_out)[old_size];
|
||||
do {
|
||||
*data++ += *--t;
|
||||
} while (t != temp);
|
||||
}
|
||||
|
||||
}; // class OutputBlock;
|
||||
@@ -133,11 +152,11 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)> create_output_type;
|
||||
using create_output_type = std::function<osmium::io::detail::OutputFormat*(const osmium::io::File&, future_string_queue_type&)>;
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<osmium::io::file_format, create_output_type> map_type;
|
||||
using map_type = std::map<osmium::io::file_format, create_output_type>;
|
||||
|
||||
map_type m_callbacks;
|
||||
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ namespace osmium {
|
||||
// between representation as double and as int
|
||||
const int64_t lonlat_resolution = 1000 * 1000 * 1000;
|
||||
|
||||
const int64_t resolution_convert = lonlat_resolution / osmium::Location::coordinate_precision;
|
||||
const int64_t resolution_convert = lonlat_resolution / osmium::detail::coordinate_precision;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
+141
-96
@@ -33,10 +33,8 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
@@ -44,35 +42,47 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <protozero/iterators.hpp>
|
||||
#include <protozero/pbf_message.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/builder/osm_object_builder.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/protobuf_tags.hpp>
|
||||
#include <osmium/io/detail/zlib.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/entity_bits.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/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/delta.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace builder {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
using ptr_len_type = std::pair<const char*, size_t>;
|
||||
using protozero::data_view;
|
||||
using osm_string_len_type = std::pair<const char*, osmium::string_size_type>;
|
||||
|
||||
class PBFPrimitiveBlockDecoder {
|
||||
|
||||
static constexpr size_t initial_buffer_size = 2 * 1024 * 1024;
|
||||
static constexpr const size_t initial_buffer_size = 2 * 1024 * 1024;
|
||||
|
||||
ptr_len_type m_data;
|
||||
data_view m_data;
|
||||
std::vector<osm_string_len_type> m_stringtable;
|
||||
|
||||
int64_t m_lon_offset = 0;
|
||||
@@ -84,18 +94,18 @@ namespace osmium {
|
||||
|
||||
osmium::memory::Buffer m_buffer { initial_buffer_size };
|
||||
|
||||
void decode_stringtable(const ptr_len_type& data) {
|
||||
void decode_stringtable(const data_view& data) {
|
||||
if (!m_stringtable.empty()) {
|
||||
throw osmium::pbf_error("more than one stringtable in pbf file");
|
||||
}
|
||||
|
||||
protozero::pbf_message<OSMFormat::StringTable> pbf_string_table(data);
|
||||
while (pbf_string_table.next(OSMFormat::StringTable::repeated_bytes_s)) {
|
||||
auto str_len = pbf_string_table.get_data();
|
||||
if (str_len.second > osmium::max_osm_string_length) {
|
||||
const auto str_view = pbf_string_table.get_view();
|
||||
if (str_view.size() > osmium::max_osm_string_length) {
|
||||
throw osmium::pbf_error("overlong string in string table");
|
||||
}
|
||||
m_stringtable.emplace_back(str_len.first, osmium::string_size_type(str_len.second));
|
||||
m_stringtable.emplace_back(str_view.data(), osmium::string_size_type(str_view.size()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +114,7 @@ namespace osmium {
|
||||
while (pbf_primitive_block.next()) {
|
||||
switch (pbf_primitive_block.tag()) {
|
||||
case OSMFormat::PrimitiveBlock::required_StringTable_stringtable:
|
||||
decode_stringtable(pbf_primitive_block.get_data());
|
||||
decode_stringtable(pbf_primitive_block.get_view());
|
||||
break;
|
||||
case OSMFormat::PrimitiveBlock::optional_int32_granularity:
|
||||
m_granularity = pbf_primitive_block.get_int32();
|
||||
@@ -132,28 +142,28 @@ namespace osmium {
|
||||
switch (pbf_primitive_group.tag()) {
|
||||
case OSMFormat::PrimitiveGroup::repeated_Node_nodes:
|
||||
if (m_read_types & osmium::osm_entity_bits::node) {
|
||||
decode_node(pbf_primitive_group.get_data());
|
||||
decode_node(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::PrimitiveGroup::optional_DenseNodes_dense:
|
||||
if (m_read_types & osmium::osm_entity_bits::node) {
|
||||
decode_dense_nodes(pbf_primitive_group.get_data());
|
||||
decode_dense_nodes(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::PrimitiveGroup::repeated_Way_ways:
|
||||
if (m_read_types & osmium::osm_entity_bits::way) {
|
||||
decode_way(pbf_primitive_group.get_data());
|
||||
decode_way(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
break;
|
||||
case OSMFormat::PrimitiveGroup::repeated_Relation_relations:
|
||||
if (m_read_types & osmium::osm_entity_bits::relation) {
|
||||
decode_relation(pbf_primitive_group.get_data());
|
||||
decode_relation(pbf_primitive_group.get_view());
|
||||
} else {
|
||||
pbf_primitive_group.skip();
|
||||
}
|
||||
@@ -165,7 +175,7 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
osm_string_len_type decode_info(const ptr_len_type& data, osmium::OSMObject& object) {
|
||||
osm_string_len_type decode_info(const data_view& data, osmium::OSMObject& object) {
|
||||
osm_string_len_type user = std::make_pair("", 0);
|
||||
|
||||
protozero::pbf_message<OSMFormat::Info> pbf_info(data);
|
||||
@@ -173,7 +183,7 @@ namespace osmium {
|
||||
switch (pbf_info.tag()) {
|
||||
case OSMFormat::Info::optional_int32_version:
|
||||
{
|
||||
auto version = pbf_info.get_int32();
|
||||
const auto version = pbf_info.get_int32();
|
||||
if (version < 0) {
|
||||
throw osmium::pbf_error("object version must not be negative");
|
||||
}
|
||||
@@ -185,7 +195,7 @@ namespace osmium {
|
||||
break;
|
||||
case OSMFormat::Info::optional_int64_changeset:
|
||||
{
|
||||
auto changeset_id = pbf_info.get_int64();
|
||||
const auto changeset_id = pbf_info.get_int64();
|
||||
if (changeset_id < 0) {
|
||||
throw osmium::pbf_error("object changeset_id must not be negative");
|
||||
}
|
||||
@@ -209,15 +219,15 @@ namespace osmium {
|
||||
return user;
|
||||
}
|
||||
|
||||
using kv_type = std::pair<protozero::pbf_reader::const_uint32_iterator, protozero::pbf_reader::const_uint32_iterator>;
|
||||
using kv_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
|
||||
|
||||
void build_tag_list(osmium::builder::Builder& builder, const kv_type& keys, const kv_type& vals) {
|
||||
if (keys.first != keys.second) {
|
||||
if (!keys.empty()) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
auto kit = keys.first;
|
||||
auto vit = vals.first;
|
||||
while (kit != keys.second) {
|
||||
if (vit == vals.second) {
|
||||
auto kit = keys.begin();
|
||||
auto vit = vals.begin();
|
||||
while (kit != keys.end()) {
|
||||
if (vit == vals.end()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
@@ -232,7 +242,7 @@ namespace osmium {
|
||||
return int32_t((c * m_granularity + m_lon_offset) / resolution_convert);
|
||||
}
|
||||
|
||||
void decode_node(const ptr_len_type& data) {
|
||||
void decode_node(const data_view& data) {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
@@ -256,7 +266,7 @@ namespace osmium {
|
||||
vals = pbf_node.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Node::optional_Info_info:
|
||||
user = decode_info(pbf_node.get_data(), builder.object());
|
||||
user = decode_info(pbf_node.get_view(), builder.object());
|
||||
break;
|
||||
case OSMFormat::Node::required_sint64_lat:
|
||||
lat = pbf_node.get_sint64();
|
||||
@@ -287,12 +297,14 @@ namespace osmium {
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_way(const ptr_len_type& data) {
|
||||
void decode_way(const data_view& data) {
|
||||
osmium::builder::WayBuilder builder(m_buffer);
|
||||
|
||||
kv_type keys;
|
||||
kv_type vals;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
|
||||
|
||||
osm_string_len_type user = { "", 0 };
|
||||
|
||||
@@ -309,11 +321,17 @@ namespace osmium {
|
||||
vals = pbf_way.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Way::optional_Info_info:
|
||||
user = decode_info(pbf_way.get_data(), builder.object());
|
||||
user = decode_info(pbf_way.get_view(), builder.object());
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_refs:
|
||||
refs = pbf_way.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_lat:
|
||||
lats = pbf_way.get_packed_sint64();
|
||||
break;
|
||||
case OSMFormat::Way::packed_sint64_lon:
|
||||
lons = pbf_way.get_packed_sint64();
|
||||
break;
|
||||
default:
|
||||
pbf_way.skip();
|
||||
}
|
||||
@@ -321,11 +339,26 @@ namespace osmium {
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
|
||||
if (refs.first != refs.second) {
|
||||
if (!refs.empty()) {
|
||||
osmium::builder::WayNodeListBuilder wnl_builder(m_buffer, &builder);
|
||||
osmium::util::DeltaDecode<int64_t> ref;
|
||||
while (refs.first != refs.second) {
|
||||
wnl_builder.add_node_ref(ref.update(*refs.first++));
|
||||
if (lats.empty()) {
|
||||
for (const auto& ref_value : refs) {
|
||||
wnl_builder.add_node_ref(ref.update(ref_value));
|
||||
}
|
||||
} else {
|
||||
osmium::util::DeltaDecode<int64_t> lon;
|
||||
osmium::util::DeltaDecode<int64_t> lat;
|
||||
while (!refs.empty() && !lons.empty() && !lats.empty()) {
|
||||
wnl_builder.add_node_ref(
|
||||
ref.update(refs.front()),
|
||||
osmium::Location{convert_pbf_coordinate(lon.update(lons.front())),
|
||||
convert_pbf_coordinate(lat.update(lats.front()))}
|
||||
);
|
||||
refs.drop_front();
|
||||
lons.drop_front();
|
||||
lats.drop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,14 +367,14 @@ namespace osmium {
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_relation(const ptr_len_type& data) {
|
||||
void decode_relation(const data_view& data) {
|
||||
osmium::builder::RelationBuilder builder(m_buffer);
|
||||
|
||||
kv_type keys;
|
||||
kv_type vals;
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> roles;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> types;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> roles;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> refs;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> types;
|
||||
|
||||
osm_string_len_type user = { "", 0 };
|
||||
|
||||
@@ -358,7 +391,7 @@ namespace osmium {
|
||||
vals = pbf_relation.get_packed_uint32();
|
||||
break;
|
||||
case OSMFormat::Relation::optional_Info_info:
|
||||
user = decode_info(pbf_relation.get_data(), builder.object());
|
||||
user = decode_info(pbf_relation.get_view(), builder.object());
|
||||
break;
|
||||
case OSMFormat::Relation::packed_int32_roles_sid:
|
||||
roles = pbf_relation.get_packed_int32();
|
||||
@@ -376,21 +409,24 @@ namespace osmium {
|
||||
|
||||
builder.add_user(user.first, user.second);
|
||||
|
||||
if (refs.first != refs.second) {
|
||||
if (!refs.empty()) {
|
||||
osmium::builder::RelationMemberListBuilder rml_builder(m_buffer, &builder);
|
||||
osmium::util::DeltaDecode<int64_t> ref;
|
||||
while (roles.first != roles.second && refs.first != refs.second && types.first != types.second) {
|
||||
const auto& r = m_stringtable.at(*roles.first++);
|
||||
int type = *types.first++;
|
||||
while (!roles.empty() && !refs.empty() && !types.empty()) {
|
||||
const auto& r = m_stringtable.at(roles.front());
|
||||
const int type = types.front();
|
||||
if (type < 0 || type > 2) {
|
||||
throw osmium::pbf_error("unknown relation member type");
|
||||
}
|
||||
rml_builder.add_member(
|
||||
osmium::item_type(type + 1),
|
||||
ref.update(*refs.first++),
|
||||
ref.update(refs.front()),
|
||||
r.first,
|
||||
r.second
|
||||
);
|
||||
roles.drop_front();
|
||||
refs.drop_front();
|
||||
types.drop_front();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,22 +435,22 @@ namespace osmium {
|
||||
m_buffer.commit();
|
||||
}
|
||||
|
||||
void decode_dense_nodes(const ptr_len_type& data) {
|
||||
void decode_dense_nodes(const data_view& data) {
|
||||
bool has_info = false;
|
||||
bool has_visibles = false;
|
||||
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> ids;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lats;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> lons;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> ids;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lats;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> lons;
|
||||
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> tags;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> tags;
|
||||
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> versions;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> timestamps;
|
||||
std::pair<protozero::pbf_reader::const_sint64_iterator, protozero::pbf_reader::const_sint64_iterator> changesets;
|
||||
std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> uids;
|
||||
std::pair<protozero::pbf_reader::const_sint32_iterator, protozero::pbf_reader::const_sint32_iterator> user_sids;
|
||||
std::pair<protozero::pbf_reader::const_int32_iterator, protozero::pbf_reader::const_int32_iterator> visibles;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> versions;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> timestamps;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint64_iterator> changesets;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> uids;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_sint32_iterator> user_sids;
|
||||
protozero::iterator_range<protozero::pbf_reader::const_int32_iterator> visibles;
|
||||
|
||||
protozero::pbf_message<OSMFormat::DenseNodes> pbf_dense_nodes(data);
|
||||
while (pbf_dense_nodes.next()) {
|
||||
@@ -475,11 +511,11 @@ namespace osmium {
|
||||
osmium::util::DeltaDecode<int64_t> dense_changeset;
|
||||
osmium::util::DeltaDecode<int64_t> dense_timestamp;
|
||||
|
||||
auto tag_it = tags.first;
|
||||
auto tag_it = tags.begin();
|
||||
|
||||
while (ids.first != ids.second) {
|
||||
if (lons.first == lons.second ||
|
||||
lats.first == lats.second) {
|
||||
while (!ids.empty()) {
|
||||
if (lons.empty() ||
|
||||
lats.empty()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
@@ -489,43 +525,50 @@ namespace osmium {
|
||||
osmium::builder::NodeBuilder builder(m_buffer);
|
||||
osmium::Node& node = builder.object();
|
||||
|
||||
node.set_id(dense_id.update(*ids.first++));
|
||||
node.set_id(dense_id.update(ids.front()));
|
||||
ids.drop_front();
|
||||
|
||||
if (has_info) {
|
||||
if (versions.first == versions.second ||
|
||||
changesets.first == changesets.second ||
|
||||
timestamps.first == timestamps.second ||
|
||||
uids.first == uids.second ||
|
||||
user_sids.first == user_sids.second) {
|
||||
if (versions.empty() ||
|
||||
changesets.empty() ||
|
||||
timestamps.empty() ||
|
||||
uids.empty() ||
|
||||
user_sids.empty()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
|
||||
auto version = *versions.first++;
|
||||
const auto version = versions.front();
|
||||
versions.drop_front();
|
||||
if (version < 0) {
|
||||
throw osmium::pbf_error("object version must not be negative");
|
||||
}
|
||||
node.set_version(static_cast<osmium::object_version_type>(version));
|
||||
|
||||
auto changeset_id = dense_changeset.update(*changesets.first++);
|
||||
const auto changeset_id = dense_changeset.update(changesets.front());
|
||||
changesets.drop_front();
|
||||
if (changeset_id < 0) {
|
||||
throw osmium::pbf_error("object changeset_id must not be negative");
|
||||
}
|
||||
node.set_changeset(static_cast<osmium::changeset_id_type>(changeset_id));
|
||||
|
||||
node.set_timestamp(dense_timestamp.update(*timestamps.first++) * m_date_factor / 1000);
|
||||
node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(*uids.first++)));
|
||||
node.set_timestamp(dense_timestamp.update(timestamps.front()) * m_date_factor / 1000);
|
||||
timestamps.drop_front();
|
||||
node.set_uid_from_signed(static_cast<osmium::signed_user_id_type>(dense_uid.update(uids.front())));
|
||||
uids.drop_front();
|
||||
|
||||
if (has_visibles) {
|
||||
if (visibles.first == visibles.second) {
|
||||
if (visibles.empty()) {
|
||||
// this is against the spec, must have same number of elements
|
||||
throw osmium::pbf_error("PBF format error");
|
||||
}
|
||||
visible = (*visibles.first++) != 0;
|
||||
visible = (visibles.front() != 0);
|
||||
visibles.drop_front();
|
||||
}
|
||||
node.set_visible(visible);
|
||||
|
||||
const auto& u = m_stringtable.at(dense_user_sid.update(*user_sids.first++));
|
||||
const auto& u = m_stringtable.at(dense_user_sid.update(user_sids.front()));
|
||||
user_sids.drop_front();
|
||||
builder.add_user(u.first, u.second);
|
||||
} else {
|
||||
builder.add_user("");
|
||||
@@ -533,8 +576,10 @@ namespace osmium {
|
||||
|
||||
// even if the node isn't visible, there's still a record
|
||||
// of its lat/lon in the dense arrays.
|
||||
const auto lon = dense_longitude.update(*lons.first++);
|
||||
const auto lat = dense_latitude.update(*lats.first++);
|
||||
const auto lon = dense_longitude.update(lons.front());
|
||||
lons.drop_front();
|
||||
const auto lat = dense_latitude.update(lats.front());
|
||||
lats.drop_front();
|
||||
if (visible) {
|
||||
builder.object().set_location(osmium::Location(
|
||||
convert_pbf_coordinate(lon),
|
||||
@@ -542,18 +587,18 @@ namespace osmium {
|
||||
));
|
||||
}
|
||||
|
||||
if (tag_it != tags.second) {
|
||||
if (tag_it != tags.end()) {
|
||||
osmium::builder::TagListBuilder tl_builder(m_buffer, &builder);
|
||||
while (tag_it != tags.second && *tag_it != 0) {
|
||||
while (tag_it != tags.end() && *tag_it != 0) {
|
||||
const auto& k = m_stringtable.at(*tag_it++);
|
||||
if (tag_it == tags.second) {
|
||||
if (tag_it == tags.end()) {
|
||||
throw osmium::pbf_error("PBF format error"); // this is against the spec, keys/vals must come in pairs
|
||||
}
|
||||
const auto& v = m_stringtable.at(*tag_it++);
|
||||
tl_builder.add_tag(k.first, k.second, v.first, v.second);
|
||||
}
|
||||
|
||||
if (tag_it != tags.second) {
|
||||
if (tag_it != tags.end()) {
|
||||
++tag_it;
|
||||
}
|
||||
}
|
||||
@@ -565,7 +610,7 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
PBFPrimitiveBlockDecoder(const ptr_len_type& data, osmium::osm_entity_bits::type read_types) :
|
||||
PBFPrimitiveBlockDecoder(const data_view& data, osmium::osm_entity_bits::type read_types) :
|
||||
m_data(data),
|
||||
m_read_types(read_types) {
|
||||
}
|
||||
@@ -582,7 +627,7 @@ namespace osmium {
|
||||
try {
|
||||
decode_primitive_block_metadata();
|
||||
decode_primitive_block_data();
|
||||
} catch (std::out_of_range&) {
|
||||
} catch (const std::out_of_range&) {
|
||||
throw osmium::pbf_error("string id out of range");
|
||||
}
|
||||
|
||||
@@ -591,17 +636,17 @@ namespace osmium {
|
||||
|
||||
}; // class PBFPrimitiveBlockDecoder
|
||||
|
||||
inline ptr_len_type decode_blob(const std::string& blob_data, std::string& output) {
|
||||
inline data_view decode_blob(const std::string& blob_data, std::string& output) {
|
||||
int32_t raw_size = 0;
|
||||
std::pair<const char*, protozero::pbf_length_type> zlib_data = {nullptr, 0};
|
||||
protozero::data_view zlib_data;
|
||||
|
||||
protozero::pbf_message<FileFormat::Blob> pbf_blob(blob_data);
|
||||
while (pbf_blob.next()) {
|
||||
switch (pbf_blob.tag()) {
|
||||
case FileFormat::Blob::optional_bytes_raw:
|
||||
{
|
||||
auto data_len = pbf_blob.get_data();
|
||||
if (data_len.second > max_uncompressed_blob_size) {
|
||||
auto data_len = pbf_blob.get_view();
|
||||
if (data_len.size() > max_uncompressed_blob_size) {
|
||||
throw osmium::pbf_error("illegal blob size");
|
||||
}
|
||||
return data_len;
|
||||
@@ -613,7 +658,7 @@ namespace osmium {
|
||||
}
|
||||
break;
|
||||
case FileFormat::Blob::optional_bytes_zlib_data:
|
||||
zlib_data = pbf_blob.get_data();
|
||||
zlib_data = pbf_blob.get_view();
|
||||
break;
|
||||
case FileFormat::Blob::optional_bytes_lzma_data:
|
||||
throw osmium::pbf_error("lzma blobs not implemented");
|
||||
@@ -622,10 +667,10 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
if (zlib_data.second != 0 && raw_size != 0) {
|
||||
if (zlib_data.size() != 0 && raw_size != 0) {
|
||||
return osmium::io::detail::zlib_uncompress_string(
|
||||
zlib_data.first,
|
||||
static_cast<unsigned long>(zlib_data.second),
|
||||
zlib_data.data(),
|
||||
static_cast<unsigned long>(zlib_data.size()),
|
||||
static_cast<unsigned long>(raw_size),
|
||||
output
|
||||
);
|
||||
@@ -634,7 +679,7 @@ namespace osmium {
|
||||
throw osmium::pbf_error("blob contains no data");
|
||||
}
|
||||
|
||||
inline osmium::Box decode_header_bbox(const ptr_len_type& data) {
|
||||
inline osmium::Box decode_header_bbox(const data_view& data) {
|
||||
int64_t left = std::numeric_limits<int64_t>::max();
|
||||
int64_t right = std::numeric_limits<int64_t>::max();
|
||||
int64_t top = std::numeric_limits<int64_t>::max();
|
||||
@@ -674,7 +719,7 @@ namespace osmium {
|
||||
return box;
|
||||
}
|
||||
|
||||
inline osmium::io::Header decode_header_block(const ptr_len_type& data) {
|
||||
inline osmium::io::Header decode_header_block(const data_view& data) {
|
||||
osmium::io::Header header;
|
||||
int i = 0;
|
||||
|
||||
@@ -682,20 +727,20 @@ namespace osmium {
|
||||
while (pbf_header_block.next()) {
|
||||
switch (pbf_header_block.tag()) {
|
||||
case OSMFormat::HeaderBlock::optional_HeaderBBox_bbox:
|
||||
header.add_box(decode_header_bbox(pbf_header_block.get_data()));
|
||||
header.add_box(decode_header_bbox(pbf_header_block.get_view()));
|
||||
break;
|
||||
case OSMFormat::HeaderBlock::repeated_string_required_features:
|
||||
{
|
||||
auto feature = pbf_header_block.get_data();
|
||||
if (!strncmp("OsmSchema-V0.6", feature.first, feature.second)) {
|
||||
auto feature = pbf_header_block.get_view();
|
||||
if (!std::strncmp("OsmSchema-V0.6", feature.data(), feature.size())) {
|
||||
// intentionally left blank
|
||||
} else if (!strncmp("DenseNodes", feature.first, feature.second)) {
|
||||
} else if (!std::strncmp("DenseNodes", feature.data(), feature.size())) {
|
||||
header.set("pbf_dense_nodes", true);
|
||||
} else if (!strncmp("HistoricalInformation", feature.first, feature.second)) {
|
||||
} else if (!std::strncmp("HistoricalInformation", feature.data(), feature.size())) {
|
||||
header.set_has_multiple_object_versions(true);
|
||||
} else {
|
||||
std::string msg("required feature not supported: ");
|
||||
msg.append(feature.first, feature.second);
|
||||
msg.append(feature.data(), feature.size());
|
||||
throw osmium::pbf_error(msg);
|
||||
}
|
||||
}
|
||||
@@ -708,7 +753,7 @@ namespace osmium {
|
||||
break;
|
||||
case OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp:
|
||||
{
|
||||
auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
|
||||
const auto timestamp = osmium::Timestamp(pbf_header_block.get_int64()).to_iso();
|
||||
header.set("osmosis_replication_timestamp", timestamp);
|
||||
header.set("timestamp", timestamp);
|
||||
}
|
||||
|
||||
@@ -38,25 +38,22 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
#include <protozero/pbf_message.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/io/detail/input_format.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/pbf_decoder.hpp>
|
||||
#include <osmium/io/detail/protobuf_tags.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/config.hpp>
|
||||
@@ -80,7 +77,7 @@ namespace osmium {
|
||||
*/
|
||||
std::string read_from_input_queue(size_t size) {
|
||||
while (m_input_buffer.size() < size) {
|
||||
std::string new_data = get_input();
|
||||
const std::string new_data = get_input();
|
||||
if (input_done()) {
|
||||
throw osmium::pbf_error("truncated data (EOF encountered)");
|
||||
}
|
||||
@@ -106,7 +103,7 @@ namespace osmium {
|
||||
try {
|
||||
const std::string input_data = read_from_input_queue(sizeof(size_in_network_byte_order));
|
||||
size_in_network_byte_order = *reinterpret_cast<const uint32_t*>(input_data.data());
|
||||
} catch (osmium::pbf_error&) {
|
||||
} catch (const osmium::pbf_error&) {
|
||||
return 0; // EOF
|
||||
}
|
||||
|
||||
@@ -123,13 +120,13 @@ namespace osmium {
|
||||
* type. Return the size of the following Blob.
|
||||
*/
|
||||
size_t decode_blob_header(protozero::pbf_message<FileFormat::BlobHeader>&& pbf_blob_header, const char* expected_type) {
|
||||
std::pair<const char*, size_t> blob_header_type;
|
||||
protozero::data_view blob_header_type;
|
||||
size_t blob_header_datasize = 0;
|
||||
|
||||
while (pbf_blob_header.next()) {
|
||||
switch (pbf_blob_header.tag()) {
|
||||
case FileFormat::BlobHeader::required_string_type:
|
||||
blob_header_type = pbf_blob_header.get_data();
|
||||
blob_header_type = pbf_blob_header.get_view();
|
||||
break;
|
||||
case FileFormat::BlobHeader::required_int32_datasize:
|
||||
blob_header_datasize = pbf_blob_header.get_int32();
|
||||
@@ -143,7 +140,7 @@ namespace osmium {
|
||||
throw osmium::pbf_error("PBF format error: BlobHeader.datasize missing or zero.");
|
||||
}
|
||||
|
||||
if (strncmp(expected_type, blob_header_type.first, blob_header_type.second)) {
|
||||
if (std::strncmp(expected_type, blob_header_type.data(), blob_header_type.size())) {
|
||||
throw osmium::pbf_error("blob does not have expected type (OSMHeader in first blob, OSMData in following blobs)");
|
||||
}
|
||||
|
||||
|
||||
@@ -41,30 +41,34 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <utility>
|
||||
|
||||
#include <protozero/pbf_builder.hpp>
|
||||
#include <protozero/pbf_writer.hpp>
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/pbf.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/protobuf_tags.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_table.hpp>
|
||||
#include <osmium/io/detail/zlib.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/pool.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
@@ -101,6 +105,9 @@ namespace osmium {
|
||||
/// Should the visible flag be added to all OSM objects?
|
||||
bool add_visible_flag;
|
||||
|
||||
/// Should node locations be added to ways?
|
||||
bool locations_on_ways;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -483,6 +490,7 @@ namespace osmium {
|
||||
m_options.add_metadata = file.is_not_false("pbf_add_metadata") && file.is_not_false("add_metadata");
|
||||
m_options.add_historical_information_flag = file.has_multiple_object_versions();
|
||||
m_options.add_visible_flag = file.has_multiple_object_versions();
|
||||
m_options.locations_on_ways = file.is_true("locations_on_ways");
|
||||
}
|
||||
|
||||
PBFOutputFormat(const PBFOutputFormat&) = delete;
|
||||
@@ -514,20 +522,24 @@ namespace osmium {
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_required_features, "HistoricalInformation");
|
||||
}
|
||||
|
||||
if (m_options.locations_on_ways) {
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::repeated_string_optional_features, "LocationsOnWays");
|
||||
}
|
||||
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_writingprogram, header.get("generator"));
|
||||
|
||||
std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
|
||||
const std::string osmosis_replication_timestamp = header.get("osmosis_replication_timestamp");
|
||||
if (!osmosis_replication_timestamp.empty()) {
|
||||
osmium::Timestamp ts(osmosis_replication_timestamp.c_str());
|
||||
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_timestamp, uint32_t(ts));
|
||||
}
|
||||
|
||||
std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
|
||||
const std::string osmosis_replication_sequence_number = header.get("osmosis_replication_sequence_number");
|
||||
if (!osmosis_replication_sequence_number.empty()) {
|
||||
pbf_header_block.add_int64(OSMFormat::HeaderBlock::optional_int64_osmosis_replication_sequence_number, std::atoll(osmosis_replication_sequence_number.c_str()));
|
||||
}
|
||||
|
||||
std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
|
||||
const std::string osmosis_replication_base_url = header.get("osmosis_replication_base_url");
|
||||
if (!osmosis_replication_base_url.empty()) {
|
||||
pbf_header_block.add_string(OSMFormat::HeaderBlock::optional_string_osmosis_replication_base_url, osmosis_replication_base_url);
|
||||
}
|
||||
@@ -571,15 +583,30 @@ namespace osmium {
|
||||
pbf_way.add_int64(OSMFormat::Way::required_int64_id, way.id());
|
||||
add_meta(way, pbf_way);
|
||||
|
||||
static auto map_node_ref = [](osmium::NodeRefList::const_iterator node_ref) noexcept -> osmium::object_id_type {
|
||||
return node_ref->ref();
|
||||
};
|
||||
typedef osmium::util::DeltaEncodeIterator<osmium::NodeRefList::const_iterator, decltype(map_node_ref), osmium::object_id_type> it_type;
|
||||
{
|
||||
osmium::util::DeltaEncode<object_id_type, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_refs)};
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
field.add_element(delta_id.update(node_ref.ref()));
|
||||
}
|
||||
}
|
||||
|
||||
const auto& nodes = way.nodes();
|
||||
it_type first { nodes.cbegin(), nodes.cend(), map_node_ref };
|
||||
it_type last { nodes.cend(), nodes.cend(), map_node_ref };
|
||||
pbf_way.add_packed_sint64(OSMFormat::Way::packed_sint64_refs, first, last);
|
||||
if (m_options.locations_on_ways) {
|
||||
{
|
||||
osmium::util::DeltaEncode<int64_t, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_lon)};
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
field.add_element(delta_id.update(lonlat2int(node_ref.location().lon_without_check())));
|
||||
}
|
||||
}
|
||||
{
|
||||
osmium::util::DeltaEncode<int64_t, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_way, protozero::pbf_tag_type(OSMFormat::Way::packed_sint64_lat)};
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
field.add_element(delta_id.update(lonlat2int(node_ref.location().lat_without_check())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void relation(const osmium::Relation& relation) {
|
||||
@@ -596,14 +623,13 @@ namespace osmium {
|
||||
}
|
||||
}
|
||||
|
||||
static auto map_member_ref = [](osmium::RelationMemberList::const_iterator member) noexcept -> osmium::object_id_type {
|
||||
return member->ref();
|
||||
};
|
||||
typedef osmium::util::DeltaEncodeIterator<osmium::RelationMemberList::const_iterator, decltype(map_member_ref), osmium::object_id_type> it_type;
|
||||
const auto& members = relation.members();
|
||||
it_type first { members.cbegin(), members.cend(), map_member_ref };
|
||||
it_type last { members.cend(), members.cend(), map_member_ref };
|
||||
pbf_relation.add_packed_sint64(OSMFormat::Relation::packed_sint64_memids, first, last);
|
||||
{
|
||||
osmium::util::DeltaEncode<object_id_type, int64_t> delta_id;
|
||||
protozero::packed_field_sint64 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_sint64_memids)};
|
||||
for (const auto& member : relation.members()) {
|
||||
field.add_element(delta_id.update(member.ref()));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
protozero::packed_field_int32 field{pbf_relation, protozero::pbf_tag_type(OSMFormat::Relation::packed_MemberType_types)};
|
||||
|
||||
@@ -146,7 +146,9 @@ namespace osmium {
|
||||
packed_uint32_keys = 2,
|
||||
packed_uint32_vals = 3,
|
||||
optional_Info_info = 4,
|
||||
packed_sint64_refs = 8
|
||||
packed_sint64_refs = 8,
|
||||
packed_sint64_lat = 9,
|
||||
packed_sint64_lon = 10
|
||||
};
|
||||
|
||||
enum class Relation : protozero::pbf_tag_type {
|
||||
|
||||
@@ -47,6 +47,9 @@ namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using future_queue_type = osmium::thread::Queue<std::future<T>>;
|
||||
|
||||
/**
|
||||
* This type of queue contains buffers with OSM data in them.
|
||||
* The "end of file" is marked by an invalid Buffer.
|
||||
@@ -54,7 +57,7 @@ namespace osmium {
|
||||
* transport exceptions. The future also helps with keeping the
|
||||
* data in order.
|
||||
*/
|
||||
using future_buffer_queue_type = osmium::thread::Queue<std::future<osmium::memory::Buffer>>;
|
||||
using future_buffer_queue_type = future_queue_type<osmium::memory::Buffer>;
|
||||
|
||||
/**
|
||||
* This type of queue contains OSM file data in the form it is
|
||||
@@ -71,24 +74,24 @@ namespace osmium {
|
||||
* transport exceptions. The future also helps with keeping the
|
||||
* data in order.
|
||||
*/
|
||||
using future_string_queue_type = osmium::thread::Queue<std::future<std::string>>;
|
||||
using future_string_queue_type = future_queue_type<std::string>;
|
||||
|
||||
template <typename T>
|
||||
inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, T&& data) {
|
||||
inline void add_to_queue(future_queue_type<T>& queue, T&& data) {
|
||||
std::promise<T> promise;
|
||||
queue.push(promise.get_future());
|
||||
promise.set_value(std::forward<T>(data));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void add_to_queue(osmium::thread::Queue<std::future<T>>& queue, std::exception_ptr&& exception) {
|
||||
inline void add_to_queue(future_queue_type<T>& queue, std::exception_ptr&& exception) {
|
||||
std::promise<T> promise;
|
||||
queue.push(promise.get_future());
|
||||
promise.set_exception(std::move(exception));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void add_end_of_data_to_queue(osmium::thread::Queue<std::future<T>>& queue) {
|
||||
inline void add_end_of_data_to_queue(future_queue_type<T>& queue) {
|
||||
add_to_queue<T>(queue, T{});
|
||||
}
|
||||
|
||||
@@ -103,14 +106,12 @@ namespace osmium {
|
||||
template <typename T>
|
||||
class queue_wrapper {
|
||||
|
||||
using queue_type = osmium::thread::Queue<std::future<T>>;
|
||||
|
||||
queue_type& m_queue;
|
||||
future_queue_type<T>& m_queue;
|
||||
bool m_has_reached_end_of_data;
|
||||
|
||||
public:
|
||||
|
||||
explicit queue_wrapper(queue_type& queue) :
|
||||
explicit queue_wrapper(future_queue_type<T>& queue) :
|
||||
m_queue(queue),
|
||||
m_has_reached_end_of_data(false) {
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
@@ -84,7 +83,7 @@ namespace osmium {
|
||||
#ifdef _WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
int fd = ::open(filename.c_str(), flags, 0666);
|
||||
const int fd = ::open(filename.c_str(), flags, 0666);
|
||||
if (fd < 0) {
|
||||
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
|
||||
}
|
||||
@@ -108,7 +107,7 @@ namespace osmium {
|
||||
#ifdef _WIN32
|
||||
flags |= O_BINARY;
|
||||
#endif
|
||||
int fd = ::open(filename.c_str(), flags);
|
||||
const int fd = ::open(filename.c_str(), flags);
|
||||
if (fd < 0) {
|
||||
throw std::system_error(errno, std::system_category(), std::string("Open failed for '") + filename + "'");
|
||||
}
|
||||
@@ -133,7 +132,7 @@ namespace osmium {
|
||||
if (write_count > max_write) {
|
||||
write_count = max_write;
|
||||
}
|
||||
auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
|
||||
const auto length = ::write(fd, output_buffer + offset, static_cast<unsigned int>(write_count));
|
||||
if (length < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "Write failed");
|
||||
}
|
||||
|
||||
+55
-22
@@ -34,13 +34,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/detail/pbf.hpp>
|
||||
|
||||
@@ -69,8 +70,8 @@ namespace osmium {
|
||||
std::list<std::string> m_chunks;
|
||||
|
||||
void add_chunk() {
|
||||
m_chunks.push_front(std::string());
|
||||
m_chunks.front().reserve(m_chunk_size);
|
||||
m_chunks.emplace_back();
|
||||
m_chunks.back().reserve(m_chunk_size);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -82,6 +83,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void clear() noexcept {
|
||||
assert(!m_chunks.empty());
|
||||
m_chunks.erase(std::next(m_chunks.begin()), m_chunks.end());
|
||||
m_chunks.front().clear();
|
||||
}
|
||||
@@ -93,31 +95,38 @@ namespace osmium {
|
||||
* allocated.
|
||||
*/
|
||||
const char* add(const char* string) {
|
||||
size_t len = std::strlen(string) + 1;
|
||||
const size_t len = std::strlen(string) + 1;
|
||||
|
||||
assert(len <= m_chunk_size);
|
||||
|
||||
size_t chunk_len = m_chunks.front().size();
|
||||
if (chunk_len + len > m_chunks.front().capacity()) {
|
||||
size_t chunk_len = m_chunks.back().size();
|
||||
if (chunk_len + len > m_chunks.back().capacity()) {
|
||||
add_chunk();
|
||||
chunk_len = 0;
|
||||
}
|
||||
|
||||
m_chunks.front().append(string);
|
||||
m_chunks.front().append(1, '\0');
|
||||
m_chunks.back().append(string);
|
||||
m_chunks.back().append(1, '\0');
|
||||
|
||||
return m_chunks.front().c_str() + chunk_len;
|
||||
return m_chunks.back().c_str() + chunk_len;
|
||||
}
|
||||
|
||||
class const_iterator : public std::iterator<std::forward_iterator_tag, const char*> {
|
||||
class const_iterator {
|
||||
|
||||
using it_type = std::list<std::string>::const_iterator;
|
||||
|
||||
typedef std::list<std::string>::const_iterator it_type;
|
||||
it_type m_it;
|
||||
const it_type m_last;
|
||||
const char* m_pos;
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = const char*;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
const_iterator(it_type it, it_type last) :
|
||||
m_it(it),
|
||||
m_last(last),
|
||||
@@ -126,7 +135,7 @@ namespace osmium {
|
||||
|
||||
const_iterator& operator++() {
|
||||
assert(m_it != m_last);
|
||||
auto last_pos = m_it->c_str() + m_it->size();
|
||||
const auto last_pos = m_it->c_str() + m_it->size();
|
||||
while (m_pos != last_pos && *m_pos) ++m_pos;
|
||||
if (m_pos != last_pos) ++m_pos;
|
||||
if (m_pos == last_pos) {
|
||||
@@ -184,18 +193,33 @@ namespace osmium {
|
||||
}
|
||||
|
||||
size_t get_used_bytes_in_last_chunk() const noexcept {
|
||||
return m_chunks.front().size();
|
||||
return m_chunks.back().size();
|
||||
}
|
||||
|
||||
}; // class StringStore
|
||||
|
||||
struct StrComp {
|
||||
struct str_equal {
|
||||
|
||||
bool operator()(const char* lhs, const char* rhs) const {
|
||||
return strcmp(lhs, rhs) < 0;
|
||||
bool operator()(const char* lhs, const char* rhs) const noexcept {
|
||||
return lhs == rhs || std::strcmp(lhs, rhs) == 0;
|
||||
}
|
||||
|
||||
}; // struct StrComp
|
||||
}; // struct str_equal
|
||||
|
||||
struct djb2_hash {
|
||||
|
||||
size_t operator()(const char* str) const noexcept {
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++)) {
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
}; // struct djb2_hash
|
||||
|
||||
class StringTable {
|
||||
|
||||
@@ -206,14 +230,23 @@ namespace osmium {
|
||||
// Blob.
|
||||
static constexpr const uint32_t max_entries = max_uncompressed_blob_size;
|
||||
|
||||
// There is one string table per PBF primitive block. Most of
|
||||
// them are really small, because most blocks are full of nodes
|
||||
// with no tags. But string tables can get really large for
|
||||
// ways with many tags or for large relations.
|
||||
// The chosen size is enough so that 99% of all string tables
|
||||
// in typical OSM files will only need a single memory
|
||||
// allocation.
|
||||
static constexpr const size_t default_stringtable_chunk_size = 100 * 1024;
|
||||
|
||||
StringStore m_strings;
|
||||
std::map<const char*, size_t, StrComp> m_index;
|
||||
std::unordered_map<const char*, size_t, djb2_hash, str_equal> m_index;
|
||||
uint32_t m_size;
|
||||
|
||||
public:
|
||||
|
||||
StringTable() :
|
||||
m_strings(1024 * 1024),
|
||||
explicit StringTable(size_t size = default_stringtable_chunk_size) :
|
||||
m_strings(size),
|
||||
m_index(),
|
||||
m_size(0) {
|
||||
m_strings.add("");
|
||||
@@ -231,7 +264,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
uint32_t add(const char* s) {
|
||||
auto f = m_index.find(s);
|
||||
const auto f = m_index.find(s);
|
||||
if (f != m_index.end()) {
|
||||
return uint32_t(f->second);
|
||||
}
|
||||
|
||||
+41
-16
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -100,36 +101,57 @@ namespace osmium {
|
||||
static const size_t max_size = 0;
|
||||
#endif
|
||||
|
||||
size_t old_size = out.size();
|
||||
const size_t old_size = out.size();
|
||||
|
||||
int len = string_snprintf(out,
|
||||
old_size,
|
||||
max_size,
|
||||
format,
|
||||
std::forward<TArgs>(args)...);
|
||||
const int len = string_snprintf(out,
|
||||
old_size,
|
||||
max_size,
|
||||
format,
|
||||
std::forward<TArgs>(args)...);
|
||||
assert(len > 0);
|
||||
|
||||
if (size_t(len) >= max_size) {
|
||||
#ifndef NDEBUG
|
||||
int len2 =
|
||||
const int len2 =
|
||||
#endif
|
||||
string_snprintf(out,
|
||||
old_size,
|
||||
size_t(len) + 1,
|
||||
format,
|
||||
std::forward<TArgs>(args)...);
|
||||
string_snprintf(out,
|
||||
old_size,
|
||||
size_t(len) + 1,
|
||||
format,
|
||||
std::forward<TArgs>(args)...);
|
||||
assert(len2 == len);
|
||||
}
|
||||
|
||||
out.resize(old_size + size_t(len));
|
||||
}
|
||||
|
||||
// Write out the value with exactly two hex digits.
|
||||
inline void append_2_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
|
||||
out += hex_digits[(value >> 4) & 0xf];
|
||||
out += hex_digits[ value & 0xf];
|
||||
}
|
||||
|
||||
// Write out the value with four or more hex digits.
|
||||
inline void append_min_4_hex_digits(std::string& out, uint32_t value, const char* const hex_digits) {
|
||||
auto
|
||||
v = value & 0xf0000000; if (v) out += hex_digits[v >> 28];
|
||||
v = value & 0x0f000000; if (v) out += hex_digits[v >> 24];
|
||||
v = value & 0x00f00000; if (v) out += hex_digits[v >> 20];
|
||||
v = value & 0x000f0000; if (v) out += hex_digits[v >> 16];
|
||||
|
||||
out += hex_digits[(value >> 12) & 0xf];
|
||||
out += hex_digits[(value >> 8) & 0xf];
|
||||
out += hex_digits[(value >> 4) & 0xf];
|
||||
out += hex_digits[ value & 0xf];
|
||||
}
|
||||
|
||||
inline void append_utf8_encoded_string(std::string& out, const char* data) {
|
||||
static const char* lookup_hex = "0123456789abcdef";
|
||||
const char* end = data + std::strlen(data);
|
||||
|
||||
while (data != end) {
|
||||
const char* last = data;
|
||||
uint32_t c = utf8::next(data, end);
|
||||
const uint32_t c = utf8::next(data, end);
|
||||
|
||||
// This is a list of Unicode code points that we let
|
||||
// through instead of escaping them. It is incomplete
|
||||
@@ -148,9 +170,9 @@ namespace osmium {
|
||||
} else {
|
||||
out += '%';
|
||||
if (c <= 0xff) {
|
||||
append_printf_formatted_string(out, "%02x", c);
|
||||
append_2_hex_digits(out, c, lookup_hex);
|
||||
} else {
|
||||
append_printf_formatted_string(out, "%04x", c);
|
||||
append_min_4_hex_digits(out, c, lookup_hex);
|
||||
}
|
||||
out += '%';
|
||||
}
|
||||
@@ -174,6 +196,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
inline void append_debug_encoded_string(std::string& out, const char* data, const char* prefix, const char* suffix) {
|
||||
static const char* lookup_hex = "0123456789ABCDEF";
|
||||
const char* end = data + std::strlen(data);
|
||||
|
||||
while (data != end) {
|
||||
@@ -194,7 +217,9 @@ namespace osmium {
|
||||
out.append(last, data);
|
||||
} else {
|
||||
out.append(prefix);
|
||||
append_printf_formatted_string(out, "<U+%04X>", c);
|
||||
out.append("<U+");
|
||||
append_min_4_hex_digits(out, c, lookup_hex);
|
||||
out.append(">");
|
||||
out.append(suffix);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
|
||||
@@ -34,10 +34,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -53,15 +50,19 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm.hpp>
|
||||
#include <osmium/osm/box.hpp>
|
||||
#include <osmium/osm/changeset.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/types_from_string.hpp>
|
||||
#include <osmium/thread/queue.hpp>
|
||||
#include <osmium/osm/way.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
|
||||
@@ -192,6 +193,17 @@ namespace osmium {
|
||||
static_cast<XMLParser*>(data)->characters(text, len);
|
||||
}
|
||||
|
||||
// This handler is called when there are any XML entities
|
||||
// declared in the OSM file. Entities are normally not used,
|
||||
// but they can be misused. See
|
||||
// https://en.wikipedia.org/wiki/Billion_laughs
|
||||
// The handler will just throw an error.
|
||||
static void entity_declaration_handler(void*,
|
||||
const XML_Char*, int, const XML_Char*, int, const XML_Char*,
|
||||
const XML_Char*, const XML_Char*, const XML_Char*) {
|
||||
throw osmium::xml_error("XML entities are not supported");
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit ExpatXMLParser(T* callback_object) :
|
||||
@@ -202,6 +214,7 @@ namespace osmium {
|
||||
XML_SetUserData(m_parser, callback_object);
|
||||
XML_SetElementHandler(m_parser, start_element_wrapper, end_element_wrapper);
|
||||
XML_SetCharacterDataHandler(m_parser, character_data_wrapper);
|
||||
XML_SetEntityDeclHandler(m_parser, entity_declaration_handler);
|
||||
}
|
||||
|
||||
ExpatXMLParser(const ExpatXMLParser&) = delete;
|
||||
@@ -240,11 +253,11 @@ namespace osmium {
|
||||
osmium::Location location;
|
||||
|
||||
check_attributes(attrs, [&location, &user, &object](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "lon")) {
|
||||
location.set_lon(std::atof(value)); // XXX doesn't detect garbage after the number
|
||||
} else if (!strcmp(name, "lat")) {
|
||||
location.set_lat(std::atof(value)); // XXX doesn't detect garbage after the number
|
||||
} else if (!strcmp(name, "user")) {
|
||||
if (!std::strcmp(name, "lon")) {
|
||||
location.set_lon(value);
|
||||
} else if (!std::strcmp(name, "lat")) {
|
||||
location.set_lat(value);
|
||||
} else if (!std::strcmp(name, "user")) {
|
||||
user = value;
|
||||
} else {
|
||||
object.set_attribute(name, value);
|
||||
@@ -265,15 +278,15 @@ namespace osmium {
|
||||
osmium::Location min;
|
||||
osmium::Location max;
|
||||
check_attributes(attrs, [&min, &max, &user, &new_changeset](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "min_lon")) {
|
||||
min.set_lon(atof(value));
|
||||
} else if (!strcmp(name, "min_lat")) {
|
||||
min.set_lat(atof(value));
|
||||
} else if (!strcmp(name, "max_lon")) {
|
||||
max.set_lon(atof(value));
|
||||
} else if (!strcmp(name, "max_lat")) {
|
||||
max.set_lat(atof(value));
|
||||
} else if (!strcmp(name, "user")) {
|
||||
if (!std::strcmp(name, "min_lon")) {
|
||||
min.set_lon(value);
|
||||
} else if (!std::strcmp(name, "min_lat")) {
|
||||
min.set_lat(value);
|
||||
} else if (!std::strcmp(name, "max_lon")) {
|
||||
max.set_lon(value);
|
||||
} else if (!std::strcmp(name, "max_lat")) {
|
||||
max.set_lat(value);
|
||||
} else if (!std::strcmp(name, "user")) {
|
||||
user = value;
|
||||
} else {
|
||||
new_changeset.set_attribute(name, value);
|
||||
@@ -309,17 +322,17 @@ namespace osmium {
|
||||
void start_element(const XML_Char* element, const XML_Char** attrs) {
|
||||
switch (m_context) {
|
||||
case context::root:
|
||||
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
|
||||
if (!strcmp(element, "osmChange")) {
|
||||
if (!std::strcmp(element, "osm") || !std::strcmp(element, "osmChange")) {
|
||||
if (!std::strcmp(element, "osmChange")) {
|
||||
m_header.set_has_multiple_object_versions(true);
|
||||
}
|
||||
check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "version")) {
|
||||
if (!std::strcmp(name, "version")) {
|
||||
m_header.set("version", value);
|
||||
if (strcmp(value, "0.6")) {
|
||||
if (std::strcmp(value, "0.6")) {
|
||||
throw osmium::format_version_error(value);
|
||||
}
|
||||
} else if (!strcmp(name, "generator")) {
|
||||
} else if (!std::strcmp(name, "generator")) {
|
||||
m_header.set("generator", value);
|
||||
}
|
||||
});
|
||||
@@ -333,7 +346,7 @@ namespace osmium {
|
||||
break;
|
||||
case context::top:
|
||||
assert(!m_tl_builder);
|
||||
if (!strcmp(element, "node")) {
|
||||
if (!std::strcmp(element, "node")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::node) {
|
||||
m_node_builder = std::unique_ptr<osmium::builder::NodeBuilder>(new osmium::builder::NodeBuilder(m_buffer));
|
||||
@@ -342,7 +355,7 @@ namespace osmium {
|
||||
} else {
|
||||
m_context = context::ignored_node;
|
||||
}
|
||||
} else if (!strcmp(element, "way")) {
|
||||
} else if (!std::strcmp(element, "way")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::way) {
|
||||
m_way_builder = std::unique_ptr<osmium::builder::WayBuilder>(new osmium::builder::WayBuilder(m_buffer));
|
||||
@@ -351,7 +364,7 @@ namespace osmium {
|
||||
} else {
|
||||
m_context = context::ignored_way;
|
||||
}
|
||||
} else if (!strcmp(element, "relation")) {
|
||||
} else if (!std::strcmp(element, "relation")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::relation) {
|
||||
m_relation_builder = std::unique_ptr<osmium::builder::RelationBuilder>(new osmium::builder::RelationBuilder(m_buffer));
|
||||
@@ -360,7 +373,7 @@ namespace osmium {
|
||||
} else {
|
||||
m_context = context::ignored_relation;
|
||||
}
|
||||
} else if (!strcmp(element, "changeset")) {
|
||||
} else if (!std::strcmp(element, "changeset")) {
|
||||
mark_header_as_done();
|
||||
if (read_types() & osmium::osm_entity_bits::changeset) {
|
||||
m_changeset_builder = std::unique_ptr<osmium::builder::ChangesetBuilder>(new osmium::builder::ChangesetBuilder(m_buffer));
|
||||
@@ -369,50 +382,56 @@ namespace osmium {
|
||||
} else {
|
||||
m_context = context::ignored_changeset;
|
||||
}
|
||||
} else if (!strcmp(element, "bounds")) {
|
||||
} else if (!std::strcmp(element, "bounds")) {
|
||||
osmium::Location min;
|
||||
osmium::Location max;
|
||||
check_attributes(attrs, [&min, &max](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "minlon")) {
|
||||
min.set_lon(atof(value));
|
||||
} else if (!strcmp(name, "minlat")) {
|
||||
min.set_lat(atof(value));
|
||||
} else if (!strcmp(name, "maxlon")) {
|
||||
max.set_lon(atof(value));
|
||||
} else if (!strcmp(name, "maxlat")) {
|
||||
max.set_lat(atof(value));
|
||||
if (!std::strcmp(name, "minlon")) {
|
||||
min.set_lon(value);
|
||||
} else if (!std::strcmp(name, "minlat")) {
|
||||
min.set_lat(value);
|
||||
} else if (!std::strcmp(name, "maxlon")) {
|
||||
max.set_lon(value);
|
||||
} else if (!std::strcmp(name, "maxlat")) {
|
||||
max.set_lat(value);
|
||||
}
|
||||
});
|
||||
osmium::Box box;
|
||||
box.extend(min).extend(max);
|
||||
m_header.add_box(box);
|
||||
} else if (!strcmp(element, "delete")) {
|
||||
} else if (!std::strcmp(element, "delete")) {
|
||||
m_in_delete_section = true;
|
||||
}
|
||||
break;
|
||||
case context::node:
|
||||
m_last_context = context::node;
|
||||
m_context = context::in_object;
|
||||
if (!strcmp(element, "tag")) {
|
||||
if (!std::strcmp(element, "tag")) {
|
||||
get_tag(m_node_builder.get(), attrs);
|
||||
}
|
||||
break;
|
||||
case context::way:
|
||||
m_last_context = context::way;
|
||||
m_context = context::in_object;
|
||||
if (!strcmp(element, "nd")) {
|
||||
if (!std::strcmp(element, "nd")) {
|
||||
m_tl_builder.reset();
|
||||
|
||||
if (!m_wnl_builder) {
|
||||
m_wnl_builder = std::unique_ptr<osmium::builder::WayNodeListBuilder>(new osmium::builder::WayNodeListBuilder(m_buffer, m_way_builder.get()));
|
||||
}
|
||||
|
||||
check_attributes(attrs, [this](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "ref")) {
|
||||
m_wnl_builder->add_node_ref(osmium::string_to_object_id(value));
|
||||
NodeRef nr;
|
||||
check_attributes(attrs, [this, &nr](const XML_Char* name, const XML_Char* value) {
|
||||
if (!std::strcmp(name, "ref")) {
|
||||
nr.set_ref(osmium::string_to_object_id(value));
|
||||
} else if (!std::strcmp(name, "lon")) {
|
||||
nr.location().set_lon(value);
|
||||
} else if (!std::strcmp(name, "lat")) {
|
||||
nr.location().set_lat(value);
|
||||
}
|
||||
});
|
||||
} else if (!strcmp(element, "tag")) {
|
||||
m_wnl_builder->add_node_ref(nr);
|
||||
} else if (!std::strcmp(element, "tag")) {
|
||||
m_wnl_builder.reset();
|
||||
get_tag(m_way_builder.get(), attrs);
|
||||
}
|
||||
@@ -420,7 +439,7 @@ namespace osmium {
|
||||
case context::relation:
|
||||
m_last_context = context::relation;
|
||||
m_context = context::in_object;
|
||||
if (!strcmp(element, "member")) {
|
||||
if (!std::strcmp(element, "member")) {
|
||||
m_tl_builder.reset();
|
||||
|
||||
if (!m_rml_builder) {
|
||||
@@ -431,11 +450,11 @@ namespace osmium {
|
||||
object_id_type ref = 0;
|
||||
const char* role = "";
|
||||
check_attributes(attrs, [&type, &ref, &role](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "type")) {
|
||||
if (!std::strcmp(name, "type")) {
|
||||
type = char_to_item_type(value[0]);
|
||||
} else if (!strcmp(name, "ref")) {
|
||||
} else if (!std::strcmp(name, "ref")) {
|
||||
ref = osmium::string_to_object_id(value);
|
||||
} else if (!strcmp(name, "role")) {
|
||||
} else if (!std::strcmp(name, "role")) {
|
||||
role = static_cast<const char*>(value);
|
||||
}
|
||||
});
|
||||
@@ -446,37 +465,37 @@ namespace osmium {
|
||||
throw osmium::xml_error("Missing ref on relation member");
|
||||
}
|
||||
m_rml_builder->add_member(type, ref, role);
|
||||
} else if (!strcmp(element, "tag")) {
|
||||
} else if (!std::strcmp(element, "tag")) {
|
||||
m_rml_builder.reset();
|
||||
get_tag(m_relation_builder.get(), attrs);
|
||||
}
|
||||
break;
|
||||
case context::changeset:
|
||||
m_last_context = context::changeset;
|
||||
if (!strcmp(element, "discussion")) {
|
||||
if (!std::strcmp(element, "discussion")) {
|
||||
m_context = context::discussion;
|
||||
m_tl_builder.reset();
|
||||
if (!m_changeset_discussion_builder) {
|
||||
m_changeset_discussion_builder = std::unique_ptr<osmium::builder::ChangesetDiscussionBuilder>(new osmium::builder::ChangesetDiscussionBuilder(m_buffer, m_changeset_builder.get()));
|
||||
}
|
||||
} else if (!strcmp(element, "tag")) {
|
||||
} else if (!std::strcmp(element, "tag")) {
|
||||
m_context = context::in_object;
|
||||
m_changeset_discussion_builder.reset();
|
||||
get_tag(m_changeset_builder.get(), attrs);
|
||||
}
|
||||
break;
|
||||
case context::discussion:
|
||||
if (!strcmp(element, "comment")) {
|
||||
if (!std::strcmp(element, "comment")) {
|
||||
m_context = context::comment;
|
||||
osmium::Timestamp date;
|
||||
osmium::user_id_type uid = 0;
|
||||
const char* user = "";
|
||||
check_attributes(attrs, [&date, &uid, &user](const XML_Char* name, const XML_Char* value) {
|
||||
if (!strcmp(name, "date")) {
|
||||
if (!std::strcmp(name, "date")) {
|
||||
date = osmium::Timestamp(value);
|
||||
} else if (!strcmp(name, "uid")) {
|
||||
} else if (!std::strcmp(name, "uid")) {
|
||||
uid = osmium::string_to_user_id(value);
|
||||
} else if (!strcmp(name, "user")) {
|
||||
} else if (!std::strcmp(name, "user")) {
|
||||
user = static_cast<const char*>(value);
|
||||
}
|
||||
});
|
||||
@@ -484,7 +503,7 @@ namespace osmium {
|
||||
}
|
||||
break;
|
||||
case context::comment:
|
||||
if (!strcmp(element, "text")) {
|
||||
if (!std::strcmp(element, "text")) {
|
||||
m_context = context::comment_text;
|
||||
}
|
||||
break;
|
||||
@@ -510,15 +529,15 @@ namespace osmium {
|
||||
assert(false); // should never be here
|
||||
break;
|
||||
case context::top:
|
||||
if (!strcmp(element, "osm") || !strcmp(element, "osmChange")) {
|
||||
if (!std::strcmp(element, "osm") || !std::strcmp(element, "osmChange")) {
|
||||
mark_header_as_done();
|
||||
m_context = context::root;
|
||||
} else if (!strcmp(element, "delete")) {
|
||||
} else if (!std::strcmp(element, "delete")) {
|
||||
m_in_delete_section = false;
|
||||
}
|
||||
break;
|
||||
case context::node:
|
||||
assert(!strcmp(element, "node"));
|
||||
assert(!std::strcmp(element, "node"));
|
||||
m_tl_builder.reset();
|
||||
m_node_builder.reset();
|
||||
m_buffer.commit();
|
||||
@@ -526,7 +545,7 @@ namespace osmium {
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::way:
|
||||
assert(!strcmp(element, "way"));
|
||||
assert(!std::strcmp(element, "way"));
|
||||
m_tl_builder.reset();
|
||||
m_wnl_builder.reset();
|
||||
m_way_builder.reset();
|
||||
@@ -535,7 +554,7 @@ namespace osmium {
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::relation:
|
||||
assert(!strcmp(element, "relation"));
|
||||
assert(!std::strcmp(element, "relation"));
|
||||
m_tl_builder.reset();
|
||||
m_rml_builder.reset();
|
||||
m_relation_builder.reset();
|
||||
@@ -544,7 +563,7 @@ namespace osmium {
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::changeset:
|
||||
assert(!strcmp(element, "changeset"));
|
||||
assert(!std::strcmp(element, "changeset"));
|
||||
m_tl_builder.reset();
|
||||
m_changeset_discussion_builder.reset();
|
||||
m_changeset_builder.reset();
|
||||
@@ -553,15 +572,15 @@ namespace osmium {
|
||||
flush_buffer();
|
||||
break;
|
||||
case context::discussion:
|
||||
assert(!strcmp(element, "discussion"));
|
||||
assert(!std::strcmp(element, "discussion"));
|
||||
m_context = context::changeset;
|
||||
break;
|
||||
case context::comment:
|
||||
assert(!strcmp(element, "comment"));
|
||||
assert(!std::strcmp(element, "comment"));
|
||||
m_context = context::discussion;
|
||||
break;
|
||||
case context::comment_text:
|
||||
assert(!strcmp(element, "text"));
|
||||
assert(!std::strcmp(element, "text"));
|
||||
m_context = context::comment;
|
||||
m_changeset_discussion_builder->add_comment_text(m_comment_text);
|
||||
break;
|
||||
@@ -569,22 +588,22 @@ namespace osmium {
|
||||
m_context = m_last_context;
|
||||
break;
|
||||
case context::ignored_node:
|
||||
if (!strcmp(element, "node")) {
|
||||
if (!std::strcmp(element, "node")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
case context::ignored_way:
|
||||
if (!strcmp(element, "way")) {
|
||||
if (!std::strcmp(element, "way")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
case context::ignored_relation:
|
||||
if (!strcmp(element, "relation")) {
|
||||
if (!std::strcmp(element, "relation")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
case context::ignored_changeset:
|
||||
if (!strcmp(element, "changeset")) {
|
||||
if (!std::strcmp(element, "changeset")) {
|
||||
m_context = context::top;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -34,27 +34,26 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/io/detail/output_format.hpp>
|
||||
#include <osmium/io/detail/queue_util.hpp>
|
||||
#include <osmium/io/detail/string_util.hpp>
|
||||
#include <osmium/io/file.hpp>
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/header.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item_iterator.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/node_ref.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/relation.hpp>
|
||||
#include <osmium/osm/tag.hpp>
|
||||
@@ -86,8 +85,26 @@ namespace osmium {
|
||||
*/
|
||||
bool use_change_ops;
|
||||
|
||||
/// Should node locations be added to ways?
|
||||
bool locations_on_ways;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline void append_lat_lon_attributes(std::string& out, const char* lat, const char* lon, const osmium::Location& location) {
|
||||
out += ' ';
|
||||
out += lat;
|
||||
out += "=\"";
|
||||
osmium::detail::append_location_coordinate_to_string(std::back_inserter(out), location.y());
|
||||
out += "\" ";
|
||||
out += lon;
|
||||
out += "=\"";
|
||||
osmium::detail::append_location_coordinate_to_string(std::back_inserter(out), location.x());
|
||||
out += "\"";
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class XMLOutputBlock : public OutputBlock {
|
||||
|
||||
// operation (create, modify, delete) for osc files
|
||||
@@ -116,12 +133,21 @@ namespace osmium {
|
||||
write_spaces(prefix_spaces());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_attribute(const char* name, T value) {
|
||||
*m_out += ' ';
|
||||
*m_out += name;
|
||||
*m_out += "=\"";
|
||||
output_int(value);
|
||||
*m_out += '"';
|
||||
}
|
||||
|
||||
void write_meta(const osmium::OSMObject& object) {
|
||||
output_formatted(" id=\"%" PRId64 "\"", object.id());
|
||||
write_attribute("id", object.id());
|
||||
|
||||
if (m_options.add_metadata) {
|
||||
if (object.version()) {
|
||||
output_formatted(" version=\"%d\"", object.version());
|
||||
write_attribute("version", object.version());
|
||||
}
|
||||
|
||||
if (object.timestamp()) {
|
||||
@@ -131,13 +157,14 @@ namespace osmium {
|
||||
}
|
||||
|
||||
if (!object.user_is_anonymous()) {
|
||||
output_formatted(" uid=\"%d\" user=\"", object.uid());
|
||||
write_attribute("uid", object.uid());
|
||||
*m_out += " user=\"";
|
||||
append_xml_encoded_string(*m_out, object.user());
|
||||
*m_out += "\"";
|
||||
}
|
||||
|
||||
if (object.changeset()) {
|
||||
output_formatted(" changeset=\"%d\"", object.changeset());
|
||||
write_attribute("changeset", object.changeset());
|
||||
}
|
||||
|
||||
if (m_options.add_visible_flag) {
|
||||
@@ -162,8 +189,11 @@ namespace osmium {
|
||||
}
|
||||
|
||||
void write_discussion(const osmium::ChangesetDiscussion& comments) {
|
||||
*m_out += " <discussion>\n";
|
||||
for (const auto& comment : comments) {
|
||||
output_formatted(" <comment uid=\"%d\" user=\"", comment.uid());
|
||||
*m_out += " <comment";
|
||||
write_attribute("uid", comment.uid());
|
||||
*m_out += " user=\"";
|
||||
append_xml_encoded_string(*m_out, comment.user());
|
||||
*m_out += "\" date=\"";
|
||||
*m_out += comment.date().to_iso();
|
||||
@@ -251,11 +281,7 @@ namespace osmium {
|
||||
write_meta(node);
|
||||
|
||||
if (node.location()) {
|
||||
*m_out += " lat=\"";
|
||||
osmium::util::double2string(std::back_inserter(*m_out), node.location().lat_without_check(), 7);
|
||||
*m_out += "\" lon=\"";
|
||||
osmium::util::double2string(std::back_inserter(*m_out), node.location().lon_without_check(), 7);
|
||||
*m_out += "\"";
|
||||
detail::append_lat_lon_attributes(*m_out, "lat", "lon", node.location());
|
||||
}
|
||||
|
||||
if (node.tags().empty()) {
|
||||
@@ -287,9 +313,23 @@ namespace osmium {
|
||||
|
||||
*m_out += ">\n";
|
||||
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
write_prefix();
|
||||
output_formatted(" <nd ref=\"%" PRId64 "\"/>\n", node_ref.ref());
|
||||
if (m_options.locations_on_ways) {
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
write_prefix();
|
||||
*m_out += " <nd";
|
||||
write_attribute("ref", node_ref.ref());
|
||||
if (node_ref.location()) {
|
||||
detail::append_lat_lon_attributes(*m_out, "lat", "lon", node_ref.location());
|
||||
}
|
||||
*m_out += "/>\n";
|
||||
}
|
||||
} else {
|
||||
for (const auto& node_ref : way.nodes()) {
|
||||
write_prefix();
|
||||
*m_out += " <nd";
|
||||
write_attribute("ref", node_ref.ref());
|
||||
*m_out += "/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
write_tags(way.tags(), prefix_spaces());
|
||||
@@ -318,7 +358,9 @@ namespace osmium {
|
||||
write_prefix();
|
||||
*m_out += " <member type=\"";
|
||||
*m_out += item_type_to_name(member.type());
|
||||
output_formatted("\" ref=\"%" PRId64 "\" role=\"", member.ref());
|
||||
*m_out += '"';
|
||||
write_attribute("ref", member.ref());
|
||||
*m_out += " role=\"";
|
||||
append_xml_encoded_string(*m_out, member.role());
|
||||
*m_out += "\"/>\n";
|
||||
}
|
||||
@@ -332,7 +374,7 @@ namespace osmium {
|
||||
void changeset(const osmium::Changeset& changeset) {
|
||||
*m_out += " <changeset";
|
||||
|
||||
output_formatted(" id=\"%" PRId32 "\"", changeset.id());
|
||||
write_attribute("id", changeset.id());
|
||||
|
||||
if (changeset.created_at()) {
|
||||
*m_out += " created_at=\"";
|
||||
@@ -351,22 +393,21 @@ namespace osmium {
|
||||
if (!changeset.user_is_anonymous()) {
|
||||
*m_out += " user=\"";
|
||||
append_xml_encoded_string(*m_out, changeset.user());
|
||||
output_formatted("\" uid=\"%d\"", changeset.uid());
|
||||
*m_out += '"';
|
||||
write_attribute("uid", changeset.uid());
|
||||
}
|
||||
|
||||
if (changeset.bounds()) {
|
||||
output_formatted(" min_lat=\"%.7f\"", changeset.bounds().bottom_left().lat_without_check());
|
||||
output_formatted(" min_lon=\"%.7f\"", changeset.bounds().bottom_left().lon_without_check());
|
||||
output_formatted(" max_lat=\"%.7f\"", changeset.bounds().top_right().lat_without_check());
|
||||
output_formatted(" max_lon=\"%.7f\"", changeset.bounds().top_right().lon_without_check());
|
||||
detail::append_lat_lon_attributes(*m_out, "min_lat", "min_lon", changeset.bounds().bottom_left());
|
||||
detail::append_lat_lon_attributes(*m_out, "max_lat", "max_lon", changeset.bounds().top_right());
|
||||
}
|
||||
|
||||
output_formatted(" num_changes=\"%" PRId32 "\"", changeset.num_changes());
|
||||
output_formatted(" comments_count=\"%" PRId32 "\"", changeset.num_comments());
|
||||
write_attribute("num_changes", changeset.num_changes());
|
||||
write_attribute("comments_count", changeset.num_comments());
|
||||
|
||||
// If there are no tags and no comments, we can close the
|
||||
// tag right here and are done.
|
||||
if (changeset.tags().empty() && changeset.num_comments() == 0) {
|
||||
if (changeset.tags().empty() && changeset.discussion().empty()) {
|
||||
*m_out += "/>\n";
|
||||
return;
|
||||
}
|
||||
@@ -375,8 +416,7 @@ namespace osmium {
|
||||
|
||||
write_tags(changeset.tags(), 0);
|
||||
|
||||
if (changeset.num_comments() > 0) {
|
||||
*m_out += " <discussion>\n";
|
||||
if (!changeset.discussion().empty()) {
|
||||
write_discussion(changeset.discussion());
|
||||
}
|
||||
|
||||
@@ -394,9 +434,10 @@ namespace osmium {
|
||||
XMLOutputFormat(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");
|
||||
m_options.use_change_ops = file.is_true("xml_change_format");
|
||||
m_options.add_visible_flag = (file.has_multiple_object_versions() || file.is_true("force_visible_flag")) && !m_options.use_change_ops;
|
||||
m_options.add_metadata = file.is_not_false("add_metadata");
|
||||
m_options.use_change_ops = file.is_true("xml_change_format");
|
||||
m_options.add_visible_flag = (file.has_multiple_object_versions() || file.is_true("force_visible_flag")) && !m_options.use_change_ops;
|
||||
m_options.locations_on_ways = file.is_true("locations_on_ways");
|
||||
}
|
||||
|
||||
XMLOutputFormat(const XMLOutputFormat&) = delete;
|
||||
@@ -425,10 +466,9 @@ namespace osmium {
|
||||
|
||||
for (const auto& box : header.boxes()) {
|
||||
out += " <bounds";
|
||||
append_printf_formatted_string(out, " minlon=\"%.7f\"", box.bottom_left().lon());
|
||||
append_printf_formatted_string(out, " minlat=\"%.7f\"", box.bottom_left().lat());
|
||||
append_printf_formatted_string(out, " maxlon=\"%.7f\"", box.top_right().lon());
|
||||
append_printf_formatted_string(out, " maxlat=\"%.7f\"/>\n", box.top_right().lat());
|
||||
detail::append_lat_lon_attributes(out, "minlat", "minlon", box.bottom_left());
|
||||
detail::append_lat_lon_attributes(out, "maxlat", "maxlon", box.top_right());
|
||||
out += "/>\n";
|
||||
}
|
||||
|
||||
send_to_output_queue(std::move(out));
|
||||
|
||||
+6
-6
@@ -33,12 +33,12 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <protozero/types.hpp>
|
||||
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace osmium {
|
||||
|
||||
std::string output(output_size, '\0');
|
||||
|
||||
auto result = ::compress(
|
||||
const auto result = ::compress(
|
||||
reinterpret_cast<unsigned char*>(const_cast<char *>(output.data())),
|
||||
&output_size,
|
||||
reinterpret_cast<const unsigned char*>(input.data()),
|
||||
@@ -89,10 +89,10 @@ namespace osmium {
|
||||
* @param output Uncompressed result data.
|
||||
* @returns Pointer and size to incompressed data.
|
||||
*/
|
||||
inline std::pair<const char*, size_t> zlib_uncompress_string(const char* input, unsigned long input_size, unsigned long raw_size, std::string& output) {
|
||||
inline protozero::data_view zlib_uncompress_string(const char* input, unsigned long input_size, unsigned long raw_size, std::string& output) {
|
||||
output.resize(raw_size);
|
||||
|
||||
auto result = ::uncompress(
|
||||
const auto result = ::uncompress(
|
||||
reinterpret_cast<unsigned char*>(&*output.begin()),
|
||||
&raw_size,
|
||||
reinterpret_cast<const unsigned char*>(input),
|
||||
@@ -103,7 +103,7 @@ namespace osmium {
|
||||
throw io_error(std::string("failed to uncompress data: ") + zError(result));
|
||||
}
|
||||
|
||||
return std::make_pair(output.data(), output.size());
|
||||
return protozero::data_view{output.data(), output.size()};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
+2
-4
@@ -34,7 +34,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -43,7 +42,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/file_format.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/util/options.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -115,7 +113,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
// if filename is a URL, default to XML format
|
||||
std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
|
||||
const std::string protocol = m_filename.substr(0, m_filename.find_first_of(':'));
|
||||
if (protocol == "http" || protocol == "https") {
|
||||
m_file_format = file_format::xml;
|
||||
}
|
||||
@@ -174,7 +172,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
for (auto& option : options) {
|
||||
size_t pos = option.find_first_of('=');
|
||||
const size_t pos = option.find_first_of('=');
|
||||
if (pos == std::string::npos) {
|
||||
set(option, true);
|
||||
} else {
|
||||
|
||||
@@ -42,15 +42,20 @@ DEALINGS IN THE SOFTWARE.
|
||||
* @attention If you include this file, you'll need to link with `libz`.
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
#include <osmium/io/error.hpp>
|
||||
#include <osmium/io/file_compression.hpp>
|
||||
#include <osmium/io/detail/read_write.hpp>
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
#include <osmium/util/cast.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
@@ -102,7 +107,7 @@ namespace osmium {
|
||||
|
||||
explicit GzipCompressor(int fd, fsync sync) :
|
||||
Compressor(sync),
|
||||
m_fd(dup(fd)),
|
||||
m_fd(::dup(fd)),
|
||||
m_gzfile(::gzdopen(fd, "w")) {
|
||||
if (!m_gzfile) {
|
||||
detail::throw_gzip_error(m_gzfile, "write initialization failed");
|
||||
@@ -171,6 +176,9 @@ namespace osmium {
|
||||
detail::throw_gzip_error(m_gzfile, "read failed");
|
||||
}
|
||||
buffer.resize(static_cast<std::string::size_type>(nread));
|
||||
#if ZLIB_VERNUM >= 0x1240
|
||||
set_offset(size_t(::gzoffset(m_gzfile)));
|
||||
#endif
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
+10
-11
@@ -41,7 +41,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -57,7 +56,7 @@ namespace osmium {
|
||||
|
||||
static_assert(std::is_base_of<osmium::memory::Item, TItem>::value, "TItem must derive from osmium::buffer::Item");
|
||||
|
||||
typedef typename osmium::memory::Buffer::t_iterator<TItem> item_iterator;
|
||||
using item_iterator = typename osmium::memory::Buffer::t_iterator<TItem>;
|
||||
|
||||
TSource* m_source;
|
||||
std::shared_ptr<osmium::memory::Buffer> m_buffer;
|
||||
@@ -69,20 +68,20 @@ namespace osmium {
|
||||
if (!m_buffer || !*m_buffer) { // end of input
|
||||
m_source = nullptr;
|
||||
m_buffer.reset();
|
||||
m_iter = item_iterator();
|
||||
m_iter = item_iterator{};
|
||||
return;
|
||||
}
|
||||
m_iter = m_buffer->begin<TItem>();
|
||||
} while (m_iter == m_buffer->end<TItem>());
|
||||
m_iter = m_buffer->select<TItem>().begin();
|
||||
} while (m_iter == m_buffer->select<TItem>().end());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef TItem value_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef TItem* pointer;
|
||||
typedef TItem& reference;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = TItem;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
explicit InputIterator(TSource& source) :
|
||||
m_source(&source) {
|
||||
@@ -99,7 +98,7 @@ namespace osmium {
|
||||
assert(m_buffer);
|
||||
assert(m_iter);
|
||||
++m_iter;
|
||||
if (m_iter == m_buffer->end<TItem>()) {
|
||||
if (m_iter == m_buffer->select<TItem>().end()) {
|
||||
update_buffer();
|
||||
}
|
||||
return *this;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef OSMIUM_IO_OPL_INPUT_HPP
|
||||
#define OSMIUM_IO_OPL_INPUT_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.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Include this file if you want to read OSM OPL files.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmium/io/reader.hpp> // IWYU pragma: export
|
||||
#include <osmium/io/detail/opl_input_format.hpp> // IWYU pragma: export
|
||||
|
||||
#endif // OSMIUM_IO_OPL_INPUT_HPP
|
||||
@@ -35,10 +35,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/diff_object.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
@@ -51,12 +48,18 @@ namespace osmium {
|
||||
namespace io {
|
||||
|
||||
template <typename TDest>
|
||||
class OutputIterator : public std::iterator<std::output_iterator_tag, osmium::memory::Item> {
|
||||
class OutputIterator {
|
||||
|
||||
TDest* m_destination;
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::output_iterator_tag;
|
||||
using value_type = void;
|
||||
using difference_type = void;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
explicit OutputIterator(TDest& destination) :
|
||||
m_destination(&destination) {
|
||||
}
|
||||
|
||||
+1
-1
@@ -34,6 +34,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma message("Including overwrite.hpp is deprecated, #include <osmium/io/writer_options.hpp> instead.")
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
#include <osmium/io/writer_options.hpp> // IWYU pragma: keep
|
||||
|
||||
#endif // OSMIUM_IO_OVERWRITE_HPP
|
||||
|
||||
+51
-10
@@ -62,11 +62,26 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/osm/entity_bits.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/config.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline size_t get_input_queue_size() noexcept {
|
||||
const size_t n = osmium::config::get_max_queue_size("INPUT", 20);
|
||||
return n > 2 ? n : 2;
|
||||
}
|
||||
|
||||
inline size_t get_osmdata_queue_size() noexcept {
|
||||
const size_t n = osmium::config::get_max_queue_size("OSMDATA", 20);
|
||||
return n > 2 ? n : 2;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* This is the user-facing interface for reading OSM files. Instantiate
|
||||
* an object of this class with a file name or osmium::io::File object
|
||||
@@ -75,9 +90,6 @@ namespace osmium {
|
||||
*/
|
||||
class Reader {
|
||||
|
||||
static constexpr size_t max_input_queue_size = 20; // XXX
|
||||
static constexpr size_t max_osmdata_queue_size = 20; // XXX
|
||||
|
||||
osmium::io::File m_file;
|
||||
osmium::osm_entity_bits::type m_read_which_entities;
|
||||
|
||||
@@ -104,6 +116,8 @@ namespace osmium {
|
||||
|
||||
osmium::thread::thread_handler m_thread;
|
||||
|
||||
size_t m_file_size;
|
||||
|
||||
// This function will run in a separate thread.
|
||||
static void parser_thread(const osmium::io::File& file,
|
||||
detail::future_string_queue_type& input_queue,
|
||||
@@ -111,8 +125,8 @@ namespace osmium {
|
||||
std::promise<osmium::io::Header>&& header_promise,
|
||||
osmium::osm_entity_bits::type read_which_entities) {
|
||||
std::promise<osmium::io::Header> promise = std::move(header_promise);
|
||||
auto creator = detail::ParserFactory::instance().get_creator_function(file);
|
||||
auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
|
||||
const auto creator = detail::ParserFactory::instance().get_creator_function(file);
|
||||
const auto parser = creator(input_queue, osmdata_queue, promise, read_which_entities);
|
||||
parser->parse();
|
||||
}
|
||||
|
||||
@@ -133,7 +147,7 @@ namespace osmium {
|
||||
if (pipe(pipefd) < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "opening pipe failed");
|
||||
}
|
||||
pid_t pid = fork();
|
||||
const pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
throw std::system_error(errno, std::system_category(), "fork failed");
|
||||
}
|
||||
@@ -202,16 +216,17 @@ namespace osmium {
|
||||
m_read_which_entities(read_which_entities),
|
||||
m_status(status::okay),
|
||||
m_childpid(0),
|
||||
m_input_queue(max_input_queue_size, "raw_input"),
|
||||
m_input_queue(detail::get_input_queue_size(), "raw_input"),
|
||||
m_decompressor(m_file.buffer() ?
|
||||
osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), m_file.buffer(), m_file.buffer_size()) :
|
||||
osmium::io::CompressionFactory::instance().create_decompressor(file.compression(), open_input_file_or_url(m_file.filename(), &m_childpid))),
|
||||
m_read_thread_manager(*m_decompressor, m_input_queue),
|
||||
m_osmdata_queue(max_osmdata_queue_size, "parser_results"),
|
||||
m_osmdata_queue(detail::get_osmdata_queue_size(), "parser_results"),
|
||||
m_osmdata_queue_wrapper(m_osmdata_queue),
|
||||
m_header_future(),
|
||||
m_header(),
|
||||
m_thread() {
|
||||
m_thread(),
|
||||
m_file_size(m_decompressor->file_size()) {
|
||||
std::promise<osmium::io::Header> header_promise;
|
||||
m_header_future = header_promise.get_future();
|
||||
m_thread = osmium::thread::thread_handler{parser_thread, std::ref(m_file), std::ref(m_input_queue), std::ref(m_osmdata_queue), std::move(header_promise), read_which_entities};
|
||||
@@ -263,7 +278,7 @@ namespace osmium {
|
||||
#ifndef _WIN32
|
||||
if (m_childpid) {
|
||||
int status;
|
||||
pid_t pid = ::waitpid(m_childpid, &status, 0);
|
||||
const pid_t pid = ::waitpid(m_childpid, &status, 0);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
if (pid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
@@ -350,6 +365,32 @@ namespace osmium {
|
||||
return m_status == status::eof || m_status == status::closed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the input file. Returns 0 if the file size
|
||||
* is not available (for instance when reading from stdin).
|
||||
*/
|
||||
size_t file_size() const noexcept {
|
||||
return m_file_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current offset into the input file. Returns 0 if
|
||||
* the offset is not available (for instance when reading from
|
||||
* stdin).
|
||||
*
|
||||
* The offset can be used together with the result of file_size()
|
||||
* to estimate how much of the file has been read. Note that due
|
||||
* to buffering inside Osmium, this value will be larger than
|
||||
* the amount of data actually available to the application.
|
||||
*
|
||||
* Do not call this function too often, certainly not for every
|
||||
* object you are reading. Depending on the file type it might
|
||||
* do an expensive system call.
|
||||
*/
|
||||
size_t offset() const noexcept {
|
||||
return m_decompressor->offset();
|
||||
}
|
||||
|
||||
}; // class Reader
|
||||
|
||||
/**
|
||||
|
||||
+20
-4
@@ -34,11 +34,13 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/io/compression.hpp>
|
||||
@@ -52,11 +54,25 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/io/writer_options.hpp>
|
||||
#include <osmium/memory/buffer.hpp>
|
||||
#include <osmium/thread/util.hpp>
|
||||
#include <osmium/util/config.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace memory {
|
||||
class Item;
|
||||
} //namespace memory
|
||||
|
||||
namespace io {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline size_t get_output_queue_size() noexcept {
|
||||
size_t n = osmium::config::get_max_queue_size("OUTPUT", 20);
|
||||
return n > 2 ? n : 2;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* This is the user-facing interface for writing OSM files. Instantiate
|
||||
* an object of this class with a file name or osmium::io::File object
|
||||
@@ -194,7 +210,7 @@ namespace osmium {
|
||||
template <typename... TArgs>
|
||||
explicit Writer(const osmium::io::File& file, TArgs&&... args) :
|
||||
m_file(file.check()),
|
||||
m_output_queue(20, "raw_output"), // XXX
|
||||
m_output_queue(detail::get_output_queue_size(), "raw_output"),
|
||||
m_output(osmium::io::detail::OutputFormatFactory::instance().create_output(m_file, m_output_queue)),
|
||||
m_buffer(),
|
||||
m_buffer_size(default_buffer_size),
|
||||
@@ -304,7 +320,7 @@ namespace osmium {
|
||||
}
|
||||
try {
|
||||
m_buffer.push_back(item);
|
||||
} catch (osmium::buffer_is_full&) {
|
||||
} catch (const osmium::buffer_is_full&) {
|
||||
do_flush();
|
||||
m_buffer.push_back(item);
|
||||
}
|
||||
|
||||
@@ -517,6 +517,16 @@ namespace osmium {
|
||||
*/
|
||||
using const_iterator = t_const_iterator<osmium::OSMEntity>;
|
||||
|
||||
template <typename T>
|
||||
ItemIteratorRange<T> select() {
|
||||
return ItemIteratorRange<T>{m_data, m_data + m_committed};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ItemIteratorRange<const T> select() const {
|
||||
return ItemIteratorRange<const T>{m_data, m_data + m_committed};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get iterator for iterating over all items of type T in the
|
||||
* buffer.
|
||||
|
||||
+11
-5
@@ -44,17 +44,23 @@ namespace osmium {
|
||||
namespace memory {
|
||||
|
||||
template <typename TMember>
|
||||
class CollectionIterator : public std::iterator<std::forward_iterator_tag, TMember> {
|
||||
class CollectionIterator {
|
||||
|
||||
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending
|
||||
// on whether TMember is const. This allows this class to be used as an iterator and
|
||||
// as a const_iterator.
|
||||
typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
|
||||
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
|
||||
|
||||
data_type m_data;
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = TMember;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
CollectionIterator() noexcept :
|
||||
m_data(nullptr) {
|
||||
}
|
||||
@@ -112,9 +118,9 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef CollectionIterator<TMember> iterator;
|
||||
typedef CollectionIterator<const TMember> const_iterator;
|
||||
typedef TMember value_type;
|
||||
using iterator = CollectionIterator<TMember>;
|
||||
using const_iterator = CollectionIterator<const TMember>;
|
||||
using value_type = TMember;
|
||||
|
||||
static constexpr osmium::item_type itemtype = TCollectionItemType;
|
||||
|
||||
|
||||
+29
-7
@@ -33,8 +33,10 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/util/cast.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -45,16 +47,21 @@ namespace osmium {
|
||||
class Builder;
|
||||
} // namespace builder
|
||||
|
||||
enum class diff_indicator_type {
|
||||
none = 0,
|
||||
left = 1,
|
||||
right = 2,
|
||||
both = 3
|
||||
}; // diff_indicator_type
|
||||
|
||||
namespace memory {
|
||||
|
||||
typedef uint32_t item_size_type;
|
||||
using item_size_type = uint32_t;
|
||||
|
||||
// align datastructures to this many bytes
|
||||
constexpr item_size_type align_bytes = 8;
|
||||
|
||||
template <typename T>
|
||||
inline T padded_length(T length) noexcept {
|
||||
static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, "Template parameter must be unsigned integral type");
|
||||
inline std::size_t padded_length(std::size_t length) noexcept {
|
||||
return (length + align_bytes - 1) & ~(align_bytes - 1);
|
||||
}
|
||||
|
||||
@@ -100,7 +107,8 @@ namespace osmium {
|
||||
item_size_type m_size;
|
||||
item_type m_type;
|
||||
uint16_t m_removed : 1;
|
||||
uint16_t m_padding : 15;
|
||||
uint16_t m_diff : 2;
|
||||
uint16_t m_padding : 13;
|
||||
|
||||
template <typename TMember>
|
||||
friend class CollectionIterator;
|
||||
@@ -121,6 +129,7 @@ namespace osmium {
|
||||
m_size(size),
|
||||
m_type(type),
|
||||
m_removed(false),
|
||||
m_diff(0),
|
||||
m_padding(0) {
|
||||
}
|
||||
|
||||
@@ -150,7 +159,7 @@ namespace osmium {
|
||||
}
|
||||
|
||||
item_size_type padded_size() const {
|
||||
return padded_length(m_size);
|
||||
return static_cast_with_assert<item_size_type>(padded_length(m_size));
|
||||
}
|
||||
|
||||
item_type type() const noexcept {
|
||||
@@ -165,6 +174,19 @@ namespace osmium {
|
||||
m_removed = removed;
|
||||
}
|
||||
|
||||
diff_indicator_type diff() const noexcept {
|
||||
return diff_indicator_type(m_diff);
|
||||
}
|
||||
|
||||
char diff_as_char() const noexcept {
|
||||
static constexpr const char* diff_chars = "*-+ ";
|
||||
return diff_chars[m_diff];
|
||||
}
|
||||
|
||||
void set_diff(diff_indicator_type diff) noexcept {
|
||||
m_diff = uint16_t(diff);
|
||||
}
|
||||
|
||||
}; // class Item
|
||||
|
||||
static_assert(sizeof(Item) == 8, "Class osmium::Item has wrong size!");
|
||||
|
||||
+110
-15
@@ -34,16 +34,29 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <iosfwd>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/fwd.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Area;
|
||||
class Changeset;
|
||||
class InnerRing;
|
||||
class Node;
|
||||
class OSMEntity;
|
||||
class OSMObject;
|
||||
class OuterRing;
|
||||
class Relation;
|
||||
class RelationMemberList;
|
||||
class TagList;
|
||||
class Way;
|
||||
class WayNodeList;
|
||||
|
||||
namespace memory {
|
||||
|
||||
namespace detail {
|
||||
@@ -116,19 +129,19 @@ namespace osmium {
|
||||
} // namespace detail
|
||||
|
||||
template <typename TMember>
|
||||
class ItemIterator : public std::iterator<std::forward_iterator_tag, TMember> {
|
||||
class ItemIterator {
|
||||
|
||||
static_assert(std::is_base_of<osmium::memory::Item, TMember>::value, "TMember must derive from osmium::memory::Item");
|
||||
|
||||
// This data_type is either 'unsigned char*' or 'const unsigned char*' depending
|
||||
// on whether TMember is const. This allows this class to be used as an iterator and
|
||||
// as a const_iterator.
|
||||
typedef typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type data_type;
|
||||
using data_type = typename std::conditional<std::is_const<TMember>::value, const unsigned char*, unsigned char*>::type;
|
||||
|
||||
data_type m_data;
|
||||
data_type m_end;
|
||||
|
||||
void advance_to_next_item_of_right_type() {
|
||||
void advance_to_next_item_of_right_type() noexcept {
|
||||
while (m_data != m_end &&
|
||||
!detail::type_is_compatible<typename std::remove_const<TMember>::type>(reinterpret_cast<const osmium::memory::Item*>(m_data)->type())) {
|
||||
m_data = reinterpret_cast<TMember*>(m_data)->next();
|
||||
@@ -137,23 +150,29 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = TMember;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
ItemIterator() noexcept :
|
||||
m_data(nullptr),
|
||||
m_end(nullptr) {
|
||||
}
|
||||
|
||||
ItemIterator(data_type data, data_type end) :
|
||||
ItemIterator(data_type data, data_type end) noexcept :
|
||||
m_data(data),
|
||||
m_end(end) {
|
||||
advance_to_next_item_of_right_type();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ItemIterator<T> cast() const {
|
||||
ItemIterator<T> cast() const noexcept {
|
||||
return ItemIterator<T>(m_data, m_end);
|
||||
}
|
||||
|
||||
ItemIterator<TMember>& operator++() {
|
||||
ItemIterator<TMember>& operator++() noexcept {
|
||||
assert(m_data);
|
||||
assert(m_data != m_end);
|
||||
m_data = reinterpret_cast<TMember*>(m_data)->next();
|
||||
@@ -166,45 +185,50 @@ namespace osmium {
|
||||
* types. Do not use this unless you know what you are
|
||||
* doing.
|
||||
*/
|
||||
ItemIterator<TMember>& advance_once() {
|
||||
ItemIterator<TMember>& advance_once() noexcept {
|
||||
assert(m_data);
|
||||
assert(m_data != m_end);
|
||||
m_data = reinterpret_cast<TMember*>(m_data)->next();
|
||||
return *static_cast<ItemIterator<TMember>*>(this);
|
||||
}
|
||||
|
||||
ItemIterator<TMember> operator++(int) {
|
||||
ItemIterator<TMember> operator++(int) noexcept {
|
||||
ItemIterator<TMember> tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(const ItemIterator<TMember>& rhs) const {
|
||||
bool operator==(const ItemIterator<TMember>& rhs) const noexcept {
|
||||
return m_data == rhs.m_data && m_end == rhs.m_end;
|
||||
}
|
||||
|
||||
bool operator!=(const ItemIterator<TMember>& rhs) const {
|
||||
bool operator!=(const ItemIterator<TMember>& rhs) const noexcept {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
unsigned char* data() const {
|
||||
data_type data() noexcept {
|
||||
assert(m_data);
|
||||
return m_data;
|
||||
}
|
||||
|
||||
TMember& operator*() const {
|
||||
const unsigned char* data() const noexcept {
|
||||
assert(m_data);
|
||||
return m_data;
|
||||
}
|
||||
|
||||
TMember& operator*() const noexcept {
|
||||
assert(m_data);
|
||||
assert(m_data != m_end);
|
||||
return *reinterpret_cast<TMember*>(m_data);
|
||||
}
|
||||
|
||||
TMember* operator->() const {
|
||||
TMember* operator->() const noexcept {
|
||||
assert(m_data);
|
||||
assert(m_data != m_end);
|
||||
return reinterpret_cast<TMember*>(m_data);
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
explicit operator bool() const noexcept {
|
||||
return (m_data != nullptr) && (m_data != m_end);
|
||||
}
|
||||
|
||||
@@ -221,6 +245,77 @@ namespace osmium {
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ItemIteratorRange {
|
||||
|
||||
static_assert(std::is_base_of<osmium::memory::Item, T>::value, "Template parameter must derive from osmium::memory::Item");
|
||||
|
||||
// This data_type is either 'unsigned char*' or
|
||||
// 'const unsigned char*' depending on whether T is const.
|
||||
using data_type = typename std::conditional<std::is_const<T>::value, const unsigned char*, unsigned char*>::type;
|
||||
|
||||
data_type m_begin;
|
||||
data_type m_end;
|
||||
|
||||
public:
|
||||
|
||||
using iterator = ItemIterator<T>;
|
||||
using const_iterator = ItemIterator<const T>;
|
||||
|
||||
ItemIteratorRange(data_type first, data_type last) noexcept :
|
||||
m_begin(first),
|
||||
m_end(last) {
|
||||
}
|
||||
|
||||
iterator begin() noexcept {
|
||||
return iterator{m_begin, m_end};
|
||||
}
|
||||
|
||||
iterator end() noexcept {
|
||||
return iterator{m_end, m_end};
|
||||
}
|
||||
|
||||
const_iterator cbegin() const noexcept {
|
||||
return const_iterator{m_begin, m_end};
|
||||
}
|
||||
|
||||
const_iterator cend() const noexcept {
|
||||
return const_iterator{m_end, m_end};
|
||||
}
|
||||
|
||||
const_iterator begin() const noexcept {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const noexcept {
|
||||
return cend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of items in this range.
|
||||
*
|
||||
* Note that this methods has worst-case complexity O(n) with n
|
||||
* being the number of items in the underlying range.
|
||||
*/
|
||||
size_t size() const {
|
||||
if (m_begin == m_end) {
|
||||
return 0;
|
||||
}
|
||||
return std::distance(cbegin(), cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this range empty?
|
||||
*
|
||||
* Note that this methods has worst-case complexity O(n) with n
|
||||
* being the number of items in the underlying range.
|
||||
*/
|
||||
bool empty() const {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
}; // class ItemIteratorRange
|
||||
|
||||
} // namespace memory
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
@@ -40,11 +40,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <boost/iterator/indirect_iterator.hpp>
|
||||
|
||||
#include <osmium/handler.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
|
||||
// IWYU pragma: no_forward_declare osmium::OSMObject
|
||||
// IWYU pragma: no_forward_declare osmium::memory::Item
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -70,8 +68,8 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject> iterator;
|
||||
typedef boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject> const_iterator;
|
||||
using iterator = boost::indirect_iterator<std::vector<osmium::OSMObject*>::iterator, osmium::OSMObject>;
|
||||
using const_iterator = boost::indirect_iterator<std::vector<osmium::OSMObject*>::const_iterator, const osmium::OSMObject>;
|
||||
|
||||
ObjectPointerCollection() noexcept :
|
||||
m_objects() {
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
#ifndef OSMIUM_OPL_HPP
|
||||
#define OSMIUM_OPL_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 <osmium/memory/buffer.hpp>
|
||||
#include <osmium/io/detail/opl_parser_functions.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* Parses one line in OPL format. The line must not have a newline
|
||||
* character at the end. Buffer.commit() is called automatically if the
|
||||
* write succeeded.
|
||||
*
|
||||
* @param data Line must be in this zero-delimited string.
|
||||
* @param buffer Result will be written to this buffer.
|
||||
*
|
||||
* @returns true if an entity was parsed, false otherwise (for instance
|
||||
* when the line is empty).
|
||||
* @throws osmium::opl_error If the parsing fails.
|
||||
*/
|
||||
inline bool opl_parse(const char* data, osmium::memory::Buffer& buffer) {
|
||||
try {
|
||||
const bool wrote_something = osmium::io::detail::opl_parse_line(0, data, buffer);
|
||||
buffer.commit();
|
||||
return wrote_something;
|
||||
} catch (const osmium::opl_error&) {
|
||||
buffer.rollback();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
|
||||
#endif // OSMIUM_OPL_HPP
|
||||
+12
-3
@@ -33,11 +33,20 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <osmium/osm/node.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/way.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/relation.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/area.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/changeset.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/entity.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/entity_bits.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/item_type.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/location.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/node.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/node_ref.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/node_ref_list.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/object.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/relation.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/timestamp.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/types.hpp> // IWYU pragma: export
|
||||
#include <osmium/osm/way.hpp> // IWYU pragma: export
|
||||
|
||||
/**
|
||||
* @brief Namespace for everything in the Osmium library.
|
||||
|
||||
+31
-4
@@ -35,14 +35,17 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/memory/item_iterator.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/node_ref_list.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -144,8 +147,8 @@ namespace osmium {
|
||||
*
|
||||
* @returns Pair (number outer rings, number inner rings)
|
||||
*/
|
||||
std::pair<int, int> num_rings() const {
|
||||
std::pair<int, int> counter { 0, 0 };
|
||||
std::pair<size_t, size_t> num_rings() const {
|
||||
std::pair<size_t, size_t> counter { 0, 0 };
|
||||
|
||||
for (auto it = cbegin(); it != cend(); ++it) {
|
||||
switch (it->type()) {
|
||||
@@ -185,27 +188,51 @@ namespace osmium {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use inner_rings() instead.
|
||||
*
|
||||
* Get iterator for iterating over all inner rings in a specified outer
|
||||
* ring.
|
||||
*
|
||||
* @param it Iterator specifying outer ring.
|
||||
* @returns Iterator to first inner ring in specified outer ring.
|
||||
*/
|
||||
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
|
||||
OSMIUM_DEPRECATED osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cbegin(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
|
||||
return it.cast<const osmium::InnerRing>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use inner_rings() instead.
|
||||
*
|
||||
* Get iterator for iterating over all inner rings in a specified outer
|
||||
* ring.
|
||||
*
|
||||
* @param it Iterator specifying outer ring.
|
||||
* @returns Iterator one past last inner ring in specified outer ring.
|
||||
*/
|
||||
osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
|
||||
OSMIUM_DEPRECATED osmium::memory::ItemIterator<const osmium::InnerRing> inner_ring_cend(const osmium::memory::ItemIterator<const osmium::OuterRing>& it) const {
|
||||
return std::next(it).cast<const osmium::InnerRing>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator range for all outer rings.
|
||||
* You can use the usual begin() and end() functions to iterate over
|
||||
* all outer rings.
|
||||
*/
|
||||
osmium::memory::ItemIteratorRange<const osmium::OuterRing> outer_rings() const {
|
||||
return subitems<const osmium::OuterRing>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an iterator range for all inner rings in the given outer
|
||||
* ring.
|
||||
* You can use the usual begin() and end() functions to iterate over
|
||||
* all outer rings.
|
||||
*/
|
||||
osmium::memory::ItemIteratorRange<const osmium::InnerRing> inner_rings(const osmium::OuterRing& outer) const {
|
||||
osmium::memory::ItemIteratorRange<const osmium::OuterRing> outer_range{outer.data(), next()};
|
||||
return osmium::memory::ItemIteratorRange<const osmium::InnerRing>{outer_range.cbegin().data(), std::next(outer_range.cbegin()).data()};
|
||||
}
|
||||
|
||||
}; // class Area
|
||||
|
||||
static_assert(sizeof(Area) % osmium::memory::align_bytes == 0, "Class osmium::Area has wrong size to be aligned properly!");
|
||||
|
||||
@@ -36,7 +36,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <cassert>
|
||||
#include <iosfwd>
|
||||
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
+16
-9
@@ -33,7 +33,9 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
@@ -131,7 +133,7 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef size_t size_type;
|
||||
using size_type = size_t;
|
||||
|
||||
ChangesetDiscussion() :
|
||||
osmium::memory::Collection<ChangesetComment, osmium::item_type::changeset_discussion>() {
|
||||
@@ -185,6 +187,11 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
// Dummy to avoid warning because of unused private fields. Do not use.
|
||||
int32_t do_not_use() const noexcept {
|
||||
return m_padding1 + m_padding2;
|
||||
}
|
||||
|
||||
/// Get ID of this changeset
|
||||
changeset_id_type id() const noexcept {
|
||||
return m_id;
|
||||
@@ -369,23 +376,23 @@ namespace osmium {
|
||||
* @param value Value of the attribute
|
||||
*/
|
||||
void set_attribute(const char* attr, const char* value) {
|
||||
if (!strcmp(attr, "id")) {
|
||||
if (!std::strcmp(attr, "id")) {
|
||||
set_id(value);
|
||||
} else if (!strcmp(attr, "num_changes")) {
|
||||
} else if (!std::strcmp(attr, "num_changes")) {
|
||||
set_num_changes(value);
|
||||
} else if (!strcmp(attr, "comments_count")) {
|
||||
} else if (!std::strcmp(attr, "comments_count")) {
|
||||
set_num_comments(value);
|
||||
} else if (!strcmp(attr, "created_at")) {
|
||||
} else if (!std::strcmp(attr, "created_at")) {
|
||||
set_created_at(osmium::Timestamp(value));
|
||||
} else if (!strcmp(attr, "closed_at")) {
|
||||
} else if (!std::strcmp(attr, "closed_at")) {
|
||||
set_closed_at(osmium::Timestamp(value));
|
||||
} else if (!strcmp(attr, "uid")) {
|
||||
} else if (!std::strcmp(attr, "uid")) {
|
||||
set_uid(value);
|
||||
}
|
||||
}
|
||||
|
||||
typedef osmium::memory::CollectionIterator<Item> iterator;
|
||||
typedef osmium::memory::CollectionIterator<const Item> const_iterator;
|
||||
using iterator = osmium::memory::CollectionIterator<Item>;
|
||||
using const_iterator = osmium::memory::CollectionIterator<const Item>;
|
||||
|
||||
iterator begin() {
|
||||
return iterator(subitems_position());
|
||||
|
||||
+18
-11
@@ -36,11 +36,17 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <cstdint>
|
||||
|
||||
#include <osmium/osm/area.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/node_ref.hpp>
|
||||
#include <osmium/osm/node_ref_list.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/util/endian.hpp>
|
||||
|
||||
@@ -71,8 +77,8 @@ namespace osmium {
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_bswap64(value);
|
||||
# else
|
||||
uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
|
||||
uint64_t val2 = byte_swap_32(value >> 32);
|
||||
const uint64_t val1 = byte_swap_32(value & 0xFFFFFFFF);
|
||||
const uint64_t val2 = byte_swap_32(value >> 32);
|
||||
return (val1 << 32) | val2;
|
||||
# endif
|
||||
}
|
||||
@@ -86,11 +92,11 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
TCRC& operator()() {
|
||||
TCRC& operator()() noexcept {
|
||||
return m_crc;
|
||||
}
|
||||
|
||||
const TCRC& operator()() const {
|
||||
const TCRC& operator()() const noexcept {
|
||||
return m_crc;
|
||||
}
|
||||
|
||||
@@ -106,7 +112,7 @@ namespace osmium {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
m_crc.process_bytes(&value, sizeof(uint16_t));
|
||||
#else
|
||||
uint16_t v = osmium::util::byte_swap_16(value);
|
||||
const uint16_t v = osmium::util::byte_swap_16(value);
|
||||
m_crc.process_bytes(&v, sizeof(uint16_t));
|
||||
#endif
|
||||
}
|
||||
@@ -115,7 +121,7 @@ namespace osmium {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
m_crc.process_bytes(&value, sizeof(uint32_t));
|
||||
#else
|
||||
uint32_t v = osmium::util::byte_swap_32(value);
|
||||
const uint32_t v = osmium::util::byte_swap_32(value);
|
||||
m_crc.process_bytes(&v, sizeof(uint32_t));
|
||||
#endif
|
||||
}
|
||||
@@ -124,7 +130,7 @@ namespace osmium {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
m_crc.process_bytes(&value, sizeof(uint64_t));
|
||||
#else
|
||||
uint64_t v = osmium::util::byte_swap_64(value);
|
||||
const uint64_t v = osmium::util::byte_swap_64(value);
|
||||
m_crc.process_bytes(&v, sizeof(uint64_t));
|
||||
#endif
|
||||
}
|
||||
@@ -151,6 +157,7 @@ namespace osmium {
|
||||
|
||||
void update(const NodeRef& node_ref) {
|
||||
update_int64(node_ref.ref());
|
||||
update(node_ref.location());
|
||||
}
|
||||
|
||||
void update(const NodeRefList& node_refs) {
|
||||
@@ -205,10 +212,10 @@ namespace osmium {
|
||||
|
||||
void update(const osmium::Area& area) {
|
||||
update(static_cast<const osmium::OSMObject&>(area));
|
||||
for (auto it = area.cbegin(); it != area.cend(); ++it) {
|
||||
if (it->type() == osmium::item_type::outer_ring ||
|
||||
it->type() == osmium::item_type::inner_ring) {
|
||||
update(static_cast<const osmium::NodeRefList&>(*it));
|
||||
for (const auto& subitem : area) {
|
||||
if (subitem.type() == osmium::item_type::outer_ring ||
|
||||
subitem.type() == osmium::item_type::inner_ring) {
|
||||
update(static_cast<const osmium::NodeRefList&>(subitem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <osmium/fwd.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
@@ -43,6 +42,10 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
namespace osmium {
|
||||
|
||||
class Node;
|
||||
class Way;
|
||||
class Relation;
|
||||
|
||||
/**
|
||||
* A DiffObject holds pointers to three OSMObjects, the current object,
|
||||
* the previous, and the next. They always have the same type (Node, Way,
|
||||
|
||||
+16
-2
@@ -33,12 +33,15 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* @brief Bitfield for OSM entity types.
|
||||
* @brief Bit field for OSM entity types.
|
||||
*/
|
||||
namespace osm_entity_bits {
|
||||
|
||||
@@ -94,8 +97,19 @@ namespace osmium {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get entity_bits from item_type.
|
||||
*
|
||||
* @pre item_type must be undefined, node, way, relation, area, or
|
||||
* changeset.
|
||||
*/
|
||||
inline type from_item_type(osmium::item_type item_type) noexcept {
|
||||
return static_cast<osmium::osm_entity_bits::type>(0x1 << (static_cast<uint16_t>(item_type) - 1));
|
||||
auto ut = static_cast<std::underlying_type<osmium::item_type>::type>(item_type);
|
||||
assert(ut <= 0x05);
|
||||
if (ut == 0) {
|
||||
return nothing;
|
||||
}
|
||||
return static_cast<osmium::osm_entity_bits::type>(0x1 << (ut - 1));
|
||||
}
|
||||
|
||||
} // namespace osm_entity_bits
|
||||
|
||||
+267
-17
@@ -35,15 +35,14 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
#include <osmium/util/double.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
@@ -62,6 +61,184 @@ namespace osmium {
|
||||
|
||||
}; // struct invalid_location
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr const int coordinate_precision = 10000000;
|
||||
|
||||
// Convert string with a floating point number into integer suitable
|
||||
// for use as coordinate in a Location.
|
||||
inline int32_t string_to_location_coordinate(const char** data) {
|
||||
const char* str = *data;
|
||||
const char* full = str;
|
||||
|
||||
int64_t result = 0;
|
||||
int sign = 1;
|
||||
|
||||
// one more than significant digits to allow rounding
|
||||
int64_t scale = 8;
|
||||
|
||||
// paranoia check for maximum number of digits
|
||||
int max_digits = 10;
|
||||
|
||||
// optional minus sign
|
||||
if (*str == '-') {
|
||||
sign = -1;
|
||||
++str;
|
||||
}
|
||||
|
||||
// there has to be at least one digit
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
result = *str - '0';
|
||||
++str;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// optional additional digits before decimal point
|
||||
while (*str >= '0' && *str <= '9' && max_digits > 0) {
|
||||
result = result * 10 + (*str - '0');
|
||||
++str;
|
||||
--max_digits;
|
||||
}
|
||||
|
||||
if (max_digits == 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// optional decimal point
|
||||
if (*str == '.') {
|
||||
++str;
|
||||
|
||||
// read significant digits
|
||||
for (; scale > 0 && *str >= '0' && *str <= '9'; --scale, ++str) {
|
||||
result = result * 10 + (*str - '0');
|
||||
}
|
||||
|
||||
// ignore non-significant digits
|
||||
max_digits = 20;
|
||||
while (*str >= '0' && *str <= '9' && max_digits > 0) {
|
||||
++str;
|
||||
--max_digits;
|
||||
}
|
||||
|
||||
if (max_digits == 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// optional exponent in scientific notation
|
||||
if (*str == 'e' || *str == 'E') {
|
||||
++str;
|
||||
|
||||
int esign = 1;
|
||||
// optional minus sign
|
||||
if (*str == '-') {
|
||||
esign = -1;
|
||||
++str;
|
||||
}
|
||||
|
||||
int64_t eresult = 0;
|
||||
|
||||
// there has to be at least one digit in exponent
|
||||
if (*str >= '0' && *str <= '9') {
|
||||
eresult = *str - '0';
|
||||
++str;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// optional additional digits in exponent
|
||||
max_digits = 5;
|
||||
while (*str >= '0' && *str <= '9' && max_digits > 0) {
|
||||
eresult = eresult * 10 + (*str - '0');
|
||||
++str;
|
||||
--max_digits;
|
||||
}
|
||||
|
||||
if (max_digits == 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
scale += eresult * esign;
|
||||
}
|
||||
|
||||
if (scale < 0) {
|
||||
result = 0;
|
||||
} else {
|
||||
for (; scale > 0; --scale) {
|
||||
result *= 10;
|
||||
}
|
||||
|
||||
result = (result + 5) / 10 * sign;
|
||||
|
||||
if (result > std::numeric_limits<int32_t>::max() ||
|
||||
result < std::numeric_limits<int32_t>::min()) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
*data = str;
|
||||
return static_cast<int32_t>(result);
|
||||
|
||||
error:
|
||||
|
||||
throw invalid_location{std::string{"wrong format for coordinate: '"} + full + "'"};
|
||||
}
|
||||
|
||||
// Convert integer as used by location for coordinates into a string.
|
||||
template <typename T>
|
||||
inline T append_location_coordinate_to_string(T iterator, int32_t value) {
|
||||
// handle negative values
|
||||
if (value < 0) {
|
||||
*iterator++ = '-';
|
||||
value = -value;
|
||||
}
|
||||
|
||||
// write digits into temporary buffer
|
||||
int32_t v = value;
|
||||
char temp[10];
|
||||
char* t = temp;
|
||||
do {
|
||||
*t++ = char(v % 10) + '0';
|
||||
v /= 10;
|
||||
} while (v != 0);
|
||||
|
||||
while (t-temp < 7) {
|
||||
*t++ = '0';
|
||||
}
|
||||
|
||||
// write out digits before decimal point
|
||||
if (value >= coordinate_precision) {
|
||||
if (value >= 10 * coordinate_precision) {
|
||||
if (value >= 100 * coordinate_precision) {
|
||||
*iterator++ = *--t;
|
||||
}
|
||||
*iterator++ = *--t;
|
||||
}
|
||||
*iterator++ = *--t;
|
||||
} else {
|
||||
*iterator++ = '0';
|
||||
}
|
||||
|
||||
// remove trailing zeros
|
||||
const char* tn = temp;
|
||||
while (tn < t && *tn == '0') {
|
||||
++tn;
|
||||
}
|
||||
|
||||
// decimal point
|
||||
if (t != tn) {
|
||||
*iterator++ = '.';
|
||||
while (t != tn) {
|
||||
*iterator++ = *--t;
|
||||
}
|
||||
}
|
||||
|
||||
return iterator;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Locations define a place on earth.
|
||||
*
|
||||
@@ -89,14 +266,12 @@ namespace osmium {
|
||||
// static constexpr int32_t undefined_coordinate = std::numeric_limits<int32_t>::max();
|
||||
static constexpr int32_t undefined_coordinate = 2147483647;
|
||||
|
||||
static constexpr int coordinate_precision = 10000000;
|
||||
|
||||
static int32_t double_to_fix(const double c) noexcept {
|
||||
return static_cast<int32_t>(std::round(c * coordinate_precision));
|
||||
return static_cast<int32_t>(std::round(c * detail::coordinate_precision));
|
||||
}
|
||||
|
||||
static constexpr double fix_to_double(const int32_t c) noexcept {
|
||||
return static_cast<double>(c) / coordinate_precision;
|
||||
return static_cast<double>(c) / detail::coordinate_precision;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,10 +329,10 @@ namespace osmium {
|
||||
* usual bounds (-180<=lon<=180, -90<=lat<=90).
|
||||
*/
|
||||
constexpr bool valid() const noexcept {
|
||||
return m_x >= -180 * coordinate_precision
|
||||
&& m_x <= 180 * coordinate_precision
|
||||
&& m_y >= -90 * coordinate_precision
|
||||
&& m_y <= 90 * coordinate_precision;
|
||||
return m_x >= -180 * detail::coordinate_precision
|
||||
&& m_x <= 180 * detail::coordinate_precision
|
||||
&& m_y >= -90 * detail::coordinate_precision
|
||||
&& m_y <= 90 * detail::coordinate_precision;
|
||||
}
|
||||
|
||||
constexpr int32_t x() const noexcept {
|
||||
@@ -226,11 +401,47 @@ namespace osmium {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Location& set_lon(const char* str) {
|
||||
const char** data = &str;
|
||||
m_x = detail::string_to_location_coordinate(data);
|
||||
if (**data != '\0') {
|
||||
throw invalid_location{std::string{"characters after coordinate: '"} + *data + "'"};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Location& set_lat(const char* str) {
|
||||
const char** data = &str;
|
||||
m_y = detail::string_to_location_coordinate(data);
|
||||
if (**data != '\0') {
|
||||
throw invalid_location{std::string{"characters after coordinate: '"} + *data + "'"};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Location& set_lon_partial(const char** str) {
|
||||
m_x = detail::string_to_location_coordinate(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Location& set_lat_partial(const char** str) {
|
||||
m_y = detail::string_to_location_coordinate(str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T as_string(T iterator, const char separator) const {
|
||||
iterator = osmium::util::double2string(iterator, lon(), 7);
|
||||
T as_string_without_check(T iterator, const char separator = ',') const {
|
||||
iterator = detail::append_location_coordinate_to_string(iterator, x());
|
||||
*iterator++ = separator;
|
||||
return osmium::util::double2string(iterator, lat(), 7);
|
||||
return detail::append_location_coordinate_to_string(iterator, y());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T as_string(T iterator, const char separator = ',') const {
|
||||
if (!valid()) {
|
||||
throw osmium::invalid_location("invalid location");
|
||||
}
|
||||
return as_string_without_check(iterator, separator);
|
||||
}
|
||||
|
||||
}; // class Location
|
||||
@@ -273,13 +484,52 @@ namespace osmium {
|
||||
template <typename TChar, typename TTraits>
|
||||
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const osmium::Location& location) {
|
||||
if (location) {
|
||||
out << '(' << location.lon() << ',' << location.lat() << ')';
|
||||
out << '(';
|
||||
location.as_string(std::ostream_iterator<char>(out), ',');
|
||||
out << ')';
|
||||
} else {
|
||||
out << "(undefined,undefined)";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <int N>
|
||||
inline size_t hash(const osmium::Location& location) noexcept {
|
||||
return location.x() ^ location.y();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline size_t hash<8>(const osmium::Location& location) noexcept {
|
||||
size_t h = location.x();
|
||||
h <<= 32;
|
||||
return h ^ location.y();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace osmium
|
||||
|
||||
namespace std {
|
||||
|
||||
// This pragma is a workaround for a bug in an old libc implementation
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template <>
|
||||
struct hash<osmium::Location> {
|
||||
using argument_type = osmium::Location;
|
||||
using result_type = size_t;
|
||||
size_t operator()(const osmium::Location& location) const noexcept {
|
||||
return osmium::detail::hash<sizeof(size_t)>(location);
|
||||
}
|
||||
};
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // OSMIUM_OSM_LOCATION_HPP
|
||||
|
||||
@@ -39,6 +39,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/osm/node_ref.hpp>
|
||||
|
||||
namespace osmium {
|
||||
@@ -66,7 +67,7 @@ namespace osmium {
|
||||
* Returns the number of NodeRefs in the collection.
|
||||
*/
|
||||
size_t size() const noexcept {
|
||||
auto size_node_refs = byte_size() - sizeof(NodeRefList);
|
||||
const auto size_node_refs = byte_size() - sizeof(NodeRefList);
|
||||
assert(size_node_refs % sizeof(NodeRef) == 0);
|
||||
return size_node_refs / sizeof(NodeRef);
|
||||
}
|
||||
|
||||
+67
-24
@@ -33,11 +33,10 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
|
||||
#include <osmium/memory/collection.hpp>
|
||||
#include <osmium/memory/item.hpp>
|
||||
@@ -49,6 +48,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
#include <osmium/osm/types_from_string.hpp>
|
||||
#include <osmium/util/misc.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
@@ -172,9 +172,9 @@ namespace osmium {
|
||||
* @returns Reference to object to make calls chainable.
|
||||
*/
|
||||
OSMObject& set_visible(const char* visible) {
|
||||
if (!strcmp("true", visible)) {
|
||||
if (!std::strcmp("true", visible)) {
|
||||
set_visible(true);
|
||||
} else if (!strcmp("false", visible)) {
|
||||
} else if (!std::strcmp("false", visible)) {
|
||||
set_visible(false);
|
||||
} else {
|
||||
throw std::invalid_argument("Unknown value for visible attribute (allowed is 'true' or 'false')");
|
||||
@@ -286,6 +286,20 @@ namespace osmium {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the timestamp when this object last changed.
|
||||
*
|
||||
* @param timestamp Timestamp in ISO format.
|
||||
* @returns Reference to object to make calls chainable.
|
||||
*/
|
||||
OSMObject& set_timestamp(const char* timestamp) {
|
||||
m_timestamp = detail::parse_timestamp(timestamp);
|
||||
if (timestamp[20] != '\0') {
|
||||
throw std::invalid_argument{"can not parse timestamp"};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Get user name for this object.
|
||||
const char* user() const noexcept {
|
||||
return reinterpret_cast<const char*>(data() + sizeof_object());
|
||||
@@ -311,25 +325,28 @@ namespace osmium {
|
||||
*
|
||||
* @param attr Name of the attribute (must be one of "id", "version", "changeset", "timestamp", "uid", "visible")
|
||||
* @param value Value of the attribute
|
||||
* @returns Reference to object to make calls chainable.
|
||||
*/
|
||||
void set_attribute(const char* attr, const char* value) {
|
||||
if (!strcmp(attr, "id")) {
|
||||
OSMObject& set_attribute(const char* attr, const char* value) {
|
||||
if (!std::strcmp(attr, "id")) {
|
||||
set_id(value);
|
||||
} else if (!strcmp(attr, "version")) {
|
||||
} else if (!std::strcmp(attr, "version")) {
|
||||
set_version(value);
|
||||
} else if (!strcmp(attr, "changeset")) {
|
||||
} else if (!std::strcmp(attr, "changeset")) {
|
||||
set_changeset(value);
|
||||
} else if (!strcmp(attr, "timestamp")) {
|
||||
set_timestamp(osmium::Timestamp(value));
|
||||
} else if (!strcmp(attr, "uid")) {
|
||||
} else if (!std::strcmp(attr, "timestamp")) {
|
||||
set_timestamp(value);
|
||||
} else if (!std::strcmp(attr, "uid")) {
|
||||
set_uid(value);
|
||||
} else if (!strcmp(attr, "visible")) {
|
||||
} else if (!std::strcmp(attr, "visible")) {
|
||||
set_visible(value);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
typedef osmium::memory::CollectionIterator<Item> iterator;
|
||||
typedef osmium::memory::CollectionIterator<const Item> const_iterator;
|
||||
using iterator = osmium::memory::CollectionIterator<Item>;
|
||||
using const_iterator = osmium::memory::CollectionIterator<const Item>;
|
||||
|
||||
iterator begin() {
|
||||
return iterator(subitems_position());
|
||||
@@ -355,6 +372,26 @@ namespace osmium {
|
||||
return cend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a range of subitems of a specific type.
|
||||
*
|
||||
* @tparam The type (must be derived from osmium::memory::Item.
|
||||
*/
|
||||
template <typename T>
|
||||
osmium::memory::ItemIteratorRange<T> subitems() {
|
||||
return osmium::memory::ItemIteratorRange<T>{subitems_position(), next()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a range of subitems of a specific type.
|
||||
*
|
||||
* @tparam The type (must be derived from osmium::memory::Item.
|
||||
*/
|
||||
template <typename T>
|
||||
osmium::memory::ItemIteratorRange<const T> subitems() const {
|
||||
return osmium::memory::ItemIteratorRange<const T>{subitems_position(), next()};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using t_iterator = osmium::memory::ItemIterator<T>;
|
||||
|
||||
@@ -399,8 +436,8 @@ namespace osmium {
|
||||
* OSMObjects are equal if their type, id, and version are equal.
|
||||
*/
|
||||
inline bool operator==(const OSMObject& lhs, const OSMObject& rhs) noexcept {
|
||||
return lhs.type() == rhs.type() &&
|
||||
lhs.id() == rhs.id() &&
|
||||
return lhs.type() == rhs.type() &&
|
||||
lhs.id() == rhs.id() &&
|
||||
lhs.version() == rhs.version();
|
||||
}
|
||||
|
||||
@@ -409,16 +446,22 @@ namespace osmium {
|
||||
}
|
||||
|
||||
/**
|
||||
* OSMObjects can be ordered by type, id and version.
|
||||
* Note that we use the absolute value of the id for a
|
||||
* better ordering of objects with negative id.
|
||||
* OSMObjects can be ordered by type, id, version, and timestamp. Usually
|
||||
* ordering by timestamp is not necessary as there shouldn't be two
|
||||
* objects with the same type, id, and version. But this can happen when
|
||||
* creating diff files from extracts, so we take the timestamp into
|
||||
* account here.
|
||||
*
|
||||
* Note that we use the absolute value of the id for a better ordering
|
||||
* of objects with negative id. If the IDs have the same absolute value,
|
||||
* the positive ID comes first.
|
||||
*
|
||||
* See object_order_type_id_reverse_version if you need a different
|
||||
* ordering.
|
||||
*/
|
||||
inline bool operator<(const OSMObject& lhs, const OSMObject& rhs) noexcept {
|
||||
if (lhs.type() != rhs.type()) {
|
||||
return lhs.type() < rhs.type();
|
||||
}
|
||||
return (lhs.id() == rhs.id() && lhs.version() < rhs.version()) ||
|
||||
lhs.positive_id() < rhs.positive_id();
|
||||
return const_tie(lhs.type(), lhs.positive_id(), lhs.id() < 0, lhs.version(), lhs.timestamp()) <
|
||||
const_tie(rhs.type(), rhs.positive_id(), rhs.id() < 0, rhs.version(), rhs.timestamp());
|
||||
}
|
||||
|
||||
inline bool operator>(const OSMObject& lhs, const OSMObject& rhs) noexcept {
|
||||
|
||||
+17
-12
@@ -33,12 +33,17 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/timestamp.hpp>
|
||||
#include <osmium/util/misc.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
/**
|
||||
* Function object class for comparing OSM objects for equality by type, id, and version.
|
||||
* Function object class for comparing OSM objects for equality by type,
|
||||
* id, and version.
|
||||
*/
|
||||
struct object_equal_type_id_version {
|
||||
|
||||
@@ -53,8 +58,8 @@ namespace osmium {
|
||||
}; // struct object_equal_type_id_version
|
||||
|
||||
/**
|
||||
* Function object class for comparing OSM objects for equality by type and id,
|
||||
* ignoring the version.
|
||||
* Function object class for comparing OSM objects for equality by type
|
||||
* and id, ignoring the version.
|
||||
*/
|
||||
struct object_equal_type_id {
|
||||
|
||||
@@ -70,7 +75,8 @@ namespace osmium {
|
||||
}; // struct object_equal_type_id
|
||||
|
||||
/**
|
||||
* Function object class for ordering OSM objects by type, id, and version.
|
||||
* Function object class for ordering OSM objects by type, id, version,
|
||||
* and timestamp.
|
||||
*/
|
||||
struct object_order_type_id_version {
|
||||
|
||||
@@ -85,18 +91,17 @@ namespace osmium {
|
||||
}; // struct object_order_type_id_version
|
||||
|
||||
/**
|
||||
* Function object class for ordering OSM objects by type, id, and reverse version,
|
||||
* ie objects are ordered by type and id, but later versions of an object are
|
||||
* ordered before earlier versions of the same object.
|
||||
* Function object class for ordering OSM objects by type, id, and
|
||||
* reverse version, timestamp. So objects are ordered by type and id, but
|
||||
* later versions of an object are ordered before earlier versions of the
|
||||
* same object. This is useful when the last version of an object needs
|
||||
* to be used.
|
||||
*/
|
||||
struct object_order_type_id_reverse_version {
|
||||
|
||||
bool operator()(const osmium::OSMObject& lhs, const osmium::OSMObject& rhs) const noexcept {
|
||||
if (lhs.type() != rhs.type()) {
|
||||
return lhs.type() < rhs.type();
|
||||
}
|
||||
return (lhs.id() == rhs.id() && lhs.version() > rhs.version()) ||
|
||||
lhs.positive_id() < rhs.positive_id();
|
||||
return const_tie(lhs.type(), lhs.id() < 0, lhs.positive_id(), rhs.version(), rhs.timestamp()) <
|
||||
const_tie(rhs.type(), rhs.id() < 0, rhs.positive_id(), lhs.version(), lhs.timestamp());
|
||||
}
|
||||
|
||||
bool operator()(const osmium::OSMObject* lhs, const osmium::OSMObject* rhs) const noexcept {
|
||||
|
||||
+2
-2
@@ -33,13 +33,13 @@ DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
|
||||
#include <osmium/memory/collection.hpp> // IWYU pragma: keep
|
||||
#include <osmium/memory/item.hpp>
|
||||
#include <osmium/osm/entity.hpp>
|
||||
#include <osmium/osm/item_type.hpp>
|
||||
#include <osmium/osm/object.hpp>
|
||||
#include <osmium/osm/types.hpp>
|
||||
@@ -149,7 +149,7 @@ namespace osmium {
|
||||
|
||||
public:
|
||||
|
||||
typedef size_t size_type;
|
||||
using size_type = size_t;
|
||||
|
||||
RelationMemberList() :
|
||||
osmium::memory::Collection<RelationMember, osmium::item_type::relation_member_list>() {
|
||||
|
||||
@@ -37,7 +37,6 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <utility>
|
||||
|
||||
#include <osmium/osm/location.hpp>
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
|
||||
namespace osmium {
|
||||
|
||||
|
||||
+50
-10
@@ -34,7 +34,7 @@ DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <iosfwd>
|
||||
#include <iterator>
|
||||
@@ -87,7 +87,7 @@ namespace osmium {
|
||||
}; // class Tag
|
||||
|
||||
inline bool operator==(const Tag& a, const Tag& b) {
|
||||
return !std::strcmp(a.key(), b.key()) && !strcmp(a.value(), b.value());
|
||||
return !std::strcmp(a.key(), b.key()) && !std::strcmp(a.value(), b.value());
|
||||
}
|
||||
|
||||
inline bool operator<(const Tag& a, const Tag& b) {
|
||||
@@ -104,32 +104,72 @@ namespace osmium {
|
||||
|
||||
class TagList : public osmium::memory::Collection<Tag, osmium::item_type::tag_list> {
|
||||
|
||||
const_iterator find_key(const char* key) const noexcept {
|
||||
return std::find_if(cbegin(), cend(), [key](const Tag& tag) {
|
||||
return !std::strcmp(tag.key(), key);
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef size_t size_type;
|
||||
using size_type = size_t;
|
||||
|
||||
TagList() :
|
||||
osmium::memory::Collection<Tag, osmium::item_type::tag_list>() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of tags in this tag list.
|
||||
*/
|
||||
size_type size() const noexcept {
|
||||
return static_cast<size_type>(std::distance(begin(), end()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag value for the given tag key. If the key is not set, returns
|
||||
* the default_value.
|
||||
*
|
||||
* @pre @code key != nullptr @endcode
|
||||
*/
|
||||
const char* get_value_by_key(const char* key, const char* default_value = nullptr) const noexcept {
|
||||
auto result = std::find_if(cbegin(), cend(), [key](const Tag& tag) {
|
||||
return !strcmp(tag.key(), key);
|
||||
});
|
||||
if (result == cend()) {
|
||||
return default_value;
|
||||
}
|
||||
return result->value();
|
||||
assert(key);
|
||||
const auto result = find_key(key);
|
||||
return result == cend() ? default_value : result->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag value for the given tag key. If the key is not set, returns
|
||||
* nullptr.
|
||||
*
|
||||
* @pre @code key != nullptr @endcode
|
||||
*/
|
||||
const char* operator[](const char* key) const noexcept {
|
||||
return get_value_by_key(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the tag with the given key is in the tag list.
|
||||
*
|
||||
* @pre @code key != nullptr @endcode
|
||||
*/
|
||||
bool has_key(const char* key) const noexcept {
|
||||
assert(key);
|
||||
return find_key(key) != cend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the tag with the given key and value is in the
|
||||
* tag list.
|
||||
*
|
||||
* @pre @code key != nullptr && value != nullptr @endcode
|
||||
*/
|
||||
bool has_tag(const char* key, const char* value) const noexcept {
|
||||
assert(key);
|
||||
assert(value);
|
||||
const auto result = find_key(key);
|
||||
return result != cend() && !std::strcmp(result->value(), value);
|
||||
}
|
||||
|
||||
}; // class TagList
|
||||
|
||||
static_assert(sizeof(TagList) % osmium::memory::align_bytes == 0, "Class osmium::TagList has wrong size to be aligned properly!");
|
||||
|
||||
+61
-22
@@ -40,12 +40,71 @@ DEALINGS IN THE SOFTWARE.
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <osmium/util/compatibility.hpp>
|
||||
#include <osmium/util/minmax.hpp> // IWYU pragma: keep
|
||||
|
||||
namespace osmium {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline time_t parse_timestamp(const char* str) {
|
||||
static const int mon_lengths[] = {
|
||||
31, 29, 31, 30, 31, 30,
|
||||
31, 31, 30, 31, 30, 31
|
||||
};
|
||||
if (str[ 0] >= '0' && str[ 0] <= '9' &&
|
||||
str[ 1] >= '0' && str[ 1] <= '9' &&
|
||||
str[ 2] >= '0' && str[ 2] <= '9' &&
|
||||
str[ 3] >= '0' && str[ 3] <= '9' &&
|
||||
str[ 4] == '-' &&
|
||||
str[ 5] >= '0' && str[ 5] <= '9' &&
|
||||
str[ 6] >= '0' && str[ 6] <= '9' &&
|
||||
str[ 7] == '-' &&
|
||||
str[ 8] >= '0' && str[ 8] <= '9' &&
|
||||
str[ 9] >= '0' && str[ 9] <= '9' &&
|
||||
str[10] == 'T' &&
|
||||
str[11] >= '0' && str[11] <= '9' &&
|
||||
str[12] >= '0' && str[12] <= '9' &&
|
||||
str[13] == ':' &&
|
||||
str[14] >= '0' && str[14] <= '9' &&
|
||||
str[15] >= '0' && str[15] <= '9' &&
|
||||
str[16] == ':' &&
|
||||
str[17] >= '0' && str[17] <= '9' &&
|
||||
str[18] >= '0' && str[18] <= '9' &&
|
||||
str[19] == 'Z') {
|
||||
struct tm tm;
|
||||
tm.tm_year = (str[ 0] - '0') * 1000 +
|
||||
(str[ 1] - '0') * 100 +
|
||||
(str[ 2] - '0') * 10 +
|
||||
(str[ 3] - '0') - 1900;
|
||||
tm.tm_mon = (str[ 5] - '0') * 10 + (str[ 6] - '0') - 1;
|
||||
tm.tm_mday = (str[ 8] - '0') * 10 + (str[ 9] - '0');
|
||||
tm.tm_hour = (str[11] - '0') * 10 + (str[12] - '0');
|
||||
tm.tm_min = (str[14] - '0') * 10 + (str[15] - '0');
|
||||
tm.tm_sec = (str[17] - '0') * 10 + (str[18] - '0');
|
||||
tm.tm_wday = 0;
|
||||
tm.tm_yday = 0;
|
||||
tm.tm_isdst = 0;
|
||||
if (tm.tm_year >= 0 &&
|
||||
tm.tm_mon >= 0 && tm.tm_mon <= 11 &&
|
||||
tm.tm_mday >= 1 && tm.tm_mday <= mon_lengths[tm.tm_mon] &&
|
||||
tm.tm_hour >= 0 && tm.tm_hour <= 23 &&
|
||||
tm.tm_min >= 0 && tm.tm_min <= 59 &&
|
||||
tm.tm_sec >= 0 && tm.tm_sec <= 60) {
|
||||
#ifndef _WIN32
|
||||
return timegm(&tm);
|
||||
#else
|
||||
return _mkgmtime(&tm);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
throw std::invalid_argument{"can not parse timestamp"};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* A timestamp. Internal representation is an unsigned 32bit integer
|
||||
* holding seconds since epoch (1970-01-01T00:00:00Z), so this will
|
||||
@@ -56,7 +115,7 @@ namespace osmium {
|
||||
class Timestamp {
|
||||
|
||||
// length of ISO timestamp string yyyy-mm-ddThh:mm:ssZ\0
|
||||
static constexpr int timestamp_length = 20 + 1;
|
||||
static constexpr const int timestamp_length = 20 + 1;
|
||||
|
||||
// The timestamp format for OSM timestamps in strftime(3) format.
|
||||
// This is the ISO-Format "yyyy-mm-ddThh:mm:ssZ".
|
||||
@@ -97,27 +156,7 @@ namespace osmium {
|
||||
* @throws std::invalid_argument if the timestamp can not be parsed.
|
||||
*/
|
||||
explicit Timestamp(const char* timestamp) {
|
||||
#ifndef _WIN32
|
||||
struct tm tm {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
if (strptime(timestamp, timestamp_format(), &tm) == nullptr) {
|
||||
throw std::invalid_argument("can't parse timestamp");
|
||||
}
|
||||
m_timestamp = static_cast<uint32_t>(timegm(&tm));
|
||||
#else
|
||||
struct tm tm;
|
||||
int n = sscanf(timestamp, "%4d-%2d-%2dT%2d:%2d:%2dZ", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
||||
if (n != 6) {
|
||||
throw std::invalid_argument("can't parse timestamp");
|
||||
}
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon--;
|
||||
tm.tm_wday = 0;
|
||||
tm.tm_yday = 0;
|
||||
tm.tm_isdst = 0;
|
||||
m_timestamp = static_cast<uint32_t>(_mkgmtime(&tm));
|
||||
#endif
|
||||
m_timestamp = static_cast<uint32_t>(detail::parse_timestamp(timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+10
-10
@@ -38,25 +38,25 @@ DEALINGS IN THE SOFTWARE.
|
||||
namespace osmium {
|
||||
|
||||
/*
|
||||
* The following typedefs are chosen so that they can represent all needed
|
||||
* The following types are chosen so that they can represent all needed
|
||||
* numbers and still be reasonably space efficient. As the OSM database
|
||||
* needs 64 bit IDs for nodes, this size is used for all object IDs.
|
||||
*/
|
||||
typedef int64_t object_id_type; ///< Type for OSM object (node, way, or relation) IDs.
|
||||
typedef uint64_t unsigned_object_id_type; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
|
||||
typedef uint32_t object_version_type; ///< Type for OSM object version number.
|
||||
typedef uint32_t changeset_id_type; ///< Type for OSM changeset IDs.
|
||||
typedef uint32_t user_id_type; ///< Type for OSM user IDs.
|
||||
typedef int32_t signed_user_id_type; ///< Type for signed OSM user IDs.
|
||||
typedef uint32_t num_changes_type; ///< Type for changeset num_changes.
|
||||
typedef uint32_t num_comments_type; ///< Type for changeset num_comments.
|
||||
using object_id_type = int64_t; ///< Type for OSM object (node, way, or relation) IDs.
|
||||
using unsigned_object_id_type = uint64_t; ///< Type for OSM object (node, way, or relation) IDs where we only allow positive IDs.
|
||||
using object_version_type = uint32_t; ///< Type for OSM object version number.
|
||||
using changeset_id_type = uint32_t; ///< Type for OSM changeset IDs.
|
||||
using user_id_type = uint32_t; ///< Type for OSM user IDs.
|
||||
using signed_user_id_type = int32_t; ///< Type for signed OSM user IDs.
|
||||
using num_changes_type = uint32_t; ///< Type for changeset num_changes.
|
||||
using num_comments_type = uint32_t; ///< Type for changeset num_comments.
|
||||
|
||||
/**
|
||||
* Size for strings in OSM data such as user names, tag keys, roles, etc.
|
||||
* In Osmium they can be up to 2^16 bytes long, but OSM usually has lower
|
||||
* defined limits.
|
||||
*/
|
||||
typedef uint16_t string_size_type;
|
||||
using string_size_type = uint16_t;
|
||||
|
||||
// maximum of 256 characters of max 4 bytes each (in UTF-8 encoding)
|
||||
constexpr const int max_osm_string_length = 256 * 4;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user