如何在Boost几何中使用多个线串创建盒子?

Posted

技术标签:

【中文标题】如何在Boost几何中使用多个线串创建盒子?【英文标题】:How to create box using multiple linestrings in Boost geometry? 【发布时间】:2021-08-11 20:32:02 【问题描述】:

我正在尝试使用多个线串创建一个框。当然这些线串是相互连接的,可以组成一个盒子。 boost中是否有任何功能可以做到这一点?谢谢!

【问题讨论】:

【参考方案1】:

我不确定您到底在寻找什么。所以,让我双向走吧。

单向

如果你有一个盒子,你可以使用分段迭代器来获取分段:

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <iostream>

namespace bg = boost::geometry;
namespace bgm = bg::model;

using Point      = bgm::d2::point_xy<int>;
using Box        = bgm::box<Point>;
using Poly       = bgm::polygon<Point>;

int main()

    Box const box  Point 0,1, 1,2 ;

    std::cout << "box: " << bg::wkt(box) << "\n";

    // now get the segments:
    Poly p;
    bg::assign(p, box);

    for (auto f = bg::segments_begin(p), l = bg::segments_end(p); f != l; ++f) 
        std::cout << bg::wkt(*f) << "\n";
    

打印

box: POLYGON((0 1,0 2,1 2,1 1,0 1))
LINESTRING(0 1,0 2)
LINESTRING(0 2,1 2)
LINESTRING(1 2,1 1)
LINESTRING(1 1,0 1)

另一种方式

最灵活的是使用envelope算法得到一个盒子:

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <iostream>

namespace bg = boost::geometry;
namespace bgm = bg::model;

using Point      = bgm::d2::point_xy<int>;
using Box        = bgm::box<Point>;
using LineString = bgm::linestring<Point>;

int main()

    LineString const ls1, 1, 1, 2, 0, 2, 0, 1;

    std::cout << "ls: " << bg::wkt(ls) << "\n";
    
    Box box;
    bg::envelope(ls, box);

    std::cout << "box: " << bg::wkt(box) << "\n";

打印

ls: LINESTRING(1 1,1 2,0 2,0 1)
box: POLYGON((0 1,0 2,1 2,1 1,0 1))

(请注意,点顺序已更正以生成有效的环)

有验证吗?

为了减少灵活性,换句话说,对输入进行更多验证,我会从点手动创建一个多边形。

验证后,您可以通过 WKT 创建一个框...这并不理想,但可能比编写自己的逻辑要好。然而,从 WKT 读取 Box 似乎只在没有任何实际验证的点上应用最小/最大算法 - 因此实际上与获取 bg::envelope 相同。

因此,IMO 解决此问题的最佳方法是将生成的框与手动多边形进行比较,以检查输入是否已经是一个框。

bool is_box(Poly const& p) 
    Box env;
    bg::envelope(p, env);
    return bg::equals(p, env);

例如使用一些输入进行测试:

 LineString1, 1, 0, 1, 0, 2, 1, 2, 1, 1,
 LineString1, 1, 1, 2, 0, 2, 0, 1,
 LineString1, 1, 1, 2, 0, 2, 0, 1, 1, 1,
 LineString1, 1, 0, 2, 0, 1, 1, 1, // triangle

is_box 将为最后一个返回 false(即使在更正多边形之后)

Live On Coliru

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <iostream>

namespace bg = boost::geometry;
namespace bgm = bg::model;

using Point      = bgm::d2::point_xy<int>;
using Box        = bgm::box<Point>;
using Poly       = bgm::polygon<Point>;
using LineString = bgm::linestring<Point>;

bool is_box(Poly const& p) 
    Box env;
    bg::envelope(p, env);
    return bg::equals(p, env);


int main()

    for (auto& ls : 
             LineString1, 1, 0, 1, 0, 2, 1, 2, 1, 1,
             LineString1, 1, 1, 2, 0, 2, 0, 1,
             LineString1, 1, 1, 2, 0, 2, 0, 1, 1, 1,
             LineString1, 1, 0, 2, 0, 1, 1, 1, // triangle
         )
    
        std::cout << " --\nls: " << bg::wkt(ls) << "\n";

        Poly p;
        bg::assign_points(p, ls);

        if (std::string reason; !bg::is_valid(p, reason)) 
            std::cout << "Trying to correct...: " << reason << "\n";
            bg::correct(p);

            if (!bg::is_valid(p))
                continue;
        
        std::cout << "poly: " << bg::wkt(p) << "\n";

        std::cout << "is a box? " << (is_box(p) ? "yes" : "no") << "\n";
    

打印

 --
ls: LINESTRING(1 1,0 1,0 2,1 2,1 1)
poly: POLYGON((1 1,0 1,0 2,1 2,1 1))
is a box? yes
 --
ls: LINESTRING(1 1,1 2,0 2,0 1)
Trying to correct...: Geometry is defined as closed but is open
poly: POLYGON((1 1,0 1,0 2,1 2,1 1))
is a box? yes
 --
ls: LINESTRING(1 1,1 2,0 2,0 1,1 1)
Trying to correct...: Geometry has wrong orientation
poly: POLYGON((1 1,0 1,0 2,1 2,1 1))
is a box? yes
 --
ls: LINESTRING(1 1,0 2,0 1,1 1)
Trying to correct...: Geometry has wrong orientation
poly: POLYGON((1 1,0 1,0 2,1 1))
is a box? no

【讨论】:

以上是关于如何在Boost几何中使用多个线串创建盒子?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用变体创建几何图形

(如何)在 boost 几何中创建自己的多边形类型并使用 multi_polygon 类型?

Boost Geometry:多边形和盒子的交集

如何有效地从点创建线串?

r - 从数据框中同一行中的两个点创建线串

如何合并文本、球体和盒子几何?