Недавно я начал экспериментировать с Processing и P5.js, и хотя я еще не эксперт, мне это очень нравится.

Я наткнулся на пост Дилемма распределения очков на сабреддите r/processing, где addictedtobiscuits пытается воссоздать следующее изображение с обработкой.

Я подумал, что это будет интересный вызов. Я быстро сделал небольшой набросок, чтобы воссоздать этот эффект, и хотел задокументировать ход своих мыслей. Я совершенно уверен, что это можно сделать разными способами, но вот мой подход и решение. Но прежде чем мы перейдем к объяснениям, я хотел бы поделиться своим конечным результатом, который довольно близок к изображению выше.

Я написал свой скетч на JavaScript с использованием P5.js, но его можно легко преобразовать в Java для обработки. Дэниел Шиффман написал отличное пособие о том, как работает распределение Гаусса. Если вы еще не видели его видео Coding Train, я очень рекомендую его.

Вот мой мыслительный процесс и подход. Для облегчения вычислений я собираюсь использовать холст размером 1000x1000px.

Шаг 1. Давайте начнем с размещения воображаемого прямоугольника на нашем холсте и добавления к нему случайных пикселей.

На приведенном выше рисунке видно, что наши произвольно расположенные точки должны располагаться между 300px и 700px по оси X и 200px. и 800px по оси Y. Мы можем перевести это в код, который выглядит примерно так:

function setup() {
  createCanvas(1000, 1000);
  background(10);
}
function draw() {
  stroke(245);
  var xloc = random(300, 700);
  var yloc = random(200, 800);
  point(xloc, yloc);
}

и после запуска этого в течение некоторого времени мы должны увидеть что-то похожее на изображение ниже:

Шаг 2. Это было легко. Теперь давайте попробуем выяснить, как мы можем сделать это с трапецией.

Мы разобьем это на 2 задачи.

Первый чуть проще. Для оси Y наши точки должны быть расположены точно так же, как и раньше, между 200px и 800px.

Второй для оси X может показаться немного сложным, но у нас есть все числа, чтобы выяснить, где должны располагаться наши случайные точки. Давайте посмотрим на верхнюю часть, она должна быть между 300px и 700px. В нижней части трапеции они должны быть между 200px и 800px.

Как мы рассчитываем, где точки должны находиться где-то между верхом и низом? Ответ заключается в том, что мы будем использовать значение переменной yloc, чтобы помочь нам в этом. Мы знаем, что он изменяется от 200px до 800px, что означает, что высота трапеции составляет 600px. Ширина нижней части трапеции также составляет 600 пикселей, что означает, что по сравнению с верхней частью она простирается на 100 пикселей влево и на 100 пикселей вправо. на дне.

По мере увеличения ylocvalue (сверху вниз) нам нужно настроить xloc так, чтобы он смещался на 100 пикселей влево и на 100 пикселей вправо. Другими словами, когда yloc равно 800px, нам нужно сделать так, чтобы диапазон xloc находился между 200px (300px — 100px = 200px) и 800px(700px + 100px = 800px) .

Теперь нам просто нужно выяснить, каковы эти 100px по отношению к высоте трапеции. (100 / 600) * 100 = 16.666666667% Таким образом, при любом заданном значении yloc наше shift должно составлять около 16,6% от значения yloc. Поскольку мы имеем дело с yloc (который попадает в границы трапеции), но начинается со значения 200px, мы можем сказать, что наш сдвиг по оси X следует рассчитывать как (yloc — 200) * 0.166.

Основываясь на всех этих вещах, мы можем придумать код для заполнения нашей трапеции случайными точками, чтобы ни одна из них не выходила за границы трапеции. Имейте в виду, что нам пришлось поднять yloc присваивание, потому что нам нужно объявить его и выбрать случайным образом, чтобы вычислить xloc

function setup() {
  createCanvas(1000, 1000);
  background(10);
}
function draw() {
  stroke(245);
  var yloc = random(200, 800);
  var shift = (yloc - 200) * 0.166;
  var xloc = random(300 - shift, 700 + shift);
  point(xloc, yloc);
}

Выполнение этого кода даст нам что-то вроде этого:

Шаг 3. Давайте уже перейдем к randomGaussian().

Эта часть довольно проста. Нам нужно определить стандартное отклонение (sd) и среднее (mean) число.

Нам нужно переключить расчет yloc с использования метода random() на использование метода randomGaussian() и внести некоторые очень незначительные корректировки.

Давайте посмотрим, как мы можем это сделать. Для стандартного отклонения мы можем выбрать произвольное число и посмотреть, насколько хорошо оно работает. Давайте выберем 180. Зная, что распределение Гаусса дает как положительные, так и отрицательные числа, мы изменим их все на положительные с помощью функции abs(), а затем добавим mean из 200, чтобы сдвинуть все вниз на 200 пикселей (помните, что здесь находится наша верхняя сторона трапеции). И затем мы ограничиваем координаты между 200px и 800px, чтобы предотвратить случайную точку, опускающуюся ниже границы трапеции. В коде это будет выглядеть так:

var sd = 180;
var mean = 200;
var yloc = randomGaussian();
yloc = abs(yloc * sd) + mean;
yloc = constrain(yloc, 200, 800);

Я думаю, что у нас есть все кусочки головоломки, и мы готовы собрать ее вместе. При этом весь наш скетч будет выглядеть так:

var sd = 180;
var mean = 200;
function setup() {
  createCanvas(1000, 1000);
  background(10);
}
function draw() {
  stroke(245);
  var yloc = randomGaussian();
  yloc = abs(yloc * sd) + mean;
  yloc = constrain(yloc, 200, 800);
  var shift = (yloc - 200) * 0.166;
  var xloc = random(300 - shift, 700 + shift);
  
  point(xloc, yloc);
}

Вуаля! Вот наш окончательный результат после запуска этого скетча в течение некоторого времени:

Вы можете найти код для этого скетча и поиграть с ним на https://editor.p5js.org/morozgrafix/sketches/Hkkiu45pm.

Чуть более изящная версия, которая создала изображение заголовка для этого поста, доступна на https://www.openprocessing.org/sketch/627094.

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

Спасибо и хорошего дня!