簡體   English   中英

如何從 boost::geometry::model::polygon 獲取多邊形?

[英]How to get a polygon from boost::geometry::model::polygon?

我正在嘗試使用boost::geometry::difference計算兩個多邊形的boost::geometry::difference其中boost::geometry::model::polygon表示我的多邊形。

如果第一個多邊形包含第二個操作的結果是單個boost::geometry::model::polygon ,其內環和外環填充了源多邊形的坐標。

如何從boost::geometry::model::polygon獲得多邊形(在基本幾何意義上)?

澄清:

在初等幾何中,多邊形是一個平面圖形,它以有限的直線段鏈為界,在環中閉合以形成閉合的鏈或回路。

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 為綠色 / 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可以由無限多個不同的法線多邊形表示。 我不在乎我得到哪一個。

您可以輕松構建一個環來模擬您預期的弱簡單多邊形 第一的:

警告

請注意,結果對於進一步使用 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))) invalid: 'Geometry has invalid self-intersections. 在 (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) 以匹配外圈的方向。

該算法並沒有試圖巧妙地找到內環的切點,這可能也意味着它不適用於具有多個內環的通用情況。

演示

這是一個完整的現場演示

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

相同代碼的輸出變成

這是舊答案。 對問題進行編輯后,我發布了一個適合給定示例的算法的簡單實現

已經是了。

如果您的意思是“簡單”的無孔多邊形,那么外環就是您想要的。 只需丟棄內環。

但是,在最通用的情況下,您最終會得到多個完全分離的多邊形,這就是為什么輸出是多邊形集合的原因 您也必須考慮這種可能性(可以選擇將不同的結果多邊形合並為一個,並在功能上根據您的需要丟棄內環)。

一個樣品:

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切成兩個單獨的部分。 因此,您必須准備好處理多個分離的輸出多邊形:

住在 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:

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM