2013-11-08 4 views
0

Мне нужна функция, которая создает 2D-массив, похожий на эллипс, где каждая ячейка является пикселем, который может быть включен (1) или выключен (0). Например, если вы запускали circlearray(5,8), она возвращает что-то вроде:Как сделать 2D-массив похожим на эллипс

[[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

Можете ли вы сделать jsfiddle для нас, чтобы играть? :) – naththedeveloper

+0

Имейте в виду, что способ отображения массива не будет соответствовать тому, как он отображается в виде растрового изображения, поскольку вы используете символы, которые имеют соотношение сторон примерно 0,4 вместо 1,0. –

ответ

1

Я предполагаю, что вы имеете в виду эллипс с большими и малыми осями выровнены по горизонтали и по вертикали , (Построение эллипса в общей ориентации является гораздо более сложной задачей.)

Вы хотите обобщение Bresenham circle algorithm для эллипсов. Хорошее описание теории и реализации описано в this paper. Простой код можно найти 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 не имеет целочисленного деления.) Вместо setPixel, вы, естественно, просто установите элемент массива равным 1.

Примечание. что это изображает одноэлементную эллипсовую границу. Если вы хотите заполненный эллипс, просто примените строку строки сканирования: итерации по строкам и заполните между двумя столбцами, которые установлены выше 1 (или оставьте одну строку, если вы не найдете два разных набора колонок). В качестве альтернативы вы могли бы выполнить описанную выше операцию с flood fill algorithm, начиная с центра прямоугольника.

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