简体   繁体   中英

Boost geometry returning inconsistent results for intersects and intersection

In my application I'm using boost geometry to perform mainly intersection and difference calculations. Unfortunately I noticed an inconsistency in the results of:

  • bg::intersects and
  • bg::intersection

在此处输入图像描述

What I do is:

  1. Calculate the intersection of polygon1 and polygon2 (= polygon3).
  2. Remove (bg::difference) this intersection from polygon1 (= poly4)
  3. The resulting polygon4 should not have any intersection with poly2.
#include <iostream>
#include <boost/geometry.hpp>

namespace bg = boost::geometry;
using point_t = bg::model::d2::point_xy<double>;
using polygon_t = bg::model::polygon<point_t>;
using mpolygon_t = bg::model::multi_polygon<polygon_t>;

int main()
{
    polygon_t poly1, poly2;
    mpolygon_t poly3, poly4, poly5;

    bg::read_wkt("POLYGON(("
        "12227.0 4967.0000000000009, 12238.0 4967.0000000000009, "
        "12238.0 4813.0000000000009, 12227.0 4813.0000000000009, "
        "12227.0 4967.0000000000009))", poly1);
    bg::read_wkt("POLYGON(("
        "12254.0 4947.0, 12219.0 4982.0, 12219.0 5020.0, 12254.0 5055.0, "
        "12261.0 5055.0, 12263.0 5055.0, 12283.0 5055.0, 12283.0 4947.0, "
        "12263.0 4947.0, 12261.0 4947.0, 12254.0 4947.0))", poly2);

    bg::intersection(poly1, poly2, poly3);
    bg::difference(poly1, poly3[0], poly4);

    // b0 = true, b1 = false
    bool b0 = bg::intersects(poly2, poly4[0]);
    bool b1 = bg::intersection(poly2, poly4, poly5) && (poly5.size() != 0);

    bool b2 = !bg::disjoint(poly2, poly4[0]) && !bg::touches(poly2, poly4[0]);
    bool b3 = bg::overlaps(poly2, poly4[0]) || bg::within(poly4[0], poly2) || bg::within(poly2, poly4[0]);

    std::cout << b0 << b1 << b2 << b3 << std::endl;
    return 1;
}

The weird thing is that bg::intersects returns true while bg::intersection returns an empty intersection.

Does anyone have an idea why this happens? (Maybe accuracy problem?) and even more interesting: How can I avoid such problems?

I tried to avoid "intersects" by using other functions but the results were not helpful. Please see calculations for b2 and b3.

PS: Unfortunately the example seems cause a crash on coliru.

In fact the return value of the intersection function is unspecified: see

What does boost::geometry::intersection return

So, you need to look at the intersection itself:

#include <iostream>
#include <boost/geometry.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>

using boost::tribool;
using boost::indeterminate;

namespace bg = boost::geometry;
using Coord = double;
using point_t = bg::model::d2::point_xy<Coord>;
using polygon_t = bg::model::polygon<point_t>;
using mpolygon_t = bg::model::multi_polygon<polygon_t>;

int main() {
    polygon_t a, b;

    bg::read_wkt("POLYGON(("
        "12227.0 4967.0000000000009, 12238.0 4967.0000000000009, "
        "12238.0 4813.0000000000009, 12227.0 4813.0000000000009, "
        "12227.0 4967.0000000000009))", a);
    bg::read_wkt("POLYGON(("
        "12254.0 4947.0, 12219.0 4982.0, 12219.0 5020.0, 12254.0 5055.0, "
        "12261.0 5055.0, 12263.0 5055.0, 12283.0 5055.0, 12283.0 4947.0, "
        "12263.0 4947.0, 12261.0 4947.0, 12254.0 4947.0))", b);

#define CHECK(expected, expr)                                                  \
    do {                                                                       \
        auto const& actual = (expr);                                           \
        auto ok = ((expected) == actual);                                      \
        if (ok == true) {                                                      \
            std::cout << "PASS";                                               \
        } else if (ok == false) {                                              \
            std::cout << "FAIL";                                               \
        } else {                                                               \
            std::cout << "?";                                                  \
        }                                                                      \
        std::cout << "\t" << #expr << " -> " << std::boolalpha << actual       \
                  << "\n";                                                     \
        if (!(ok == true))                                                               \
            std::cout << "  (expected value was " << (expected) << ")\n";      \
    } while (false)

    mpolygon_t ab_intersect;
    auto dump = [](auto label, auto& geo) {
        std::cout << label << " area " << bg::area(geo) << " " << bg::wkt(geo) << "\n";
    };

    CHECK(true, bg::intersection(a, b, ab_intersect));
    CHECK(1, ab_intersect.size());
    dump("a", a);
    dump("b", b);
    dump("ab_intersect", ab_intersect);

    mpolygon_t a_minus_b, b_minus_a;
    bg::difference(a, ab_intersect, a_minus_b);
    bg::difference(b, ab_intersect, b_minus_a);
    CHECK(1, a_minus_b.size());
    CHECK(1, b_minus_a.size());
    dump("a_minus_b", a_minus_b);
    dump("b_minus_a", b_minus_a);

    auto checks = [dump](auto& reduced, auto& other) {
        CHECK(true, bg::intersects(reduced, other));

        mpolygon_t check;
        bg::intersection(reduced, other, check);

        CHECK(true, check.empty());
        dump("check", check);
    };

    std::cout << "-- reduced a vs b: -------\n";
    checks(a_minus_b, b);
    std::cout << "-- reduced b vs a: -------\n";
    checks(b_minus_a, a);
}

Prints

PASS    bg::intersection(a, b, ab_intersect) -> true
PASS    ab_intersect.size() -> 1
a area 1694 POLYGON((12227 4967,12238 4967,12238 4813,12227 4813,12227 4967))
b area 5687 POLYGON((12254 4947,12219 4982,12219 5020,12254 5055,12261 5055,12263 5055,12283 5055,12283 4947,12263 4947,12261 4947,12254 4947))
ab_intersect area 8 MULTIPOLYGON(((12234 4967,12238 4967,12238 4963,12234 4967)))
PASS    a_minus_b.size() -> 1
PASS    b_minus_a.size() -> 1
a_minus_b area 1686 MULTIPOLYGON(((12234 4967,12238 4963,12238 4813,12227 4813,12227 4967,12234 4967)))
b_minus_a area 5679 MULTIPOLYGON(((12238 4963,12238 4967,12234 4967,12219 4982,12219 5020,12254 5055,12261 5055,12263 5055,12283 5055,12283 4947,12263 4947,12261 4947,12254 4947,12238 4963)))
-- reduced a vs b: -------
PASS    bg::intersects(reduced, other) -> true
PASS    check.empty() -> true
check area 0 MULTIPOLYGON()
-- reduced b vs a: -------
PASS    bg::intersects(reduced, other) -> true
PASS    check.empty() -> true
check area 0 MULTIPOLYGON()

The behavior I mentioned is not a bug but fully correct:

bg::intersection() returns an empty polygon BUT

if I call it with a linestring as output parameter:

using linestring_t = bg::model::linestring<point_t>;
linestring_t int1;
bg::intersection(poly2, poly4, int1);
std::cout << "int1: " << bg::wkt(int1) << std::endl;

it works.

TL;DR The usage and my interpretation of bg::intersects() and bg::intersection() was wrong!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM