在3d

时间:2017-02-15 13:27:25

标签: data-structures 3d packing

我想表示多个三维矩形框的排列(可能在一个更大的盒子里......一个容器)。盒子的长度,宽度,高度和重量表示。

我现在的问题是,我如何有效地表示这些盒子的“位置”,以便我可以计算总体安排的一些属性:

  • 最大身高
  • 质心
  • 总量
  • 坚固性(建筑布局的整体表面有多粗糙。即表面内有多少台阶和多大的台阶......光滑表面的对应部分)
  • ...

需要有效地渲染,转换,旋转,显示......数据结构,我发现大多数解决方案都试图改进。

两种可能的方法:

  

我想到的第一种方法是包含所有方框的列表   和一个额外的给定位置(在x轴,y轴和z轴上)   3d空间。从这个基本方法,我可以计算所有属性   但是,要找到合适的位置是很困难的   一个新的盒子。我想我必须使用另一个表示法   找到合适的位置,然后将此表示转换为   被描述的那个。

     

另一个想法是将3d空间视为体素。放一个盒子   在空间内意味着分配代表的体素   空间盒子,这使得为盒子找到一个新的地方非常容易。   一旦建立了这个结构,就可以计算出这些属性   快速而简单,但在定义时我可能缺乏准确性   大体素。增加体素的数量会减慢体重   再次计算,需要更多的记忆。

我现在已经看了很长时间了,但是找不到我觉得合适的代表。

您是否有任何其他想法,或者您能指出我更好的解决方案,或者其中一种方法已经是一种好方法?

1 个答案:

答案 0 :(得分:1)

在框内组织框,特别是如果你可以在整数空间中工作并将尺寸表示为体素,可以很好地适应八叉树。

https://en.wikipedia.org/wiki/Octree

虽然八叉树可以用作3D交互的空间划分方案 - 例如,为了快速找到最接近3D射线的大点云中的点,您可以使用八叉树作为起点用于组织数据。它不是最适合这个问题的,但它是一个很好的数据结构。

基本理念:

  1. 从要划分的空间的整体(x,y,z)长方体边界开始。
  2. 将3D长方体划分为八个子长方体(八个节点),每个长方体占据父盒的宽度,长度和高度的一半。 (八个节点,因此"八叉树。"类似的二维结构是一个四叉树。)
  3. 对于每个节点,保持指向其父节点及其八个子节点的指针。
  4. 迭代地将每个节点细分为另外八个节点。
  5. 继续细分,直到算法达到预定义的暂停条件,例如最大深度,最小尺寸或最小体积。
  6. 另见这个问题: Auto-balancing (or cheaply balanced) 3D datastructure

    对于细分太多次的树,您可能很容易遇到内存问题。例如,一旦超过8 ^ 5个节点,您可能不喜欢有多少内存被咀嚼。传统使用八叉树的一个技巧是引入暂停条件,使得如果特定节点为空则不会被细分。

    八叉树可能无法解决您的问题,但如果不是因为这个特殊问题,那么空间划分技术有一天会派上用场。

    此外,对于八叉树,最基本的实现并未考虑对象可以跨越属于不同父节点的两个节点。为了在2D中表达这一点,想象两个正方形进一步细分为四个正方形:a,b,c,d和e,f,g,h:

    a b  e f
    c d  g h
    

    虽然" d"和" g"彼此相邻,他们属于不同的父母方格,不知道"知道"他们是邻居。由于您的最小和最大坐标为" d"然而," g",它很简单,可以计算他们是否是邻居。

    对于许多基本计算而言,您不需要将3D盒子表示为某种体素化的3D空间,而是用于衡量"坚固性" 3D数据网格是一种很好的方法。

    如果记忆不是问题,那么你可以考虑一个类似下面的方案,假设你只需处理几十个盒子,并且(或许很奇怪)盒子可以重叠:

    1. 定义表示整数空间所需的完整体积的3D数组(或等效物)。假设1个体素在满时可以表示盒子的精确边缘。 (稍后将详细介绍此假设。)
    2. 为每个体素分配一个32位或64位整数。
    3. 为每个框分配0到31或0到63的索引。
    4. 对于每个框,循环显示框中的所有像素(x,y,z)。
    5. 在框中的每个体素上,将相应的位设置为1.例如,对于从0开始的框索引2,将整数值设置为.... 0100。
    6. 对所有方框重复此过程。
    7. 在遍历框列表的循环中,动态运行计算,这样您就不必再次遍历整个3D空间:保持运行的质心计算;跟踪总体积的最小和最大点数;等
    8. 在遍历所有框及其尺寸之后,您将拥有一个3D空间,其中在每个体素中定义了存在/不存在,并且为每个框分配了唯一的ID(这可能会被证明是方便的)。

      如果框不能重叠,因为它们代表刚性长方体或真正的纸板箱,那么您只需将每个体素的框索引指定为十进制值即可。

      如果为了内存而定义整数空间但需要更高的精度,则可以使用单独的数据结构来跟踪盒子最外层体素的精度。因此,虽然对于某些处理,检查体素是否被占用(值> 0)可能就足够了,如果您需要精确地找到边缘,则可以:

      1. (可选)使用一位将体素标记为边缘体素,这意味着至少有一个邻居的值为0.
      2. 对于任何边缘体素,请使用框的索引来引用框尺寸列表。例如,如果边缘体素具有按位值... 0010,则它由框索引1占据。框索引1可以从(201.3,12.4,13.8)到(304.6,75.3,102.8)定义。从最小/最大点和边缘体素,您可以确定精确的位置。
      3. 分配完所有框后,您将遍历列表并使空体素更有意义。例如,可以为每个空体素分配指示到最近框的距离的值。例如,如果在空体素(x,y,z)处,如果任何方向上最近的框是10个体素距离,则可以使用负整数值-10(作为小数)。如果距离最近的盒子是10个体素,然后以那个空体素为中心,你可以打包另一个半宽= 9的盒子。

        根据记忆力的限制和你的耐心,在每个空体素中,你可以计算到+ x,-x,+ y,-y,+ z和-z方向(也许是其他方向)到壁橱盒的距离)。

        无论您的盒子是否与轴对齐,使用体素化3D方案都可以轻松计算"坚固性"或粗糙。一种简单的技术是想象总体积的每一侧都是深度图,或者是2D投影,其中每个像素"是盒子的距离。然后可以如下计算粗糙度:

        1. 选择要计算粗糙度的方框(或方向)。我们假设您选择XY面,以便Z指向总体积。
        2. 在每个XY点,确定从盒子面到第一个盒子的距离(如果有的话)。将此值存储在尺寸为XY面的2D数组中。
        3. 以这种方式迭代所有点。
        4. 估算粗糙度,以衡量整个像素的体积和XY面的面积。
        5. 您可以通过几种不同的方式计算粗糙度,具体取决于盒子是否完全填满空间。例如,让我们说有很多盒子填满空间,因为"看到"从XY侧,所有都在距离XY面10-20个体素的范围内。只需从表面的2D轮廓测量标准粗糙度,您就可以为3D表面开发几种粗糙度测量中的任何一种:

          • 所有箱子距离的总范围(最大 - 最小)。这假设您忽略从XY侧看到的完全为空的体素列。
          • 距离的标准偏差。
          • 与平均距离的绝对偏差之和除以占用的面积。

          对于最后一个例子,想象两种情况:无论盒子占据什么空间,所有盒子都与封闭体积的XY面相距一距离D.这可以是0.0的粗糙度,因为距离没有变化,如果目标是(比方说)在框上放置大的平面物体,这是有用的。如果框之间的空间定义了粗糙度,"然后你可以执行如上所述的简单计算或近似某些物理特征:如果放在盒子上,布料会变形多少?

          使用3D卷可以更容易地思考问题,并且(在我看来)将更容易调试。更复杂的方案也可以起作用。例如,每个框可以简单地是具有指向其他最接近的框的指针的数据结构,并且这些框可以布置在一些相当复杂的结构中。通过在单个超级体素内连接的空体素的替换的立方体区域,可以略微减小体素空间要求。"但这些技术都不像调试那么有趣。