繁体   English   中英

如何将几何体分成块?

[英]How to break a geometry into blocks?

我确信已经有一些算法可以满足我的需求,但我不确定谷歌会使用什么词组,或者算法类别是什么。

这是我的问题:我有一个由多个接触块(hyperslabs)组成的多面体,即边缘是轴对齐的,边缘之间的角度是90°。 多面体内可能有孔。

我想把这个凹面多面体分解成一个小的凸矩形轴对齐的整块是可能的(如果原始的多面体是凸的并且没有孔,那么它已经是这样的块,因此,解决方案)。 为了说明,我制作了一些二维图像(但我需要3-D的解决方案,最好是ND):

我有这个几何:

原版的

一个可能分解成块的是:

可能

但我想要的是这个(尽可能少的块):

正确

我的印象是一个精确的算法可能太昂贵了(这个问题是NP难吗?),所以近似算法是合适的。

一个细节可能会使问题更容易,因此可能有一个更合适/专业的算法是所有边都有一些固定值的大小倍数(你可能认为所有边大小都是整数,或几何是由均匀的小方块或体素组成)。

背景:这是PDE域的结构化网格离散化。

什么算法可以解决这个问题? 我应该搜索哪种算法?

更新:在你回答这个问题之前,我想指出我的回答略微偏离主题。 原始海报有关于多面体分解的问题,这些多面体具有轴对齐的面。 鉴于这种多面体,问题是将其分解为凸面部分。 问题是3D,可能是nD。 我的答案是关于一般多面体的分解。 因此,当我给出给定实现的答案时,该答案适用于多面体轴对齐的特殊情况,但可能是对于轴对齐的多面体存在更好的实现。 当我的回答说通用多面体的问题是NP完全时,可能存在针对轴对齐多面体的特殊情况的多项式解。 我不知道。

现在这是我的(稍微偏离主题)答案,低于横向规则......


CGAL C ++库有一个算法,给定2D多边形,可以计算该多边形的最佳凸分解。 该方法在手册的2D多边形分区部分中提到。 该方法名为CGAL::optimal_convex_partition_2 我引用手册:

该函数提供了Greene动态编程算法的实现,以实现最佳分区 [2]。 在最坏的情况下,该算法需要O(n 4 )时间和O(n 3 )空间。

CGAL章节参考书目中,文章[2]是:

[2] Daniel H. Greene。 多边形分解为凸起部分。 在Franco P. Preparata编辑, Computational GeometryAdv。第1卷 COMPUT。 RES。 ,第235-259页。 JAI出版社,格林威治,康涅狄格州,1983年。

它似乎正是你在寻找的。

请注意,CGAL手册的同一章也提到了在O(n): CGAL::approx_convex_partition_2中运行的近似值,因此不是最优的。

编辑,关于3D案例:

在3D中,CGAL还有另一章关于多面体的凸分解 本章的第二段说“这个问题已知是NP难[1] ”。 参考文献[1]是:

[1] Bernard Chazelle。 多面体的凸分区:下界和最坏情况下的最优算法。 SIAM J. Comput。 ,13:488-507,1984。

CGAL有一个CGAL::convex_decomposition_3方法,用于计算非最优分解。

我觉得你的问题是NP难的。 我建议第一步可能是将图形分成沿所有超平面的子矩形。 因此,在您的示例中,将有三个超平面(线)和四个生成的矩形。 然后问题变成将矩形重新组合成更大的矩形以最小化矩形的最终数量。 也许0-1整数编程?

我认为动态编程可能是你的朋友。

我看到的第一步是将多面体划分为一个简单的块集合,这样每个可能的面都可用(即切片并将其切成最小的块)。 这应该是微不足道的,因为所有东西都是轴对齐的盒子,因此类似k树的解决方案就足够了。

这似乎是合理的,因为我可以看看它的成本。 这样做的代价是我“忘记”了hyperslabs的原始配置,选择用一组新的hyperslabs替换它。 这可能导致我误入歧途的唯一方法是,原始配置是否可以为解决方案提供一些东西。 鉴于您希望为所有配置提供“最佳”解决方案,我们必须假设原始结构不是很有用。 我不知道是否可以证明这些原始信息是无用的,但我将在这个答案中做出这样的假设。

现在问题已经减少到类似于约束生成林问题的图形问题。 我认为查看问题的最自然的方法是将其视为图形着色问题(只要你可以避免将它与更着名的图形着色问题混淆,即在没有相同颜色共享的两种状态的情况下尝试着色地图边框)。 我有一个节点图(小块),我希望每个节点都分配一种颜色(最终将是覆盖该块的“hyperslab”)。 我有约束,我必须在hyperslab形状中分配颜色。

现在一个关键的观察是,并非所有可能性都必须考虑在内。 拍摄我们想要看到的最终彩色图表。 我们可以通过将任何穿过分区的hyperslab分成两部分来以任何方式对该图进行分区。 但是,并非每个分区都有意义。 唯一有意义的分区是轴对齐切割,它总是将超级圆柱体分成两个超级圆柱体(与切割不是轴对齐时可能出现的任何更复杂的形状相反)。

现在这种削减与我们真正试图解决的问题相反。 切割实际上是我们在第一步中所做的事情。 虽然我们想要找到最佳合并算法,但要撤消这些切割。 但是,这显示了我们将在动态编程中使用的一个关键特性:合并的唯一特征是在切割的暴露表面上。 一旦我们找到形成中心区域的最佳方式,它通常不会在算法中起作用。

因此,让我们首先构建一个hyperslab-spaces集合,它不仅可以定义一个普通的hyperslab,而且可以定义任何超大空间的配置,例如带洞的那些。 每个hyperslab空间记录:

  • 其中包含的叶片超大数量(这是我们最终试图最小化的数量)
  • hyperslabs的内部配置。
  • 超大空间表面的地图,可用于合并。

然后我们定义一个“合并”规则,将两个或多个相邻的hyperslab空间转换为一个:

  • Hyperslab-spaces只能组合成新的hyperslab-spaces(所以你需要组合足够的碎片来创建一个新的hyperslab,而不是一些更奇特的形状)
  • 简单地通过比较表面来完成合并。 如果存在具有匹配维度的特征,则将它们合并(因为显示如果特征匹配,则总是更好地合并超文本而不是)

现在这足以用蛮力解决问题了。 解决方案肯定是NP完全的。 但是,我们可以添加一个额外的规则,这将大大降低这个成本:“如果一个超大空间覆盖相同的空间,并且在它们的表面上具有完全相同的特征,那么一个超大空间被认为比另一个更好”。在这种情况下,一个内部更少的hypelalabs是更好的选择。“

现在的想法是,在算法的早期,你必须跟踪各种组合,以防万一它们是最有用的。 然而,随着合并算法使事情变得越来越大,内部细节将不太可能暴露在hyperslab空间的表面上。 考虑

+===+===+===+---+---+---+---+
|   :   : A | X :   :   :   :
+---+---+---+---+---+---+---+
|   :   : B | Y :   :   :   :
+---+---+---+---+---+---+---+
|   :   :   |   :   :   :   :
+===+===+===+   +---+---+---+

看看左侧的盒子,我可以自由地用更强的线条标记。 在将盒子与世界其他地方合并时,AB:XY表面就是最重要的。 因此,只有少数合并模式可以在此表面发生

  • 没有合并可能
  • 答:X允许合并,但B:Y不允许合并
  • B:Y允许合并,但A:X不允许合并
  • A:X和B:Y都允许合并(两个独立的合并)
  • 我们可以合并一个更大的正方形,AB:XY

有很多方法可以覆盖3x3平方(至少几十个)。 但是,我们只需要记住实现每个合并过程的最佳方法。 因此,一旦我们在动态编程中达到这一点,我们就可以忘记可能发生的所有其他组合,并且只关注实现每组表面特征的最佳方法。

实际上,这为一个简单的贪婪算法设置了问题,该算法探索了哪些合并为减少hyperslabs的数量提供了最好的承诺,总是记住实现给定的一组表面特征的最佳方法。 当算法完成合并时,无论最终的hyperslab空间包含什么,都是最佳布局。

我不知道它是否可证明,但我的直觉认为这将是一个O(n ^ d)算法,其中d是维数。 我认为最糟糕的解决方案就是收集hyperslabs,当它们组合在一起时,形成一个巨大的hyperslab。 在这种情况下,我相信算法最终会以k-tree算法的反向运行。 再一次,没有给出证据......这只是我的直觉本能。

您可以尝试约束delaunay三角测量。 它提供的三角形非常少。

你能确定每条线的方程吗? 如果是这样,也许你可以得到这些线之间的交点(点)。 然后,如果您采用一个轴,并开始寻找具有两个以上点的值(共享此值),那么您应该“绘制”一条线。 (在扫描开始时将有零点,然后是两个(您的第一对),当您找到两个以上的点时,您将能够确定哪个点是第一个多边形,哪个是第二个多边形。

例如,如果你有这些线:

垂直(红色):

x = 0,x = 2,x = 5

水平线(黄色):

y = 0,y = 2,y = 3,y = 5

线条和点的图像

并且你开始扫过X轴,你会得到p1和p2,(我们知道它们属于哪个线方程式)然后你会得到p3,p4,p5和p6 !! 所以在这里你可以检查哪些点共享p1和p2的同一行。 在这种情况下p4和p5。 所以你的第一个新多边形是p1,p2,p4,p5。 现在我们保存“新”点(p3,p6)并继续扫描直到下一个点。 这里我们有p7,p8,p9和p10,寻找与先前点(p3和p6)共享线的点,我们得到p7和p10。 这些是你的第二个多边形的点。

当我们为Y轴重复练习时,我们将获得两个点(p3,p7),然后只有三个点(p1,p2,p8)! 在这种情况下,我们应该在新发现点的同一行中使用最远点(p8)。

由于我们使用线方程和点2或更多维度,程序应该非常相似

ps,对不起我的英文:S

我希望这有帮助 :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM