找到了一个java实现 https://github.com/yunchi/Dynamic_Convex_Hull
一个c++实现 https://code.google.com/archive/p/convex-hull-of-dynamic-set/source/default/source
@article{overmars_maintenance_1981,
title = {Maintenance of configurations in the plane},
volume = {23},
issn = {00220000},
url = {https://linkinghub.elsevier.com/retrieve/pii/002200008190012X},
doi = {10.1016/0022-0000(81)90012-X},
language = {en},
number = {2},
urldate = {2023-05-24},
journal = {Journal of Computer and System Sciences},
author = {Overmars, Mark H. and Van Leeuwen, Jan},
month = oct,
year = {1981},
pages = {166--204},
}
想法大概是: 一个点集的凸包可以由左半凸包和右半凸包两部分组合成,(注意这里左半凸包和右半凸包不是把点集分成左半和右半两部分再求凸包, 而是整个点集并上
有这样一个lemma
LEMMA 3.1. Given the lc- and rc-hull of a set of n points, one can determine whether an arbitrary point p lies inside, outside or on the convex hull in only
steps.
只考虑左半凸包, 判断一个给定的点是在凸包内还是在凸包上还是凸包外. binary search 找到与过给定的点的水平直线相交的凸包上的线段. 判断点在线段的左边还是右边.
计算左半凸包的过程也可以分治. 给定一个点集
THEOREM 3.2. Let
be arbitrary points in the plane, ordered by y-coordinate. If the representations of the lc-hull of , and of are known (any ), then the lc-hull of the entire set can be built in steps.
实际上我们要做的就是找到 bridge. 也就是找到 bitangent. 假设途中的 A 和 C 的左半凸包都保存在平衡树里面. 都是按照 y-coordinate 排序的. 现在假设我们知道 B 是 A 中的 u 和 C 中的 d 连接起来的, 我们需要把 A 的 lc-hull(表示左半凸包) 在 u 上面的部分拿出来(包含 u), 把 C 的 lc-hull 在 d 下面的部分拿出来(包含 d), 然后把两部分合起来. 平衡树中这种操作需要
Preparata, F. P., ‘An Optimal Real-Time Algorithm for Planar Convex Hulls’, Communications of the ACM, 22.7 (1979), 402–5 https://doi.org/10.1145/359131.359132 文章里提到支持 binary search 就能在
关于这个问题, 这本书 https://www.cs.kent.edu/~dragan/CG/CG-Book.pdf 117页 section 3.3.6 讲了 Preparata 的文章和里面提到的失败的算法. 失败的算法的想法是, 把凸包上的点按照顺时针或者逆时针的顺序保存在一个平衡树当中, 然后当要插入一个新的点 p 的时候, 首先可以用
继续 fully dynamic convex hull 当中
这是仅有的需要通过过 p 和 q 的切线交点和 y=m 的关系来判断的情况(关于 p 和 q 的位置, 可以像上面一样通过 pq 向量与 p 相邻的两条边的叉积来判断) 注意, 所有这些case的处理都要在
依照这种方法只要两个不相交的 convex polygons 点是有序的并且支持二分查找, 我们都能用类似的方法把四个 bitangent 都找出来.
下面是插入和删除的方法.
数据是这样存的: 所有的点都按照纵坐标排序, 放在一个 binary search tree 里面. 树上的每个节点都保存一个平衡树(或者叫作 concatenable queue). 我们构建这个树的时候每个节点用
数据结构初始化好之后就是一个二分查找树套平衡树, 二分查找树的每个点都有一个平衡树, 保存的是他的父节点没有用来构建 lc-hull 的点中属于这个儿子那一部分的点的 lc-hull.(为什么保存的是父节点没有用来构建 lc-hull …? 和上一段合并 lc-hull 的时候把子节点的concatenable queue破坏掉的原因一样, 实际上是因为concatenable queue是平衡树, 合并的时候是把原来的两个平衡树破坏了.)(这里外层的二分查找树会把所有数据都保存在叶子节点, 中间的节点不保存实际的数据.)
在这个数据结构中, 我们想知道任何一个 binary search tree 节点的完整的 lc-hull 都只需要