3 About Kernels and Traits Classes

本文探讨了凸包算法中的模板参数使用,特别是Graham/Andrew扫描算法,并详细解释了Traits参数的作用及其所需提供的类型,如用于点类型、排序及方向判断等。

If you look at the manual page of the function convex_hull_2() and the other 2D convex hull algorithms, you see that they come in two versions. In the examples we have seen so far the function that takes two iterators for the range of input points and an output iterator for writing the result to. The second version has an additional template parameter Traits, and an additional parameter of this type.

template<class InputIterator , class OutputIterator , class Traits >
OutputIterator 
convex_hull_2(InputIterator first,
              InputIterator beyond,
              OutputIterator result,
              const Traits & ch_traits)
What are the geometric primitives a typical convex hull algorithm uses? Of course, this depends on the algorithm, so let us consider what is probably the simplest efficient algorithm, the so-called "Graham/Andrew Scan". This algorithm first sorts the points from left to right, and then builds the convex hull incrementally by adding one point after another from the sorted list. To do this, it must at least know about some point type, it should have some idea how to sort those points, and it must be able to evaluate the orientation of a triple of points.

And that is where the template parameter Traits comes in. For ch_graham_andrew() it must provide the following nested types:

  • Traits::Point_2
  • Traits::Less_xy_2
  • Traits::Left_turn_2
  • Traits::Equal_2
As you can guess,  Left_turn_2  is responsible for the orientation test, while  Less_xy_2  is used for sorting the points. The requirements these types have to satisfy are documented in full with the concept  ConvexHullTraits_2 .

template < class InputIterator, class OutputIterator, class Po int_2, class Less_xy_2, class Left_turn_2, class Equal_2>
InputIterator beyond,
OutputIterator result);

#include <iostream>
#include <iterator>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Projection_traits_yz_3.h>
#include <CGAL/convex_hull_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K3;
typedef CGAL::Projection_traits_yz_3<K3> K;
typedef K::Point_2 Point_2;
int main()
{
  std::istream_iterator< Point_2 >  input_begin( std::cin );
  std::istream_iterator< Point_2 >  input_end;
  std::ostream_iterator< Point_2 >  output( std::cout, "\n" );
  CGAL::convex_hull_2( input_begin, input_end, output, K() );
  return 0;
}


### Graham 扫描法的算法实现与原理 Graham 扫描法是一种经典的用于计算平面点集凸包的算法,其核心思想是通过极角排序和栈操作来逐步构建凸包。以下是关于该算法的具体实现及其涉及的关键概念。 #### 算法的核心步骤 1. **选择起始点** 首先,在给定的一组平面上的点中,找出 \(y\) 坐标最小的点作为起始点。如果有多个点具有相同的 \(y\) 坐标,则进一步比较它们的 \(x\) 坐标,取其中 \(x\) 最小的一个[^1]。此点被标记为 \(p_0\) 并加入到结果集合中。 2. **极角排序** 将剩余的点相对于 \(p_0\) 的位置进行极角排序。具体来说,对于任意两点 \(A(x_1, y_1)\) 和 \(B(x_2, y_2)\),可以通过计算向量 \(\overrightarrow{OA}\) 和 \(\overrightarrow{OB}\) 的夹角来进行排序[^2]。当两者的极角相同(即共线)时,保留离 \(p_0\) 更近的点。 3. **利用栈结构构造凸包** 使用一个栈来存储当前已知的凸包顶点。初始状态下,将前两个经过排序的点压入栈中。随后逐一处理剩下的每一个点,并执行如下逻辑: - 对于每一点 \(p_i\),检查它是否能够形成一个“左转”的路径。这是通过计算叉积完成的:设栈顶两个点分别为 \(top_1\) 和 \(top_2\),则判断向量 \((\overrightarrow{top_2 top_1})\) 与 \((\overrightarrow{top_1 p_i})\) 是否满足正交关系。 如果叉积大于零,说明形成了一个逆时针转向,因此可以安全地将 \(p_i\) 加入栈中; 否则,移除栈顶元素直到条件成立为止[^3]。 4. **返回结果** 当所有点都被遍历完毕后,留在栈内的节点即是所求得的凸包边界上的全部顶点。 #### Python 实现代码示例 下面提供了一个基于上述描述编写的简单版本的 Graham Scan Algorithm: ```python def cross_product(o, a, b): """ 计算三个点 o,a,b 构成的有符号面积 """ return (a[0]-o[0])*(b[1]-o[1])-(a[1]-o[1])*(b[0]-o[0]) def graham_scan(points): # 寻找最低点(若有多个同高度者择最左侧) points.sort(key=lambda point:(point[1], point[0])) P0 = points[0] # 按照极角排序其余各点 def polar_angle_and_distance(p): angle = math.atan2(p[1]-P0[1], p[0]-P0[0]) distance_sqrd = (p[1]-P0[1])**2+(p[0]-P0[0])**2 return (angle,distance_sqrd) sorted_points = [P0]+sorted(points[1:], key=polar_angle_and_distance) stack = [] for p in sorted_points: while len(stack)>=2 and cross_product(stack[-2],stack[-1],p)<=0: stack.pop() stack.append(tuple(p)) return stack[:-1] if len(sorted_points)>2 else stack[:] # 测试数据 points = [(0,3),(1,1),(2,2),(4,4),(-1,-1)] convex_hull = graham_scan(points) print(convex_hull) ``` #### 几何意义下的排序方式 在实际应用过程中,“极角排序”是非常重要的环节之一。为了确保整个过程高效稳定,通常采用 atan2 函数配合平方欧几里德距离共同决定次序排列标准[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值