如何制作类似于椭圆的2D数组

时间:2013-11-08 15:09:14

标签: javascript arrays geometry ellipse

我需要一个创建类似于椭圆的2D数组的函数,其中每个单元格都可以是(1)或关闭(0)的像素。例如,如果您运行circlearray(5,8),它将返回类似于:

的内容
[[0, 1, 1, 1, 0],
 [0, 1, 1, 1, 0],
 [1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1],
 [1, 1, 1, 1, 1],
 [0, 1, 1, 1, 0],
 [0, 1, 1, 1, 0]];

我之前尝试过这个,但似乎无法得到舍入(十进制到整数,而不是使它成为椭圆)。我使用的公式是:f(x) = h/w * sqrt(w^2 - x^2),其中h是椭圆顶部半径的长度,w是椭圆边的半径长度。它给出了给定行的圆圈应该有多少列,但是对于圆圈,我注意到它的侧面是不同的直立,我知道不应该这样。我似乎无法通过Math.round(f(x))Math.floor(f(x))Math.ceil(f(x))获得正确的圈子。我也不想使用jQuery。

这是一个jsFiddle显示我的发现:http://jsfiddle.net/r7cH5/

以下是如何使用公式的示例:http://www.desmos.com/calculator/v5qbcd1jkm

2 个答案:

答案 0 :(得分:1)

我假设你的意思是一个椭圆,其长轴和短轴水平和垂直对齐。 (在一般方向上绘制椭圆是一个更加困难的问题。)

您想要省略Bresenham circle algorithm的省略号。 this paper中描述了对理论和实现的一个很好的描述。对于线,圆,椭圆和贝塞尔曲线使用Bresenham算法,可以找到简单的代码here。从后一个站点,这里是在指定矩形内绘制椭圆的代码:

void plotEllipseRect(int x0, int y0, int x1, int y1)
{
   int a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */
   long dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
   long err = dx+dy+b1*a*a, e2; /* error of 1.step */

   if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped points */
   if (y0 > y1) y0 = y1; /* .. exchange them */
   y0 += (b+1)/2; y1 = y0-b1;   /* starting pixel */
   a *= 8*a; b1 = 8*b*b;

   do {
       setPixel(x1, y0); /*   I. Quadrant */
       setPixel(x0, y0); /*  II. Quadrant */
       setPixel(x0, y1); /* III. Quadrant */
       setPixel(x1, y1); /*  IV. Quadrant */
       e2 = 2*err;
       if (e2 <= dy) { y0++; y1--; err += dy += a; }  /* y step */ 
       if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */
   } while (x0 <= x1);

   while (y0-y1 < b) {  /* too early stop of flat ellipses a=1 */
       setPixel(x0-1, y0); /* -> finish tip of ellipse */
       setPixel(x1+1, y0++); 
       setPixel(x0-1, y1);
       setPixel(x1+1, y1--); 
   }
}

当然,这不是JavaScript,但转换应该很简单。 (由于不涉及整数除法,因此您不必担心JavaScript没有整数除法这一事实。)当然,您只需将数组元素设置为1,而不是setPixel。 / p>

请注意,这会绘制一个像素厚的椭圆边界。如果你想要一个填充的椭圆,只需应用一个扫描线填充:逐行迭代并填充由上面设置为1的两列之间(如果没有找到两个不同的列,则保留行。)或者,您可以从矩形中心开始用flood fill algorithm跟进上述内容。

答案 1 :(得分:0)

var width = 100,
    height = 160,
    span = document.createElement('span'),
    output = document.getElementById("output");

function ellipse(x) {
    return Math.floor((height / width) * Math.sqrt((width * width) - (x * x))); // Times itself doesn't give NaN as often as squared.
}

for (var i = -1 * width; i <= width; i++) {
    var s = span.cloneNode(false);
    s.style.height = ellipse(i) + 'px';
    output.appendChild(s)
}

Demo