Esempio n. 1
0
 inline bool y_range_overlap(const NodeRefSegment& s1, const NodeRefSegment& s2) {
     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) {
         return false;
     }
     return true;
 }
Esempio n. 2
0
            /**
             * Calculate the intersection between two 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.
             *
             * This function uses integer arithmentic 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 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();
                }

                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);

                if (d != 0) {
                    int64_t na = (s2bx - s2ax) * (s1ay - s2ay) -
                                 (s2by - s2ay) * (s1ax - s2ax);

                    int64_t nb = (s1bx - s1ax) * (s1ay - s2ay) -
                                 (s1by - s1ay) * (s1ax - s2ax);

                    if ((d > 0 && na >= 0 && na <= d && nb >= 0 && nb <= d) ||
                        (d < 0 && na <= 0 && na >= d && nb <= 0 && nb >= d)) {

                        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(ix, iy);
                    }
                }

                return osmium::Location();
            }
            /**
             * 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 {
                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();
            }
Esempio n. 4
0
 inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
     if (s1.first().location().x() > s2.second().location().x()) {
         return true;
     }
     return false;
 }
Esempio n. 5
0
 /**
  * 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) noexcept {
     return (lhs.first().location() == rhs.first().location() && lhs.second().location() < rhs.second().location()) || lhs.first().location() < rhs.first().location();
 }
            /**
             * Calculate the intersection between two 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.
             *
             * 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 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 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) 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{};
                }

                const vec pd = p1 - p0;
                const int64_t d = pd * (q1 - q0);

                if (d != 0) {
                    // segments are not collinear

                    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)};
                    }

                    return osmium::Location{};
                }

                // 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& lhs, const seg_loc& rhs) {
                        return lhs.location < rhs.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;
                        }
                        return sl[1].location;
                    }
                }

                return osmium::Location{};
            }
 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());
     return !(m1.first > m2.second || m2.first > m1.second);
 }
 inline bool outside_x_range(const NodeRefSegment& s1, const NodeRefSegment& s2) noexcept {
     return s1.first().location().x() > s2.second().location().x();
 }
#include "catch.hpp"

#include <osmium/area/detail/node_ref_segment.hpp>

using osmium::area::detail::NodeRefSegment;

TEST_CASE("NodeRefSegmentClass") {

    SECTION("instantiation_with_default_parameters") {
        NodeRefSegment s;
        REQUIRE(s.first().ref() == 0);
        REQUIRE(s.first().location() == osmium::Location());
        REQUIRE(s.second().ref() == 0);
        REQUIRE(s.second().location() == osmium::Location());
    }

    SECTION("instantiation") {
        osmium::NodeRef nr1(1, { 1.2, 3.4 });
        osmium::NodeRef nr2(2, { 1.4, 3.1 });
        osmium::NodeRef nr3(3, { 1.2, 3.6 });
        osmium::NodeRef nr4(4, { 1.2, 3.7 });

        NodeRefSegment s1(nr1, nr2);
        REQUIRE(s1.first().ref() == 1);
        REQUIRE(s1.second().ref() == 2);

        NodeRefSegment s2(nr2, nr3);
        REQUIRE(s2.first().ref() == 3);
        REQUIRE(s2.second().ref() == 2);

        NodeRefSegment s3(nr3, nr4);