Анимация в MATLAB. Часть 4
В этой публикации мы коснёмся анимации в MATLAB.
Имеется 2 подхода для создание анимаций:
- Через изменение свойств отображаемого объекта напрямую.
- Выполнение преобразований над объектом или над группами объектов: трансляций, поворотов и масштабирования.
О них и пойдёт речь ниже.
Перед рассмотрением непосредственно анимации освежим в памяти то, как отображается графика в MATLAB в целом. Это будет полезно и даже необходимо для вдумчивого понимания наших действий в этой публикации.
Когда нужно рисовать график, используются команды типа plot, scatter, и т.д., а для изменения особенных свойств используется Property Inspector или команды типа legend, xlim и т.д.
Некоторые из этих хорошо известных вам команд порождают объекты, другие меняют свойства этих объектов. В MATLAB существует четкая иерархия типов объектов отображения, а к свойствам этих объектов (таким как оси, линии и т.д.) можно обращаться непосредственно из кода.
![]()
Окно графика формируется следующим образом: сначала появляется поле окна (класс Figure), на котором могут отображаться, в свою очередь, другие объекты, в частности, поля для графиков (класс Axes). Некоторые свойства объектов типа Axes наследуются от объекта типа Figure, на котором он был отображен. Говоря шире, класс Axes является "классом-наследником" по отношению к классу Figure, а класс Figure, в свою очередь, является "классом-родителем" по отношению к Axes.
Другими подобными объектами являются линии (создаваемые функцией plot, например), текстовые окна, стрелки и т п, все из них обладают разными, но известными свойствами.
Теперь перейдём непосредственно к анимации.
В MATLAB имеется 2 подхода для создание анимаций:
- Через изменение свойств отображаемого объекта напрямую.
- Выполнение преобразований над объектом или над группами объектов: трансляций, поворотов и масштабирования.
У объектов типа line есть свойства XData, YData (для трёхмерных линий ZData), которые содержат в себе координаты отображаемых точек. Их можно изменять в цикле, что и позволит создать анимацию.
Второй подход заключается в преобразовании объектов типа transform, но об этом детальнее поговорим позже. Итак, перейдём к первому примеру.
1-й подход к созданию анимаций посредством изменения свойств отображаемого объекта напрямую.
Пример 1. Зашумление синуса.
![]()
Давайте нарисуем наш первый анимированный график.
На осях будут 2 графика:
- первый – синус в виде линии.
- Второй будет точечный и изначально тоже синус.
С течением времени к значению в каждой точке будет прибавляться некоторая случайная величина. Посмотрим, как это реализовать.
![]()
Сначала нарисуем оба этих графика стандартными функциями. Далее добавим цикл для отображения анимации. Можно использовать цикл for, но можно поступить и по-другому. Пусть наша анимация будет работать, пока фигура не будет закрыта. Когда фигура закрывается, ссылка на неё становится недействительной. Проверить действительна ли ссылка можно функцией isvalid.
Реализуем цикл while.
![]()
Укажем задержку – функцией pause в 0.01 секунду, далее к данным по оси ординат будет прибавлять нормально распределённую случайную величину, укажем команду drawnow, которая обновит графику с учётом изменённых свойств. Запустим скрипт.
![]()
Работает.
Пример 2. Два круга + экспорт в видеоформат.
![]()
Отобразим 2 круга: один будет изменять свой радиус, а другой будет вращаться вокруг первого. Также научимся экспортировать анимацию из матлаба в видеофайл.
![]()
Сначала нарисуем оба круга, зададим радиусы и сделаем оси равными в масштабе. Будем одновременно менять свойства XData и YData для обеих кривых, будем также менять радиус первой кривой с течением времени.
![]()
![]()
Теперь попробуем записать анимацию в видеофайл. Будем использовать для этого функцию getframe. Эта функция позволяет запоминать текущее изображение фигуры - фрейм.
![]()
Сначала мы создадим массив из фреймов через наш цикл отображения. Полученный массив изображений или фреймов можно преобразовать в видео с помощью следующей техники:
- Создадим видеофайл с помощью функции Videowriter;
- Укажем количество кадров в секунду – фреймрейт;
- Откроем видеофайл;
- Организуем цикл записи через функцию writeVideo, принимающую на вход название файла и сам фрейм;
- Закроем видео.
Цикл while лучше заменить на конечный цикл, ибо если мы закроем фигуру в момент, когда фрейм считывается, то получим ошибку и остановку скрипта.
Запустим скрипт и увидим, что видео записалось.
![]()
Рассмотрим ещё один пример – изменяющуюся во времени поверхность.
Пример 3. Изменяющаяся поверхность.
![]()
Из центра координат распространяется некое подобие волны: синусоидальная функция, помноженная на затухающую экспоненту.
![]()
Сначала выполним разметку командой meshgrid, после чего получим соответственно матрицу значений искомой функции. Нарисуем поверхность командой surf, при этом ограничим вертикальную ось.
![]()
Получилось.
Теперь организуем анимацию через цикл while.
![]()
Будем изменять свойство ZData объекта S типа Surf таким образом, чтобы волны двигались из центра. Запустим скрипт.
Теперь рассмотрим альтернативный способ отрисовки анимированных линий – объект типа animatedline.
Пример 4.1. Движение по спирали.
![]()
Также посмотрим, как изменять положение объектов других типов, в данном случае – объектов типа Text.
![]()
Создадим на осях объект типа animatedline. Изначально это объект, не имеющий данных для отображения. Эти данные можно добавить командой addpoints: добавим к линии a1 начало координат. Также нарисуем красный кружок известной командой plot, а также добавим текстовое поле командой text, указав левый верхний угол текстового поля, а также его содержимое – координаты текущей точки.
Организуем анимацию движения по спирали уже отработанным способом: через цикл while. Двигаться будем по спирали, которая будет логарифмически расширяться. Командой addpoints будем добавлять новые точки в каждом цикле. У текстового поля будем изменять положение его верхнего левого угла и отображаемый текст. Красный кружок будет также двигаться по спирали. Запустим.
![]()
Работает.
Как можно догадаться, при длительной работе animatedline разрастается. Чтобы этой потенциальной проблемы избежать можно задать, сколько точек сохранять и отображать. Для этого определим свойство MaximumNumPoints.
![]()
Запустим ещё раз. Будет видно, что отображаются только ограниченное количество точек, при этом старые точки затираются. Это может быть полезно, когда вы хотите визуализировать в MATLAB данные, полученные с приборов в реальном времени
2-й подход к отображения анимации в MATLAB – посредством преобразований.
Допустим применить преобразование сразу к группе объектов: например, подвинуть их на какое-то расстояние, повернуть их или масштабировать. Наши объекты во-первых, не сгруппированы, а во-вторых, напрямую обращаться к ним как к изображениям не получится. Для этого существует класс transform. Объекты этого класса создаются на осях, и с ними уже можно проводить преобразования.
Следует перенести объекты с осей axes на объект класса transform. Это можно сделать для отображаемых объектов в свойстве Parent, явно указав родителя, – объект класса transform. Сами преобразования можно осуществлять с помощью знакомых многим матриц преобразования размерами 4х4, которые содержат информацию о преобразовании: будь то трансляция, поворот или масштабирование.
Эти матрицы можно создавать вручную, а можно воспользоваться функцией makehgtform, в которой следует явно указать тип преобразования и его параметры. Последний шаг - полученную матрицу следует записать в свойство Matrix объекта класса transform.
![]()
Организовав такие преобразования в цикле, мы и получим желаемую анимацию.
Переходим к следующему примеру - движение по спирали преобразованием.
Пример 4.2. Движение по спирали преобразованием.
![]()
На этот раз будем использовать преобразование для группы из двух объектов: красного кружочка и текстового поля.
Итак, скрипт уже нам знаком: у нас просто рисуется анимированная линия и отображается текстовое поле и красный кружок в начале координат.
![]()
Заставим их двигаться с помощью преобразования.
![]()
Теперь создадим объект класса transform на осях ax, явно указав родственную связь. Нарисуем также красный кружочек командой plot, также указав родственную связь. То же самое делаем и с текстовым полем. В цикле создаём матрицу преобразования. Это будет трансляция на x по оси x, на y по оси y и на 0 по оси z соответственно.Полученную матрицу запишем в свойство объекта h.
![]()
Запустим скрипт. Работает.
Пример 5. Табуретка.
Следующий, последний пример анимации преобразований – это двигающаяся по кругу, вращающаяся и изменяющаяся в размерах табуретка, состоящая из четырёх прямоугольников и одного сплюснутого эллипсоида.
![]()
Посмотрим, как нарисовать такой шедевр и как заставить эту конструкцию двигаться. Действовать будем так: сначала нарисуем один параллелепипед, потом нарисуем ножки, потом эллипсоид, соединим их в единый объект, поместим его в объект типа transform, после чего организуем в цикле сразу 3 типа преобразований одновременно: поворот, трансляцию и масштабирование.
![]()
Для начала создадим функцию, которая подготавливает точки для рисования параллелепипеда. Проверим, правильно ли рисует параллелепипед?
![]()
Как видим – правильно.
Создадим эллипсоид и четыре ножки, записав все эти поверхности в виде массива в переменную.
![]()
Проверим, корректно ли отобразили объект.
![]()
Отобразили правильно.
Перейдем непосредственно к преобразованию. Создадим объект типа transform известной нам командой, укажем родителя. Организуем цикл, в нём создадим 3 матрицы, для поворота относительно вертикальной оси, для трансляции и для масштабирования. Матрицы следует перемножать в определенном порядке: следует перемножить матрицу поворота на матрицу трансляций, и только потом на матрицу масштабирований. Теперь изменим Удалим лишний параллелепипед, который мы рисовали в начале.
![]()
Запустим скрипт. Всё работает.
Видеообзор по теме решения систем Д/У описанный в публикации доступен по ссылке.
Предыдущие публикации по теме:
Часть 1. Решение систем обыкновенных дифференциальных уравнений в среде MATLAB
Часть 2. Решение систем обыкновенных дифференциальных уравнений в среде MATLAB. Опции решателей odeXY
Комментарии