问题描述
我有一个点集 P,它表示平面多边形的(有序)边界点,内部没有任何点。多边形可能是凹面的,并且至少是 weakly simple。可以将所有多边形约束为简单的。我的目标是比 O(n^2) 更快地对平面多边形进行三角剖分。
集合P的大小从几百个点到1-200万不等。由于这些多边形是如何生成的特定原因,很难简单地进行下采样并获得较小的集合 P。
我使用 Python 工作——我对我使用的软件包或他们拥有的许可证没有任何限制。
我尝试过的方法
我的“稳定”软件是围绕 earclipping algorithm 构建的。这对于具有数百或数千个点的小示例非常有效,但对于大型多边形来说运行时间过长。它没有利用边界和边界排序的知识(而且很挑剔,会产生非常难看的网格)。
最近我尝试使用 Triangle
,通过一些 python bindings 和受约束的 delaunay 算法。即使在提供边界边时,受约束的 delaunay 在凹形上运行也会返回多边形边界腔内的三角形。注意:我不需要(准)delaunay 三角剖分,我正在查看 Triangle
,因为它紧凑、广受好评且速度快。
凹度填充的一个简单解决方案是检查生成的三角形是否在边界内(例如,计算每个三角形的质心并运行点入多边形算法)。然而,简单的点入多边形算法(例如光线投射)在 O(n^2) 时间内运行,因为对于 P 中的 n 个点,有 n 个边界边缘,必须检查 ~n 个生成的 tris。
问题的具体形式
根据我在下面链接到的其他一些 SO 帖子,听起来 Triangle
满足了上述一项或两项,而我只是没有充分利用它(可能也是python 绑定?)。我有 C 的功能上不存在的知识;到目前为止,对 Triangle
代码的挖掘一直没有结果。
我看过类似的问题,但并没有完全解决我的问题:
- Triangulating a planar point set with known Boundary
- Concave Mesh Triangulation With Known Boundary
- Triangulate a set of points with a concave domain
解决方法
我对此有 2 个建议:
- 您可以找到一种执行甜蜜三角测量的算法,但速度不会比
O(n**2)
- 您可以更快地找到算法
O(n*log(n))
,但它总是(根据我的经验)以牺牲三角剖分的质量为代价
当生成连接仅来自表面轮廓的点的三角形时,通常将其命名为贪心三角剖分。
1.对于最快的三角剖分
有两种算法(据我所知):
- 直接三角测量的人
- 那些将给定的非凸轮廓分割成较小的凸轮廓(或至少是单调的),然后才对它们进行三角剖分(这很容易,因为这是凸轮廓)
两者都基于所谓的sweepline algorithms,简而言之:
- 选择飞机的方向(无论是什么)
- 按照那个方向排序你的观点
- 按照它们在排序列表中的顺序考虑匹配点
[ ] - A publication for the 1st kind
[ ] - this wikipedia page 也很有用。
2.最好的三角剖分
有多种方法,但我所知道的最好的方法是通过减少轮廓进行三角测量:
- 选择一个点,您将放置一个与其直接相邻的三角形
- 创建一个三角形并从轮廓中删除最新的点
- 再做一次,直到没有轮廓
- 有一些启发式方法可以知道每次迭代优先制作哪个三角形
这就是在madcad.triangulation中所做的,它的复杂度是O(n*k)
,k = 凹点数
from madcad.triangulation import *
outline = Wire([ ... your points ... ])
triangulation(outline) # this is triangulating the outline,it even works with holes in the surface
triangulation_outline(outline) # this function is a subpart of the latest,working only on outlines with no holes
结论
我取决于你需要什么:) 我个人在大多数用例中都放弃了最快的三角剖分,因为在平滑轮廓的情况下三角形的质量非常差。
如果您需要对生成的网格执行一些计算,非常细的三角形将导致使用浮点的精度显着下降。
,如果你对 Triangle 不满意,也许你可以试试 CGAL python 绑定:https://github.com/CGAL/cgal-swig-bindings
它们在 test.pypi.org 上作为预编译包提供:https://test.pypi.org/project/cgal/