提问人:Mykola Kotsabiuk 提问时间:8/23/2018 最后编辑:Mykola Kotsabiuk 更新时间:8/27/2018 访问量:762
查找包围点云中所有点的最小三角形数
Find minimum number of triangles enclosing all points in the point cloud
问:
输入
您有一个表示 2D 点云的点列表。
输出
您必须生成一个三角形列表(应尽可能少的三角形),以便满足以下限制:
云中的每个点都应该是三角形的顶点或 在三角形内。
三角形只能建立在以下点上 原始点云。
- 三角形不应与每个三角形相交 其他。
- 云的一个点可以是多个三角形的顶点。
- 如果三角形顶点位于另一个三角形的边上,我们假设这样的三角形不相交。
- 如果点位于三角形的边上,我们假设该点位于三角形内。
例如
调查
我发明了一种方法,可以找到给定点集的凸包并将该凸包分成三角形,但这不是正确的解决方案。
猜猜如何解决吗?
答:
这是我的意见。
- 创建点云的 Delaunay 三角测量。
- 通过半边折叠进行网格简化。
对于步骤 1,三角测量的边界将是凸包。如果需要遵守非凸边界,也可以使用约束 Delaunay 三角剖分 (CDT)。
对于步骤 2,半边折叠操作将保留现有折点,因此不会添加新折点。请注意,在您的例子中,折叠不是删除顶点,而是删除边。在应用边折叠之前,应检查是否未引入三角形反转(产生自相交),并且没有点在三角形之外。坍塌的顺序很重要,但您可以遵循通常的规则,即通过引入质量较差的三角形(即具有锐角的三角形)来衡量坍塌的“成本”。因此,您应该选择尽可能产生最多等距三角形的折叠。
编辑:
折叠的顺序将简化引导到不同的结果。除了最小化锐角之外,还可以通过其他标准来指导它。我认为可以通过选择产生最填充的三角形与最空的三角形的折叠来最小化最空的三角形。尽管如此,所有标准都是 euristics。
评论
关于三角形和凸包的一些思考
忽略任何具有 2 个或更少点的集合,并且 3 个点给出总是给出 1 个三角形。
- 做一个凸包。
- 选择任意随机内部点。
- 除非所有点都在船体中......
船体中的所有点都必须是三角形的一部分,因为根据凸船壳的定义,它们不能是内部的。
现在我们有一个三角形的上限,即船体中的点数。
- 上限也是四舍五入的点数 / 3,因为您可以制作那么多独立的三角形。
- 所以上限是上面两个的最小值
- 我们还可以猜测下界四舍五入(船体点 / 3),因为每 3 个相邻点可以形成一个三角形,任何盈余都可以重用 1-2。
现在困难的部分降低上限
walk through the inner points using them as center for all triangles.
If any triangle is empty we can save a triangle by removing the hull edge.
if two or more adjacent triangles are empty we will have to keep every other triangle or join the 3 points to a new triangle, as the middle point can be left out.
note the best result.
难道这个教授没有更好的结果吗?不。 如果存在一个环绕所有剩余点的三角形,那就更好了。
N = number of points
U = upper bound
L = lower bound
T = set of triangles
R = set of remaining points
A = set of all points
B = best solution
BestSolution(A)
if A < 3 return NoSolution
if A == 3 return A
if not Sorted(A) // O(N)
SortByX(A) // O(n lg n) or radex if possible O(N)
H = ConvexHull(A)
noneHull = A - H
B = HullTriangles(H, noneHull) // removing empty triangles
U = size B
if noneHull == 0
return U // make triangles of 3 successive points in H and add the remaining to the last
if U > Roundup(N/3)
U = Roundup(N/3)
B = MakeIndepenTriangles(A)
AddTriangle(empty, A)
return // B is best solution, size B is number of triangles.
AddTriangle(T, R)
if size T+1 >= U return // no reason to test if we just end up with another U solution
ForEach r in R // O(N)
ForEach p2 in A-r // O(N)
ForEach p3 in A-r-p2 // O(N)
t = Triangle(r, p2, p3)
c = Candidate(t, T, R)
if c < 0
return c+1 // found better solution
return 0
Candidate(t, T, R)
if not Overlap(t, T) // pt. 3, O(T), T < U
left = R-t
left -= ContainedPoints(t) // O(R) -> O(N)
if left is empty
u = U
U = size T + 1
B = T+t
return U-u // found better solution
return AddTriangle(T+t, left)
return 0
所以。。。总运行时间...
候选人 O(N) 加三角形 O(N^3) 递归仅限于当前最佳解U
O((N N^3)^U) -> O((N^4)^U) 空间为 O(U N)
因此,在我们使用蛮力之前减少 U 是必不可少的。 - 快速减少 R 应该会减少递归 - 因此,从更大、希望更多的封闭三角形开始会很好 - 船体中的任何 3 个点都应该成为一些不错的候选者 - 这些将剩余的点分成 3 个部分,可以独立调查 - 将每个部分视为一个船体,其中它的 2 个基点是三角形的一部分,但第 3 个基点不在集合中。 - 如果可能的话,把它做成一个BFS,这样我们就可以先选择最封闭的 - 空间可能是一个问题 - O(H(H) - 否则,首先从船体周围 1/3 的点开始。
AddTriangle 的性能真的很差,所以我们真的能制作多少个三角形
从 N 中选择 3 个是
N!/(N-3)!
我们不在乎秩序,所以
N!/(3!(N-3)!)
N!/(6(N-3)!)
N (N-1) (n-2) / 6
对于循环来说,这仍然是 O(N^3),但它让我们感觉更好。如果排列时间过长,循环可能仍然更快。
AddTriangle(T, R)
if size T+1 >= U return // no reason to test if we just end up with another U solution
while t = LazySelectUnordered(3, R, A) // always select one from R first O(R (N-1)(N-2) / 6) aka O(N^3)
c = Candidate(t, T, R)
if c < 0
return c+1 // found better solution
return 0
上一个:用不均匀的圆盘实现最佳覆盖
评论