当前位置: 首页 > 知识库问答 >
问题:

给定一些AABB,找到包含它们的最小总表面积AABB?

庄嘉
2023-03-14

我有许多对象需要渲染到HTML5画布上。我的输入是轴对齐边界框的有序列表。这些框经常重叠,但也经常在它们之间留下大面积的空白。

我想尽量减少我必须创建的画布表面面积,以便以正确的顺序渲染所有这些项目,而不必在多个画布上渲染单个对象的部分(从而避免简单地创建紧贴所有占用空间的画布)。

所以基本上,我希望紧密的对象组都呈现在同一个画布上,而不重叠的对象应该呈现在单独的画布上。但是,并不是所有重叠的对象都应该呈现在单个画布上——例如,一个非常高、非常宽的对象稍微重叠形成一个L,仍然应该呈现在两个单独的画布上,因为将它们组合在一起会导致L的开放部分浪费很多画布空间。

维护 Z 顺序也会导致一些困难的情况。例如,下图表示一种潜在的排列方式:

在这种情况下,您可能希望将蓝色和绿色图层合并到一个画布中,但是如果不包括红色图层,您就无法以这种方式产生正确的分层,并且您最终会有很多死空间。

但是你也不能只将组合图层限制在Z顺序连续的项目上。Z顺序可能与上图相同,但是红色项目可能碰巧与其他项目不重叠,在这种情况下,你确实想组合蓝色和绿色图层。

我在苦苦思索这个问题的好算法。有人想插话吗?

共有3个答案

祝叶五
2023-03-14

从AABBs的z排序数组开始,

>

  • 将每个 AABB 添加到结果数组中,也按 z 顺序排序

    一个。将这些要添加的 AAB 中的每一个与结果数组中已有的所有其他 AAB 进行比较

    >

  • 查看要添加的AABB和任何其他AABB的哪个组合会产生最小的额外表面积。(可能没有一个会,并且要添加的AABB不应该与任何其他组合。)

    当合并会导致表面区域变小时,请检查相交问题(即,另一个AABB与另一个AABB重叠,并且与要添加的AABB重叠)

    如果不存在这样的交叉问题,请记住另一个AABB,继续寻找更好的可能组合

    湾。当最终找到最佳组合(或没有组合)时,将待添加的AABB添加到结果数组中

    >

  • 根据交叉点问题的存在,要添加的AABB可以与结果数组中的其他AABB组合并插入到其他AABB的位置

    否则,组合或新AABB本身被添加到结果数组的顶部

    对下一个 AABB 重复上述步骤

    它不是一个很好的算法,也不能完美地完成所有事情。首先,当发现AABB的组合时,它不会试图找出是否也可以将第三或第四(或第五)个AABB添加到组合中以改进区域保护。

    以下是此算法在 Java 脚本中的实现:

    algorithm = function(allAABBsInSortedOrder) {
        var smallestCanvasSurfaceArea = [];
    
        goog.array.forEach(allAABBsInSortedOrder, function(aabb) {
            smallestCanvasSurfaceArea = findSmallestSurfaceArea(aabb, smallestCanvasSurfaceArea);
        })
    };
    
    findSmallestSurfaceArea = function(nextAABB, combinedAABBsInSortedOrder) {
        var nextAABBarea = areaOf(nextAABB);
    
        if (!nextAABB) {
            return combinedAABBsInSortedOrder;
        }
    
        var aabbToCombineWith = {'index': -1, 'area': nextAABBarea, 'upOrDown': 0};
    
        goog.array.forEach(combinedAABBsInSortedOrder, function(aabb, idx) {
            // Improvement - exhaustive combinations (three AABBs? Four?)
            if (areaOf(combine(aabb, nextAABB) - nextAABBarea <= aabbToCombineWith['area']) {
                var overlapLower = false;
                var overlapNext = false;
    
                goog.array.forEach(combinedAABBsInSortedOrder, function(intersectAABB, intersectIdx) {
                    if (intersectIdx > idx) {
                        if (checkForIntersect(aabb, intersectAABB)) {
                            overlapLower = true;
                        }
                        if (checkForIntersect(nextAABB, intersectAABB)) {
                            overlapNext = true;
                        }
                    }
                });
    
                if (overlapLower && !overlapNext) {
                    aabbsToCombineWith['index'] = idx;
                    aabbsToCombineWith['area'] = areaOf(aabb);
                    aabbsToCombineWith['upOrDown'] = -1;
                }
                else if (!overlapLower && overlapNext) {
                    aabbsToCombineWith['index'] = idx;
                    aabbsToCombineWith['area'] = areaOf(aabb);
                    aabbsToCombineWith['upOrDown'] = 1;
                }
                else if (!overlapLower && !overlapNext) {
                    aabbsToCombineWith['index'] = idx;
                    aabbsToCombineWith['area'] = areaOf(aabb);
                    aabbsToCombineWith['upOrDown'] = 0;
                }
            }
        });
    
        if (aabbToCombineWith['index'] != -1) {
            var combinedAABB = combine(combinedAABBsInSortedOrder[aabbToCombineWith['index']], nextAABB);
            if (aabbToCombineWith['upOrDown'] == -1) {
                combinedAABBsInSortedOrder[aabbToCombineWith['index']] = combinedAABB;
            }
            else {
                combinedAABBsInSortedOrder.push(combinedAABB);
                combinedAABBsInSortedOrder.splice(aabbToConbineWith['index'], 1);
            }
        }
        else {
            combinedAABBsInSortedOrder.push(nextAABB);
        }
    
        return combinedAABBsInSortedOrder;
    };
    

  • 周玺
    2023-03-14

    这里有一个简单的建议,它可能不会解决某些角落问题,但至少可以部分解决,并有望提出更好的解决方案

    a = <a z-ordered list of the objects> ;
    b = [];
    bounds = null;
    objects = [];
    while ( a.length > 0) {
        c = a.pop();
        if( <c overlaps bounds> && <area of combined canvases> < <area of seperate canvases> || bounds === null) {
             objects.push(c);
             bounds = <union of bounds and c, or bounds of c if bounds is null>;
         } else {
              b.push(c);
         }
         if( a.length === 0) {
              a = b;
              b = [];
              <do something with the current bounds and objects list>
              bounds = null;
              objects = [];
         }
    }
    

    在哪里

     < area of combined canvases> = sum( < area of each canvas> ) - sum( <interesections> )
     < area of seperate conavases> = sum( < area of each canvas> )
    

    这不会捕捉到两个非相交对象都与一个公共对象相交的情况,但可以通过在每次迭代时回顾所有较低z顺序的对象来改进这种情况。

    穆鸿飞
    2023-03-14

    此问题在 3D 中众所周知,用于在光线追踪或碰撞检测中构建高性能 AABB 层次结构。尝试在谷歌上搜索“BVH”,“表面积启发式”和/或“SAH”。以下论文的3.1节具有良好的启发式算法;这应该很容易适应你的2D案例:http://graphics.stanford.edu/~boulos/papers/togbvh.pdf

     类似资料:
    • 在加权无向图中,我需要找到一个包含给定边“e”的最小生成树,如果可能的话。我该怎么做呢?Kruskal从“e”开始?

    • 例如,给定一个占用网格: 其中, 表示一个被占用的块,表示一个自由块, 表示一个感兴趣的点(或块),那么找到包含 但不包含任何障碍物(即任何 )的最大矩形的最省时的算法是什么? 例如,所提供网格的解决方案将是: 鉴于我们有一个已知的起点,我不禁认为必须有一个简单的解决方案来将线条“捕捉”到外部边界以创建最大的矩形。 我目前的想法是以循环的方式将线捕捉到最大位置偏移(即转到下一行或下一列,直到遇到障

    • 我试图解决类似于这个问题,但有一些修改: “给定一个值V,如果我们想换V美分,并且我们有无限量的C={C1,C2,…,Cm}值硬币,那么换硬币的最小数量是多少?” 输入:硬币[]={25,10,5},V=30 输出:至少需要2个硬币 我们可以用一枚25美分的硬币和一枚5美分的硬币 在我的例子中,我有一个对象数组,而不仅仅是一个数字数组。每件物品都有数量和价格。我想打印构成给定数量的最小数量的对象,

    • 这是考试准备的一部分。我知道这和最大流量算法有关,但我很乐意给你一个提示: 设为无向连通图,为权函数,为边,。描述一种算法,该算法确定是否可以从图中最多删除边,以便属于新图的最小生成树。 我认为生成树是一种完美的匹配。但是,如何使它最小化,包含e和适当数量的其他边?

    • 这是一个面试问题。 我们被赋予各种矩形的尺寸,我们必须找出可以包围所有矩形的矩形面积(最小值)?矩形也可以旋转。 在将矩形拟合到最小可能区域之前,我曾问过一个类似的问题。 上述方法考虑了所有可能性、旋转,并在所有布局情况下确定了所有此类可能性的最小值<我们不能先求矩形面积之和,然后再求最大长度、最大宽度吗?

    • 我有一个元素数组< code>[(A1,B1),...,(An,Bn)](都是正浮点和Bi 毫无疑问,我可以尝试所有这些方法,并选择一个给出最小和的方法(这将给出正确的结果O(n!)). 我尝试将总和更改为并尝试使用贪婪算法,该算法在每个步骤上获取最大的Ai元素(这不会产生正确的结果)。 现在,当我看最新的方程时,我觉得这里我看到了最优子结构,因此我必须使用动态编程,但我无法找出正确的方向。有什么