如何从boost :: geometry :: model :: polygon获取多边形?

时间:2016-05-06 11:17:14

标签: c++ boost boost-geometry

我正在尝试使用boost::geometry::difference计算两个多边形的差异,boost::geometry::model::polygon代表我的多边形。

如果第一个多边形包含第二个结果,则操作的结果是单个boost::geometry::model::polygon,内圈和外圈填充了源多边形的坐标。

如何从boost::geometry::model::polygon获取多边形(in the elementary geometry sense)?

澄清:

  

在基本几何中,多边形是一个平面图形,由一条有限的直线段链接而成,这些直线段在一个环中闭合,形成一个封闭的链或电路。

boost::geometry::model::polygon的外环是多边形,内环也是多边形。整体而言boost::geometry::model::polygon不是多边形。

所以,我在问:如何将boost::geometry::model::polygon转换为普通多边形(具有单条直线段链),它代表平面上的相同区域。

以下是我想要实现的目标:

polygon1   = (0,0), (0,8), (8,8), (8,0), (0,0)
polygon2   = (2,2), (2,6), (6,6), (6,2), (2,2)

多边形1& 2 in green / oker:

difference = (0,0), (0,4), (2,4), (2,2), (6,2), (6,6), (2,6), (2,4), (0,4), (0,8), (8,8), (8,0), (0,0)

灰色的预期差异:

我知道具有内环的相同boost::geometry::model::polygon可以由无数多个不同的普通多边形表示。我不在乎我得到哪一个。

2 个答案:

答案 0 :(得分:1)

您可以轻松构建一个模拟预期弱简单多边形的环。第一:

买者

请注意,结果无法与Boost Geometry库的算法一起使用。

以你的文字为例:

std::string reason;
poly expected;
bg::read_wkt("POLYGON((0 0, 0 4, 2 4, 2 2, 6 2, 6 6, 2 6, 2 4, 0 4, 0 8, 8 8, 8 0, 0 0))", expected);
bool ok = bg::is_valid(expected, reason);
std::cout << "Expected: " << bg::dsv(expected) << (ok?" valid":" invalid: '" + reason + "'") << "\n";

打印

  

期望:(((0,0),(0,4),(2,4),(2,2),(6,2),(6,6),(2,6),( 2,4),(0,4),(0,8),(8,8),(8,0),(0,0)))无效:'几何具有无效的自相交。在(0,4)处发现了自交点;方法:t;操作:x / u;段ID {source,multi,ring,segment}:{0,-1,-1,0} / {0,-1,-1,7}'

算法实现

有了这个,这里有一个简单的算法来构造给定多边形的简单弱多边形:

ring weak_simple_ring(poly& p) {
    ring r = p.outer();

    for (auto& i: p.inners()) {
        auto last = r.back();
        r.insert(r.end(), i.rbegin(), i.rend());
        r.insert(r.end(), last);
    }

    return r;
}

唯一更微妙的一点就是反转内圈的方向(CW / CCW)以匹配外圈的方向。

该算法不会试图找到内环的切点,这也可能意味着它对于具有多个内环的通用情况不会很好地工作。

样本

这是一个完整的现场演示

<强> Live On Coliru

输入为

bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 2, 2 6, 6 6, 6 2, 2 2))", b);

转型是

std::vector<poly> output;
bg::difference(a, b, output);

for (auto& p : output) {
    ring r = weak_simple_ring(p);
    bg::convert(r, p);
}

结果变为

更复杂的样本

考虑b何时有漏洞:

bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 2, 2 6, 6 6, 6 2, 2 2)(3 3, 5 3, 5 5, 3 5, 3 3))", b);

具有相同代码的输出变为

答案 1 :(得分:0)

  

这是旧答案。在编辑问题后,我发布了a simple implementation of an algorithm that suits the sample given

已经是。

如果你的意思是,&#34;简单&#34;无孔的多边形,外圈就是你想要的。只需丢弃内圈。

但是,在最通用的情况下,您最终可能会有多个完全不相关的多边形,这就是the output is a collection of polygons的原因。你也必须考虑这种可能性(可选择将不同的结果多边形连接到一个并丢弃内环,如果这是你想要的,在功能上)。

样本:

bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
bg::read_wkt("POLYGON((2 -2,2 12,5 12,5 -2,2 -2))", b);

此处,ba分成两个单独的部分。因此,您必须准备好处理多个,不相交的输出多边形:

<强> Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/io.hpp>
#include <iostream>
#include <fstream>

namespace bg = boost::geometry;
using pt   = bg::model::d2::point_xy<int>;
using poly = bg::model::polygon<pt>;

int main() {
    poly a, b;
    bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", a);
    bg::read_wkt("POLYGON((2 -2,2 12,5 12,5 -2,2 -2))", b);

    std::cout << bg::dsv(a) << "\n";
    std::cout << bg::dsv(b) << "\n";

    {
        std::ofstream svg("/tmp/input.svg");
        boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
        mapper.add(a);
        mapper.add(b);

        mapper.map(a, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
        mapper.map(b, "fill-opacity:0.5;fill:rgb(204,153,0);stroke:rgb(202,153,0);stroke-width:2");
    }

    std::vector<poly> output;
    bg::difference(a, b, output);
    for (auto& p : output)
        std::cout << "\n\t" << bg::dsv(p);

    {
        std::ofstream svg("/tmp/output.svg");
        boost::geometry::svg_mapper<pt> mapper(svg, 400, 400);
        assert(output.size() == 2);
        mapper.add(output[0]);
        mapper.add(output[1]);
        mapper.add(b);

        mapper.map(output[0], "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
        mapper.map(output[1], "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2");
        mapper.map(b, "fill-opacity:0.15;fill:rgb(153,153,153);stroke-width:0");
    }
}

打印:

(((0, 0), (0, 10), (10, 10), (10, 0), (0, 0)))
(((2, -2), (2, 12), (5, 12), (5, -2), (2, -2)))

    (((5, 10), (10, 10), (10, 0), (5, 0), (5, 10)))
    (((2, 10), (2, 0), (0, 0), (0, 10), (2, 10)))

呈现的SVG:

enter image description here