我试图在二维平铺世界中找到一组相邻单元格(row,col)的边界多边形(可转换为矩形)。
处理for循环中的单元格并使用相邻单元格的邻域属性,我可以消除所有内部边缘并存储其余边缘。 边缘存储在std :: vector;
中现在我需要合并有共同顶点的边,斜率是相同的。 合并边后,我需要制作边界多边形,从逆时针旋转的顶点开始。
请帮助找到使其成为可能的方法。
答案 0 :(得分:2)
我认为这是一个实现这一目标的简单算法。
考虑我们将此作为输入:
| | | | | |
-+---+---+---+---+---+-
| | | | | |
-+---+---+---+---+---+-
| | | a | | |
-+---+---+---+---+---+-
| | b | c | d | |
-+---+---+---+---+---+-
| | | e | | |
-+---+---+---+---+---+-
| | | | | |
a
,b
,c
,d
和e
是我们的输入磁贴,存储为成对的对象(坐标):
std::vector<std::pair<unsigned,unsigned>> tiles;
我们想要的是:
| | | | | |
-+---+---+---+---+---+-
| | | | | |
-+---+---*---*---+---+-
| | | | | |
-+---*---* *---*---+-
| | | |
-+---*---* *---*---+-
| | | | | |
-+---+---*---*---+---+-
| | | | | |
该算法的工作原理如下:
构建一组包含整个图块的布尔值。您必须遍历该集以查找该矩形的边界。将数组的位置设置为true,表示该组的图块,否则为false
示例中的输出将是(T是true
,f是false
):
+---+---+---+
| f | T | f |
+---+---+---+
| T | T | T |
+---+---+---+
| f | T | f ]
+---+---+---+
现在你必须遍历船体多边形的边界。从标记数组中标记为true
的第一个元素开始,沿相同方向移动顶点,直到再次到达第一个顶点,使用以下规则:
如果当前方向/位置前面的两个图块为false,则顺时针旋转并将顶点添加到输出列表(多边形):
(*
是添加到多边形的顶点,X
当前顶点,箭头是当前方向)
+---+---+---+
| f | f | f |
*---+---X---+ --->
| T | T | f |
*---+---+---+
| f | T | f ]
+---+---+---+
goes to
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---X---+
| f | T | f ]
+---+---+---+
如果一个图块为假而一个为真,则向同一方向行进(请注意,true-false或false-true表示您处于边框内):
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---X---+
| f | T | f ]
+---+---+---+
goes to
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---+---+
| f | T | f ]
+---+---X---+
如果两个图块均为true,则逆时针旋转并将顶点添加到输出列表(请注意,true-true表示您已到达部分图块,a& #34;壁&#34):
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---X---+
| f | T | T ]
+---+---+---+
goes to
+---+---+---+
| f | f | f |
+---+---*---+
| T | T | f | --->
+---+---*---X
| f | T | T ]
+---+---+---+
flag-array表示tilemap放置的tilemap的矩形区域。因此,其第一个元素(tile)的tilemap坐标为(left,top)
,其中left
是所选tile集的最小x坐标,top
是最小y坐标选定的一组图块。
在算法的第二步中,您将使用数组作为指导,遍历该组图块的边界(边界)。请注意,您真正想要的是该数组,因此您必须将坐标从flag-coordinates(逻辑坐标)转换为tilemap-coordinates(物理坐标)来存储多边形的顶点。当然那很容易。
另请注意,算法抽象步骤会横切边缘的顶点(物理图块坐标),而非逻辑坐标。你必须确定&#34;我在那个顶点&#34; 意味着什么&#34;提前&#34; 和&#34 ; 转&#34;以标志数组坐标表示。
我们已经定义了三个规则来沿着这组瓷砖的边界前进。我们使用旗形阵列作为指导来决定做什么(前进,顺时针转动或逆时针转动)。请注意,当当前顶点位于数组的边框中时,您可以(您应该)认为它具有错误值的邻居图块。
例如:
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---+---+
| f | T | f ]
+---+---X---+
转到
+---+---+---+
| f | f | f |
*---+---*---+ <--
| T | T | f |
*---+---+---+
| f | T | f ]
+---X---*---+
就像是这样:
+---+---+---+
| f | f | f | |
*---+---*---+ |
| T | T | f | v
*---+---+---+
| f | T | f ]
+---+---X---+
| f | f | f |
*---*---*---+
第一步计算标志数组,因为算法将选择的一组平铺作为向量。如果您的磁贴引擎支持它,您可以向磁贴添加属性(bool selected
)并直接传递tilemap,避免计算和顶点协调转换。
给定这个flag-array:
+---+---+---+
| T | f | f |
+---+---+---+
| T | T | T |
+---+---+---+
| f | T | T |
+---+---+---+
执行如下(请注意,图纸是执行步骤后的状态):
找到第一个true
磁贴。在这种情况下(0,0)
。所以我们从它的一个顶点开始(左下顶点,向上看,例如。注意,因为它是第一个真正的平铺,你可以使用该顶点确保它属于多边形。所以首先添加顶点到多边形):
Current position: (0,1)
Polygon: {(0,1)}
+---+---+---+ ^
| T | f | f | |
X---+---+---+ |
| T | T | T |
+---+---+---+
| f | T | T |
+---+---+---+
开始横向移动。在这种情况下,前方图块为false-true
,因此提前:
Current position: (0,0)
Polygon: {(0,1)}
X---+---+---+ ^
| T | f | f | |
*---+---+---+ |
| T | T | T |
+---+---+---+
| f | T | T |
+---+---+---+
前面的瓷砖是false-false
(我们在边框中),所以顺时针旋转并添加顶点:
Current position: (1,0)
Polygon: {(0,1),(0,0)}
*---X---+---+
| T | f | f |
*---+---+---+
| T | T | T | --->
+---+---+---+
| f | T | T |
+---+---+---+
现在fron-tiles是false-false
(一个是数组之外,另一个是false
)。 顺时针旋转并添加顶点:
Current position: (1,1)
Polygon: {(0,1),(0,0),(1,0)}
*---*---+---+
| T | f | f | |
*---X---+---+ |
| T | T | T | v
+---+---+---+
| f | T | T |
+---+---+---+
两个前贴片为true
:逆时针旋转并添加顶点:
Current position: (1,2)
Polygon: {(0,1),(0,0),(1,0),(1,1)}
*---*---+---+
| T | f | f |
*---*---X---+
| T | T | T | --->
+---+---+---+
| f | T | T |
+---+---+---+
一个图块为false
,另一个图块为true
:高级:
Current position: (1,3)
Polygon: {(0,1),(0,0),(1,0),(1,1)}
*---*---+---+
| T | f | f |
*---*---+---X
| T | T | T | --->
+---+---+---+
| f | T | T |
+---+---+---+
两个false
个图块(两个都不在数组中):顺时针旋转并添加顶点:
Current position: (2,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1)}
*---*---+---+
| T | f | f | |
*---*---+---* |
| T | T | T | v
+---+---+---X
| f | T | T |
+---+---+---+
一个true
和一个false
(数组外):提前:
Current position: (3,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1)}
*---*---+---+
| T | f | f | |
*---*---+---* |
| T | T | T | v
+---+---+---+
| f | T | T |
+---+---+---X
两个false
(数组外)前贴片:顺时针旋转并添加顶点:
Current position: (2,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3)}
*---*---+---+
| T | f | f |
*---*---+---*
| T | T | T | <---
+---+---+---+
| f | T | T |
+---+---X---*
true-false
(一个true
和一个超出范围):提前:
Current position: (1,3)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3)}
*---*---+---+
| T | f | f |
*---*---+---*
| T | T | T | <---
+---+---+---+
| f | T | T |
+---X---+---*
false-false
(一个false
和一个超出范围):顺时针旋转并添加顶点:
Current position: (1,2)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3)}
*---*---+---+
| T | f | f | ^
*---*---+---* |
| T | T | T | |
+---X---+---+
| f | T | T |
+---*---+---*
true-true
前贴片:逆时针旋转并添加顶点:
Current position: (0,2)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3),(1,2)}
*---*---+---+
| T | f | f |
*---*---+---*
| T | T | T | <---
X---*---+---+
| f | T | T |
+---*---+---*
false-false
前贴片:顺时针旋转并添加顶点:
Current position: (0,1)
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3),(1,2),(0,2)}
*---*---+---+
| T | f | f | ^
X---*---+---* |
| T | T | T | |
*---*---+---+
| f | T | T |
+---*---+---*
当前顶点是多边形的第一个顶点:执行已完成。结果如下:
Polygon: {(0,1),(0,0),(1,0),(1,1),(3,1),(3,3),(1,3),(1,2),(0,2)}
*---*
| |
* *-------*
| |
*---* |
| |
*-------*
答案 1 :(得分:0)
由于瓷砖,这是寻找边界多边形的“特例”。我会采用一些简单的方法。
平铺(x,y)由顶点[(x,y),(x + 1,y),(x + 1,y + 1),(x,y + 1)]组成。如果边界多边形位于1,2或3个图块中,则它是边界多边形的一部分。要在边界上找到顶点,就足以计算它所在的平铺数量。为此,它足以通过平铺并增加平铺4顶点的顶点外观计数。平铺计数为1,2或3的顶点位于边界多边形上。
要对顶点进行排序,从边界上的某个顶点开始并查找也在边界上的相邻顶点就足够了。要在相同方向上遍历顶点,重要的是要检查相邻顶点的方向顺序以进行检查。例如。如果最后一个顶点在-x上,则检查方向的顺序是+ y,+ x,-y。
由于最后一条边的方向是已知的,如果下一条边与该顶点的方向相同,则用于移除。如果区域是简单连接的,那么也可以从瓦片计数中知道移除。如果顶点的平铺计数为2,则顶点用于删除。
目前我们无法保证订单顺时针方向。可以通过检查(某些)最上边缘(顺时针方向)来检查。如果不是,则反向多边形。