33.Boost Geometry 空间索引谓词概念详解
在 Boost.Geometry 库的空间索引(Spatial Indexes)模块中,**谓词(Predicates)**是执行高效空间查询的核心机制。它们允许开发者定义几何对象之间的空间关系或自定义逻辑,从而从 R-Tree 等索引结构中精确筛选出目标数据。
1. 查询函数概览
所有谓词最终都通过 rtree 的 query 成员函数生效。该函数支持组合多个谓词,仅当所有条件均满足时,对应的值才会被返回。
函数原型
template <typename Predicates, typename OutIter>
size_type query(Predicates const& predicates, OutIter out_it);
参数说明
| 类型 | 名称 | 描述 |
|---|---|---|
Predicates const& |
predicates |
一个或多个谓词的组合(通过 && 连接)。 |
OutIter |
out_it |
输出迭代器,用于接收查询结果(例如 std::back_inserter)。 |
返回值
返回找到的元素数量(size_type)。
核心规则
- 逻辑与连接:多个谓词可通过
operator&&()连接,表示必须同时满足所有条件。 - 最近邻限制:在一个查询中,只能使用一个
nearest谓词。若传递多个,将导致编译错误。 - 否定操作:空间谓词支持取反操作(
!),用于排除特定空间关系。 - 方向性关键:所有空间谓词的判定逻辑中,第一个参数始终是 R-Tree 中的“索引值”,第二个参数是用户传入的“参考几何”。
2. 空间关系谓词 (Spatial Predicates)
此类谓词基于 OGC 标准定义的空间拓扑关系。理解的关键在于明确谁相对于谁的关系。
2.1 contains (包含)
功能描述:
生成一个谓词,用于查询那些完全包含给定几何对象的索引值。
- 直观理解:索引值是“大容器”,给定几何是“小物体”。我们要找的是那些能把给定几何包住的索引值。
判定逻辑:
当 boost::geometry::contains(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:这里检查的是 索引值 是否包含 给定几何。
函数原型:
template<typename Geometry>
unspecified contains(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
作为被包含对象的参考几何。 |
2.2 covered_by (被覆盖)
功能描述:
生成一个谓词,用于查询那些被给定几何对象完全覆盖的索引值。
- 直观理解:索引值是“小物体”,给定几何是“大容器”。我们要找的是那些完全落在给定几何内部(含边界)的索引值。
判定逻辑:
当 boost::geometry::covered_by(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:这里检查的是 索引值 是否被 给定几何 覆盖。
函数原型:
template<typename Geometry>
unspecified covered_by(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
作为覆盖者的参考几何。 |
2.3 covers (覆盖)
功能描述:
生成一个谓词,用于查询那些完全覆盖给定几何对象的索引值。
- 直观理解:这是
covered_by的逆运算。索引值是“大容器”,给定几何是“小物体”。我们要找的是那些能盖住给定几何的索引值。
判定逻辑:
当 boost::geometry::covers(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:这里检查的是 索引值 是否覆盖 给定几何。
函数原型:
template<typename Geometry>
unspecified covers(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
被覆盖的参考几何。 |
2.4 disjoint (不相交)
功能描述:
生成一个谓词,用于查询那些与给定几何对象完全没有交集的索引值。
- 应用场景:常用于排除法查询,寻找远离某区域的物体。
判定逻辑:
当 boost::geometry::disjoint(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:检查 索引值 与 给定几何 是否互不接触。
函数原型:
template<typename Geometry>
unspecified disjoint(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
用于检测交集的参考几何。 |
2.5 intersects (相交)
功能描述:
生成一个谓词,用于查询那些与给定几何对象存在任何形式交集的索引值。
- 应用场景:最常用的空间查询,适用于碰撞检测、范围搜索等。
判定逻辑:
当 boost::geometry::intersects(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:检查 索引值 是否与 给定几何 有重叠。
函数原型:
template<typename Geometry>
unspecified intersects(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
用于检测相交的参考几何。 |
2.6 overlaps (重叠)
功能描述:
生成一个谓词,用于查询那些与给定几何对象部分重叠的索引值。
- 注意:重叠通常指两个几何体维度相同,且有公共内部点,但互不包含。
判定逻辑:
当 boost::geometry::overlaps(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:检查 索引值 是否与 给定几何 发生重叠。
函数原型:
template<typename Geometry>
unspecified overlaps(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
用于检测重叠的参考几何。 |
2.7 within (在…内部)
功能描述:
生成一个谓词,用于查询那些完全位于给定几何对象内部的索引值。
- 直观理解:索引值是“小物体”,给定几何是“大容器”。我们要找的是那些完全在给定几何里面的索引值。
- 对比:这与
contains正好相反。within(g)找的是在g里面的;contains(g)找的是包住g的。
判定逻辑:
当 boost::geometry::within(索引值, 给定几何) 返回 true 时,该索引值被选中。
注意:检查 索引值 是否在 给定几何 内部。
函数原型:
template<typename Geometry>
unspecified within(Geometry const& g);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
g |
作为容器的参考几何。 |
3. 特殊功能谓词
除了标准的空间拓扑关系外,Boost 还提供了更灵活的谓词以满足复杂需求。
3.1 satisfies (满足自定义条件)
功能描述:
这是一个通用的包装器,允许用户传入自定义的一元谓词(函数、函数对象或 Lambda 表达式)。
- 作用:对通过空间过滤后的候选值进行二次筛选,或者在不依赖空间关系时直接过滤数据。
- 灵活性:可以检查值的属性(如 ID、颜色、类型等非几何属性)。
判定逻辑:
当用户定义的谓词函数 pred(索引值) 返回 true 时,该索引值被选中。
函数原型:
template<typename UnaryPredicate>
unspecified satisfies(UnaryPredicate const& pred);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
UnaryPredicate const& |
pred |
一元谓词函数或函数对象。该对象需接受索引值类型作为参数,并返回 bool。 |
使用提示:
常与空间谓词组合使用,例如:intersects(box) && satisfies(is_red),意为“查找与框相交且为红色的元素”。
3.2 nearest (最近邻搜索)
功能描述:
触发 K-最近邻 (K-Nearest Neighbor, KNN) 搜索模式。
- 作用:根据距离度量,找到离给定几何对象最近的 kkk 个索引值。
- 底层机制:内部使用
boost::geometry::comparable_distance(索引值, 给定几何)计算距离。 - 约束:单次查询中仅限使用一个
nearest谓词。
判定逻辑:
不按布尔值判断,而是按距离排序,选取距离 给定几何 最近的 kkk 个 索引值。
函数原型:
template<typename Geometry>
unspecified nearest(Geometry const& geometry, std::size_t k);
参数说明:
| 类型 | 名称 | 描述 |
|---|---|---|
Geometry const& |
geometry |
参考几何对象,距离计算的起点。 |
std::size_t |
k |
需要返回的最近邻元素的最大数量。 |
组合使用:nearest 可以与其他空间谓词组合。例如:nearest(pt, 5) && intersects(box) 表示“查找与框相交的、离点 pt 最近的 5 个元素”。
3. 示例代码
#include <iostream>
#include <vector>
#include <string>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/index/rtree.hpp>
// 命名空间简化
namespace bg = boost::geometry;
namespace bgi = boost::geometry::index;
// 定义几何类型
// 2D 点类型 (double 精度)
typedef bg::model::d2::point_xy<double> point_t;
// 2D 包围盒类型 (最小点, 最大点)
typedef bg::model::box<point_t> box_t;
// R-Tree 存储的值类型: <几何对象, 唯一ID>
typedef std::pair<box_t, int> value_t;
void DemoPredicates()
{
// ==========================================
// 1. 初始化 R-Tree
// ==========================================
// 创建一个基于二次分割算法的 R-Tree
bgi::rtree<value_t, bgi::quadratic<16>> rtree;
// ==========================================
// 2. 插入测试数据
// ==========================================
// 我们创建几个不同位置的矩形盒子
// Box A: [0, 0] to [2, 2] (左下角区域)
rtree.insert({box_t(point_t(0, 0), point_t(2, 2)), 1});
// Box B: [1, 1] to [3, 3] (与 A 重叠的区域)
rtree.insert({box_t(point_t(1, 1), point_t(3, 3)), 2});
// Box C: [5, 5] to [7, 7] (远离 A 和 B 的区域)
rtree.insert({box_t(point_t(5, 5), point_t(7, 7)), 3});
// Box D: [0, 0] to [10, 10] (一个大盒子,完全包含 A, B, C)
rtree.insert({box_t(point_t(0, 0), point_t(10, 10)), 4});
std::cout << "=== Data Inserted ===" << std::endl;
std::cout << "Total elements in R-Tree: " << rtree.size() << std::endl;
std::cout << std::endl;
// 辅助函数:打印查询结果
auto print_results = [](const std::string& query_name, const std::vector<value_t>& result) {
std::cout << "--- Query: " << query_name << " ---" << std::endl;
if (result.empty()) {
std::cout << "No results found." << std::endl;
} else {
for (const auto& v : result) {
// 获取盒子的最小和最大坐标以便展示
point_t min_p = bg::return_centroid<point_t>(v.first); // 简单展示用中心点
std::cout << "Found ID: " << v.second
<< " (Centroid approx: " << min_p.get<0>() << ", " << min_p.get<1>() << ")" << std::endl;
}
}
std::cout << std::endl;
};
// 存储结果的容器
std::vector<value_t> result;
// ==========================================
// 3. 谓词演示
// ==========================================
// --- 3.1 intersects (相交) ---
// 描述:查找与给定查询框有任何重叠部分的元素
// 场景:查询框 [1.5, 1.5] 到 [2.5, 2.5]
// 预期:应命中 Box A (ID 1), Box B (ID 2), 和 Box D (ID 4)
{
box_t query_box(point_t(1.5, 1.5), point_t(2.5, 2.5));
result.clear();
// 执行查询:bgi::intersects 是核心谓词
rtree.query(bgi::intersects(query_box), std::back_inserter(result));
print_results("intersects(query_box)", result);
}
// --- 3.2 within (在...内部) ---
// 描述:查找完全位于给定查询框内部的元素
// 场景:查询框 [0, 0] 到 [2.5, 2.5]
// 预期:Box A (ID 1) 完全在其中。Box B (ID 2) 部分超出,所以不会被选中。Box D (ID 4) 比查询框大,也不会被选中。
{
box_t query_box(point_t(0, 0), point_t(2.5, 2.5));
result.clear();
rtree.query(bgi::within(query_box), std::back_inserter(result));
print_results("within(query_box)", result);
}
// --- 3.3 contains (包含) ---
// 描述:查找完全包含给定查询框的元素
// 场景:查询框 [1.5, 1.5] 到 [2.5, 2.5]
// 预期:只有 Box D (ID 4) 足够大,能完全包住这个查询框。
{
box_t query_box(point_t(1.5, 1.5), point_t(2.5, 2.5));
result.clear();
rtree.query(bgi::contains(query_box), std::back_inserter(result));
print_results("contains(query_box)", result);
}
// --- 3.4 disjoint (不相交) ---
// 描述:查找与给定查询框完全没有交集的元素
// 场景:查询框 [0, 0] 到 [2, 2] (即 Box A 的位置)
// 预期:Box C (ID 3) 离得远,不相交。Box D (ID 4) 包含了它,所以相交(不选)。Box A 和 B 都相交。
// 注意:通常 disjoint 用于排除法,这里只展示逻辑。
{
box_t query_box(point_t(0, 0), point_t(2, 2));
result.clear();
rtree.query(bgi::disjoint(query_box), std::back_inserter(result));
print_results("disjoint(query_box)", result);
}
// --- 3.5 nearest (最近邻) ---
// 描述:查找距离给定点最近的 K 个元素
// 场景:参考点 (6, 6),查找最近的 2 个元素
// 预期:Box C (ID 3) 最近 (中心在 6,6),其次是 Box B (ID 2) 或 Box D (ID 4) 取决于距离计算细节
{
point_t query_point(6.0, 6.0);
result.clear();
size_t k = 2;
// 语法:bgi::nearest(geometry, k)
rtree.query(bgi::nearest(query_point, k), std::back_inserter(result));
print_results("nearest(point, 2)", result);
}
// --- 3.6 satisfies (自定义谓词) ---
// 描述:使用 Lambda 表达式进行自定义逻辑过滤
// 场景:找出所有 ID 为偶数的元素,不管位置在哪里
// 注意:satisfies 通常与其他空间谓词组合使用效率更高,但也可以单独使用(会遍历所有)
{
result.clear();
// Lambda: 检查值的 second (ID) 是否为偶数
auto is_even_id = [](const value_t& v) {
return v.second % 2 == 0;
};
// 语法:bgi::satisfies(predicate_function)
rtree.query(bgi::satisfies(is_even_id), std::back_inserter(result));
print_results("satisfies(is_even_id)", result);
}
// --- 3.7 组合谓词 (Logical AND) ---
// 描述:同时满足多个条件
// 场景:查找与 Box [0,0]-[4,4] 相交 (intersects) 且 ID 为偶数 (satisfies) 的元素
// 预期:
// Box A (ID 1): 相交,但 ID 奇数 -> 排除
// Box B (ID 2): 相交,ID 偶数 -> 选中
// Box D (ID 4): 相交,ID 偶数 -> 选中
// Box C (ID 3): 不相交 -> 排除
{
box_t query_box(point_t(0, 0), point_t(4, 4));
result.clear();
auto is_even_id = [](const value_t& v) {
return v.second % 2 == 0;
};
// 使用 && 操作符连接两个谓词
// 注意:括号对于运算符优先级很重要
rtree.query(bgi::intersects(query_box) && bgi::satisfies(is_even_id),
std::back_inserter(result));
print_results("intersects(box) && satisfies(is_even)", result);
}
// --- 3.8 否定谓词 (Logical NOT) ---
// 描述:查找不满足特定空间关系的元素
// 场景:查找 不 与 Box [0,0]-[2,2] 相交的元素
// 预期:Box C (ID 3) 和 Box D (ID 4)?
// 等等,Box D (0,0 to 10,10) 与 (0,0 to 2,2) 是相交的。
// 所以只有 Box C (ID 3) 会被选中。
{
box_t query_box(point_t(0, 0), point_t(2, 2));
result.clear();
// 使用 ! 操作符取反
rtree.query(!bgi::intersects(query_box), std::back_inserter(result));
print_results("!intersects(query_box)", result);
}
}
输出
=== Data Inserted ===
Total elements in R-Tree: 4
--- Query: intersects(query_box) ---
Found ID: 1 (Centroid approx: 1, 1)
Found ID: 2 (Centroid approx: 2, 2)
Found ID: 4 (Centroid approx: 5, 5)
--- Query: within(query_box) ---
Found ID: 1 (Centroid approx: 1, 1)
--- Query: contains(query_box) ---
Found ID: 2 (Centroid approx: 2, 2)
Found ID: 4 (Centroid approx: 5, 5)
--- Query: disjoint(query_box) ---
Found ID: 3 (Centroid approx: 6, 6)
--- Query: nearest(point, 2) ---
Found ID: 3 (Centroid approx: 6, 6)
Found ID: 4 (Centroid approx: 5, 5)
--- Query: satisfies(is_even_id) ---
Found ID: 2 (Centroid approx: 2, 2)
Found ID: 4 (Centroid approx: 5, 5)
--- Query: intersects(box) && satisfies(is_even) ---
Found ID: 2 (Centroid approx: 2, 2)
Found ID: 4 (Centroid approx: 5, 5)
--- Query: !intersects(query_box) ---
Found ID: 3 (Centroid approx: 6, 6)
总结与速查表
Boost.Geometry 的谓词系统提供了一套声明式的查询语言。为了避免混淆,请牢记以下方向性规则:所有谓词 P(g) 的内部逻辑均为 boost::geometry::P(索引值, g)。
| 谓词函数 | 语义方向 (索引值 vs 参考几何 g) | 通俗记忆 |
|---|---|---|
contains(g) |
索引值 包含 g | 找“大盒子” (能装下 g 的) |
within(g) |
索引值 在 g 内部 | 找“小物体” (被 g 装下的) |
covers(g) |
索引值 覆盖 g | 找“大盖子” (能盖住 g 的) |
covered_by(g) |
索引值 被 g 覆盖 | 找“被盖物” (被 g 盖住的) |
intersects(g) |
索引值 与 g 相交 | 找“有接触的” |
disjoint(g) |
索引值 与 g 不相交 | 找“没接触的” |
overlaps(g) |
索引值 与 g 重叠 | 找“部分重合的” |
satisfies(fn) |
fn(索引值) 为真 | 找“符合自定义条件的” |
nearest(g, k) |
距 g 最近的 k 个索引值 | 找“离得最近的” |
通过灵活组合这些谓词(使用 && 连接),开发者可以轻松实现从简单的范围查询到复杂的混合条件搜索,充分发挥 R-Tree 空间索引的性能优势。
更多推荐

所有评论(0)