簡體   English   中英

使用 Boost Geometry 進行多邊形緩沖時結果不佳或不正確

[英]Poor or incorrect results when using Boost Geometry for polygon buffering

我正在使用 Boost::Geometry::Buffer 來創建不規則多邊形的內部偏移或膨脹。 下圖顯示了示例輸入和輸出。 原始多邊形顯示為白色,偏移多邊形顯示為紫色。 紫色多邊形的右側有兩組無關的線(被視為較粗/較亮的區域),左側有一個長的無關尖峰。

Boost::Geometry::Buffer 的示例輸出

示例中使用的多邊形非常基礎。 它缺乏任何對稱性,但沒有急轉彎或鋸齒狀邊緣。 輸入多邊形的原始數據是這個笛卡爾點列表:

x: 61.2101898, y: 81.9854202
x: 61.3715706, y: 82.0616913
x: 61.4335442, y: 82.1924744
x: 61.4778328, y: 82.2606735
x: 61.5202942, y: 82.3236465
x: 61.5283432, y: 82.3527832
x: 61.5431557, y: 82.4063950
x: 61.5221367, y: 82.4381790
x: 61.3944855, y: 82.4706116
x: 61.3497124, y: 82.4679184
x: 61.3284111, y: 82.4674301
x: 61.1539803, y: 82.3401947
x: 61.1297760, y: 82.2854843
x: 61.0671043, y: 82.1489639
x: 61.0682831, y: 82.0264740
x: 61.0667953, y: 82.0112915
x: 61.0663414, y: 82.0066376
x: 61.0707321, y: 81.9976196
x: 61.0998306, y: 81.9980850
x: 61.2101898, y: 81.9854202

這是我用來生成偏移多邊形的代碼:

namespace bg = boost::geometry;
typedef bg::model::d2::point_xy<float> BoostPoint;
typedef bg::model::polygon<BoostPoint> BoostPolygon;
typedef bg::model::multi_polygon<BoostPolygon> BoostMultipolygon;

std::vector<BoostPoint> points;
BoostPoint tmpPoint;
BoostPolygon input;
BoostMultipolygon output;

/* currentContour is a pointer to a non-Boost specialized polygon
*  structure. It contains a bool indicating clockwise/counterclockwise
*  direction and a list of lines, each line defined by two x-y points.
*  For each line, point 2 follows point 1 in the clockwise/counterclockwise
*  direction of that polygon.
*/

if (currentContour->clockwise) {
    for (int line = 0; line < currentContour->lines.size(); line++) {
        bg::set<0>(tmpPoint, currentContour->lines[line].x1);
        bg::set<1>(tmpPoint, currentContour->lines[line].y1);
        points.push_back(tmpPoint);
    }
    // Add last point to wrap back around to starting point.
    bg::set<0>(tmpPoint, currentContour->lines.back().x2);
    bg::set<1>(tmpPoint, currentContour->lines.back().y2);
    points.push_back(tmpPoint);
}
else {
    for (int line = currentContour->lines.size() - 1; line >= 0; line--) {
        bg::set<0>(tmpPoint, currentContour->lines[line].x2);
        bg::set<1>(tmpPoint, currentContour->lines[line].y2);
        points.push_back(tmpPoint);
    }
    // Add last point to wrap back around to starting point.
    bg::set<0>(tmpPoint, currentContour->lines.front().x1);
    bg::set<1>(tmpPoint, currentContour->lines.front().y1);
    points.push_back(tmpPoint);
}

// Transfer points to polygon object.
bg::assign_points(input, points);
// Declare boost strategies for buffer function.
bg::strategy::buffer::distance_symmetric<double> distance_strategy(-0.05);
bg::strategy::buffer::join_miter join_strategy;
bg::strategy::buffer::end_round end_strategy;
bg::strategy::buffer::point_circle point_strategy;
bg::strategy::buffer::side_straight side_strategy;
// Perform polygon buffering.
bg::buffer(input, output, distance_strategy, side_strategy, join_strategy,
    end_strategy, point_strategy);

Boost 是一個著名的主要庫,所以我很難相信它的幾何 API 會在如此簡單的多邊形上失敗。 為什么我會收到那些無關的線路? 如果任何其他信息有幫助,我將很樂意提供。

我們無法判斷,因為您沒有包含源數據。 您的“currentContour”可以包含任何內容。

幸運的是,我使用包含的原始數據代替了 WKT 中的多邊形:

boost::geometry::read_wkt("POLYGON((61.2101898 81.9854202, 61.3715706 82.0616913, 61.4335442 82.1924744, 61.4778328 82.2606735, 61.5202942 82.3236465, 61.5283432 82.3527832, 61.5431557 82.4063950, 61.5221367 82.4381790, 61.3944855 82.4706116, 61.3497124 82.4679184, 61.3284111 82.4674301, 61.1539803 82.3401947, 61.1297760 82.2854843, 61.0671043 82.1489639, 61.0682831 82.0264740, 61.0667953 82.0112915, 61.0663414 82.0066376, 61.0707321 81.9976196, 61.0998306 81.9980850, 61.2101898 81.9854202))", input);

驗證失敗,因為方向錯誤:

我無法判斷您的方向是否由順時針標志正確管理,因此請按如下方式檢查:

{
    std::string reason;
    if (!bg::is_valid(input, reason))
        std::cout << "Input is not valid: " << reason << "\n";
}

如果您需要修復任何可修復的錯誤:

bg::correct(input);

之后我得到了一個干凈的緩沖區,但我看到了尖峰。 由於不精通buffer的所有選項,我“隨機”將join_miter更改為join_round並且它消失了:

現場直播

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

namespace bg = boost::geometry;
typedef bg::model::d2::point_xy<float> BoostPoint;
typedef bg::model::polygon<BoostPoint> BoostPolygon;
typedef bg::model::multi_polygon<BoostPolygon> BoostMultipolygon;

int main() {
    BoostPolygon input;
    BoostMultipolygon output;

    boost::geometry::read_wkt("POLYGON((61.2101898 81.9854202, 61.3715706 82.0616913, 61.4335442 82.1924744, 61.4778328 82.2606735, 61.5202942 82.3236465, 61.5283432 82.3527832, 61.5431557 82.4063950, 61.5221367 82.4381790, 61.3944855 82.4706116, 61.3497124 82.4679184, 61.3284111 82.4674301, 61.1539803 82.3401947, 61.1297760 82.2854843, 61.0671043 82.1489639, 61.0682831 82.0264740, 61.0667953 82.0112915, 61.0663414 82.0066376, 61.0707321 81.9976196, 61.0998306 81.9980850, 61.2101898 81.9854202))", input);
    {
        std::string reason;
        if (!bg::is_valid(input, reason))
            std::cout << "Input is not valid: " << reason << "\n";
    }
    bg::correct(input);
    {
        std::string reason;
        if (!bg::is_valid(input, reason))
            std::cout << "Input is not valid: " << reason << "\n";
        else
            std::cout << "Input is valid";
    }

    // Declare boost strategies for buffer function.
    bg::strategy::buffer::distance_symmetric<double> distance_strategy(-0.05);
    bg::strategy::buffer::join_round join_strategy;
    bg::strategy::buffer::end_round end_strategy;
    bg::strategy::buffer::point_circle point_strategy;
    bg::strategy::buffer::side_straight side_strategy;
    // Perform polygon buffering.
    bg::buffer(input, output, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy);

    {
        std::ofstream svg("output.svg");
        boost::geometry::svg_mapper<BoostPoint> mapper(svg, 400, 400);
        mapper.add(output);
        mapper.add(input);

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

在此處輸入圖像描述

Boost::geometry::strategy::buffer::join_miter 在 1.71 版本之前有一個導致此行為的錯誤。 更新 boost 應該可以解決這個問題。

相關 GitHub 問題: https ://github.com/boostorg/geometry/issues/596

我無法使用 Boost 來獲得斜接。 相反,我切換到Clipper 庫,它可以順利處理斜接端。

暫無
暫無

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

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