(k=1..frames). Последовательная смена таких фреймов собственно и составляет суть процесса анимации. По animate-функции создается графическая структура данных вида:
PLOT(ANIMATE([2D-ГО_1], [2D-ГО_2], ..., [2D-ГО_n]), графические опции) где 2D-ГО_k представляет собой базовую графическую plot-структуру CURVES-типа для к-го фрейма анимируемого ГО, организация которой рассматривалась нами выше. Выбор анимируемого 2D-ГО сенситивно переводит ядро в режим анимации с одновременным выходом в графическое подокно 2D-анимации. Средства анимационного подокна обеспечивают оперативный доступ к ряду функций, позволяющих управлять режимом анимации выделенного 2D-ГО, а именно: 9 кнопок 4-й строки GUI имеют следующее функциональное назначение:
(1) - немедленное прекращение процесса анимации (g); (кнопка 1)
(2) - инициация начала процесса анимации (4); (кнопка 2)
(3) - переход к следующему фрейму анимации ГО ( ▌); (кнопка 3)
(4) - определение {обратного|прямого} направления процесса анимации ({-| }); (4, 5)
(5) - {уменьшение|увеличение} скорости анимации (частоты смены фреймов) ({«|»}); (6, 7)
(6) - определение режима анимации в рамках одного цикла фреймов (⇌); (кнопка 8) (7) - определение периодического режима анимации цикла фреймов (↻). (кнопка 9) При этом следует отметить, что переключатели Animation-группы GUI полностью дублируются более оперативными кнопками 4-й строки окна, что делает Animation-группу с ее нынешним функциональным наполнением в значительной мере избыточным средством, хотя в ряде случаев они оказываются единственно доступными.
Вызов animate-функции возвращает график анимируемой функции, точнее первый его фрейм. Последующее его выделение (визуализируется рамкой ГО) переводит ядро пакета в состояние графического animation-подокна, структура которого рассмотрена выше. Для дальнейшего управления процессом анимации выделенного ГО вполне достаточно средств 4-й строки GUI. Активировав кнопку {8|9} определяем соответственно режим {одноцикловый|периодический} смены набора (пакета) фреймов; в первом случае после выполнения цикла (последовательности всех фреймов) процесс анимации прекращается, во втором - состоит из бесконечного чередования цикла фреймов. По кнопке 2 производится запуск собственно процесса анимации, а по кнопке 1 - его прекращение. Процесс анимации продолжается в фоновом видеорежиме до его явного прекращения, не влияя на выполнение других вычислений в среде пакета. В состоянии анимации одновременно может находиться несколько 2D-ГО. Более того, созданный по animate-функции графический объект может в последующем участвовать в процессе анимации без предварительного вызова создавшей его функции. При этом, анимация производится не в состоянии вычислений и не может прерываться по stop-кнопке 3-й строки GUI. Кнопки {4,5} позволяют изменять с точностью “до наоборот” порядок выполнения фреймов в цикле. Наконец, 3я кнопка действует только после активации одной из кнопок {4, 5} и позволяет производить переход в рамках одного цикла от фрейма к фрейму в определенном указанными кнопками порядке.
С учетом сказанного, управление процессом анимации достаточно прозрачно и легко усваивается на практической основе. Имея возможность визуально отслеживать процесс анимации, пользователю уже относительно несложно выбирать необходимые значения для рассмотренных выше параметров процесса анимации, а то и вовсе изменять характер самой функциональной зависимости с целью получения желаемой динамики. Именно таким способом могут быть обнаружены функциональные зависимости с весьма интересной динамикой [11-14,41,103].
По вызову with(plots) обеспечивается доступ ко всем средствам plots-модуля, включая и animate-функцию. Затем на основе animate-функции создается графический 2D-ГО согласно представленной выше процедуре. С учетом ожидаемой динамики поведения ГО в процессе его анимации уделяется повышенное внимание выбору диапазона для ведущей х-переменной анимируемой функции и а-диапазона, управляющего собственно самой анимацией. Весьма существенную роль играет и выбор количества участвующих в процессе анимации фреймов (frames-опция). Вызов animate-функции допускает использование и установок для plot-опций, например, color, но здесь имеются проблемы.
Следующий фрагмент на основе графической animate-структуры позволяет выделять из нее (оставляем разбор деталей искушенному читателю) и вывести все фреймы цикла некоторого анимируемого ГО. Именно последовательность смены этих фреймов и вызывает эффект анимации данного конкретного 2D-ГО. Ради простоты и в целях компактности выбран цикл только из 9 фреймов. В частности, данный прием можно успешно использовать и для разложения динамики функциональных зависимостей на элементарные составляющие. Читателю в порядке и полезного, и захватывающего по зрелищности упражнения рекомендуется практическое освоение рассмотренных средств анимации Maple-языка.
В случае определения по color-опции расцветки для нескольких кривых, участвующих в анимации по animate-функции, выбирается общий для них цвет; при этом, каждый новый вызов animate-функции циклически изменяет цвет кривых.Так, по вызову вида: animate({cos(t*x), sin(t*x)}, x=-Pi..Pi, t=-Pi..Pi, color=green) производится анимация графиков двух кривых, окрашенных общим цветом; совершенно аналогичная картина имеет место и при отсутствия color-опции. Следовательно, попытки определения цветности для различных кривых имеют идентичный эффект, искажая смысл color-опции. Данный момент существенно ограничивает эффект от анимации и ее наглядность в случае многофункционального 2D-ГО. О других особенностях анимации можно найти в [12].
В целях снятия ограничений на возможность окрашивания анимируемой по функции animate кривой можно воспользоваться методом динамической модификации соответствующей ей ANIMATE-структуры, как это иллюстрирует следующий фрагмент:
A_Color := proc(Art::function) local k n m p z h t d v Kr LC LC1 L L1 Ln F, , , , , , , , , , , , , , , ; [interface(labelling = false), assign(F = cat(currentdir( ), "/$6$3$"))]; Kr LC1 n L p h t m L1, , , , , , , , := convert(Art, 'symbol'), [ ], nops [( op(op 1,( Art))]), [ ] 1 0 0, , , , length(convert(Art, 'symbol')), [ ]; LC := [seq(op(op(op(op(1, Art))[k]))[-1], k = 1 .. n)]; `if`(nargs < 2, ERROR("Number of real arguments is incorrect: %1"args, ), NULL) ; `if`(nops(LC) ≠ nargs − 1, ERROR( "Number of Color-arguments is not equal to number of frames: %1"args),, NULL); for k from 2 to nargs do LC1 := [op(LC1), op convert(( args[ ]k , 'PLOToptions'))] end do; LC1 := map(convert LC1, , 'symbol'); |
do z := searchtext '( COLOUR Kr', , p .. m); if z = 0 then break else L := [op(L), z + h]; h := h + + z 3; p := h + 1 end if end do; for k to nops(L) do h := searchtext(")", Kr, L[k] .. m); L1 := [op(L1), L[k] + h − 1] end do; assign(' 't = open(F, 'WRITE')), writebytes ,(t cat(`D_R_Col:=`, substring(Kr, 1 .. L[1] − 1))); for k to nops(L) − 1 do writebytes(t, LC1[k]); writebytes ,(t substring(Kr, L1 k[ ] + 1 .. L[k + 1] − 1)) end do; writebytes ,(t LC1[nargs − 1]); [writebytes ,(t cat(substring(Kr, L1[nargs − 1] + 1 .. m), `;`)), close ( )t ]; (proc(x) read x end proc )(F), [fremove(F), RETURN(D_R_Col, unassign '( D_R_Col'))] end proc > Art:=animate(sin(t*x^2), x=-Pi..Pi, t=1..3, frames=7, thickness=2): A_Color(Art, color= red, color=green, color=tan, color=pink, color=gold, color=navy, color=blue); |
Данный фрагмент представляет процедуру A_Color(Art) [41] от неопределенного числа формальных аргументов, предназначенную для модификации расцветки фреймов анимируемой 2D-функциональной зависимости. Первый фактический Art-аргумент процедуры определяет ANIMATE-структуру, тогда как все последующие ее аргументы кодируются в виде последовательности уравнений вида color = цвет. При этом, их количество должно строго соответствовать количеству фреймов (frames-опция) для анимируемого объекта. Суть алгоритма, реализуемого данной процедурой, в общих чертах достаточно прозрачна и оставляется читателю в качестве весьма полезного упражнения тем более, что использованные в процедуре приемы можно успешно применять при программировании модификаций ANIMATE-структур и в более широком аспекте.
Porshen := proc(N::posint) local k z tor C Lf, , , , ; [With(plots, 'display'), With(plottools, 'torus', 'cylinder'), assign(Lf = [ ], C = [XYZ XY Z ZGREYSCALE ZHUE, , , , ]), assign(tor = torus [( 0 0 0, , ], ,5 12))]; for k from 0 to N do z := 12×sin(evalf(2× ×k π/N)); Lf := [op(Lf), display(tor, cylinder [( 0 0, , z − 16], 3 32, , 'shading' = C[(k mod 5) + 1]))] end do; display(Lf, 'insequence' = true, 'orientation' = [45, 64], 'scaling' = 'constrained') end proc |
Как уже упоминалось выше, по display-функции установка insequence = true опции также определяет режим анимации для элементов списка 2D_ГО-структур (первого аргумента), рассматриваемых в качестве последовательности фреймов. Созданный таким образом анимируемый объект аналогичен созданному по функции animate за некоторыми исключениями (см. прилож. 1 [12]). При этом, следует иметь в виду, что определение режима анимации на основе display-функции в целом ряде случаев более предпочтительно, позволяя несколько шире использовать plot-опции и совмещать в анимационном процессе как сугубо графические, так и текстовые фреймы, а также объекты, которые не допускают определения для них параметров анимации, включая графические примитивы, определяеиые как пакетным модулем plottools, так и самим пользователем. В предыдущем фрагменте представлен например анимации тора и цилиндра [12,103].
Animate2D := proc(F::algebraic, x::symbol, xa::range) local a b c d n k, , , , , ; global __0; `if`(map(type, {rhs(xa), lhs(xa)}, 'numeric') = {true}, NULL, ERROR "3rd argument is invalid" );( ) assign(a = Indets(F), n = nargs, '__0' = [ ], b = "", d = ""); if not member( ,x a) then error "quantity of unknowns is more than 1" elif not (nops(a) = 1) and nargs = 3 then error "<%1> contains non-numeric values",F elif n = 3 then return plot( ,F x = xa) elif not (nops(a) − 2 ≤ nargs − 3) then error "quantity of parameters for animation is invalid" else a := a minus { }x ; if nargs − 3 < nops(a minus { }x ) then error "quantity of parameters for a\ nimation is more than quantity of variation ranges for them" elif {seq( type(args[ ]k , {'set'('numeric'), 'list'('numeric'), 'range'('numeric')}), k = 4 .. nargs)} ≠ {true} then error "values of parameters for animation are invalid" else for k to nops(a) do b := cat(b, "seq(") end do; for k to nops(a) do d := cat(d, a k[ ], "=" convert(, args[3 + k], 'string'), "),") end do; c := cat("assign('`__0`'=[op(`__0`),", convert(F, 'string'), "]),"); parse(cat(b c, , cat(d[1 .. -2], ":")), 'statement'); assign('__0' = map(evalf __0, )) end if end if; plots[display](map(plot, __0, x = xa), insequence = true), unassign('__0') end proc > p:=evalf(2*Pi): Animate2D(cos(d*x)*(c*x + a)*sin(b*x), x, -p..p, [1, 2, 3], {5, 6, 7}, 7..15, {7, 15}, [1, 5, 7]); |
Функция animate из пакетного модуля plots обеспечивает анимацию 2D-функциональных зависимостей, зависящих только от одного параметра анимации, что в целом ряде случаев недостаточно. Поэтому нами была определена процедура Animate2D, представленная предыдушим фрагментом. Процедура допускает любое конечное число анимирующих параметоров для алгебраического выражения F(x, a, b, c, …) от одной ведущей переменной x и конечного числа параметров {a, b, c, …} анимации. Детальнее с данной процедурой можно ознакомиться в [41,103,109,112,113].