Использованы материалы сайта Арбуз - угощение для технической интеллигенции
Мыльный пузырь, пожалуй, самое восхитительное
и самое
изысканное явление природы.
Марк Твен
Из многих замечательных и до конца не изученных свойств воды самым
потрясающим является, конечно же, эффект поверхностного натяжения. Благодаря ему
струйка из крана становится тоньше и разрывается, роса на траве выпадает в виде
капелек, а пылинки держатся на поверхности лужи. Пена и пузыри — фантастические
объекты, они привлекательны не только с эстетической точки зрения, но и тем, что
тянут за собой шлейф занимательных задач.
Часто бывает, увидишь
картинку, придумаешь алгоритм, а идея не отпускает. Так вот и с пузырями. Суть в
том, что на плоскости случайным образом задаются точки, и из них, как из
центров, строятся окружности с увеличивающимися радиусами и уменьшающейся
яркостью. В каждой точке плоскости цвет берется от окружности с большей
яркостью, т.е. от ближайшей. На картинке получается нечто похожее на взбитую
пену.
Private Sub Command1_Click() Dim vc(), yc(), r() Cls Randomize (Timer) xmax = 650 ymax = 530 v = 5 ' Количество пузырей, передается из формы ss=6 ' Шаг движения по x и y, передается из формы ReDim xc(v), yc(v), r(v) For i = 1 To v xc(i) = Rnd * xmax yc(i) = Rnd * ymax Next i For x = 5 To xmax Step ss For y = 5 To ymax Step ss For q = 1 To v r(q) = ((xc(q) - x) ^ 2 + (yc(q) - y) ^ 2) ^ 0.5 Next q For k = 1 To v - 1 For j = 1 To v - 1 If r(j) > r(j + 1) Then uu = r(j)
r(j) = r(j + 1) r(j + 1) = uu End If Next j, k red = 255 - Int(r(1)) green = 255 - Int(r(1) * 1.3) blue = 255 - Int(r(1) * 1.1) If red < 0 Then red = 0 If green < 0 Then green = 0 If blue < 0 Then blue = 0 Col = RGB(red, green, blue) If ss > 1 Then Line (x, y)-Step(ss, ss), Col, BF If ss = 1 Then PSet (x, y), Col Next y Next x End Sub
Процедура обработки нажатия кнопки «Пуск», запускающая процесс появления
пены, проста и прозрачна. Количество пузырей, точнее, размерность массивов
(переменная v), в которых расположены координаты центров и радиуса, передается
из формы. Причем массив сначала объявляется пустым, а позже оператором Redim
задается его размерность. Цикл с переменной i задает центры пузырей случайным
образом. Для того чтобы при каждом запуске датчик случайных чисел давал разные
значения, привяжем его к текущему времени — Randomize(timer). В цикле с
переменной q по теореме Пифагора вычисляем для каждой точки с координатами x и y
расстояние до каждого из центров пузырей r(q), чтобы выбрать наименьший из них.
Выбор происходит в циклах с переменными k и j. Разберетесь, как они работают —
получите удовольствие от приобщения к классике программирования: сортировке
элементов массива методом пузырьков. (Это не каламбур, название метода не имеет
отношения к теме статьи, просто с каждым проходом цикла меньшие числа «всплывают
вверх». Вообще, переменная uu и присвоение ей значения r(j+1) нужны только в
случае сохранения всего массива для дальнейшей работы, нас же интересует только
наименьшее значение r(1), поэтому цикл можно сократить на две строки, имеющие,
скорее, методический смысл.)
Получив минимальный радиус для текущей
точки, можно приступать к формированию цвета — это и есть изюминка всей затеи.
Каждая составляющая rgb-функции цвета уменьшается пропорционально радиусу. Меняя
коэффициенты и максимальное значение, равное в примере 255, на меньшее, можно
получать различные оттенки пены и регулировать контрастность рисунка.
Программа
предоставляет безграничный простор для экспериментов. Попробуйте сделать так,
чтобы яркость не уменьшалась с удалением от центра пузыря, а увеличивалась, и вы
будете поражены получившейся картиной. Попробуйте при вычислении радиуса
поменять показатель степени с 0,5 на 0,55 или 0,45 (поэтому мы и не
воспользовались функцией Sqr). Попробуйте вместо формулы r2=x2+y2 применить
r2=x2-y2, чтобы получить нечто гиперболическое… А бесконечные игры с цветами,
шагом и количеством пузырей... Естественно, что с уменьшением шага рисования и
увеличением количества пузырей время рисования возрастает, т.к. в каждой точке
рисунка проверяются расстояния до всех центров пузырей, а любые попытки
оптимизировать алгоритм лишь замедлят работу программы. А что если разукрасить
пузыри — каждый в свой цвет? Тут придется поработать, ведь нужно не только
задать массив цветов для каждого пузыря и заполнить его случайным образом, но и,
отслеживая соответствие каждой точки плоскости ближайшему центру, запоминать еще
его цвет. Это непросто, потому что при выборе наименьшего радиуса его индекс в
массиве теряется. Задача, конечно, решаемая, и если вы с ней справитесь, то
будете сторицей вознаграждены получившейся картиной. Экран заполняется
разноцветными шариками, как в моделях сложных молекул, или одинокими фонариками
— в зависимости от ваших настроек.
Вот и все. Как ни странно, нам
удалось связать вместе пену, Visual Basic и мобильники. Отладка программы и
попутные опыты доставят вам массу удовольствия. Задание на дом: научите пену
бурлить, чтобы некоторые пузыри лопались, а соседи занимали их место. Да, и не
забудьте выложить изображения на свой сайт… Созерцание пузырей рождает
прекрасные мысли, недоступные в обыденной суете. Может, в этом и состоит их
предназначение? Поразмышляйте об этом на досуге.