使用Boost Geometry进行多边形缓冲时,结果不佳或不正确

问题描述 投票:2回答:2

我正在使用Boost :: Geometry :: Buffer来创建不规则形状多边形的内部偏移或扩张。下图显示了输入和输出的示例。原始多边形以白色显示,偏移多边形以紫色显示。在紫色多边形的右侧有两组外来线(看起来是较厚/较亮的区域),左侧有一个长的无关尖峰。

Example output from 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会在多边形上失败如此简单。为什么我会得到那些无关紧要的台词?如果任何其他信息有用,我将很乐意提供。

c++ boost buffer polygon boost-geometry
2个回答
3
投票

我们无法分辨,因为您未能包含源数据。你的“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并且它消失了:

Live On Wandbox

#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");
    }
}

enter image description here


0
投票

我无法得到与Boost合作的结果。我改为切换到Clipper Library,它毫无障碍地处理了斜接的结尾。

© www.soinside.com 2019 - 2024. All rights reserved.