从坐标/点数组中创建矩形

时间:2012-11-26 16:47:24

标签: algorithm rectangles

http://img853.imageshack.us/img853/2475/picture1eu.jpg

我有一个点/坐标的ArrayList,它代表一个直线多边形。我现在想要使用我的ArrayList中存储的点将这个形状分解为矩形。

我已经启动了算法,但我无法完成它,我觉得必须有一个更简单的方法:

ArrayList被称为“allCoordinates”。
ArrayList“xMatch”和“yMatch”是allCoordinates的子集。

算法:

ArrayList yMatch = All matching Coordinates in respect to 'y'


因此,在上图的情况下:
(设置1 = [x1,y1] - [x8,y8],
Set2 = [x7,y7] - [x2 ,y2],
Set3 = [x4,y4] [x5,x5],
Set4 = [x3,y3] [x6,x6])

ArrayList xMatch = All matching Coordinates in respect to 'x'


因此,在上图的情况下:
(设置1 = [x1,y1] - [x2,y2],
Set2 = [x3,y3] - [x4 ,y4],
Set3 = [x5,y5] [x6,x6],
Set4 = [x7,y7] [x8,x8])


所以现在我有两个数组列表,所有垂直边缘和所有水平边缘。现在我需要一些方法来检查它们是否全部连接在一起?就像我说的那样,必须有一种更简单的方式......?

编辑:

我可以澄清一下,必须使用在现有坐标上开始和结束的相交线来形成矩形。例如,可以从(x6,y6)水平绘制一条线,并在边缘(x1,y1) - (x8,y8)上完成。此行将从现有坐标开始,但不会在现有坐标上完成。因此该行无效。

4 个答案:

答案 0 :(得分:5)

你可能已经注意到了,我一直回到这个问题。部分是因为我喜欢弄清楚这些问题,但也因为它让我感到烦恼,我找不到一个优雅的算法,看起来很容易。

好吧,不要被愚弄,这不是一个小问题,你可以通过一些简单的点操作来解决,虽然它看起来确实如此。造成这种情况的部分原因是,虽然您认为自己只使用积分,但您也隐含地操纵线段及其所包含的区域,这些区域也有自己的约束(即区段应该总是形成一个或多个闭合的链,除了在我们用它们定义它们的顶点之外不能相交。

此外,您的算法必须适用于任何类型的输入。也就是说,不允许产生任何答案或错误的答案,因为你喂它的多边形的方向是你的算法不喜欢的方式。
但是,您可以做的是限制算法接受的输入类型。因此,要求输入多边形仅包含轴对齐的段是完全有效的 ("之间的区别是错误的方式"和"只有轴对齐的段"第一个是模糊的标准,如果不在算法上测试它就无法确定 - 而第二个是要求可以)。

总结一下,我们正在寻找一种方法将任何直线多边形(即仅由轴对齐的线段组成)水平分割成矩形。

Example of a rectilinear polygon 直线多边形的示例

这是计划:

  1. 选择我们的构建块
  2. 允许额外的顶点
  3. 在网格上对齐。
  4. 使用不等大小的网格单元。
  5. 您的多边形中有哪些单元格?
  6. 构建矩形。
  7. 选择我们的构建块

    尽管这些都是实现细节,但事先清楚地了解这一点可能有助于您更好地了解算法的工作原理。

    在代码中,我们将使用以下类型的对象作为基本构建块来表示我们的多边形:

    • Point,由x和y坐标组成。 (例如使用Point2D.Double
    • 细分,包含起点和终点(例如使用Line2D.Double
    • 多边形,由一段封闭的Segments链组成(例如,使用Line2D.Double的ArrayList),其中一个段在与下一个段的起点相同的点上结束。

    此外,我们将使用网格,可以将其建模为二维数组。

    允许额外的顶点。

    您声明" 矩形必须使用在现有坐标上开始和结束的相交线形成。"。但是,请注意,大多数直线多边形不能仅通过使用现有顶点划分为矩形 - 请参阅上面的示例(以及您之前提供的大篷车示例)。

    因此,即使我们实际上没有明确地创建新顶点,也必须采用这种约束。

    在网格上对齐。

    思考实验:如果你的多边形只存在长度为10,20,30或40的(轴对齐的)段,即10的倍数怎么办?然后我们可以在网格上投影多边形,并使用位于多边形内部的网格单元来组成矩形。此外,确定这些矩形的尺寸将是轻而易举的:只计算位于多边形内的水平连续单元格的数量并乘以10;那是你的宽度。

    Grid-aligned polygon 网格对齐的多边形

    好主意,除了:

    • 多边形不仅包含相同或多个长度的段
    • 我们如何确定哪些网格单元位于多边形内?

    接下来我们将解决所有这些问题。

    使用不等大小的网格单元。

    如果你仔细想想,所有网格单元都没有真正的理由来拥有相同的宽度和高度。因此,我们可以设计一个间隔网格,使我们的多边形完美地对齐它。

    获取网格水平轴的宽度:

    • 收集构成多边形的顶点的所有x坐标。
    • 重复删除并按值增加对其进行排序。
    • 然后,两个后续值之间的差异定义该列的宽度。

    Grid aligned to the polygon 网格与多边形对齐

    显然,细胞的高度可以用同样的方法确定。您应该确定这些宽度和高度,并将它们分别存储在两个名为gridWidthsgridHeights的数组中。

    现在我们知道了单元格的数量及其尺寸,我们可以开始对网格内容进行建模。

    多边形内有哪些单元格?

    请记住,我们的多边形存储为一系列线段。要确定网格单元是否位于此多边形内,我们可以使用even-odd rule:构造从外部*多边形到我们要测试的单元格中心的线段,并计算此线段之间的交叉点数和多边形的片段(即使用Line2D.Double's intersectsLine()方法)。如果数字是偶数,则它位于多边形之外,如果它是奇数,则它在多边形内。

    * - 最好只构建单元格中心之间的水平线段(如示例所示),这样您就不会冒险与段端点相交 - 这可能会计为0或2个交叉点,弄乱你的计数总数。

    因此,我们将此网格建模为grid,这是一个二维的布尔数组。以这种方式处理网格的每个单元格,并将grid中的相应点标记为true(内部多边形)或false(外部多边形)。

    Inside (T) or outside(F) based on the even-odd rule 基于奇偶规则的内部(T)或外部(F)

    构造矩形。

    现在我们有多边形的网格表示,以及每个单元格的实际宽度和高度,我们可以开始构造矩形。我假设您只对每个矩形的宽度和高度感兴趣,而不是对形成矩形的实际顶点坐标感兴趣(尽管现在也很容易)。

    Foreach row in grid
      run_start = null
      Foreach cell C in row
        if C is marked as true and run_start = null
          //Found the start of a new run
          run_start = C
        else if C is marked as false and run_start != null
          //Found the end of a run
          The cells [run_start...C] form a horizontal rectangle.
          Use the gridWidths and gridHeights arrays to determine the 
          dimensions, and report this rectangle as a result
    
          //Prepare for the next run
          run_start = null
    

    The polygon, partitioned into rectangles. 多边形,划分为矩形。

    请注意,左上角的两个矩形共享相同的起始和结束x坐标,因此可以视为一个矩形。如果需要,可以实现合并这些类型矩形的附加传递。

    结论

    通过将直线多边形映射到网格上,我们可以轻松地将其水平分割为矩形,而无需借助更高级的几何数据结构。
    请注意,有一些优化可以使这个算法运行得更快,但我认为它对于当前的输入大小并不重要,并且会使实现更加困难。

答案 1 :(得分:3)

这并不容易:

我认为你不会成功解决这个问题:

更多信息,请参阅

  

Preparata,Shamos:计算几何:第8章:几何学   矩形。

首先应熟悉平面扫描算法和Intervall树。

如果我找到更多,我会更新。 发现更多:

Algorithm for finding the fewest rectangles to cover a set of rectangles without overlapping

答案 2 :(得分:1)

注意:我不打算在这里找到理论上最优的解决方案,而只是针对一种产生正确答案的方法,并且在100个顶点的输入多边形上运行得足够快。此外,现在不考虑特殊情况,例如带有孔的输入多边形。此外,非x-单调*的多边形需要预处理,我将不讨论 *含义:从P的任何最左侧位置开始,您可以通过向上,向下或向右移动到达任何其他位置,但不会向左移动。

<强>假设
如您earlier post所述,部分问题是铺设铺面板(或“矩形”)的方向,以尽量减少使用的铺面板数量。我将假设您的输入多边形P将主要由轴对齐的段组成,因此方向上的选择将减少到水平或垂直。对于其余部分,我将假设单个装饰板始终垂直定向(即从顶部到底部)。要使用水平装饰板计算结果,只需将P旋转90度即可。

问题陈述
我们将尝试使用装饰板覆盖P,每个装饰板具有无限长度和最大宽度W.更具体地说,我们正在寻找覆盖范围,以最小化所有使用的装饰板的总长度。落在P外的使用过的铺板的部分(即浪费)不能用于覆盖P的其他部分。 为了最大限度地减少浪费,将装饰板的左边界或右边界与P的顶点对齐,或者将装饰板放在另一个装饰板旁边是有意义的。

<强>解决方案
朝向这一步的第一步是将P分割为垂直平板的集合:取P中所有顶点的不同x坐标并对它们进行排序:每对连续的x坐标然后定义P的平板S. Figure 1

接下来认识到,对于每个平板S,我们有4种可能的方法将(一个或多个)平板对齐到它:
*(SL)从左侧开始,即将装饰板的左侧与平板的左侧对齐 *(CL)继续向左,即继续由其左侧的板确定的装饰板图案 *(CR)继续向右,即继续由其右侧的板确定的装饰板图案 *(SR)向右开始,即将铺板的右侧与板的右侧对齐。

因此,如果我们考虑每个板坯S的4个对准的所有可能组合,我们具有所有可能的铺面配置。请注意,并非所有对齐组合都是允许的; SL和SR可用于任何板坯,但CL只能在其左侧的板坯为SL或CL时使用,而CR只能在其右侧的板坯为SR或CR时使用。

-Snip- 问题似乎与此处尝试解决的问题有很大不同,所以我不会完成这篇文章。

答案 3 :(得分:0)

我找到了一个解决方案,但它可能不是最优的。


link http://img842.imageshack.us/img842/9672/picture1ou.png

所以这里我们有坐标和前面提到的两个ArrayLists - xMatch和yMatch。

xMatch =具有匹配的x坐标的坐标对的ArrayList
yMatch =具有匹配的y坐标的坐标对的ArrayList

我创建了一个名为“Point2Point”的类,它按特定顺序保存了两个coorindate。 xMatch和yMatch都是“Point2Point”类型。像任何矢量一样,顺序很重要。我使用的订单是:


Point1 =起点
Point2 =终点。

所以现在使用“for”循环我将来自xMatch的元素与来自yMatch的元素相对于Point1(起始点)进行匹配。将它们配对会给你以下形状:



Link2 http://img846.imageshack.us/img846/452/picture2zu.png


现在,您可以看到,为了使这两个矢量成为矩形的一部分,必须存在坐标(?,?)。使用rectange的属性我知道(?,?)等于(yMatch.Point2.x,xMatch.Point2.y)或关于此图(x3,y2)。


现在我知道要查找哪个坐标我可以搜索我的ArrayList“allCoordinates”来查看这个坐标是否存在。如果是的话 - 我有一个矩形,如果没有 - 它是一个哑巴!!