【问题标题】:Find Boost rtree elements inside a polygon在多边形内查找 Boost rtree 元素
【发布时间】:2018-05-25 22:48:42
【问题描述】:

我想使用 Boost C++ 库查找与多边形外环相交但不完全位于任何孔内的 rtree 中索引的所有元素。

我知道如何让元素与外环相交:

// Constructing the exterior ring polygon
Boost2dRing p;
for (int i = 0; i < numPunts; i++)
{
    x = Punts.at(i).x;
    y = Punts.at(i).y;
    p.push_back(Boost2dPoint(x, y));
}

// Getting the intersecting elements with that polygon
m_RTree.query(bgi::intersects(p), std::back_inserter(res));
...
// Constructing the polygon for the inner ring (hole)
Boost2dRing p;
for (int i = 0; i < numPuntsHole; i++)
{
    x = PuntsHole.at(i).x;
    y = PuntsHole.at(i).y;
    pHole.push_back(Boost2dPoint(x, y));
}

// Now I try to get the elements inside completely this polygon but I get a compilation error
m_RTree.query(bgi::within(pHole), std::back_inserter(res));

错误信息:

错误 C2664:'int boost::mpl::assertion_failed(boost::mpl::assert::type)': 无法从 'boost::mpl::failed 转换参数 1 ************(__cdecl boost::geometry::strategy::within::services::default_strategy::NOT_IMPLEMENTED_FOR_THESE_TYPES::* ***********)(boost::mpl::assert_::types)' 到 'boost::mpl::assert::type' 1> with 1> [ 1> Geometry1=Boost2dBox,1> Geometry2=Boost2dRing,1>
GeometryContained=Boost2dBox, 1>
GeometryContaining=Boost2dRing 1> ] 注意:没有构造函数 可以采用源类型,或者构造函数重载决议是 模棱两可

有什么实现这个目标的提示吗?

【问题讨论】:

    标签: c++ boost boost-geometry


    【解决方案1】:

    对于您选择的几何操作数,未实现 within 谓词。

    但是,您可以用更多 更少的工作来做您想做的事。假设你有你的戒指,例如:

    Boost2dRing exterior, interior;
    bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1))", exterior);
    bg::read_wkt("POLYGON((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2))", interior);
    

    现在,Boost Geometry 有了Polygon 的概念,它是一个外环和(多个)内环:

    多边形是由一个外部边界和零个或多个内部边界定义的平面表面 (OGC Simple Feature Specification)

    所以,让我们用它来代替:

    bg::reverse(interior);
    Boost2dPolygon polygon;
    polygon.outer() = exterior;
    polygon.inners().push_back(interior);
    

    注意内圈的方向是颠倒的。

    或者,实际上,直接使用构造函数:

    Boost2dPolygon polygon({exterior, interior});
    

    或者,甚至一次从 WKT 读取它:

    bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1) (0.2 0.2,0.4 0.2,0.4 0.4,0.2 0.4,0.2 0.2))", polygon);
    

    现在您可以一次性查询:

    std::vector<RTree::value_type> res;
    m_RTree.query(bgi::intersects(polygon), std::back_inserter(res));
    

    完整演示!

    鉴于以下sample() 树内容:

    using RTree = bgi::rtree<std::pair<Boost2dBox, std::string>, bgi::rstar<16> >;
    RTree sample() {
        RTree tree;
    
        std::pair<std::string, std::string> items[] = {
            { "BOX(0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2)",           "ok" },
            { "BOX(0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28)", "within gap" },
            { "BOX(0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28)", "small overlap" },
            { "BOX(2 2,2 4,4 4,4 2,2 2)",                               "outside exterior" },
        };
        for (auto& item : items) {
            Boost2dBox box;
            bg::read_wkt(item.first, box);
            checks("box", box);
            tree.insert({box, item.second});
        }
    
        return tree;
    }
    

    我们可以手动测试:

    RTree const m_RTree = sample();
    
    std::cout << "Sample tree:\n";
    for (auto& value : m_RTree) {
        std::cout << " - " << std::quoted(value.second) << ": " << bg::wkt(value.first) << "\n";
    
        Boost2dMultiPolygon mp;
        if (bg::intersection(polygon, value.first, mp))
            std::cout << "      (intersection is " << bg::wkt(mp) << ")\n";
    }
    

    打印出来的

    Sample tree:
     - "ok": POLYGON((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2))
          (intersection is MULTIPOLYGON(((0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2),(0.25 0.25,0.35 0.25,0.35 0.35,0.25 0.35,0.25 0.25))))
     - "within gap": POLYGON((0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28))
          (intersection is MULTIPOLYGON())
     - "small overlap": POLYGON((0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28))
          (intersection is MULTIPOLYGON(((0.35 0.32,0.36 0.32,0.36 0.28,0.35 0.28,0.35 0.32))))
     - "outside exterior": POLYGON((2 2,2 4,4 4,4 2,2 2))
          (intersection is MULTIPOLYGON())
    

    并验证与树查询比较的结果:

    m_RTree.query(bgi::intersects(polygon), std::back_inserter(matches));
    
    std::cout << "Intersecting with: ";
    for (auto& match : matches) std::cout << " " << std::quoted(match.second) << " ";
    

    哪些打印:

    Intersecting with:  "ok"  "small overlap" 
    

    全部查看Live On Coliru

    #include <boost/geometry.hpp>
    #include <boost/geometry/geometries/point_xy.hpp>
    #include <boost/geometry/geometries/multi_polygon.hpp>
    #include <boost/geometry/geometries/linestring.hpp>
    #include <boost/geometry/geometries/multi_polygon.hpp>
    #include <boost/geometry/core/cs.hpp>
    #include <boost/geometry/arithmetic/arithmetic.hpp>
    #include <boost/geometry/algorithms/within.hpp>
    #include <boost/geometry/algorithms/intersects.hpp>
    #include <boost/geometry/algorithms/envelope.hpp>
    #include <boost/geometry/algorithms/intersection.hpp>
    #include <boost/geometry/index/rtree.hpp>
    #include <boost/geometry/index/predicates.hpp>
    #include <boost/geometry/index/adaptors/query.hpp>
    #include <boost/geometry/io/io.hpp>
    #include <iostream>
    #include <fstream>
    
    namespace bg = boost::geometry;
    namespace bgi = boost::geometry::index;
    
    using Boost2dPoint        = bg::model::d2::point_xy<double>;
    using Boost2dRing         = bg::model::ring<Boost2dPoint>;
    using Boost2dPolygon      = bg::model::polygon<Boost2dPoint>;
    using Boost2dMultiPolygon = bg::model::multi_polygon<Boost2dPolygon>;
    using Boost2dBox          = bg::model::box<Boost2dPoint>;
    
    template <typename G> void checks(std::string name, G& geom) {
        std::cout << name << ": " << bg::wkt(geom) << "\n";
    
        std::string reason;
        if (!bg::is_valid(geom, reason)) {
            std::cout << name << ": " << reason << "\n";
    
            bg::correct(geom);
    
            std::cout << bg::wkt(geom) << "\n";
            if (!bg::is_valid(geom, reason)) {
                std::cout << name << " corrected: " << reason << "\n";
            }
        }
    }
    
    using RTree = bgi::rtree<std::pair<Boost2dBox, std::string>, bgi::rstar<16> >;
    RTree sample() {
        RTree tree;
    
        std::pair<std::string, std::string> items[] = {
            { "BOX(0.2 0.2,0.2 0.4,0.4 0.4,0.4 0.2,0.2 0.2)",           "ok" },
            { "BOX(0.28 0.28,0.28 0.32,0.32 0.32,0.32 0.28,0.28 0.28)", "within gap" },
            { "BOX(0.28 0.28,0.28 0.32,0.36 0.32,0.36 0.28,0.28 0.28)", "small overlap" },
            { "BOX(2 2,2 4,4 4,4 2,2 2)",                               "outside exterior" },
        };
        for (auto& item : items) {
            Boost2dBox box;
            bg::read_wkt(item.first, box);
            checks("box", box);
            tree.insert({box, item.second});
        }
    
        return tree;
    }
    
    int main() {
        Boost2dPolygon polygon;
        bg::read_wkt("POLYGON((0.1 0.1,0.1 0.5,0.5 0.5,0.5 0.1,0.1 0.1) (0.25 0.25,0.35 0.25,0.35 0.35,0.25 0.35,0.25 0.25))", polygon);
        checks("polygon", polygon);
    
        RTree const m_RTree = sample();
    
        std::cout << "Sample tree:\n";
        for (auto& value : m_RTree) {
            std::cout << " - " << std::quoted(value.second) << ": " << bg::wkt(value.first) << "\n";
    
            Boost2dMultiPolygon mp;
            if (bg::intersection(polygon, value.first, mp))
                std::cout << "      (intersection is " << bg::wkt(mp) << ")\n";
        }
        std::cout << "\n";
    
        std::vector<RTree::value_type> matches;
        m_RTree.query(bgi::intersects(polygon), std::back_inserter(matches));
    
        std::cout << "Intersecting with: ";
        for (auto& match : matches) std::cout << " " << std::quoted(match.second) << " ";
        std::cout << "\n";
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 2012-04-30
    • 1970-01-01
    • 2021-04-25
    • 2011-06-17
    • 1970-01-01
    • 2013-07-14
    相关资源
    最近更新 更多