Esempio n. 1
0
                /**
                 * 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;
                }
Esempio n. 2
0
/**
 * Checks if there are intersections between any coastline segments.
 * Returns the number of intersections and overlaps.
 */
unsigned int CoastlineRingCollection::check_for_intersections(OutputDatabase& output, int segments_fd) {
    unsigned int overlaps = 0;

    std::vector<osmium::UndirectedSegment> segments;
    if (debug) std::cerr << "Setting up segments...\n";
    for (const auto& ring : m_list) {
        ring->add_segments_to_vector(segments);
    }

    if (debug) std::cerr << "Sorting...\n";
    std::sort(segments.begin(), segments.end());

    if (segments_fd >= 0) {
        if (debug) std::cerr << "Writing segments to file...\n";
        ssize_t length = segments.size() * sizeof(osmium::UndirectedSegment);
#ifndef _MSC_VER
        if (::write(segments_fd, segments.data(), length) != length) {
#else
        if (_write(segments_fd, segments.data(), length) != length) {
#endif
            throw std::runtime_error{"Write error"};
        }
    }

    if (debug) std::cerr << "Finding intersections...\n";
    std::vector<osmium::Location> intersections;
    for (auto it1 = segments.cbegin(); it1 != segments.cend()-1; ++it1) {
        const osmium::UndirectedSegment& s1 = *it1;
        for (auto it2 = it1+1; it2 != segments.cend(); ++it2) {
            const osmium::UndirectedSegment& s2 = *it2;
            if (s1 == s2) {
                std::unique_ptr<OGRLineString> line = create_ogr_linestring(s1);
                output.add_error_line(std::move(line), "overlap");
                overlaps++;
            } else {
                if (outside_x_range(s2, s1)) {
                    break;
                }
                if (y_range_overlap(s1, s2)) {
                    osmium::Location i = intersection(s1, s2);
                    if (i) {
                        intersections.push_back(i);
                    }
                }
            }
        }
    }

    for (const auto& intersection : intersections) {
        std::unique_ptr<OGRPoint> point{new OGRPoint(intersection.lon(), intersection.lat())};
        output.add_error_point(std::move(point), "intersection");
    }

    return intersections.size() + overlaps;
}

bool CoastlineRingCollection::close_antarctica_ring(int epsg) {
    for (const auto& ring : m_list) {
        const osmium::Location fpos = ring->first_position();
        const osmium::Location lpos = ring->last_position();
        if (fpos.lon() > 179.99 && lpos.lon() < -179.99 &&
            fpos.lat() <  -77.0 && fpos.lat() >  -78.0 &&
            lpos.lat() <  -77.0 && lpos.lat() >  -78.0) {

            m_end_nodes.erase(ring->last_node_id());
            m_start_nodes.erase(ring->first_node_id());
            ring->close_antarctica_ring(epsg);
            return true;
        }
    }
    return false;
}

void CoastlineRingCollection::close_rings(OutputDatabase& output, bool debug, double max_distance) {
    std::vector<Connection> connections;

    // Create vector with all possible combinations of connections between rings.
    for (idmap_type::iterator eit = m_end_nodes.begin(); eit != m_end_nodes.end(); ++eit) {
        for (idmap_type::iterator sit = m_start_nodes.begin(); sit != m_start_nodes.end(); ++sit) {
            const double distance = (*sit->second)->distance_to_start_position((*eit->second)->last_position());
            if (distance < max_distance) {
                connections.emplace_back(distance, eit->first, sit->first);
            }
        }
    }

    // Sort vector by distance, shortest at end.
    std::sort(connections.begin(), connections.end(), Connection::sort_by_distance);

    // Go through vector starting with the shortest connections and close rings
    // using the connections in turn.
    while (!connections.empty()) {
        Connection conn = connections.back();
        connections.pop_back();

        // Invalidate all other connections using one of the same end points.
        connections.erase(remove_if(connections.begin(), connections.end(), conn), connections.end());

        idmap_type::iterator eit = m_end_nodes.find(conn.start_id);
        idmap_type::iterator sit = m_start_nodes.find(conn.end_id);

        if (eit != m_end_nodes.end() && sit != m_start_nodes.end()) {
            if (debug) {
                std::cerr << "Closing ring between node " << conn.end_id << " and node " << conn.start_id << "\n";
            }

            m_fixed_rings++;

            CoastlineRing* e = eit->second->get();
            CoastlineRing* s = sit->second->get();

            output.add_error_point(e->ogr_last_point(), "fixed_end_point", e->last_node_id());
            output.add_error_point(s->ogr_first_point(), "fixed_end_point", s->first_node_id());

            if (e->last_position() != s->first_position()) {
                std::unique_ptr<OGRLineString> linestring{new OGRLineString};
                linestring->addPoint(e->last_position().lon(), e->last_position().lat());
                linestring->addPoint(s->first_position().lon(), s->first_position().lat());
                output.add_error_line(std::move(linestring), "added_line");
            }

            if (e == s) {
                // connect to itself by closing ring
                e->close_ring();

                m_end_nodes.erase(eit);
                m_start_nodes.erase(sit);
            } else {
                // connect to other ring
                e->join_over_gap(*s);

                m_list.erase(sit->second);
                if (e->first_position() == e->last_position()) {
                    output.add_error_point(e->ogr_first_point(), "double_node", e->first_node_id());
                    m_start_nodes.erase(e->first_node_id());
                    m_end_nodes.erase(eit);
                    m_start_nodes.erase(sit);
                    m_end_nodes.erase(e->last_node_id());
                    e->fake_close();
                } else {
                    m_end_nodes[e->last_node_id()] = eit->second;
                    m_end_nodes.erase(eit);
                    m_start_nodes.erase(sit);
                }
            }
        }
    }
}