Реализация гладкой раскраски множества Мандельброта

Воссоздание того, как я раскрашиваю свой набор Мандельброта. Мне трудно реализовать его в JavaScript. В настоящее время я использую общий алгоритм «времени побега»:

 for(px = 0; px < a; px+=scale){
   for(py = 0; py < b; py+=scale){
    x0 = panX + px/zm;
    y0 = panY + py/zm;

    var x = 0;
    var y = 0;

    var i = 0;
     var xtemp;

     var xSquare = x*x;
     var ySquare = y*y;

    while (x*x + y*y <= 4  &&  i < maxI) {
      xtemp = x*x - y*y + x0
      y = 2*x*y + y0
      x = xtemp
          i += 1;
    }

    //coloring
    var shade = pallete.colourAt(i);
    c.fillStyle = "#"+shade;
    c.fillRect(px,py,scale, scale);
    }
 }

Вот полный код. Я хочу реализовать часть выше к этому псевдокоду, найденному в Википедии.

Для каждого пикселя (Px, Py) на экране выполните: { x0 = масштабированная координата x пикселя (масштабированная, чтобы лежать в масштабе Мандельброта X (-2,5, 1)) y0 = масштабированная координата y пикселя (масштабированная, чтобы лежать в шкала Y Мандельброта (-1, 1)) x = 0,0 y = 0,0 iteration = 0 max_iteration = 1000 // Здесь N=2^8 выбрано как разумный радиус спасения. в то время как ( xx + yy ‹= (1 ‹‹ 16) AND iteration ‹ max_iteration ) { xtemp = xx - yy + x0 y = 2*x< em>y + y0 x = xtemp iteration = iteration + 1 } // Используется, чтобы избежать проблем с плавающей запятой с точками внутри набора. if ( iteration ‹ max_iteration ) { // sqrt внутреннего термина удален с использованием правил упрощения журнала. log_zn = log( xx + y*y ) / 2 nu = log( log_zn / log(2)) / log(2) // Перестановка потенциальной функции. // Делим log_zn на log(2) вместо log(N = 1‹‹8) // потому что мы хотим, чтобы вся палитра располагалась // от центра до радиуса 2, а НЕ нашего радиуса спасения. итерация = итерация + 1 - nu } цвет1 = палитра[этаж(итерация)] цвет2 = палитра[этаж(итерация) + 1] // итерация % 1 = дробная часть итерации. color = linear_interpolate(color1, color2, iteration % 1) plot(Px, Py, color) }

К этому:

for(px = 0; px < a; px+=scale){
  for(py = 0; py < b; py+=scale){
    //zoom factors
    x0 = panX + px/zm;
    y0 = panY + py/zm;

    var x = 0;
    var y = 0;

    var i = 0;
    var xtemp;

    var xSquare = x*x;
    var ySquare = y*y;

    while (x*x + y*y <= 4  &&  i < maxI) {
      /*ticks++
      xtemp = x*x - y*y + x0
      y = 2*x*y + y0
      x = xtemp
      i = i + 1*/

      y = x*y;
      y += y;
      y += y0;

      x = xSquare - ySquare + x0;
      xSquare = Math.pow(x,2);
      ySquare = Math.pow(y,2);
      i += 1;
    }


    if ( i < maxI ) {

    log_zn = Math.log( x*x + y*y ) / 2
    nu = Math.log( log_zn / Math.log(2) ) / Math.log(2)



    i += 1 - nu
    }
    color1 = palette.colourAt(Math.floor(i))
    color2 = palette.colourAt(Math.floor(i) + 1)

    /*****************
    I dont know how to implement this.....
    color = linear_interpolate(color1, color2, iteration % 1)
    *****************/

    c.fillStyle = color
    c.fillRect(px,py,scale, scale);
    }
}

Но я не знаю, как реализовать эту часть псевдокода:

color1 = palette[floor(iteration)]
color2 = palette[floor(iteration) + 1]
 // iteration % 1 = fractional part of iteration.
color = linear_interpolate(color1, color2, iteration % 1)
plot(Px, Py, color)

Может ли кто-нибудь помочь мне понять и дать способ реализовать это?


person MMJM    schedule 07.05.2019    source источник
comment
Предварительный просмотр в реальном времени на https://htmlpreview.github.io/?https://github.com/pvzzombs/mandelbrots-in-javascript/blob/master/test.html   -  person MMJM    schedule 09.05.2019


Ответы (1)


Предполагается, что функция linear_interpolate вычисляет цвет между двумя цветами на основе линейной функции y = mx + b. Чтобы применить линейную функцию к цветам, y — это выходной цвет, m — разница между двумя цветами, b — начальный цвет, а x — значение от 0 до 1. Когда x равно 0, эта функция выводит начальный цвет. Когда x равно 1, эта функция выводит конечный цвет.

Для этого расчета нам нужен цвет в виде трех чисел. Если вам нужно использовать шестнадцатеричные строки, вам придется разделить их и проанализировать каждые два символа как 16-битное число. Я буду использовать палитру, которая уже имеет числовую форму, потому что это проще.

Вот моя трехцветная палитра. Я не рекомендую вам использовать эти цвета, это просто для демонстрации:

let palette = [{r:255,g:0,b:0},{r:0,g:255,b:0},{r:0,g:0,b:0}]

Эта первая функция выполняет итерацию, которая, вероятно, не является целым числом и может быть больше 1. Она занимает пол итерации, превращая его в целое число, которым должен быть индекс массива. Затем остаток итерации делится на 1, чтобы получить число от 0 до 1.

function interpolation(iteration) {
    let color1 = palette[Math.floor(iteration)];
    let color2 = palette[Math.floor(iteration) + 1];
    return linear_interpolate(color1, color2, iteration % 1);
}

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

function linear_interpolate(color1, color2, ratio) {
    let r = Math.floor((color2.r - color1.r) * ratio + color1.r);
    let g = Math.floor((color2.g - color1.g) * ratio + color1.g);
    let b = Math.floor((color2.b - color1.b) * ratio + color1.b);
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

Вот прямоугольники штриховки кода: https://jsfiddle.net/q7kLszud/

person aptriangle    schedule 07.05.2019