2D Bin Packing / Tile算法 - 多边形内的矩形瓷砖

时间:2016-06-10 18:33:49

标签: algorithm polygon tile bin-packing

我正在解决一个问题。我想有效地平铺多边形。

  • 多边形是随机的。它可以是从三角形(边数= 3)到圆形(边数=无穷大)的任何形状。它可以是凹的或凸的。
  • 所有瓷砖都是固定尺寸的矩形。
  • 所有瓷砖都具有相同的方向。
  • 如果它使对话更容易,我们可以使用正方形作为平铺形状。
  • 瓷砖平行/垂直于多边形的最长腿,无论如何。
  • 我在浏览器上使用JavaScript运行,而我只使用一个多边形。实际上,多边形是由用户手动生成的。
  • 我不需要疯狂的高包装效率,但需要合理的性能来平铺多边形。 (我不是在寻找NP难解决方案..)
  • 我只会填充一个多边形,我怀疑图块数量是否会超过100.

我找到了测试多边形到多边形干扰的出色参考。代码从Paul Bourke撰写的this posting,中熠熠生辉。

两个多边形之间的一般交叉测试如下:

/*
   Return FALSE if two polygon intersect.
   Polygon p1[] is of length n1 and polygon p2[] is of length n2.
   Polygons are define with vertices ordered clockwise.
*/
int PolygonPolygon(XY *p1,XY *p2,int n1,int n2)
{
   int i,j;
   // Reject if a vertex of p1 is inside p2, And visa versa
   for (i=0;i<n2;i++) {
      if (InsidePolygon(p1,n1,p2[i]))
         return(FALSE);
   }
   for (i=0;i<n1;i++) {
      if (InsidePolygon(p2,n2,p1[i]))
         return(FALSE);
   }
   // Reject any intersecting edges
   for (j=0;j<n1;j++) {
      for (i=0;i<n2;i++) {
         if (LineIntersect(p1[j].x,p1[j].y,p1[(j+1)%n1].x,p1[(j+1)%n1].y,
                           p2[i].x,p2[i].y,p2[(i+1)%n2].x,p2[(i+1)%n2].y))
            return(FALSE);
      }
   }
   return(TRUE);
}

这些测试的支持功能在这里给出:LineIntersect.c和这里:InsidePolygon.c。 (更新:显然我需要稍微修改这三个函数,看看是否瓷砖是多边形的完全OUTSIDE还是与多边形相交的边缘。抱歉最初将它留下......不用说我必须转换它们也适用于JavaScript。)

我的问题与合理的算法有关。

方法1(盲人领导盲人)

  • 转到多边形外边界的左上角。使用图块的网格布局,直到所有边界都被图块覆盖。测试干扰或超出范围。
  • 如果干扰,请移除瓷砖。
  • 我必须修改此方法的交叉点测试以包含测试“是否所有四个顶点都位于多边形之外?”如果是,请删除该磁贴。

方法2(滑动直至停止)

  • 选择质心到达多边形边界的点。
  • 将瓷砖居中。测试干扰。
  • 如果干扰,抓住距离质心的另一个随机点XYZ距离,再试一次。在不同方向尝试X次,如果失败,则再次增加半径y并再次尝试。如果完全没有去,叹气,并提示用户在多边形内的最大开放区域中单击鼠标。
  • 从那一点开始,向多边形最长腿的中心滑动,即设置瓷砖角度方向的中心。增量,测试,增量测试。在某些时候,瓷砖会碰到一些东西。将瓷砖滑到“*左下角”,它会点击其他东西。停止。从那里平铺多边形的其余部分直到你到达边界。删除多边形之外的所有切片或干扰多边形的边界。

我的直觉说方法2会产生更好的结果,但是就是这个用例:tile into polygon

我对bin打包做了很多评论,但因为多边形的形状很奇怪,所以它们看起来并不合适。这是一个很好的参考,Solving the 2D Packing Problem by Rod Stephens瓷砖上有很多东西/包装一个矩形,在包装多边形时根本不多。

有更好的算法吗?我的两种算法都有漏洞吗?以前有人来过这里吗?非常感谢。

编辑:我收到了一条评论,要求显示所需输出的图像。在我准备解决方案时,我在原始陈述的问题中意识到了一些错误(涉及所需的干扰测试)。我添加了一个带有标记图块的所需输出图像,以简化接下来的对话。我也意识到我应该添加第三种方法。

方法#3,一次一条。滑动并检查。

  • 从多边形的最长腿的左侧开始。添加一块瓷砖,看它是否合适,如果有干扰,请将其“向右”滑动直到没有干扰。
  • 添加更多图块以完成该行。
  • 从开始行的正上方开始下一行。将瓷砖推到尽可能“向左”的位置。
  • 添加更多图块以完成该行。
  • 继续添加行,向左滑动,然后向右滑动。
  • 在所示示例的顶行上有一个真正的技巧。瓦片#11和#12让人感到惊讶,我想添加了一个修改......当行结束时,你应该继续增量滑动并重新测试,直到到达多边形的外边界。

建议的完整解决方案:

square tiles contained within a polygon

注意:我没有一种能够识别瓷砖#13的方法,除非它只适用于使用盲运的方法一。

0 个答案:

没有答案