我有一个填充算法(Flood-fill)可以填充24x24矩阵。我想为每个组使用完全相同的cspots点绘制一个类似于正方形的形状,因为cspots可以包含任意数量。所有组的cspots值的总和将等于(24 * 24),因此随着绘图的进行,面积将变得越来越不像正方形,但我想保持正方形的相似性。在此示例中,存在10组变化的cspots值,并且它们都需要尽可能全部绘制在24 * 24矩阵中。此处的Matrix为24x24,但随着生产中的小组增加,尺寸会更大。代码:
Main code:
var cspots, // number of spots per group
gArr=[]; // global array which contains all group spots
var tArr = new Array(gArr.length); // touch array for flood-fill
for(var spot in inArr) {
for (var tspot in tArr) // initialise touch array
tArr[tspot]=0;
for(gspot in gArr) { // find lowest open y*24+x ordinal
if (gArr[gspot][0] == 0)
break;
tArr[gspot]=1;
}
cspots = inArr[spot].GD;
userFill(gArr[gspot][1],gArr[gspot][2],inArr[spot].KY,tArr);
}
function userFill(x,y,elem,tArr) {
var gord, qt=0;
if (!cspots) return;
if ((x >= 0) && (x <= 23) && (y >= 0) && (y <= 23)) {
gord = y*24 + x;
if (gArr[gord][0] != 0 || tArr[gord])
return;
gArr[gord][0] = elem;
tArr[gord] = 1;
--cspots;
userFill(x+1,y,elem,tArr);
userFill(x-1,y,elem,tArr);
// before the y-change we need to see if there are any open spots on this line
for(gord=y*24; gord<=(y*24)+23; gord++) {
if (gArr[gord][0] == 0) {
qt=1;
break;
}
}
if (!qt) {
userFill(x,y+1,elem,tArr);
userFill(x,y-1,elem,tArr);
}
}
};
这是标准的泛洪填充递归算法(带有用于标记任何触摸的随附触摸数组),带有附加代码,我在更改y之前检查每个x平面上的所有x值是否都设置为非零-值。这将产生一个像这样的矩阵:
问题在于它看起来不太好(imo),因为大多数区域都沿x平面拉出。我想要的是每个不同的组区域都尽可能地呈正方形。类似于此示例(使用字母表示不同的分组区域):
V V V W W W W X X X X X
V V Y W W W W X X X X Z
Y Y Y W W W W Z Z Z Z Z
Y Y W W W W Z Z Z Z Z
... and so on
因此,我已将userFill更改为一个boxX变量,它只是(每个区域的平方)+1,希望我可以使用它来限制每个区域以形成正方形。还有一个preX变量来存储每个组区域中的锚点,因此我知道添加了多少个斑点。这是新的userFill:
Main code:
var tArr = new Array(gArr.length);
for(var spot in inArr) {
for (var tspot in tArr) // initialise touch array
tArr[tspot]=0;
for(gspot in gArr) { // find lowest open y*24+x ordinal
if (gArr[gspot][0] == 0)
break;
tArr[gspot]=1;
}
cspots = inArr[spot].GD;
boxX = Math.ceil(Math.sqrt(cspots));
preX = gArr[gspot][1];
userFill(gArr[gspot][1],gArr[gspot][2],inArr[spot].KY,tArr);
}
function userFill(x,y,elem,tArr) {
var gord, qt=0;
if (!cspots) return;
if ((x >= 0) && (x <= 23) && (y >= 0) && (y <= 23)) {
gord = y*24 + x;
if (gArr[gord][0] != 0 || tArr[gord])
return;
gArr[gord][0] = elem;
tArr[gord] = 1;
--cspots;
// before the x-change we need to see if we have done a boxX number of changes to maintain square-shape
if (Math.abs(x-preX) == boxX) {
userFill(preX,y+1,elem,tArr);
userFill(preX,y-1,elem,tArr);
return;
}
userFill(x+1,y,elem,tArr);
userFill(x-1,y,elem,tArr);
// before the y-change we need to see if there are any open spots on this line
for(gord=y*24; gord<=(y*24)+boxX; gord++) {
if (gArr[gord][0] == 0) {
qt=1;
break;
}
}
if (!qt) {
userFill(x,y+1,elem,tArr);
userFill(x,y-1,elem,tArr);
}
}
};
唯一的区别是,我检查是否已添加boxX点,然后递归调用userFill来更改y平面。
这是输出,它看起来更好,因为大多数区域都是正方形的,但是显然它需要工作(缺少大多数斑点,淡蓝色组区域的形状很奇怪,根本不是正方形的),但是我想知道是否有更好的算法可以将洪水填充量从基于行的更改为基于正方形的。
已修复:
我使用了广度优先搜索,该搜索为每个组区域创建了正方形结构。代码是:
function bfsFill(x,y,elem,tArr) {
var gord, i=0, pt, queue=[], cnt=0;
if (!cspots) return;
if (isOutOfBounds(x,y)) return;
queue.push([x,y]);
while(cspots>0 && queue.length>0) {
pt = queue.shift();
gord = pt[1]*24 + pt[0];
tArr[gord] = 1;
gArr[gord][0] = elem;
--cspots;
var rArr = neighbours(pt);
async.eachSeries(rArr, function(el, cb2) {
if (!isOutOfBounds(el[0],el[1])) {
gord = el[1]*24 + el[0];
if (tArr[gord] == 0 && gArr[gord][0] == 0) {
for(var qi in queue) {
if (queue[qi][0] == el[0] && queue[qi][1]==el[1]) {
cb2();
return;
}
}
queue.push(el);
}
}
cb2();
}, function(err) {
});
}
};