Урок 2.2. Элементарное моделирование в Processing
Базовый курс "Программирование микроконтроллеров"
Модуль 2. Создание интерактивных интерфейсов в среде Processing
Processing позволяет решать большое количество задач: от простого рисования до анализа изображений. Довольно часто им пользуются художники и учёные для визуализации различных процессов.
Нашей целью на этом занятии будет визуализировать движение группы молекул в замкнутом сосуде. Для простоты пока что не будем учитывать столкновения молекул друг с другом, но будем учитывать столкновения молекул со стенками сосуда. Начнём с создания одной молекулы, круга, который будет “чувствовать” стенки окна и отскакивать от них.
Для этого рассмотрим случаи пересечения круга с границами окна.
Пересечение с правой границей окна
При приближении круга к правому краю, он коснется его как только выполнится условие X_{c}+R \geq width, а отскок от края окна мы получим простым умножением горизонтальной скорости V_{x} – 1.
Напишем простой код для отскока круга от правого края:
void loop() {
int duration;
float cm;
// генерируем на выводе Trig положительный импульс длиной 10 мкс
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// считываем длительность импульса, т.е. время между испусканием УЗ волны и её возвратом
duration = pulseIn(echoPin, HIGH);
// вычисляем расстояние
cm = (float)duration / 58;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Dist = " + String(cm) + " cm");
delay(200);
}
Пересечение с левой границей окна
Когда круг приблизиться к левому краю, он коснется его как только выполнится условие X_{c}-R \leq 0.
Напишем простой код, для отскока круга от правого края и левого:
// координаты центра окружности
float x_c;
float y_c;
// радиус окружности в пикселях
float R=20;
// скорость нашей молекулы
float Vx=2;
float Vy=0;
void setup() {
size(800, 800);
colorMode(HSB, 360, 100, 100);
background(0);
// установка начальной позиции окружности по центру экрана
x_c = width/2;
y_c = height/2;
}
void draw() {
background(0);
fill(200, 100, 100);
circle(x_c, y_c, 2*R);
// сдвигаем молекулу
x_c=x_c+Vx;
y_c=y_c+Vy;
// есkи край молекулы коснулся края окна то изменяем скорость на противоположную
if (x_c + R >= width)
Vx=-Vx;
}
Пересечение с нижней границей окна
Когда круг приблизиться к нижнему краю, он коснется его как только выполнится условие Y_{c}+R \geq height.
Напишем простой код, для отскока круга от правого края, левого и нижнего:
// координаты центра окружности
float x_c;
float y_c;
// радиус окружности в пикселях
float R=20;
// скорость нашей молекулы
float Vx=0;
float Vy=2;
void setup() {
size(800, 800);
colorMode(HSB, 360, 100, 100);
background(0);
// установка начальной позиции окружности по центру экрана
x_c = width/2;
y_c = height/2;
}
void draw() {
background(0);
fill(200, 100, 100);
circle(x_c, y_c, 2*R);
// сдвигаем молекулу
x_c=x_c+Vx;
y_c=y_c+Vy;
// если край молекулы коснулся края окна то изменяем скорость на противоположную
if (x_c + R >= width || x_c - R <= 0)
Vx=-Vx;
if (y_c + R >= height)
Vy=-Vy;
}
Пересечение с верхней границей окна
Когда круг приблизиться к верхнему краю, он коснется его как только выполнится условие Y_{c}-R \leq 0.
Закончим наш код для отскока круга от всех границ окна:
// координаты центра окружности
float x_c;
float y_c;
// радиус окружности в пикселях
float R=20;
// скорость нашей молекулы
float Vx=3;
float Vy=2;
void setup() {
size(800, 800);
colorMode(HSB, 360, 100, 100);
background(0);
// установка начальной позиции окружности по центру экрана
x_c = width/2;
y_c = height/2;
}
void draw() {
background(0);
fill(200, 100, 100);
circle(x_c, y_c, 2*R);
// сдвигаем молекулу
x_c=x_c+Vx;
y_c=y_c+Vy;
// если край молекулы коснулся края окна то изменяем скорость на противоположную
if (x_c + R >= width || x_c - R <= 0)
Vx=-Vx;
if (y_c + R >= height || y_c - R <= 0)
Vy=-Vy;
}
Увеличение количества молекул и изменение их параметров
Теперь увеличим количество молекул, для этого создадим массивы, в которых будут хранится характеристики наших молекул, и для разнообразия при каждом запуске программы их параметры будут генерироваться случайно:
// количество молекул
int N=10;
// массив координат центра окружностей
float[] x_c= new float[N];
float[] y_c= new float[N];
// массив радиуса окружностей в пикселях
float[] R= new float[N];
// массив скоростей наших молекул
float[] Vx= new float[N];
float[] Vy= new float[N];
// массив цветов молекул
color[] c= new color[N];
void setup() {
size(800, 800);
colorMode(HSB, 360, 100, 100);
background(0);
// установка начальных параметров молекул
for (int i=0; i<N; i++)
{
R[i]=random(20, 60);
//генерация координаты от размеров молекулы до ширины - размеры молекулы, что бы молекулы не генерировались за пределами окна
x_c[i]=random(R[i], width - R[i]);
y_c[i]=random(R[i], height - R[i]);
// ((int)random(0,2) == 0 ? 1 : -1); генерация случайного значения 0 или 1, далее идёт короткая запись переключателя if
// если сгенерируется 0 то скорость умножим на 1, если сгенерируется 0 то скорость умножим на -1
Vx[i]=random(1, 5)*(int(random(0, 2)) == 0 ? 1 : -1);
Vy[i]=random(1, 5)*(int(random(0, 2)) == 0 ? 1 : -1);
c[i]=color(random(360), 100, 100);
}
}
void draw() {
background(0);
for (int i=0; i<N; i++)
{
fill(c[i]);
circle(x_c[i], y_c[i], 2*R[i]);
x_c[i]=x_c[i]+Vx[i];
y_c[i]=y_c[i]+Vy[i];
if (x_c[i] + R[i] >= width || x_c[i] - R[i] <= 0)
Vx[i]=-Vx[i];
if (y_c[i] + R[i] >= height || y_c[i] - R[i] <= 0)
Vy[i]=-Vy[i];
}
}
Далее разнообразим нашу анимацию, пусть при соударении молекулы с границей окна, она будет “отдавать” свою энергию и уменьшаться в размерах, когда она уменьшится до нуля то “возродится”.
// количество молекул
int N=10;
// массив координат центра окружностей
float[] x_c= new float[N];
float[] y_c= new float[N];
// массив радиуса окружностей в пикселях
float[] R= new float[N];
// массив скоростей наших молекул
float[] Vx= new float[N];
float[] Vy= new float[N];
// массив цветов молекул
color[] c= new color[N];
void setup() {
size(800, 800);
colorMode(HSB, 360, 100, 100);
background(0);
// установка начальных параметров молекул
for (int i=0; i<N; i++)
{
R[i]=random(20, 60);
//генерация координаты от размеров молекулы до ширины - размеры молекулы,
//чтобы молекулы не генерировались за пределами окна
x_c[i]=random(R[i], width - R[i]);
y_c[i]=random(R[i], height - R[i]);
// ((int)random(0,2) == 0 ? 1 : -1); генерация рандомного значения 0 или 1, далее идёт короткая запись переключателя if
// если сгенерируется 0 то скорость умножим на 1, если сгенерируется 0 то скорость умножим на -1
Vx[i]=random(1, 5)*(int(random(0, 2)) == 0 ? 1 : -1);
Vy[i]=random(1, 5)*(int(random(0, 2)) == 0 ? 1 : -1);
c[i]=color(random(360), 100, 100);
}
}
void draw() {
background(0);
for (int i=0; i<N; i++)
{
fill(c[i]);
circle(x_c[i], y_c[i], 2*R[i]);
x_c[i]=x_c[i]+Vx[i];
y_c[i]=y_c[i]+Vy[i];
if (x_c[i] + R[i] >= width || x_c[i] - R[i] <= 0)
{
Vx[i]=-Vx[i];
// если молекула ударилась о стенку окна уменьшаем её диаметр на 10 пикселей
R[i] = R[i] - 5;
}
if (y_c[i] + R[i] >= height || y_c[i] - R[i] <= 0)
{
Vy[i]=-Vy[i];
// если молекула ударилась о стенку окна уменьшаем её диаметр на 10 пикселей
R[i] = R[i] - 5;
}
if (R[i]<=0)
{
R[i]=random(20, 60);
//генерация координаты от размеров молекулы до ширины - размеры молекулы,
//чтобы молекулы не генерировались за пределами окна
x_c[i]=random(R[i], width - R[i]);
y_c[i]=random(R[i], height - R[i]);
}
}
}
Ну и напоследок, визуализируем связи между нашими молекулами, нарисовав линии между ними:
// количество молекул
int N=10;
// массив координат центра окружностей
float[] x_c= new float[N];
float[] y_c= new float[N];
// массив радиуса окружностей в пикселях
float[] R= new float[N];
// массив скоростей наших молекул
float[] Vx= new float[N];
float[] Vy= new float[N];
// массив цветов молекул
color[] c= new color[N];
void setup() {
size(800, 800);
colorMode(HSB, 360, 100, 100);
background(0);
// установка начальных параметров молекул
for (int i=0; i<N; i++)
{
R[i]=random(20, 60);
//генерация координаты от размеров молекулы до ширины - размеры молекулы,
//чтобы молекулы не генерировались за пределами окна
x_c[i]=random(R[i], width - R[i]);
y_c[i]=random(R[i], height - R[i]);
// ((int)random(0,2) == 0 ? 1 : -1); генерация рандомного значения 0 или 1, далее идёт короткая запись переключателя if
// если сгенерируется 0 то скорость умножим на 1, если сгенерируется 0 то скорость умножим на -1
Vx[i]=random(1, 5)*(int(random(0, 2)) == 0 ? 1 : -1);
Vy[i]=random(1, 5)*(int(random(0, 2)) == 0 ? 1 : -1);
c[i]=color(random(360), 100, 100);
}
}
void draw() {
background(0);
for (int i=0; i<N; i++)
{
fill(c[i]);
circle(x_c[i], y_c[i], 2*R[i]);
x_c[i]=x_c[i]+Vx[i];
y_c[i]=y_c[i]+Vy[i];
if (x_c[i] + R[i] >= width || x_c[i] - R[i] <= 0)
{
Vx[i]=-Vx[i];
// если молекула ударилась о стенку окна уменьшаем её диаметр на 10 пикселей
R[i] = R[i] - 5;
}
if (y_c[i] + R[i] >= height || y_c[i] - R[i] <= 0)
{
Vy[i]=-Vy[i];
// если молекула ударилась о стенку окна уменьшаем её диаметр на 10 пикселей
R[i] = R[i] - 5;
}
if (R[i]<=0)
{
R[i]=random(20, 60);
//генерация координаты от размеров молекулы до ширины - размеры молекулы,
//чтобы молекулы не генерировались за пределами окна
x_c[i]=random(R[i], width - R[i]);
y_c[i]=random(R[i], height - R[i]);
}
}
}