Boost.Geometry 库提供了一系列标准的几何模型(Models),用于表示各种几何对象。这些模型遵循 OGC(开放地理空间联盟)标准,并实现了相应的概念(Concepts),使得开发者可以方便地进行几何计算、空间分析和数据转换。本文将详细介绍 multi_linestring、multi_polygon、box、ring、segment 和 referring_segment 这六种核心几何模型的接口定义、功能描述及参数说明。
1. 多线串 (model::multi_linestring)
功能描述
multi_linestring 用于表示一组线串(linestring)的集合。它适用于需要将多条独立的线段逻辑上归为一组的场景,例如表示一条被中断的高速公路、河流系统或复杂的道路网络。该模型实现了 MultiLineString 概念。
类原型
template <
typename LineString,
template <typename, typename> class Container = std::vector,
template <typename> class Allocator = std::allocator
>
class model::multi_linestring : public std::vector<LineString, std::allocator<LineString>> {
};
模板参数说明
| 参数 | 默认值 | 描述 |
|---|
LineString | (无) | 线串的类型,通常是 model::linestring<Point>。 |
Container | std::vector | 底层容器类型,用于存储线串集合。 |
Allocator | std::allocator | 内存分配器类型。 |
构造函数
| 函数原型 | 描述 | 参数说明 |
|---|
multi_linestring() | 默认构造函数,创建一个空的多线串对象。 | 无 |
multi_linestring(std::initializer_list<LineString> l) | 初始化列表构造函数,使用给定的线串列表填充多线串。 | l: LineString 类型的初始化列表。 |
头文件
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/multi_linestring.hpp>
2. 多边形集合 (model::multi_polygon)
功能描述
multi_polygon 用于表示一组多边形(polygon)的集合。它常用于表示由多个不连续区域组成的地理实体,例如群岛(如夏威夷)、分散的行政区或多个独立的地块。该模型实现了 MultiPolygon 概念。
类原型
template <
typename Polygon,
template <typename, typename> class Container = std::vector,
template <typename> class Allocator = std::allocator
>
class model::multi_polygon : public std::vector<Polygon, std::allocator<Polygon>> {
};
模板参数说明
| 参数 | 默认值 | 描述 |
|---|
Polygon | (无) | 多边形的类型,通常是 model::polygon<Point>。 |
Container | std::vector | 底层容器类型,用于存储多边形集合。 |
Allocator | std::allocator | 内存分配器类型。 |
构造函数
| 函数原型 | 描述 | 参数说明 |
|---|
multi_polygon() | 默认构造函数,创建一个空的多边形集合。 | 无 |
multi_polygon(std::initializer_list<Polygon> l) | 初始化列表构造函数,使用给定的多边形列表填充集合。 | l: Polygon 类型的初始化列表。 |
头文件
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
3. 矩形盒 (model::box)
功能描述
box 定义了一个由两个对角点(最小角点和最大角点)描述的轴对齐矩形(或超矩形)。它是进行空间索引(如 R-Tree)和快速边界检查(Bounding Box Check)的基础数据结构。与通用的多边形不同,box 始终由最小和最大坐标定义,效率更高。该模型实现了 Box 概念。
类原型
template <typename Point>
class model::box {
};
模板参数说明
| 参数 | 描述 |
|---|
Point | 点类型。可以是 2D、3D 或更高维度的点,也可以是地理坐标(经纬度)点。 |
构造函数
| 函数原型 | 描述 | 参数说明 |
|---|
box() | 默认构造函数,不进行初始化。 | 无 |
box(Point const& min_corner, Point const& max_corner) | 构造函数,通过指定最小角点和最大角点来创建矩形。 | min_corner: 最小坐标点。max_corner: 最大坐标点。 |
成员函数
| 函数原型 | 描述 | 返回值 |
|---|
constexpr Point const& min_corner() | 获取最小角点的常量引用。 | Point const& |
constexpr Point const& max_corner() | 获取最大角点的常量引用。 | Point const& |
Point& min_corner() | 获取最小角点的非常量引用,用于修改。 | Point& |
Point& max_corner() | 获取最大角点的非常量引用,用于修改。 | Point& |
头文件
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/box.hpp>
4. 环 (model::ring)
功能描述
ring(也称为线性环 linear ring)是一个闭合的线串,通常不自交。它是构成多边形外边界或内孔(洞)的基本单元。环可以是顺时针或逆时针方向,且可以选择是否显式闭合(即首尾点坐标相同)。该模型实现了 Ring 概念。
类原型
template <
typename Point,
bool ClockWise = true,
bool Closed = true,
template <typename, typename> class Container = std::vector,
template <typename> class Allocator = std::allocator
>
class model::ring : public std::vector<Point, std::allocator<Point>> {
};
模板参数说明
| 参数 | 默认值 | 描述 |
|---|
Point | (无) | 点类型。 |
ClockWise | true | 方向标识。true 表示顺时针,false 表示逆时针。 |
Closed | true | 闭合标识。true 表示闭合多边形(最后一个点等于第一个点),false 表示开放。 |
Container | std::vector | 底层容器类型。 |
Allocator | std::allocator | 内存分配器类型。 |
构造函数
| 函数原型 | 描述 | 参数说明 |
|---|
ring() | 默认构造函数,创建一个空的环。 | 无 |
ring(Iterator begin, Iterator end) | 迭代器构造函数,使用指定范围的点填充环。 | begin: 起始迭代器。end: 结束迭代器。 |
ring(std::initializer_list<Point> l) | 初始化列表构造函数,使用点列表填充环。 | l: Point 类型的初始化列表。 |
头文件
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/ring.hpp>
5. 线段 (model::segment)
功能描述
segment 是一个包含两个端点的小型类,表示几何中的线段。线段由两个不同的端点界定,并包含这两点之间的所有点。它常用于距离计算、相交测试等基础几何操作。该模型实现了 Segment 概念,底层继承自 std::pair<Point, Point>。
类原型
template <typename Point>
class model::segment : public std::pair<Point, Point> {
};
模板参数说明
构造函数
| 函数原型 | 描述 | 参数说明 |
|---|
segment() | 默认构造函数,不进行初始化。 | 无 |
segment(Point const& p1, Point const& p2) | 构造函数,通过指定起点和终点创建线段。 | p1: 第一个点(起点)。p2: 第二个点(终点)。 |
头文件
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/segment.hpp>
6. 引用线段 (model::referring_segment)
功能描述
referring_segment 与 segment 类似,但它不拥有点的副本,而是持有两个点的引用。这使得它非常适合用于临时计算或算法中,避免不必要的数据拷贝,特别是当点数据已经存在于其他结构中时。它可以引用非常量点或常量点。
类原型
template <typename ConstOrNonConstPoint>
class model::referring_segment {
};
模板参数说明
| 参数 | 描述 |
|---|
ConstOrNonConstPoint | 点类型,可以是 Point& 或 const Point&,决定了引用的可变性。 |
构造函数
| 函数原型 | 描述 | 参数说明 |
|---|
referring_segment(point_type& p1, point_type& p2) | 构造函数,通过引用两个现有点来创建线段视图。 | p1: 第一个点的引用。p2: 第二个点的引用。 |
头文件
#include <boost/geometry/geometries/geometries.hpp>
#include <boost/geometry/geometries/segment.hpp>
7.示例代码
#include <iostream>
#include <vector>
#include <string>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/ring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/multi_linestring.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
namespace bg = boost::geometry;
namespace model = bg::model;
void DemoModel() {
using point_t = model::point<double, 2, bg::cs::cartesian>;
using linestring_t = model::linestring<point_t>;
using ring_t = model::ring<point_t>;
using polygon_t = model::polygon<point_t>;
std::cout << "--- Testing Segment ---" << std::endl;
point_t p1(0.0, 0.0);
point_t p2(3.0, 4.0);
model::segment<point_t> seg(p1, p2);
double length = bg::length(seg);
std::cout << "Segment length: " << length << std::endl;
model::box<point_t> env = bg::return_envelope<model::box<point_t>>(seg);
std::cout << "Segment envelope min: ("
<< bg::get<0>(env.min_corner()) << ", " << bg::get<1>(env.min_corner()) << ")" << std::endl;
std::cout << "Segment envelope max: ("
<< bg::get<0>(env.max_corner()) << ", " << bg::get<1>(env.max_corner()) << ")" << std::endl;
std::cout << "\n--- Testing Referring Segment ---" << std::endl;
bg::set<0>(p2, 6.0);
bg::set<1>(p2, 8.0);
model::referring_segment<point_t> ref_seg(p1, p2);
double ref_length = bg::length(ref_seg);
std::cout << "Referring Segment length (after moving point): " << ref_length << std::endl;
std::cout << "Note: Referring segment reflects changes in original points without copying." << std::endl;
std::cout << "\n--- Testing Box ---" << std::endl;
point_t min_point(1.0, 1.0);
point_t max_point(5.0, 5.0);
model::box<point_t> box(min_point, max_point);
double area = bg::area(box);
std::cout << "Box area: " << area << std::endl;
point_t test_point(3.0, 3.0);
bool within = bg::within(test_point, box);
std::cout << "Point (3,3) is within box: " << (within ? "true" : "false") << std::endl;
std::cout << "\n--- Testing Ring ---" << std::endl;
ring_t ring;
bg::append(ring, point_t(0.0, 0.0));
bg::append(ring, point_t(0.0, 4.0));
bg::append(ring, point_t(4.0, 4.0));
bg::append(ring, point_t(4.0, 0.0));
bg::append(ring, point_t(0.0, 0.0));
bg::correct(ring);
double ring_area = bg::area(ring);
std::cout << "Ring area: " << ring_area << std::endl;
std::cout << "\n--- Testing Multi_Linestring ---" << std::endl;
using multi_ls_t = model::multi_linestring<linestring_t>;
multi_ls_t multi_ls;
linestring_t ls1;
bg::append(ls1, point_t(0.0, 0.0));
bg::append(ls1, point_t(1.0, 1.0));
linestring_t ls2;
bg::append(ls2, point_t(2.0, 2.0));
bg::append(ls2, point_t(3.0, 3.0));
multi_ls.push_back(ls1);
multi_ls.push_back(ls2);
double total_len = bg::length(multi_ls);
std::cout << "Multi_Linestring total length: " << total_len << std::endl;
std::cout << "Number of linestrings in collection: " << multi_ls.size() << std::endl;
std::cout << "\n--- Testing Multi_Polygon ---" << std::endl;
using multi_poly_t = model::multi_polygon<polygon_t>;
multi_poly_t multi_poly;
polygon_t poly1;
ring_t& outer1 = poly1.outer();
bg::append(outer1, point_t(0.0, 0.0));
bg::append(outer1, point_t(0.0, 2.0));
bg::append(outer1, point_t(2.0, 2.0));
bg::append(outer1, point_t(2.0, 0.0));
bg::append(outer1, point_t(0.0, 0.0));
bg::correct(poly1);
polygon_t poly2;
ring_t& outer2 = poly2.outer();
bg::append(outer2, point_t(3.0, 3.0));
bg::append(outer2, point_t(3.0, 5.0));
bg::append(outer2, point_t(5.0, 5.0));
bg::append(outer2, point_t(5.0, 3.0));
bg::append(outer2, point_t(3.0, 3.0));
bg::correct(poly2);
multi_poly.push_back(poly1);
multi_poly.push_back(poly2);
double total_area = bg::area(multi_poly);
std::cout << "Multi_Polygon total area: " << total_area << std::endl;
model::box<point_t> multi_env = bg::return_envelope<model::box<point_t>>(multi_poly);
std::cout << "Multi_Polygon envelope covers from ("
<< bg::get<0>(multi_env.min_corner()) << ", " << bg::get<1>(multi_env.min_corner()) << ") to ("
<< bg::get<0>(multi_env.max_corner()) << ", " << bg::get<1>(multi_env.max_corner()) << ")" << std::endl;
std::cout << "\nAll tests completed successfully." << std::endl;
}
输出
--- Testing Segment ---
Segment length: 5
Segment envelope min: (0, 0)
Segment envelope max: (3, 4)
--- Testing Referring Segment ---
Referring Segment length (after moving point): 10
Note: Referring segment reflects changes in original points without copying.
--- Testing Box ---
Box area: 16
Point (3,3) is within box: true
--- Testing Ring ---
Ring area: 16
--- Testing Multi_Linestring ---
Multi_Linestring total length: 2.82843
Number of linestrings in collection: 2
--- Testing Multi_Polygon ---
Multi_Polygon total area: 8
Multi_Polygon envelope covers from (0, 0) to (5, 5)
All tests completed successfully.
总结
Boost.Geometry 的这些模型提供了灵活且高效的几何数据表示方式:
- 组合型模型(
multi_linestring, multi_polygon)允许将多个基本几何体逻辑分组,适合处理复杂地理实体。 - 基础结构模型(
box, ring, segment)构成了更复杂几何体(如多边形)的基石,并针对特定计算场景进行了优化。 - 引用模型(
referring_segment)提供了零拷贝的几何视图,提升了算法执行效率。
在使用时,开发者应根据具体的应用场景(如是否需要拥有数据、维度要求、方向要求等)选择合适的模板参数进行实例化。