Информационный сервер для программистов: Исходники со всего света. Паскальные исходники со всего света
  Powered by Поисковый сервер Яndex: Найдется ВСЁ!
На Главную Pascal Форум Информер Страны мира
   Статьи о Паскале    >>    Пузыри и сотовая связь
   
 
 Этюды о бесполезной красоте - Пузыри и сотовая связь    Евгений Скляревский 25.09.2001


Этюды о бесполезной красоте. Этюд 3 - Пузыри и сотовая связь.
С помощью математики можно описать самые восхитительные и самые изысканные явления природы. Попытаемся описать и нарисовать пузыри и пену (хотя некоторые заявляют, что это "попки" ;)


44k 
 

Автор:   Евгений Скляревский
Адаптация для TMT Pascal:        Валерий Вотинцев


Оригинал статьи для Visual Basic: Журнал Hard'n'Soft
Этюды о бесполезной красоте

Этюд третий. Пузыри и сотовая связь

Мыльный пузырь, пожалуй, самое восхитительное и самое изысканное явление природы.
Марк Твен.



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

Часто бывает, увидишь картинку, придумаешь алгоритм, а идея не отпускает. Так вот и с пузырями. Суть в том, что на плоскости случайным образом задаются точки, и из них, как из центров, строятся окружности с увеличивающимися радиусами и уменьшающейся яркостью. В каждой точке плоскости цвет берется от окружности с большей яркостью, т.е. от ближайшей. На картинке получается нечто похожее на взбитую пену.

Программа рисования пузырей несложная. Задается их количество, случайным образом выбираются координаты, потом в цикле проходятся все точки плоскости с определением расстояния до ближайшего центра, и соответственно этому расстоянию уменьшается яркость. Небольшое замечание: предварительно экран стоит перевести в режим 16- или 24-битного представления цвета.

Увеличив количество пузырей до 100 или 200, получим пену, похожую на легкие или какие-то другие объекты явно биологического происхождения.

Продолжая увеличивать количество пузырей, мы заставим их тесниться и уплотняться, в связи с чем возникают интересные вопросы. Сколько соседей в среднем у каждого пузыря и как эта величина зависит от плотности размещения? Влияют ли скорость уменьшения яркости и рост радиуса на вид пены (на количество соседних пузырей)? Нет ли здесь каких-нибудь фрактальных закономерностей, связанных с размерностью объектов, и если да, то как определить фрактальную размерность пузырей? Или еще - интересно, мыльная пена такая же, как пивная, или ее параметры зависят от коэффициента поверхностного натяжения?

А при чем здесь, спросите вы, сотовая связь? Очень просто. Мобильный телефон с помощью компьютера выбирает антенну, от которой идет самый сильный сигнал, обычно она оказывается ближайшей. При перемещении телефона его сопровождение передается от одной антенны к другой, с самым сильным сигналом для данной точки. Лучшей иллюстрации этого процесса, чем наша картинка с пузырями, не найти.

Но приступим к делу. Приведенная ниже программа создана в TMT Pascal 4, хотя вы можете реализовать этот нехитрый алгоритм на любом доступном языке. Я, например, свои первые пузыри рисовал на Visual FoxPro 6.0 и Visual Basic 6. Скопируйте приведенный ниже текст в окно редактора TMT Pascal и запустите программу.

Program Bubbles;
(***********************************************)
(* Пузыри                                      *)
(* Автор алгоритма: Евгений Скляревский (VB)   *)
(* ------------------------------------------- *)
(* Адаптация для TMT Pascal:                   *)
(*                  Валерий Вотинцев           *)
(*   MS-DOS 32-bit protected mode              *)
(***********************************************)
uses CRT, Math, Graph;
Type
  dArray = Array[0..0] of LongInt;
  pArray = ^dArray;
var
  i, j, k,
  x, y, q, step,
  xmax, ymax,
  v, col, uu: longint;
  ColDepth: word;
  red, green, blue: LongInt;
  xc, yc, r: pArray;
begin
  xmax     := 800; // Разрешение по горизонтали
  ymax     := 600; // Разрешение по вертикали
  ColDepth := 16;  // Максимальная глубина цвета (бит на пиксел)
  v        := 8;   // Количество пузырей
  step     := 4;   // Шаг движения по x и y ("мозаичность" картины):
                   // step = 1 ->   Рисование по 1 пикселу
                   // step > 1 ->   Рисование квадратами step*step
  Randomize;
  // Установим графический режим
  SetSVGAMode(xmax,ymax,ColDepth,LFBorBanked);
  if GraphResult<>grOk then begin             // Проверка результата
    Writeln('Mode not supported..');
    Halt(0);
  end;
  // Выделяем память для трех массивов
  GetMem(xc,v*SizeOf(LongInt));
  GetMem(yc,v*SizeOf(LongInt));
  GetMem(r, v*SizeOf(LongInt));
  // Задаем случайные координаты пузырькам
  For i := 0 To pred(v) do begin
    xc^[i] := Random(xmax);
    yc^[i] := Random(ymax);
  end;
  // В цикле проходим все поле по X и Y
  x := 0;
  While (x < xmax) do begin
    y := 0;
    While (y < ymax) do begin
      For q := 0 To pred(v) do begin
{1}     r^[q] := Trunc(Power(IntPower((xc^[q] - x),2) +
                                 IntPower((yc^[q] - y),2),0.5));
{1a}    {r^[q] := Trunc(Power(IntPower((xc^[q] - x),2) +
                                 IntPower((yc^[q] - y),2),0.8));}
{1b}    {r^[q] := Trunc(Power(Abs(IntPower((xc^[q] - x),2) -
                                 IntPower((yc^[q] - y),2)),0.5));}
      end;
      // Сортируем пузырьки методом пузырька по возрастанию радиуса
      For k := 0 To v - 2 do begin
        For j := 0 To v - 2 do begin
          If r^[j] > r^[j + 1] Then begin
            uu := r^[j];
            r^[j] := r^[j + 1];
            r^[j + 1] := uu;
          End;
        end;
      end;
      // Задаем цвет
{2}   red   := 255 - r^[0];
      green := 255 - Trunc(r^[0] * 1.3);
      blue  := 255 - Trunc(r^[0] * 1.1);
{2a}  {red   := 100 - r^[0];
      green := 100 - Trunc(r^[0] * 1.3);
      blue  := 100 - Trunc(r^[0] * 1.1);}
{2b}  {red   := 255 - Trunc(r^[0] * 2.5);
      green := 255 - Trunc(r^[0] * 1.1);
      blue  := 255 - Trunc(r^[0] * 1.1);}
      If red   < 0 Then red   := 0;
      If green < 0 Then green := 0;
      If blue  < 0 Then blue  := 0;
      Col := RGBColor(red, green, blue);
      // Рисуем очередную точку или квадрат
      If (step = 1) Then PutPixel(x, y, Col)
      else begin
        SetFillColor(Col);
        Bar (x, y, x + step, y + step);
      end;
      Inc(y,step);
    end;
    Inc(x,step);
  end;
  // Освобождаем выделенную память
  FreeMem(xc,v*SizeOf(LongInt));
  FreeMem(yc,v*SizeOf(LongInt));
  FreeMem(r, v*SizeOf(LongInt));
  // Ждем нажатия Esc
  Repeat until ReadKey=#27;
  CloseGraph;
end.

Количество пузырей, точнее, размерность массивов, в которых расположены координаты центров и радиуса, задается переменной v. Причем память под массивы выделяется динамически, в зависимости от заданного значения v. Цикл с переменной i задает центры пузырей случайным образом. Для того, чтобы при каждом запуске расположение пузырей было разным, мы используем функцию Random. В цикле с переменной q по теореме Пифагора вычисляем для каждой точки с координатами x и y расстояние до каждого из центров пузырей r^[q], чтобы выбрать наименьший из них. Выбор происходит в циклах с переменными k и j. Разберетесь, как они работают - получите удовольствие от приобщения к классике программирования: сортировке элементов массива методом пузырьков. (Это не каламбур, название метода не имеет отношения к теме статьи, просто с каждым проходом цикла меньшие числа <всплывают вверх>. Вообще, переменная uu и присвоение ей значения r^[j+1] нужны только в случае сохранения всего массива для дальнейшей работы, нас же интересует только наименьшее значение r^[0], поэтому цикл можно сократить на две строки, имеющие, скорее, методический смысл.)

Получив минимальный радиус для текущей точки, можно приступать к формированию цвета - это и есть изюминка всей затеи. Каждая составляющая rgb-функции цвета уменьшается пропорционально радиусу. Меняя коэффициенты и максимальное значение, равное в примере 255, на меньшее, можно получать различные оттенки пены и регулировать контрастность рисунка. Попробуйте убрать комментарии с блоков, помеченных как {2a} и {2b}.

Программа предоставляет безграничный простор для экспериментов. Попробуйте сделать так, чтобы яркость не уменьшалась с удалением от центра пузыря, а увеличивалась, и вы будете поражены получившейся картиной. Попробуйте при вычислении радиуса поменять показатель степени с 0,5 на 0,8 или 0,3 (кстати, именно для этого мы и воспользовались функцией Power, а не Sqrt). Уберите комментарии со строки {1a}.

Попробуйте также вместо формулы r2=x2+y2 применить r2=x2-y2, чтобы получить нечто гиперболическое. Для этого раскройте комментарий вокруг строки {1b}.

А бесконечные игры с цветами, шагом и количеством пузырей... Естественно, что с уменьшением шага рисования (переменная step) и увеличением количества пузырей (v) время рисования возрастает, т.к. в каждой точке рисунка проверяются расстояния до всех центров пузырей, а любые попытки оптимизировать алгоритм лишь замедлят работу программы.

А что если разукрасить пузыри - каждый в свой цвет? Тут придется поработать, ведь нужно не только задать массив цветов для каждого пузыря и заполнить его случайным образом, но и, отслеживая соответствие каждой точки плоскости ближайшему центру, запоминать еще его цвет. Это непросто, потому что при выборе наименьшего радиуса его индекс в массиве теряется. Задача, конечно, решаемая, и если вы с ней справитесь, то будете сторицей вознаграждены получившейся картиной. Экран заполняется разноцветными шариками, как в моделях сложных молекул, или одинокими фонариками - в зависимости от ваших настроек.

     

Вот и все. Как ни странно, нам удалось связать вместе пену, TMT Pascal и мобильники. Отладка программы и попутные опыты доставят вам массу удовольствия. Задание на дом: научите пену бурлить, чтобы некоторые пузыри лопались, а соседи занимали их место. Да, и не забудьте выложить изображения на свой сайт: Созерцание пузырей рождает прекрасные мысли, недоступные в обыденной суете. Может, в этом и состоит их предназначение? Поразмышляйте об этом на досуге.