填充带圆形区域的二维阵列

时间:2015-06-01 23:05:03

标签: javascript arrays geometry

我想要一个看起来像这样的数组:

[
[0,0,1,1,1,0,0],
[0,1,1,1,1,1,0],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[0,1,1,1,1,1,0],
[0,0,1,1,1,0,0],
]

我的第一个方法是获得周长

var steps = 100;
var coord = [];
var x,y;
for (var i = 0; i < steps; i++) {
    var phase = 2 * Math.PI * i / steps;
    x = Math.round(cenx + range * Math.cos(phase));
    y = Math.round(ceny + range * Math.sin(phase))

    if(x>=0 && y >=0){
        coord.push([x,y]);
    }
}

并且由此产生的坐标我可能已经玩弄周围以获得圆形区域。但我怀疑这是否有效。

所以我的第二种方法是检查数组的每个条目是否与我的圆心有一定的距离(即半径)。但对于那些不具备高性能的巨大地图。也许仅在合理的框架内进行检查会更明智。

但我确定有一个更好的方法来解决这个问题。 我需要这个以实现战争迷雾。

3 个答案:

答案 0 :(得分:3)

测试数组中每个点的第二个建议方法很容易实现,并且可以优化为内循环中每个元素的一个减法,一个乘法和一个测试。

基本测试是((x - centerX) * (x - centerX)) + ((y - centerY) * (y - centerY)) > radiusSq,但由于((y - centerY) * (y - centerY))对于给定的行是常量,因此您可以将其移到循环外。

鉴于您必须访问数组中的每个元素并设置它(意味着您的算法在圆半径上始终为O(n 2 )),测试成本可以忽略不计:

    // circle generation code:
    function makeCircle(centerX, centerY, radius, a, arrayWidth, arrayHeight)
    {
        var x, y, d, yDiff, threshold, radiusSq;
        radius = (radius * 2) + 1;
        radiusSq = (radius * radius) / 4;
        for(y = 0; y < arrayHeight; y++)
        {
            yDiff = y - centerY;
            threshold = radiusSq - (yDiff * yDiff);
            for(x = 0; x < arrayWidth; x++)
            {
                d = x - centerX;
                a[y][x] = ((d * d) > threshold) ? 0 : 1;
            }
        }
    }
    
    // test code:
    var width = 7;
    var dim = (width * 2) + 1;
    var array = new Array(dim);
    for(row = 0; row < dim; row++)
        array[row] = new Array(dim);
    
    makeCircle(width, width, width, array, dim, dim);
    
    for(var y = 0, s = ""; y < dim; y++)
    {
        for(var x = 0; x < dim; x++)
        {
            s += array[y][x];
        }
        s += "<br>";
    }
    document.body.innerHTML += s + "<br>";

答案 1 :(得分:2)

我会使用mid-point circle算法并将数组视为位图。

我曾经做过这个JavaScript实现,在这里进行了修改,使用数组作为“像素”的目标源。请注意,圆形将产生奇数宽度和高度,因为距离始终来自单个中心点,在这种情况下我们只能使用整数值。

提示:为了提高速度,您可以使用类型化数组而不是常规数组(如下所示)。

实施例

确保使用整数值作为输入,代码将剪切值位于“位图”/数组之外 -

var width = 7, height = 7,
    array = new Uint8Array(width * height);

// "draw" circle into array
circle(3, 3, 3);
renderDOM();

// circle example 2
width = height = 17;
array = new Uint8Array(width * height);

circle(8, 8, 8);
renderDOM();

function circle(xc, yc, r) {
  if (r < 1) return;

  var x = r, y = 0,  // for Bresenham / mid-point circle
      cd = 0,
      xoff = 0,
      yoff = r,
      b = -r,
      p0, p1, w0, w1;

  while (xoff <= yoff) {
    p0 = xc - xoff;
    p1 = xc - yoff;
    w0 = xoff + xoff;
    w1 = yoff + yoff;

    hl(p0, yc - yoff, yc + yoff, w0);  // fill a "line"
    hl(p1, yc - xoff, yc + xoff, w1);

    if ((b += xoff+++xoff) >= 0) {
      b -= --yoff + yoff;
    }
  }

  // for fill
  function hl(x, y1, y2, w) {
    w++;
    var xw = 0;
    while (w--) {
      xw = x + w;
      setPixel(xw, y1);
      setPixel(xw, y2);
    }
  }

  function setPixel(x, y) {
	if (x < width && y < height && x >= 0 && y >= 0)
		array[y * width + x] = 1;
  }
}

function renderDOM() {
  for(var i = 0, str = ""; i < array.length; i++) {
    if (i > 0 && !(i % width)) str += "<br>";
    str += array[i];
  }
  document.body.innerHTML += str + "<br><br>";
}
body {font:18px monospace}

答案 2 :(得分:1)

对于奇数大小的数组(2r + 1 x 2r + 1),

for (row= 0; row < 2 * r + 1; row++)
{
  f= (row + 1) * (row - 2 * r - 1) + r * r + r;
  for (col= 0; col < 2 * r + 1; f+= 2 * (col - r) + 1; col++)
  {
    array[row][col]= f >= 0;
  }
}