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)上完成。此行将从现有坐标开始,但不会在现有坐标上完成。因此该行无效。
答案 0 :(得分:5)
你可能已经注意到了,我一直回到这个问题。部分是因为我喜欢弄清楚这些问题,但也因为它让我感到烦恼,我找不到一个优雅的算法,看起来很容易。
好吧,不要被愚弄,这不是一个小问题,你可以通过一些简单的点操作来解决,虽然它看起来确实如此。造成这种情况的部分原因是,虽然您认为自己只使用积分,但您也隐含地操纵线段及其所包含的区域,这些区域也有自己的约束(即区段应该总是形成一个或多个闭合的链,除了在我们用它们定义它们的顶点之外不能相交。
此外,您的算法必须适用于任何类型的输入。也就是说,不允许产生任何答案或错误的答案,因为你喂它的多边形的方向是你的算法不喜欢的方式。
但是,您可以做的是限制算法接受的输入类型。因此,要求输入多边形仅包含轴对齐的段是完全有效的
("之间的区别是错误的方式"和"只有轴对齐的段"第一个是模糊的标准,如果不在算法上测试它就无法确定 - 而第二个是要求可以)。
总结一下,我们正在寻找一种方法将任何直线多边形(即仅由轴对齐的线段组成)水平分割成矩形。
直线多边形的示例
这是计划:
尽管这些都是实现细节,但事先清楚地了解这一点可能有助于您更好地了解算法的工作原理。
在代码中,我们将使用以下类型的对象作为基本构建块来表示我们的多边形:
此外,我们将使用网格,可以将其建模为二维数组。
您声明" 矩形必须使用在现有坐标上开始和结束的相交线形成。"。但是,请注意,大多数直线多边形不能仅通过使用现有顶点划分为矩形 - 请参阅上面的示例(以及您之前提供的大篷车示例)。
因此,即使我们实际上没有明确地创建新顶点,也必须采用这种约束。
思考实验:如果你的多边形只存在长度为10,20,30或40的(轴对齐的)段,即10的倍数怎么办?然后我们可以在网格上投影多边形,并使用位于多边形内部的网格单元来组成矩形。此外,确定这些矩形的尺寸将是轻而易举的:只计算位于多边形内的水平连续单元格的数量并乘以10;那是你的宽度。
网格对齐的多边形
好主意,除了:
接下来我们将解决所有这些问题。
如果你仔细想想,所有网格单元都没有真正的理由来拥有相同的宽度和高度。因此,我们可以设计一个间隔网格,使我们的多边形完美地对齐它。
获取网格水平轴的宽度:
网格与多边形对齐
显然,细胞的高度可以用同样的方法确定。您应该确定这些宽度和高度,并将它们分别存储在两个名为gridWidths
和gridHeights
的数组中。
现在我们知道了单元格的数量及其尺寸,我们可以开始对网格内容进行建模。
请记住,我们的多边形存储为一系列线段。要确定网格单元是否位于此多边形内,我们可以使用even-odd rule:构造从外部*多边形到我们要测试的单元格中心的线段,并计算此线段之间的交叉点数和多边形的片段(即使用Line2D.Double's intersectsLine()方法)。如果数字是偶数,则它位于多边形之外,如果它是奇数,则它在多边形内。
* - 最好只构建单元格中心之间的水平线段(如示例所示),这样您就不会冒险与段端点相交 - 这可能会计为0或2个交叉点,弄乱你的计数总数。
因此,我们将此网格建模为grid
,这是一个二维的布尔数组。以这种方式处理网格的每个单元格,并将grid
中的相应点标记为true(内部多边形)或false(外部多边形)。
基于奇偶规则的内部(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
多边形,划分为矩形。
请注意,左上角的两个矩形共享相同的起始和结束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.
接下来认识到,对于每个平板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”来查看这个坐标是否存在。如果是的话 - 我有一个矩形,如果没有 - 它是一个哑巴!!