Html 给定一些AABB,找出包含它们的最小总表面积AABB?
我有许多对象需要渲染到Html 给定一些AABB,找出包含它们的最小总表面积AABB?,html,algorithm,math,graphics,html5-canvas,Html,Algorithm,Math,Graphics,Html5 Canvas,我有许多对象需要渲染到HTML5画布上。我的输入是轴对齐边界框的有序列表。这些盒子经常重叠,但也经常在它们之间留下大面积的空白 我希望尽可能减少必须创建的画布表面面积,以便以正确的顺序渲染所有这些项目,同时不必在多个画布上渲染单个对象的部分(从而避免只创建紧密适合所有占用空间的画布的简单解决方案) 因此,基本上,我希望紧密的对象组都在同一画布上渲染,而不重叠的对象应该在单独的画布上渲染。但并非所有重叠对象都应该在单个画布上渲染——例如,一个非常高且非常宽的对象稍微重叠形成一个L,仍然应该在两个单
HTML5
画布上。我的输入是轴对齐边界框的有序列表。这些盒子经常重叠,但也经常在它们之间留下大面积的空白
我希望尽可能减少必须创建的画布表面面积,以便以正确的顺序渲染所有这些项目,同时不必在多个画布上渲染单个对象的部分(从而避免只创建紧密适合所有占用空间的画布的简单解决方案)
因此,基本上,我希望紧密的对象组都在同一画布上渲染,而不重叠的对象应该在单独的画布上渲染。但并非所有重叠对象都应该在单个画布上渲染——例如,一个非常高且非常宽的对象稍微重叠形成一个L,仍然应该在两个单独的画布上渲染,因为组合它们会在L的开放部分浪费大量画布空间
维持Z顺序也会导致一些困难的情况。例如,下图表示一种可能的排列:
在这种情况下,您可能希望将蓝色和绿色层组合到一个画布中,但如果不同时包含红色层,则无法生成正确的分层,最终会导致大量死角
但您也不能仅将组合层限制为Z顺序上连续的项目。Z顺序可能与上图相同,但红色项目可能与其他项目不重叠,在这种情况下,您确实希望合并蓝色和绿色层
我正在努力想出一个解决这个问题的好算法。有人愿意插话吗?这里有一个简单的建议,它可能不会解决一些棘手的问题,但至少可以部分解决问题,希望能提出更好的解决方案:
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 = [];
}
}
a=;
b=[];
界限=零;
对象=[];
而(a.length>0){
c=a.pop();
如果(&&<| |边界===null){
物体。推(c);
界限=;
}否则{
b、 推(c);
}
如果(a.length==0){
a=b;
b=[];
界限=零;
对象=[];
}
}
在哪里
< area of combined canvases> = sum( < area of each canvas> ) - sum( <interesections> )
< area of seperate conavases> = sum( < area of each canvas> )
=sum()-sum()
<独立画布面积>=总和(<各画布面积>)
这不会捕捉到两个非相交对象都与一个公共对象相交的情况,但可以通过在每次迭代中回顾所有较低z阶对象来改进这种情况。从Aabs的z阶数组开始
- 查看要添加的AABB和任何其他AABB的哪种组合将产生最小的附加表面积。(可能不会,且待添加的AABB不应与任何其他AABB组合。)
- 当组合将导致较小的表面积时,检查交叉点问题(即,另一个AABB与另一个AABB重叠,并与待添加的AABB重叠)
- 如果不存在此类交叉问题,请记住另一个AABB,并继续寻找更好的可能组合
- 根据交叉点问题的存在,将要添加的AABB可以与结果数组中的其他AABB组合并插入其中
- 否则,组合或新AABB本身将添加到结果数组的顶部
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;
};
算法=函数(AllaabsinssortedOrder){
var smallestcanvassurfaceearea=[];
goog.array.forEach(allabbsinssortedorder,函数(aabb){
smallestCanvasSurfaceArea=FindSalestSurfaceArea(aabb,smallestCanvasSurfaceArea);
})
};
FindSalestSurfaceArea=函数(nextAABB,组合aAbsSinsortedOrder){
var NextaAb面积=面积(nextAABB);
如果(!nextabb){
返回组合式Abbsin分拣机;
}
var aabbToCombineWith={'index':-1,'area':nextAABBarea,'upOrDown':0};
goog.array.forEach(组合AbbsinsSortedOrder,函数(aabb,idx){
//改进-详尽的组合(三个AABB?四个?)
if(联合收割机区域(aabb,nextAABB)-nextAABB区域idx){
if(检查相交(aabb,相交aabb)){
重叠下限=真;
}
if(检查交叉点(下一个TAABB,交叉点AABB)){
重叠下一个=真;
}
}
});
if(overlapplower&!overlappnext){
aabbsToCombineWith['index']=idx;
AABBS与['area']=面积(aabb)组合;
aabbsToCombineWith['upOrDown']=-1;
}
else if(!OverlappLower&&OverlappNext){
aabbsToCombineWith['index']=idx;
AABBS与['area']=面积(aabb)组合;
aabbsToCombineWith['upOrDown']=1;
}
如果(!OverlappLower&&!OverlappNext),则为else{
aabbsToCombineWith['index']=idx;
AABBS与['area']=面积(aabb)组合;
aabbsToCombineWith['upOrDown']=0
function minBoxes(boxes) {
var result = [];
boxes.forEach(function(box1) {
var bestCombinedBox,
bestIndex;
result.reduce(function(bestSavings, box2, i) {
var x = Math.min(box1.x, box2.x),
y = Math.min(box1.y, box2.y),
w = Math.max(box1.x + box1.w, box2.x + box2.w) - x,
h = Math.max(box1.y + box1.h, box2.y + box2.h) - y;
var savings = box1.w * box1.h + box2.w * box2.h - w * h;
if(savings > bestSavings) {
bestCombinedBox = {x:x, y:y, w:w, h:h};
bestIndex = i;
return savings;
}
return bestSavings;
}, 0);
if(bestCombinedBox) {
result[bestIndex] = bestCombinedBox; //faster than splicing
} else {
result.push(box1);
}
});
return result;
}
minBoxes([{x:0, y:0, w:5, h:5}, {x:1, y:1, w:5, y:5}]);
function minBoxes(boxes) {
boxes = boxes.sort(function(box1, box2) {
return box1.z - box2.z;
}).map(function(box1) {
var overlapping = {};
boxes.forEach(function(box2) {
if(box1 != box2
&& box1.x + box1.w > box2.x
&& box2.x + box2.w > box1.x
&& box1.y + box1.h > box2.y
&& box2.y + box2.h > box1.y
) {
overlapping[box2.z] = true;
}
});
return {
x: box1.x,
y: box1.y,
w: box1.w,
h: box1.h,
minZ: box1.z,
maxZ: box1.z,
overlapping: overlapping
};
});
var result = [];
boxes.forEach(function(box1) {
var bestBox,
bestIndex;
function combinedBox(box2) {
var x = Math.min(box1.x, box2.x),
y = Math.min(box1.y, box2.y);
return {
x: x,
y: y,
w: Math.max(box1.x + box1.w, box2.x + box2.w) - x,
h: Math.max(box1.y + box1.h, box2.y + box2.h) - y
};
}
result.reduce(function(bestSavings, box2, i) {
//check z-order
var min = Math.max(Math.min(box1.minZ, box2.maxZ), Math.min(box1.maxZ, box2.minZ)),
max = Math.min(Math.max(box1.minZ, box2.maxZ), Math.max(box1.maxZ, box2.minZ));
for(var z in box1.overlapping) {
if(min < z && z < max && z in box2.overlapping) {
return bestSavings;
}
}
for(var z in box2.overlapping) {
if(min < z && z < max && z in box1.overlapping) {
return bestSavings;
}
}
//check area savings
var combined = combinedBox(box2);
var savings = box1.w * box1.h + box2.w * box2.h - combined.w * combined.h;
if(savings > bestSavings) {
bestBox = box2;
bestIndex = i;
return savings;
}
return bestSavings;
}, 0);
if(bestBox) {
var combined = combinedBox(bestBox);
combined.minZ = Math.min(box1.minZ, bestBox.minZ);
combined.maxZ = Math.max(box1.maxZ, bestBox.maxZ);
combined.overlapping = box1.overlapping;
for(var z in bestBox.overlapping) {
combined.overlapping[z] = true;
}
result[bestIndex] = combined; //faster than splicing
} else {
result.push(box1);
}
});
return result.map(function(box) {
return {
x: box.x,
y: box.y,
w: box.w,
h: box.h,
z: (box.minZ + box.maxZ) / 2 //really, any value in this range will work
};
});
}
minBoxes([{x:0, y:0, w:5, h:5, z:0}, {x:1, y:1, w:5, y:5, z:1}]);