移动矩形使它们不重叠

时间:2011-07-19 16:08:51

标签: javascript performance geometry collision-detection

这是半编程,半数学问题。

我有一些盒子,它们代表四个角点。它们是真正的矩形,是两组平行线的交点,每组中的每一行都与另一组中的两条直线成直角(我们很清楚。)

对于任何一组n个框,我怎样才能有效地计算移动它们的位置(最小距离),使它们不相互重叠?

我在这里使用javascript工作。这是数据:

//an array of indefinite length of boxes
//boxes represented as arrays of four points
//points represented as arrays of two things, an x and a y, measured in
//pixels from the upper left corner

var boxes = [[[504.36100124308336,110.58685958804978],[916.3610012430834,110.58685958804978],[916.3610012430834,149.58685958804978],[504.36100124308336,149.58685958804978]],[[504.4114378910622,312.3334473005064],[554.4114378910622,312.3334473005064],[554.4114378910622,396.3334473005064],[504.4114378910622,396.3334473005064]],[[479.4272869132357,343.82042608058134],[516.4272869132358,343.82042608058134],[516.4272869132358,427.82042608058134],[479.4272869132357,427.82042608058134]],[[345.0558946408693,400.12499171846],[632.0558946408694,400.12499171846],[632.0558946408694,439.12499171846],[345.0558946408693,439.12499171846]],[[164.54073131913765,374.02074227992966],[264.54073131913765,374.02074227992966],[264.54073131913765,428.02074227992966],[164.54073131913765,428.02074227992966]],[[89.76601656567325,257.7956256799442],[176.76601656567325,257.7956256799442],[176.76601656567325,311.7956256799442],[89.76601656567325,311.7956256799442]],[[60.711850703535845,103.10558195262593],[185.71185070353584,103.10558195262593],[185.71185070353584,157.10558195262593],[60.711850703535845,157.10558195262593]],[[169.5240557746245,23.743626531766495],[231.5240557746245,23.743626531766495],[231.5240557746245,92.7436265317665],[169.5240557746245,92.7436265317665]],[[241.6776988694169,24.30106373152889],[278.6776988694169,24.30106373152889],[278.6776988694169,63.30106373152889],[241.6776988694169,63.30106373152889]],[[272.7734457459479,15.53275710947554],[305.7734457459479,15.53275710947554],[305.7734457459479,54.53275710947554],[272.7734457459479,54.53275710947554]],[[304.2905062327675,-3.9599943474960035],[341.2905062327675,-3.9599943474960035],[341.2905062327675,50.04000565250399],[304.2905062327675,50.04000565250399]],[[334.86335590542114,12.526345270766143],[367.86335590542114,12.526345270766143],[367.86335590542114,51.52634527076614],[334.86335590542114,51.52634527076614]],[[504.36100124308336,110.58685958804978],[916.3610012430834,110.58685958804978],[916.3610012430834,149.58685958804978],[504.36100124308336,149.58685958804978]],[[504.4114378910622,312.3334473005064],[554.4114378910622,312.3334473005064],[554.4114378910622,396.3334473005064],[504.4114378910622,396.3334473005064]],[[479.4272869132357,343.82042608058134],[516.4272869132358,343.82042608058134],[516.4272869132358,427.82042608058134],[479.4272869132357,427.82042608058134]],[[345.0558946408693,400.12499171846],[632.0558946408694,400.12499171846],[632.0558946408694,439.12499171846],[345.0558946408693,439.12499171846]],[[164.54073131913765,374.02074227992966],[264.54073131913765,374.02074227992966],[264.54073131913765,428.02074227992966],[164.54073131913765,428.02074227992966]],[[89.76601656567325,257.7956256799442],[176.76601656567325,257.7956256799442],[176.76601656567325,311.7956256799442],[89.76601656567325,311.7956256799442]],[[60.711850703535845,103.10558195262593],[185.71185070353584,103.10558195262593],[185.71185070353584,157.10558195262593],[60.711850703535845,157.10558195262593]],[[169.5240557746245,23.743626531766495],[231.5240557746245,23.743626531766495],[231.5240557746245,92.7436265317665],[169.5240557746245,92.7436265317665]],[[241.6776988694169,24.30106373152889],[278.6776988694169,24.30106373152889],[278.6776988694169,63.30106373152889],[241.6776988694169,63.30106373152889]],[[272.7734457459479,15.53275710947554],[305.7734457459479,15.53275710947554],[305.7734457459479,54.53275710947554],[272.7734457459479,54.53275710947554]],[[304.2905062327675,-3.9599943474960035],[341.2905062327675,-3.9599943474960035],[341.2905062327675,50.04000565250399],[304.2905062327675,50.04000565250399]],[[334.86335590542114,12.526345270766143],[367.86335590542114,12.526345270766143],[367.86335590542114,51.52634527076614],[334.86335590542114,51.52634527076614]]]

This fiddle shows the boxes drawn on a canvas semi-transparently for clarity.

3 个答案:

答案 0 :(得分:4)

您可以使用贪心算法。它将远非最佳,但可能“足够好”。这是一幅草图:

 1 Sort the rectangles by the x-axis, topmost first. (n log n)
 2 for each rectangle r1, top to bottom
       //check for intersections with the rectangles below it.
       // you only have to check the first few b/c they are sorted 
 3     for every other rectangle r2 that might intersect with it 
 4         if r1 and r2 intersect //this part is easy, see @Jose's answer
 5             left = the amount needed to resolve the collision by moving r2 left
 6             right = the amount needed to resolve the collision by moving r2 right
 7             down = the amount needed to resolve the collision by moving r2 down

 8             move r2 according to the minimum value of (left, right down)
               // (this may create new collisions, they will be resolved in later steps)
 9         end if

10     end
11 end

注意步骤8可能会与先前的矩形创建新的碰撞,但无法正确解析。嗯。您可能需要携带一些有关前一个矩形的元数据以避免这种情况。想...

答案 1 :(得分:0)

请记住框模型,给定任意两个矩形,你必须计算两个框的宽度和高度,添加它们各自的边距,填充和边框(添加它们的左/右以检测x轴上的碰撞,和顶部/底部检测y轴上的碰撞),然后你可以计算元素1和2之间的距离,将结果加到它们各自的坐标位置,例如((positionX2 + totalWidth2) - (positionX1 + totalWidth1))来计算沿X轴碰撞。如果是负数,则它们是重叠的。一旦你知道这一点,如果他们不会通过移动它们重叠,你可以正常移动它们,否则你必须从你想要移动它们的值中减去它们重叠的空间量。

由于环境是2D平面,因此这应该非常简单。使用像jQuery这样的库会是一个玩笑,但即使在简单的js中也只是基本的成瘾和减法。

答案 2 :(得分:0)

假设这些框与注释中的x和y轴对齐,首先我将每个矩形的表示更改为4个点:顶部,右侧,底部,左侧,并将它们存储为矩形上的点。其次,让我们将问题简化为“给定n个矩形,矩形r可以移动到哪里的最近点,以便它不与任何其他矩形重叠”?这大大简化了问题,但也应该提供一个体面的解决方案。因此,我们有我们的功能:

function deOverlapTheHonkOuttaTheRectangle(rectangle, otherRectangles){
    ..
}

现在,每个其他矩形将禁止原始矩形的特定运动范围。因此,您计算所有这些不允许的动作。通过这些,您可以计算与原点和彼此重叠的不允许形状。例如,假设rect1不允许-3px to 5px向右和向4px to 10px向上移动,而rect2不允许-4px to 1px向右和向-2px to 5px向上移动。直到rect2出现时才考虑rect1,因为那个与原点和rect1重叠。从rect2开始,您将拥有[[-4, -2],[1,-2],[1,5],[-4,5]]。在rect1中进行计算得到[[-4, -2],[1,-2],[1,4],[5,4],[5,10],[-3,10],[-3,5],[-4,5]](见下图以便澄清)。你会为每个重叠的不允许的矩形继续构建它们。一旦考虑了所有矩形,就可以使用原点的距离公式来获得移动矩形并移动它的最小距离。

Disallowed Moves

最后,对所有剩余的矩形重复此过程。