Revert "fixing line endings"

This reverts commit dc75469e78.
This commit is contained in:
Dennis Luxen
2014-08-15 18:53:00 +02:00
parent dc75469e78
commit 5efa9664db
131 changed files with 0 additions and 21457 deletions
-767
View File
@@ -1,767 +0,0 @@
#ifndef OSMIUM_AREA_ASSEMBLER_HPP
#define OSMIUM_AREA_ASSEMBLER_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <algorithm>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <vector>
#include <osmium/builder/osm_object_builder.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/area.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/tags/filter.hpp>
#include <osmium/area/detail/proto_ring.hpp>
#include <osmium/area/detail/node_ref_segment.hpp>
#include <osmium/area/detail/segment_list.hpp>
#include <osmium/area/problem_reporter.hpp>
namespace osmium {
namespace area {
using osmium::area::detail::ProtoRing;
struct AssemblerConfig {
osmium::area::ProblemReporter* problem_reporter;
// Enables debug output to stderr
bool debug;
explicit AssemblerConfig(osmium::area::ProblemReporter* pr = nullptr, bool d=false) :
problem_reporter(pr),
debug(d) {
}
/**
* Enable or disable debug output to stderr. This is for Osmium
* developers only.
*/
void enable_debug_output(bool d=true) {
debug = d;
}
}; // struct AssemblerConfig
/**
* Assembles area objects from multipolygon relations and their
* members. This is called by the MultipolygonCollector object
* after all members have been collected.
*/
class Assembler {
const AssemblerConfig m_config;
// The way segments
osmium::area::detail::SegmentList m_segment_list;
// The rings we are building from the way segments
std::list<ProtoRing> m_rings {};
std::vector<ProtoRing*> m_outer_rings {};
std::vector<ProtoRing*> m_inner_rings {};
int m_inner_outer_mismatches { 0 };
bool debug() const {
return m_config.debug;
}
/**
* Checks whether the given NodeRefs have the same location.
* Uses the actual location for the test, not the id. If both
* have the same location, but not the same id, a problem
* point will be added to the list of problem points.
*/
bool has_same_location(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2) {
if (nr1.location() != nr2.location()) {
return false;
}
if (nr1.ref() != nr2.ref()) {
if (m_config.problem_reporter) {
m_config.problem_reporter->report_duplicate_node(nr1.ref(), nr2.ref(), nr1.location());
}
}
return true;
}
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Way& way) const {
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
for (const osmium::Tag& tag : way.tags()) {
tl_builder.add_tag(tag.key(), tag.value());
}
}
void add_common_tags(osmium::builder::TagListBuilder& tl_builder, std::set<const osmium::Way*>& ways) const {
std::map<std::string, size_t> counter;
for (const osmium::Way* way : ways) {
for (const auto& tag : way->tags()) {
std::string kv {tag.key()};
kv.append(1, '\0');
kv.append(tag.value());
++counter[kv];
}
}
size_t num_ways = ways.size();
for (const auto& t_c : counter) {
if (debug()) {
std::cerr << " tag " << t_c.first << " is used " << t_c.second << " times in " << num_ways << " ways\n";
}
if (t_c.second == num_ways) {
size_t len = std::strlen(t_c.first.c_str());
tl_builder.add_tag(t_c.first.c_str(), t_c.first.c_str() + len + 1);
}
}
}
void add_tags_to_area(osmium::builder::AreaBuilder& builder, const osmium::Relation& relation) const {
osmium::tags::KeyFilter filter(true);
filter.add(false, "type").add(false, "created_by").add(false, "source").add(false, "note");
filter.add(false, "test:id").add(false, "test:section");
osmium::tags::KeyFilter::iterator fi_begin(filter, relation.tags().begin(), relation.tags().end());
osmium::tags::KeyFilter::iterator fi_end(filter, relation.tags().end(), relation.tags().end());
auto count = std::distance(fi_begin, fi_end);
if (debug()) {
std::cerr << " found " << count << " tags on relation (without ignored ones)\n";
}
if (count > 0) {
if (debug()) {
std::cerr << " use tags from relation\n";
}
// write out all tags except type=*
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
for (const osmium::Tag& tag : relation.tags()) {
if (strcmp(tag.key(), "type")) {
tl_builder.add_tag(tag.key(), tag.value());
}
}
} else {
if (debug()) {
std::cerr << " use tags from outer ways\n";
}
std::set<const osmium::Way*> ways;
for (const auto& ring : m_outer_rings) {
ring->get_ways(ways);
}
if (ways.size() == 1) {
if (debug()) {
std::cerr << " only one outer way\n";
}
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
for (const osmium::Tag& tag : (*ways.begin())->tags()) {
tl_builder.add_tag(tag.key(), tag.value());
}
} else {
if (debug()) {
std::cerr << " multiple outer ways, get common tags\n";
}
osmium::builder::TagListBuilder tl_builder(builder.buffer(), &builder);
add_common_tags(tl_builder, ways);
}
}
}
/**
* Go through all the rings and find rings that are not closed.
* Problems are reported through the problem reporter.
*
* @returns true if any rings were not closed, false otherwise
*/
bool check_for_open_rings() {
bool open_rings = false;
for (const auto& ring : m_rings) {
if (!ring.closed()) {
open_rings = true;
if (m_config.problem_reporter) {
m_config.problem_reporter->report_ring_not_closed(ring.get_segment_front().first().location(), ring.get_segment_back().second().location());
}
}
}
return open_rings;
}
/**
* Check whether there are any rings that can be combined with the
* given ring to one larger ring by appending the other ring to
* the end of this ring.
* If the rings can be combined they are and the function returns
* true.
*/
bool possibly_combine_rings_back(ProtoRing& ring) {
const osmium::NodeRef& nr = ring.get_segment_back().second();
if (debug()) {
std::cerr << " possibly_combine_rings_back()\n";
}
for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
if (&*it != &ring && !it->closed()) {
if (has_same_location(nr, it->get_segment_front().first())) {
if (debug()) {
std::cerr << " ring.last=it->first\n";
}
ring.merge_ring(*it, debug());
m_rings.erase(it);
return true;
}
if (has_same_location(nr, it->get_segment_back().second())) {
if (debug()) {
std::cerr << " ring.last=it->last\n";
}
ring.merge_ring_reverse(*it, debug());
m_rings.erase(it);
return true;
}
}
}
return false;
}
/**
* Check whether there are any rings that can be combined with the
* given ring to one larger ring by prepending the other ring to
* the start of this ring.
* If the rings can be combined they are and the function returns
* true.
*/
bool possibly_combine_rings_front(ProtoRing& ring) {
const osmium::NodeRef& nr = ring.get_segment_front().first();
if (debug()) {
std::cerr << " possibly_combine_rings_front()\n";
}
for (auto it = m_rings.begin(); it != m_rings.end(); ++it) {
if (&*it != &ring && !it->closed()) {
if (has_same_location(nr, it->get_segment_back().second())) {
if (debug()) {
std::cerr << " ring.first=it->last\n";
}
ring.swap_segments(*it);
ring.merge_ring(*it, debug());
m_rings.erase(it);
return true;
}
if (has_same_location(nr, it->get_segment_front().first())) {
if (debug()) {
std::cerr << " ring.first=it->first\n";
}
ring.reverse();
ring.merge_ring(*it, debug());
m_rings.erase(it);
return true;
}
}
}
return false;
}
void split_off_subring(osmium::area::detail::ProtoRing& ring, osmium::area::detail::ProtoRing::segments_type::iterator it, osmium::area::detail::ProtoRing::segments_type::iterator it_begin, osmium::area::detail::ProtoRing::segments_type::iterator it_end) {
if (debug()) {
std::cerr << " subring found at: " << *it << "\n";
}
ProtoRing new_ring(it_begin, it_end);
ring.remove_segments(it_begin, it_end);
if (debug()) {
std::cerr << " split into two rings:\n";
std::cerr << " " << new_ring << "\n";
std::cerr << " " << ring << "\n";
}
m_rings.push_back(std::move(new_ring));
}
bool has_closed_subring_back(ProtoRing& ring, const NodeRef& nr) {
if (ring.segments().size() < 3) {
return false;
}
if (debug()) {
std::cerr << " has_closed_subring_back()\n";
}
auto end = ring.segments().end();
for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
if (has_same_location(nr, it->first())) {
split_off_subring(ring, it, it, end);
return true;
}
}
return false;
}
bool has_closed_subring_front(ProtoRing& ring, const NodeRef& nr) {
if (ring.segments().size() < 3) {
return false;
}
if (debug()) {
std::cerr << " has_closed_subring_front()\n";
}
auto end = ring.segments().end();
for (auto it = ring.segments().begin() + 1; it != end - 1; ++it) {
if (has_same_location(nr, it->second())) {
split_off_subring(ring, it, ring.segments().begin(), it+1);
return true;
}
}
return false;
}
bool check_for_closed_subring(ProtoRing& ring) {
if (debug()) {
std::cerr << " check_for_closed_subring()\n";
}
osmium::area::detail::ProtoRing::segments_type segments(ring.segments().size());
std::copy(ring.segments().begin(), ring.segments().end(), segments.begin());
std::sort(segments.begin(), segments.end());
auto it = std::adjacent_find(segments.begin(), segments.end(), [this](const osmium::area::detail::NodeRefSegment& s1, const osmium::area::detail::NodeRefSegment& s2) {
return has_same_location(s1.first(), s2.first());
});
if (it == segments.end()) {
return false;
}
auto r1 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it, it+1);
assert(r1 != ring.segments().end());
auto r2 = std::find_first_of(ring.segments().begin(), ring.segments().end(), it+1, it+2);
assert(r2 != ring.segments().end());
if (debug()) {
std::cerr << " found subring in ring " << ring << " at " << it->first() << "\n";
}
auto m = std::minmax(r1, r2);
ProtoRing new_ring(m.first, m.second);
ring.remove_segments(m.first, m.second);
if (debug()) {
std::cerr << " split ring1=" << new_ring << "\n";
std::cerr << " split ring2=" << ring << "\n";
}
m_rings.emplace_back(new_ring);
return true;
}
void combine_rings_front(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
if (debug()) {
std::cerr << " => match at front of ring\n";
}
ring.add_segment_front(segment);
has_closed_subring_front(ring, segment.first());
if (possibly_combine_rings_front(ring)) {
check_for_closed_subring(ring);
}
}
void combine_rings_back(const osmium::area::detail::NodeRefSegment& segment, ProtoRing& ring) {
if (debug()) {
std::cerr << " => match at back of ring\n";
}
ring.add_segment_back(segment);
has_closed_subring_back(ring, segment.second());
if (possibly_combine_rings_back(ring)) {
check_for_closed_subring(ring);
}
}
/**
* Append each outer ring together with its inner rings to the
* area in the buffer.
*/
void add_rings_to_area(osmium::builder::AreaBuilder& builder) const {
for (const ProtoRing* ring : m_outer_rings) {
if (debug()) {
std::cerr << " ring " << *ring << " is outer\n";
}
{
osmium::builder::OuterRingBuilder ring_builder(builder.buffer(), &builder);
ring_builder.add_node_ref(ring->get_segment_front().first());
for (const auto& segment : ring->segments()) {
ring_builder.add_node_ref(segment.second());
}
}
for (ProtoRing* inner : ring->inner_rings()) {
osmium::builder::InnerRingBuilder ring_builder(builder.buffer(), &builder);
ring_builder.add_node_ref(inner->get_segment_front().first());
for (const auto& segment : inner->segments()) {
ring_builder.add_node_ref(segment.second());
}
}
}
}
bool add_to_existing_ring(osmium::area::detail::NodeRefSegment segment) {
int n=0;
for (auto& ring : m_rings) {
if (debug()) {
std::cerr << " check against ring " << n << " " << ring;
}
if (ring.closed()) {
if (debug()) {
std::cerr << " => ring CLOSED\n";
}
} else {
if (has_same_location(ring.get_segment_back().second(), segment.first())) {
combine_rings_back(segment, ring);
return true;
}
if (has_same_location(ring.get_segment_back().second(), segment.second())) {
segment.swap_locations();
combine_rings_back(segment, ring);
return true;
}
if (has_same_location(ring.get_segment_front().first(), segment.first())) {
segment.swap_locations();
combine_rings_front(segment, ring);
return true;
}
if (has_same_location(ring.get_segment_front().first(), segment.second())) {
combine_rings_front(segment, ring);
return true;
}
if (debug()) {
std::cerr << " => no match\n";
}
}
++n;
}
return false;
}
void check_inner_outer(ProtoRing& ring) {
const osmium::NodeRef& min_node = ring.min_node();
if (debug()) {
std::cerr << " check_inner_outer min_node=" << min_node << "\n";
}
int count = 0;
int above = 0;
for (auto it = m_segment_list.begin(); it != m_segment_list.end() && it->first().location().x() <= min_node.location().x(); ++it) {
if (!ring.contains(*it)) {
if (debug()) {
std::cerr << " segments for count: " << *it;
}
if (it->to_left_of(min_node.location())) {
++count;
if (debug()) {
std::cerr << " counted\n";
}
} else {
if (debug()) {
std::cerr << " not counted\n";
}
}
if (it->first().location() == min_node.location()) {
if (it->second().location().y() > min_node.location().y()) {
++above;
}
}
if (it->second().location() == min_node.location()) {
if (it->first().location().y() > min_node.location().y()) {
++above;
}
}
}
}
if (debug()) {
std::cerr << " count=" << count << " above=" << above << "\n";
}
count += above % 2;
if (count % 2) {
ring.set_inner();
}
}
void check_inner_outer_roles() {
if (debug()) {
std::cerr << " check_inner_outer_roles\n";
}
for (const auto ringptr : m_outer_rings) {
for (const auto segment : ringptr->segments()) {
if (!segment.role_outer()) {
++m_inner_outer_mismatches;
if (debug()) {
std::cerr << " segment " << segment << " from way " << segment.way()->id() << " should have role 'outer'\n";
}
if (m_config.problem_reporter) {
m_config.problem_reporter->report_role_should_be_outer(segment.way()->id(), segment.first().location(), segment.second().location());
}
}
}
}
for (const auto ringptr : m_inner_rings) {
for (const auto segment : ringptr->segments()) {
if (!segment.role_inner()) {
++m_inner_outer_mismatches;
if (debug()) {
std::cerr << " segment " << segment << " from way " << segment.way()->id() << " should have role 'inner'\n";
}
if (m_config.problem_reporter) {
m_config.problem_reporter->report_role_should_be_inner(segment.way()->id(), segment.first().location(), segment.second().location());
}
}
}
}
}
/**
* Create rings from segments.
*/
bool create_rings() {
m_segment_list.sort();
m_segment_list.erase_duplicate_segments();
// Now we look for segments crossing each other. If there are
// any, the multipolygon is invalid.
// In the future this could be improved by trying to fix those
// cases.
if (m_segment_list.find_intersections(m_config.problem_reporter)) {
return false;
}
// Now iterator over all segments and add them to rings. Each segment
// is tacked on to either end of an existing ring if possible, or a
// new ring is started with it.
for (const auto& segment : m_segment_list) {
if (debug()) {
std::cerr << " checking segment " << segment << "\n";
}
if (!add_to_existing_ring(segment)) {
if (debug()) {
std::cerr << " new ring for segment " << segment << "\n";
}
m_rings.emplace_back(segment);
}
}
if (debug()) {
std::cerr << " Rings:\n";
for (const auto& ring : m_rings) {
std::cerr << " " << ring;
if (ring.closed()) {
std::cerr << " (closed)";
}
std::cerr << "\n";
}
}
if (check_for_open_rings()) {
if (debug()) {
std::cerr << " not all rings are closed\n";
}
return false;
}
if (debug()) {
std::cerr << " Find inner/outer...\n";
}
if (m_rings.size() == 1) {
m_outer_rings.push_back(&m_rings.front());
} else {
for (auto& ring : m_rings) {
check_inner_outer(ring);
if (ring.outer()) {
if (!ring.is_cw()) {
ring.reverse();
}
m_outer_rings.push_back(&ring);
} else {
if (ring.is_cw()) {
ring.reverse();
}
m_inner_rings.push_back(&ring);
}
}
if (m_outer_rings.size() == 1) {
for (auto inner : m_inner_rings) {
m_outer_rings.front()->add_inner_ring(inner);
}
} else {
// sort outer rings by size, smallest first
std::sort(m_outer_rings.begin(), m_outer_rings.end(), [](ProtoRing* a, ProtoRing* b) {
return a->area() < b->area();
});
for (auto inner : m_inner_rings) {
for (auto outer : m_outer_rings) {
if (inner->is_in(outer)) {
outer->add_inner_ring(inner);
break;
}
}
}
}
}
check_inner_outer_roles();
return true;
}
public:
typedef osmium::area::AssemblerConfig config_type;
explicit Assembler(const config_type& config) :
m_config(config),
m_segment_list(config.debug) {
}
~Assembler() = default;
/**
* Assemble an area from the given way.
* The resulting area is put into the out_buffer.
*/
void operator()(const osmium::Way& way, osmium::memory::Buffer& out_buffer) {
if (m_config.problem_reporter) {
m_config.problem_reporter->set_object(osmium::item_type::way, way.id());
}
if (!way.ends_have_same_id()) {
if (m_config.problem_reporter) {
m_config.problem_reporter->report_duplicate_node(way.nodes().front().ref(), way.nodes().back().ref(), way.nodes().front().location());
}
}
m_segment_list.extract_segments_from_way(way, "outer");
if (debug()) {
std::cerr << "\nBuild way id()=" << way.id() << " segments.size()=" << m_segment_list.size() << "\n";
}
// Now create the Area object and add the attributes and tags
// from the relation.
{
osmium::builder::AreaBuilder builder(out_buffer);
builder.initialize_from_object(way);
if (create_rings()) {
add_tags_to_area(builder, way);
add_rings_to_area(builder);
}
}
out_buffer.commit();
}
/**
* Assemble an area from the given relation and its members.
* All members are to be found in the in_buffer at the offsets
* given by the members parameter.
* The resulting area is put into the out_buffer.
*/
void operator()(const osmium::Relation& relation, const std::vector<size_t>& members, const osmium::memory::Buffer& in_buffer, osmium::memory::Buffer& out_buffer) {
if (m_config.problem_reporter) {
m_config.problem_reporter->set_object(osmium::item_type::relation, relation.id());
}
m_segment_list.extract_segments_from_ways(relation, members, in_buffer);
if (debug()) {
std::cerr << "\nBuild relation id()=" << relation.id() << " members.size()=" << members.size() << " segments.size()=" << m_segment_list.size() << "\n";
}
size_t area_offset = out_buffer.committed();
// Now create the Area object and add the attributes and tags
// from the relation.
{
osmium::builder::AreaBuilder builder(out_buffer);
builder.initialize_from_object(relation);
if (create_rings()) {
add_tags_to_area(builder, relation);
add_rings_to_area(builder);
}
}
out_buffer.commit();
const osmium::TagList& area_tags = out_buffer.get<osmium::Area>(area_offset).tags(); // tags of the area we just built
if (m_inner_outer_mismatches == 0) {
auto memit = relation.members().begin();
for (size_t offset : members) {
if (!std::strcmp(memit->role(), "inner")) {
const osmium::Way& way = in_buffer.get<const osmium::Way>(offset);
if (way.is_closed() && way.tags().size() > 0) {
osmium::tags::KeyFilter filter(true);
filter.add(false, "created_by").add(false, "source").add(false, "note");
filter.add(false, "test:id").add(false, "test:section");
osmium::tags::KeyFilter::iterator fi_begin(filter, way.tags().begin(), way.tags().end());
osmium::tags::KeyFilter::iterator fi_end(filter, way.tags().end(), way.tags().end());
auto d = std::distance(fi_begin, fi_end);
if (d > 0) {
osmium::tags::KeyFilter::iterator area_fi_begin(filter, area_tags.begin(), area_tags.end());
osmium::tags::KeyFilter::iterator area_fi_end(filter, area_tags.end(), area_tags.end());
if (!std::equal(fi_begin, fi_end, area_fi_begin) || d != std::distance(area_fi_begin, area_fi_end)) {
Assembler assembler(m_config);
assembler(way, out_buffer);
}
}
}
}
++memit;
}
}
}
}; // class Assembler
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_ASSEMBLER_HPP
-242
View File
@@ -1,242 +0,0 @@
#ifndef OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
#define OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <algorithm>
#include <cstdint>
#include <cstring>
#include <iosfwd>
#include <utility>
#include <osmium/osm/location.hpp>
#include <osmium/osm/node_ref.hpp>
#include <osmium/util/operators.hpp>
namespace osmium {
class Way;
namespace area {
/**
* @brief Namespace for Osmium internal use
*/
namespace detail {
/**
* 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.
*/
class NodeRefSegment : osmium::totally_ordered<NodeRefSegment> {
osmium::NodeRef m_first;
osmium::NodeRef m_second;
/// Role of the member this segment was from.
const char* m_role;
/// Way this segment was from.
const osmium::Way* m_way;
public:
void swap_locations() {
using std::swap;
swap(m_first, m_second);
}
explicit NodeRefSegment() :
m_first(),
m_second(),
m_role(nullptr),
m_way(nullptr) {
}
explicit NodeRefSegment(const osmium::NodeRef& nr1, const osmium::NodeRef& nr2, const char* role, const osmium::Way* way) :
m_first(nr1),
m_second(nr2),
m_role(role),
m_way(way) {
if (nr2.location() < nr1.location()) {
swap_locations();
}
}
NodeRefSegment(const NodeRefSegment&) = default;
NodeRefSegment(NodeRefSegment&&) = default;
NodeRefSegment& operator=(const NodeRefSegment&) = default;
NodeRefSegment& operator=(NodeRefSegment&&) = default;
~NodeRefSegment() = default;
/// Return first NodeRef of Segment according to sorting order (bottom left to top right).
const osmium::NodeRef& first() const {
return m_first;
}
/// Return second NodeRef of Segment according to sorting order (bottom left to top right).
const osmium::NodeRef& second() const {
return m_second;
}
bool to_left_of(const osmium::Location location) const {
// std::cerr << "segment " << first() << "--" << second() << " to_left_of(" << location << "\n";
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;
}
bool role_outer() const {
return !strcmp(m_role, "outer");
}
bool role_inner() const {
return !strcmp(m_role, "inner");
}
const osmium::Way* way() const {
return m_way;
}
}; // class NodeRefSegment
/// NodeRefSegments are equal if both their locations are equal
inline bool operator==(const NodeRefSegment& lhs, const NodeRefSegment& rhs) {
return lhs.first().location() == rhs.first().location() && lhs.second().location() == rhs.second().location();
}
/**
* 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.
*/
inline bool operator<(const NodeRefSegment& lhs, const NodeRefSegment& rhs) {
return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
}
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();
}
inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) {
if (s1.first().location().x() > s2.second().location().x()) {
return true;
}
return false;
}
inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
auto m1 = std::minmax(s1.first().location().y(), s1.second().location().y());
auto m2 = std::minmax(s2.first().location().y(), s2.second().location().y());
if (m1.first > m2.second || m2.first > m1.second) {
return false;
}
return true;
}
/**
* Calculate the intersection between to NodeRefSegments. The result is returned
* as a Location. Note that because the Location uses integers with limited
* precision internally, the result might be slightly different than the
* numerically correct location.
*
* If the segments touch in one 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.
*
* @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()) {
return osmium::Location();
}
double denom = ((s2.second().lat() - s2.first().lat())*(s1.second().lon() - s1.first().lon())) -
((s2.second().lon() - s2.first().lon())*(s1.second().lat() - s1.first().lat()));
if (denom != 0) {
double nume_a = ((s2.second().lon() - s2.first().lon())*(s1.first().lat() - s2.first().lat())) -
((s2.second().lat() - s2.first().lat())*(s1.first().lon() - s2.first().lon()));
double nume_b = ((s1.second().lon() - s1.first().lon())*(s1.first().lat() - s2.first().lat())) -
((s1.second().lat() - s1.first().lat())*(s1.first().lon() - s2.first().lon()));
if ((denom > 0 && nume_a >= 0 && nume_a <= denom && nume_b >= 0 && nume_b <= denom) ||
(denom < 0 && nume_a <= 0 && nume_a >= denom && nume_b <= 0 && nume_b >= denom)) {
double ua = nume_a / denom;
double ix = s1.first().lon() + ua*(s1.second().lon() - s1.first().lon());
double iy = s1.first().lat() + ua*(s1.second().lat() - s1.first().lat());
return osmium::Location(ix, iy);
}
}
return osmium::Location();
}
} // namespace detail
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_DETAIL_NODE_REF_SEGMENT_HPP
-274
View File
@@ -1,274 +0,0 @@
#ifndef OSMIUM_AREA_DETAIL_PROTO_RING_HPP
#define OSMIUM_AREA_DETAIL_PROTO_RING_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <algorithm>
#include <cassert>
#include <iostream>
#include <list>
#include <set>
#include <vector>
#include <osmium/osm/node_ref.hpp>
#include <osmium/area/detail/node_ref_segment.hpp>
namespace osmium {
namespace area {
namespace detail {
/**
* A ring in the process of being built by the Assembler object.
*/
class ProtoRing {
public:
typedef std::vector<NodeRefSegment> segments_type;
private:
// 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)
std::vector<ProtoRing*> m_inner {};
public:
explicit ProtoRing(const NodeRefSegment& segment) :
m_segments() {
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());
}
bool outer() const {
return m_outer;
}
void set_inner() {
m_outer = false;
}
segments_type& segments() {
return m_segments;
}
const segments_type& segments() const {
return m_segments;
}
void remove_segments(segments_type::iterator sbegin, segments_type::iterator send) {
m_segments.erase(sbegin, send);
}
void add_segment_front(const NodeRefSegment& segment) {
m_segments.insert(m_segments.begin(), segment);
}
void add_segment_back(const NodeRefSegment& segment) {
m_segments.push_back(segment);
}
const NodeRefSegment& get_segment_front() const {
return m_segments.front();
}
NodeRefSegment& get_segment_front() {
return m_segments.front();
}
const NodeRefSegment& get_segment_back() const {
return m_segments.back();
}
NodeRefSegment& get_segment_back() {
return m_segments.back();
}
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());
}
return sum;
}
bool is_cw() const {
return sum() <= 0;
}
int64_t area() const {
return std::abs(sum()) / 2;
}
void swap_segments(ProtoRing& other) {
std::swap(m_segments, other.m_segments);
}
void add_inner_ring(ProtoRing* ring) {
m_inner.push_back(ring);
}
const std::vector<ProtoRing*> inner_rings() const {
return m_inner;
}
void print(std::ostream& out) const {
out << "[";
bool first = true;
for (const auto& segment : m_segments) {
if (first) {
out << segment.first().ref();
}
out << ',' << segment.second().ref();
first = false;
}
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;
}
}; // class ProtoRing
template <typename TChar, typename TTraits>
inline std::basic_ostream<TChar, TTraits>& operator<<(std::basic_ostream<TChar, TTraits>& out, const ProtoRing& ring) {
ring.print(out);
return out;
}
} // namespace detail
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_DETAIL_PROTO_RING_HPP
-216
View File
@@ -1,216 +0,0 @@
#ifndef OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
#define OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <algorithm>
#include <cassert>
#include <iostream>
#include <vector>
#include <osmium/area/problem_reporter.hpp>
#include <osmium/area/detail/node_ref_segment.hpp>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/way.hpp>
namespace osmium {
namespace area {
namespace detail {
/**
* This is a helper class for the area assembler. It models
* a list of segments.
*/
class SegmentList {
typedef std::vector<NodeRefSegment> slist_type;
slist_type m_segments {};
bool m_debug;
public:
explicit SegmentList(bool debug) :
m_debug(debug) {
}
~SegmentList() = default;
SegmentList(const SegmentList& other) = delete;
SegmentList(SegmentList&& other) = delete;
SegmentList& operator=(const SegmentList& other) = delete;
SegmentList& operator=(SegmentList&& other) = delete;
/// The number of segments in the list.
size_t size() const {
return m_segments.size();
}
bool empty() const {
return m_segments.empty();
}
typedef slist_type::const_iterator const_iterator;
const_iterator begin() const {
return m_segments.begin();
}
const_iterator end() const {
return m_segments.end();
}
/**
* Enable or disable debug output to stderr. This is for Osmium
* developers only.
*/
void enable_debug_output(bool debug=true) {
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());
}
/**
* 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?
*/
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;
}
}
/**
* 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;
}
}
/**
* Find duplicate segments (ie same start and end point) in the
* list and remove them. This will always remove pairs of the same
* segment. So if there are three, for instance, two will be
* removed and one will be left.
*/
void erase_duplicate_segments() {
while (true) {
auto it = std::adjacent_find(m_segments.begin(), m_segments.end());
if (it == m_segments.end()) {
return;
}
if (m_debug) {
std::cerr << " erase duplicate segment: " << *it << "\n";
}
m_segments.erase(it, it+2);
}
}
/**
* Find intersection between segments.
*
* @param problem_reporter Any intersections found are reported to this object.
* @returns true if there are intersections.
*/
bool find_intersections(osmium::area::ProblemReporter* problem_reporter) const {
if (m_segments.empty()) {
return false;
}
bool found_intersections = false;
for (auto it1 = m_segments.begin(); it1 != m_segments.end()-1; ++it1) {
const NodeRefSegment& s1 = *it1;
for (auto it2 = it1+1; it2 != m_segments.end(); ++it2) {
const NodeRefSegment& s2 = *it2;
assert(s1 != s2); // erase_duplicate_segments() should have made sure of that
if (outside_x_range(s2, s1)) {
break;
}
if (y_range_overlap(s1, s2)) {
osmium::Location intersection = calculate_intersection(s1, s2);
if (intersection) {
found_intersections = true;
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);
}
}
}
}
}
return found_intersections;
}
}; // class SegmentList
} // namespace detail
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_DETAIL_SEGMENT_LIST_HPP
-211
View File
@@ -1,211 +0,0 @@
#ifndef OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
#define OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
#include <vector>
#include <osmium/memory/buffer.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/relation.hpp>
#include <osmium/osm/tag.hpp>
#include <osmium/osm/way.hpp>
#include <osmium/relations/collector.hpp>
#include <osmium/relations/detail/member_meta.hpp>
namespace osmium {
struct invalid_location;
namespace relations {
class RelationMeta;
}
/**
* @brief Code related to the building of areas (multipolygons) from relations.
*/
namespace area {
/**
* This class collects all data needed for creating areas from
* relations tagged with type=multipolygon or type=boundary.
* Most of its functionality is derived from the parent class
* osmium::relations::Collector.
*
* The actual assembling of the areas is done by the assembler
* class given as template argument.
*
* @tparam TAssembler Multipolygon Assembler class.
*/
template <class TAssembler>
class MultipolygonCollector : public osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> {
typedef typename osmium::relations::Collector<MultipolygonCollector<TAssembler>, false, true, false> collector_type;
typedef typename TAssembler::config_type assembler_config_type;
const assembler_config_type m_assembler_config;
osmium::memory::Buffer m_output_buffer;
static constexpr size_t initial_output_buffer_size = 1024 * 1024;
static constexpr size_t max_buffer_size_for_flush = 100 * 1024;
void flush_output_buffer() {
if (this->callback()) {
this->callback()(m_output_buffer);
m_output_buffer.clear();
}
}
void possibly_flush_output_buffer() {
if (m_output_buffer.committed() > max_buffer_size_for_flush) {
flush_output_buffer();
}
}
public:
explicit MultipolygonCollector(const assembler_config_type& assembler_config) :
collector_type(),
m_assembler_config(assembler_config),
m_output_buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes) {
}
/**
* We are interested in all relations tagged with type=multipolygon or
* type=boundary.
*
* Overwritten from the base class.
*/
bool keep_relation(const osmium::Relation& relation) const {
const char* type = relation.tags().get_value_by_key("type");
// ignore relations without "type" tag
if (!type) {
return false;
}
if ((!strcmp(type, "multipolygon")) || (!strcmp(type, "boundary"))) {
return true;
}
return false;
}
/**
* Overwritten from the base class.
*/
bool keep_member(const osmium::relations::RelationMeta& /*relation_meta*/, const osmium::RelationMember& member) const {
// We are only interested in members of type way.
return member.type() == osmium::item_type::way;
}
/**
* This is called when a way is not in any multipolygon
* relation.
*
* Overwritten from the base class.
*/
void way_not_in_any_relation(const osmium::Way& way) {
if (way.ends_have_same_location() && way.nodes().size() > 3) {
// way is closed and has enough nodes, build simple multipolygon
try {
TAssembler assembler(m_assembler_config);
assembler(way, m_output_buffer);
possibly_flush_output_buffer();
} catch (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;
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
offsets.push_back(this->get_offset(member.type(), member.ref()));
}
}
try {
TAssembler assembler(m_assembler_config);
assembler(relation, offsets, this->members_buffer(), m_output_buffer);
possibly_flush_output_buffer();
} catch (osmium::invalid_location&) {
// XXX ignore
}
// clear member metas
for (const auto& member : relation.members()) {
if (member.ref() != 0) {
auto& mmv = this->member_meta(member.type());
auto range = std::equal_range(mmv.begin(), mmv.end(), osmium::relations::MemberMeta(member.ref()));
assert(range.first != range.second);
// if this is the last time this object was needed
// then mark it as removed
if (range.first + 1 == range.second) {
this->get_member(range.first->buffer_offset()).removed(true);
}
for (auto it = range.first; it != range.second; ++it) {
if (relation.id() == this->get_relation(it->relation_pos()).id()) {
mmv.erase(it);
break;
}
}
}
}
}
void flush() {
flush_output_buffer();
}
osmium::memory::Buffer read() {
osmium::memory::Buffer buffer(initial_output_buffer_size, osmium::memory::Buffer::auto_grow::yes);
std::swap(buffer, m_output_buffer);
return buffer;
}
}; // class MultipolygonCollector
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_MULTIPOLYGON_COLLECTOR_HPP
-149
View File
@@ -1,149 +0,0 @@
#ifndef OSMIUM_AREA_PROBLEM_REPORTER_HPP
#define OSMIUM_AREA_PROBLEM_REPORTER_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
namespace osmium {
namespace area {
/**
* When assembling a multipolygon/area from a multipolygon relation
* or a closed way several problems can be detected. This includes
* intersections between lines, wrong role attributes on relation
* members etc. These problems are reported by the area::Assembler
* class to the ProblemReporter class or one of its child classes.
*
* This is the parent class which does nothing with the reports.
* Child classes are expected to implement different ways of
* reporting the problems.
*/
class ProblemReporter {
protected:
// Type of object we are currently working on
osmium::item_type m_object_type;
// ID of the relation/way we are currently working on
osmium::object_id_type m_object_id;
public:
ProblemReporter() = default;
virtual ~ProblemReporter() = default;
/**
* Set the object the next problem reports will be on.
*
* @param object_type The type of the object.
* @param object_id The ID of the object.
*/
void set_object(osmium::item_type object_type, osmium::object_id_type object_id) {
m_object_type = object_type;
m_object_id = object_id;
}
// 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
#pragma GCC diagnostic ignored "-Wunused-parameter"
/**
* 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.
*/
virtual void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) {
}
/**
* Report an intersection between two segments.
*
* @param way1_id ID of the first involved way.
* @param way1_seg_start Location where the segment of the first way with the intersection starts
* @param way1_seg_end Location where the segment of the first way with the intersection ends
* @param way2_id ID of the second involved way.
* @param way2_seg_start Location where the segment of the second way with the intersection starts
* @param way2_seg_end Location where the segment of the second way with the intersection ends
* @param intersection Location of the intersection. This might be slightly off the correct location due to rounding.
*/
virtual 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) {
}
/**
* Report an open ring.
*
* @param end1 Location of the first open end.
* @param end2 Location of the second open end.
*/
virtual void report_ring_not_closed(osmium::Location end1, osmium::Location end2) {
}
/**
* 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.
*/
virtual void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
}
/**
* Report a segment that should have role "inner", 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.
*/
virtual void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) {
}
#pragma GCC diagnostic pop
}; // class ProblemReporter
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_PROBLEM_REPORTER_HPP
-96
View File
@@ -1,96 +0,0 @@
#ifndef OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
#define OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <sstream>
#include <stdexcept>
#include <osmium/area/problem_reporter_stream.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
namespace osmium {
namespace area {
class ProblemReporterException : public ProblemReporterStream {
std::stringstream m_sstream;
public:
ProblemReporterException() :
ProblemReporterStream(m_sstream) {
}
virtual ~ProblemReporterException() = default;
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
m_sstream.str();
ProblemReporterStream::report_duplicate_node(node_id1, node_id2, 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();
ProblemReporterStream::report_intersection(way1_id, way1_seg_start, way1_seg_end, way2_id, way2_seg_start, way2_seg_end, intersection);
throw std::runtime_error(m_sstream.str());
}
void report_ring_not_closed(osmium::Location end1, osmium::Location end2) override {
m_sstream.str();
ProblemReporterStream::report_ring_not_closed(end1, end2);
throw std::runtime_error(m_sstream.str());
}
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
m_sstream.str();
ProblemReporterStream::report_role_should_be_outer(way_id, seg_start, seg_end);
throw std::runtime_error(m_sstream.str());
}
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
m_sstream.str();
ProblemReporterStream::report_role_should_be_inner(way_id, seg_start, seg_end);
throw std::runtime_error(m_sstream.str());
}
}; // class ProblemReporterException
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_PROBLEM_REPORTER_EXCEPTION_HPP
-202
View File
@@ -1,202 +0,0 @@
#ifndef OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
#define OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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.
*/
#define OSMIUM_COMPILE_WITH_CFLAGS_OGR `gdal-config --cflags`
#define OSMIUM_LINK_WITH_LIBS_OGR `gdal-config --libs`
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wredundant-decls"
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
# include <ogr_api.h>
# include <ogrsf_frmts.h>
#pragma GCC diagnostic pop
#include <memory>
#include <stdexcept>
#include <osmium/area/problem_reporter.hpp>
#include <osmium/geom/ogr.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
namespace osmium {
namespace area {
/**
* Report problems when assembling areas by adding them to
* layers in an OGR datasource.
*/
class ProblemReporterOGR : public ProblemReporter {
osmium::geom::OGRFactory<> m_ogr_factory {};
OGRDataSource* m_data_source;
OGRLayer* m_layer_perror;
OGRLayer* m_layer_lerror;
void write_point(const char* problem_type, osmium::object_id_type id1, osmium::object_id_type id2, osmium::Location location) {
OGRFeature* feature = OGRFeature::CreateFeature(m_layer_perror->GetLayerDefn());
std::unique_ptr<OGRPoint> ogr_point = m_ogr_factory.create_point(location);
feature->SetGeometry(ogr_point.get());
feature->SetField("id1", static_cast<double>(id1));
feature->SetField("id2", static_cast<double>(id2));
feature->SetField("problem_type", problem_type);
if (m_layer_perror->CreateFeature(feature) != OGRERR_NONE) {
std::runtime_error("Failed to create feature on layer 'perrors'");
}
OGRFeature::DestroyFeature(feature);
}
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());
OGRFeature* feature = OGRFeature::CreateFeature(m_layer_lerror->GetLayerDefn());
feature->SetGeometry(ogr_linestring.get());
feature->SetField("id1", static_cast<double>(id1));
feature->SetField("id2", static_cast<double>(id2));
feature->SetField("problem_type", problem_type);
if (m_layer_lerror->CreateFeature(feature) != OGRERR_NONE) {
std::runtime_error("Failed to create feature on layer 'lerrors'");
}
OGRFeature::DestroyFeature(feature);
}
public:
explicit ProblemReporterOGR(OGRDataSource* data_source) :
m_data_source(data_source) {
OGRSpatialReference sparef;
sparef.SetWellKnownGeogCS("WGS84");
m_layer_perror = m_data_source->CreateLayer("perrors", &sparef, wkbPoint, nullptr);
if (!m_layer_perror) {
std::runtime_error("Layer creation failed for layer 'perrors'");
}
OGRFieldDefn layer_perror_field_id1("id1", OFTReal);
layer_perror_field_id1.SetWidth(10);
if (m_layer_perror->CreateField(&layer_perror_field_id1) != OGRERR_NONE) {
std::runtime_error("Creating field 'id1' failed for layer 'perrors'");
}
OGRFieldDefn layer_perror_field_id2("id2", OFTReal);
layer_perror_field_id2.SetWidth(10);
if (m_layer_perror->CreateField(&layer_perror_field_id2) != OGRERR_NONE) {
std::runtime_error("Creating field 'id2' failed for layer 'perrors'");
}
OGRFieldDefn layer_perror_field_problem_type("problem_type", OFTString);
layer_perror_field_problem_type.SetWidth(30);
if (m_layer_perror->CreateField(&layer_perror_field_problem_type) != OGRERR_NONE) {
std::runtime_error("Creating field 'problem_type' failed for layer 'perrors'");
}
/**************/
m_layer_lerror = m_data_source->CreateLayer("lerrors", &sparef, wkbLineString, nullptr);
if (!m_layer_lerror) {
std::runtime_error("Layer creation failed for layer 'lerrors'");
}
OGRFieldDefn layer_lerror_field_id1("id1", OFTReal);
layer_lerror_field_id1.SetWidth(10);
if (m_layer_lerror->CreateField(&layer_lerror_field_id1) != OGRERR_NONE) {
std::runtime_error("Creating field 'id1' failed for layer 'lerrors'");
}
OGRFieldDefn layer_lerror_field_id2("id2", OFTReal);
layer_lerror_field_id2.SetWidth(10);
if (m_layer_lerror->CreateField(&layer_lerror_field_id2) != OGRERR_NONE) {
std::runtime_error("Creating field 'id2' failed for layer 'lerrors'");
}
OGRFieldDefn layer_lerror_field_problem_type("problem_type", OFTString);
layer_lerror_field_problem_type.SetWidth(30);
if (m_layer_lerror->CreateField(&layer_lerror_field_problem_type) != OGRERR_NONE) {
std::runtime_error("Creating field 'problem_type' failed for layer 'lerrors'");
}
}
virtual ~ProblemReporterOGR() = default;
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
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_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_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);
}
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);
}
}; // class ProblemReporterOGR
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_PROBLEM_REPORTER_OGR_HPP
-96
View File
@@ -1,96 +0,0 @@
#ifndef OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
#define OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP
/*
This file is part of Osmium (http://osmcode.org/libosmium).
Copyright 2014 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 <ostream>
#include <osmium/area/problem_reporter.hpp>
#include <osmium/osm/item_type.hpp>
#include <osmium/osm/location.hpp>
#include <osmium/osm/types.hpp>
namespace osmium {
namespace area {
class ProblemReporterStream : public ProblemReporter {
std::ostream& m_out;
public:
explicit ProblemReporterStream(std::ostream& out) :
m_out(out) {
}
virtual ~ProblemReporterStream() = default;
void header(const char* msg) {
m_out << "DATA PROBLEM: " << msg << " on " << item_type_to_char(m_object_type) << m_object_id << ": ";
}
void report_duplicate_node(osmium::object_id_type node_id1, osmium::object_id_type node_id2, osmium::Location location) override {
header("duplicate node");
m_out << "node_id1=" << node_id1 << " node_id2=" << node_id2 << " 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");
m_out << "way1_id=" << way1_id << " way1_seg_start=" << way1_seg_start << " way1_seg_end=" << way1_seg_end
<< " 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 {
header("ring not closed");
m_out << "end1=" << end1 << " end2=" << end2 << "\n";
}
void report_role_should_be_outer(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
header("role should be outer");
m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
}
void report_role_should_be_inner(osmium::object_id_type way_id, osmium::Location seg_start, osmium::Location seg_end) override {
header("role should be inner");
m_out << "way_id=" << way_id << " seg_start=" << seg_start << " seg_end=" << seg_end << "\n";
}
}; // class ProblemReporterStream
} // namespace area
} // namespace osmium
#endif // OSMIUM_AREA_PROBLEM_REPORTER_STREAM_HPP