0

我需要一个函数来创建一个类似于椭圆的二维数组,其中每个单元格都是一个像素,可以打开 (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

4

2 回答 2

1

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

您想要对椭圆的Bresenham 圆算法进行概括。本文对理论和实现进行了很好的描述。可以在这里找到简单的代码,用于使用 Bresenham 的直线、圆、椭圆和 Bézier 曲线的算法。从后一个站点,这里是在指定矩形内绘制椭圆的代码:

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 没有整数除法这一事实。)setPixel当然,您只需将数组元素设置为 1 即可。

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

于 2013-11-08T17:16:48.197 回答
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)
}

演示

于 2013-11-08T17:27:13.057 回答