Интерполяция некомм. дуал. компл. числами

Aug 24, 2024 16:35

Мы немного поигрались с некоммутирующими дуальными комплексными числами: сделали анимацию паровоза, а потом добавили "параллакс", когда разные части фона как будто бы расположены на разном отдалении от зрителя. Мне понравилось работать с такими числами, но каких-то неведомых "суперспособностей" данный формализм пока не дал, всё то же самое мы могли бы осуществить и без них.

Интерполяция - другое дело, тут нам очень помогает наличие простой "формулы Эйлера" для взятия экспоненты от некомм. дуал. компл. числа! Из неё можно вывести и обратную операцию: натуральный логарифм, а из них двоих получить взятие произвольной степени от числа, в том числе и корень степени N, т.е одно движение разбить на N одинаковых движений, композиция которых и переведёт объект из начальной в конечную точку.

Конечно, и от матрицы 3х3 можно взять "матричную экспоненту", сегодня с утра вспоминал, как это делается, вроде вывел матричную экспоненту от "генератора произвольного движения на плоскости", матрицы вида



но пока не понял, можно ли сколько-нибудь легко и обратную операцию, "логарифм", записать.

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


При возне с паровозом мы уже заметили, что одними и теми же числами мы на самом деле описываем две совершенно разные сущности:
1. Векторы, или точки на плоскости. Обычно они бы представлялись просто двумя числами, здесь у них появилось две дополнительные компоненты. Одна (мнимая) позволяет разместить вектор на "другой плоскости", другая (скалярная/действительная) пока нами не использовалась, при движениях она попросту остаётся неизменной. Если с параллаксом мы играться не собираемся, то вектор (x;y) мы записываем как i+xj+yk, или (0;1;x;y).

2. Операторы движения: вращения, параллельные переносы или комбинация их двух. Обычно мы бы разделяли параллельный перенос (описываемый просто вектором смещения) и поворот (описываемый матрицей 2х2), либо объединили бы их в матрицу 3х3 (см. выше) и ввели "гомогенные координаты", где вектор всё же станет трёхмерным, но в компоненте Z будет лежать просто единичка. Наша запись чуть компактнее: 4 числа выражают произвольное движение на плоскости, для чего самый минимум понадобилось бы 3 числа (два смещения и угол поворота). Ещё и масштаб можно сюда добавить, но о нём поговорим попозже.

Сейчас, при рассмотрении интерполяции, мы вообще практически позабудем о точках/векторах, нас будут интересовать исключительно операторы движения. Ведь положение твёрдого тела на плоскости можно описать ровно таким оператором! Единичка будет означать, что объект расположен строго в начале координат, и оси координат также совпадают. В общем случае, мы будем описывать, как именно надо переместить объект из начала координат, чтобы он принял то положение и ориентацию, какое занимает сейчас.

Введём числа Sn (от слова Step), где n=0..N-1. Это положения объекта, причём начальное S0 и конечное SN-1 мы уже знаем, а промежуточные хотим найти.

А дальше мы можем описать две разных ситуации, "внешнее" и "внутреннее" движение. В первом случае наш объект на каждом шаге вращается ВОКРУГ НАЧАЛА СИСТЕМЫ КООРДИНАТ и ещё смещается АБСОЛЮТНО (например, всегда ВПРАВО). Чтобы описать такое движение, надо текущее положение умножать на оператор СЛЕВА. Получаем:



здесь ΔT - искомый оператор движения, описывающий один шажок. ext - сокращённо от external, т.е "внешнее". Ставлю ли я этот (ext) в верхний или нижний индекс - не ищите глубокого смысла. Где есть место - туда и запихиваю...

Либо мы можем описать, как объект вращается ВОКРУГ СВОЕЙ ОСИ, а ещё смещается куда-то В СВОЕЙ СИСТЕМЕ КООРДИНАТ. Грубо говоря, автомобиль с выкрученным рулём - на каждом шажке поворачивается на 5° и при этом уезжает условно вперёд. Для такого движения мы получаем:



Интуитивно два этих движения кажутся совершенно разными, и величина одного "шажка", ΔT, будет в этих двух случаях получаться разной, но шаги интерполяции окажутся ПОЛНОСТЬЮ ИДЕНТИЧНЫМИ! Изначально я это увидел при симуляции на компьютере, и лишь потом смог худо-бедно обосновать математически.

Показать это можно, вспомнив, что эти наши некоммутирующие дуальные комплексные числа - это вариант кватернионов с бесконечно большой разницей в масштабе осей X и Y/Z, и мы всё ещё можем любое движение на плоскости рассматривать как вращения (в т.ч бесконечно малые) на единичной сфере.

В главе " кватернионы и спиноры, порядок поворотов" мы рассматривали ситуацию, когда ориентация объекта задавалась кватернионом Λ, и объект совершил поворот, который в его связанных осях описывается кватернионом ΔΜ. Чтобы описать поворот объекта в инерциальной системе координат, мы пересчитали ΔΜ в инерциальную систему:



(это можно было сделать, поскольку скалярная компонента, выражающая угол поворота, в такой операции остаётся неизменной, а векторная компонента поворачивается как любой другой вектор, т.е ось поворота остаётся неизменной, просто выраженной в другой системе координат)

и затем посчитали кватернион ориентации объекта после этого поворота:



(тут мы полагаем, что все рассмотренные кватернионы имеют единичную норму, т.е выражают только поворот, но не масштабирование)

Именно так мы вывели в своё время, что поворот, описываемый во "внешней", обычно инерциальной, системе координат, применяется с помощью умножения СЛЕВА, тогда как поворот в связанных осях применяется умножением СПРАВА.

Но давайте сделаем ещё один шажок, посмотрим, как выразится в инерциальной системе ещё один такой же поворот ΔΜ, при том, что ориентация объекта уже поменялась, и может показаться, что теперь этот поворот в инерциальной системе отсчёта запишется по-другому:



Но нет, кватернион остался тем же самым! То есть, последовательное умножение на один и тот же кватернион СПРАВА можно заменить на последовательное умножение на какой-то другой кватернион СЛЕВА, и наоборот. А учитывая, что начальное и конечное состояние при обоих описаниях одинаковое, то и все промежуточные шаги совпадут.

В общем-то, в случае поворотов это кажется практически очевидным: ведь сама ось поворота во время поворота остаётся неизменной, поэтому её достаточно пересчитать лишь однажды! А вот для произвольного движения на плоскости очевидность куда-то уходит...

Давайте проиллюстрируем эту "дуальность" на простейшем примере: мы начинаем с объекта, имеющего нулевое вращение (т.е его ось X сонаправлена оси X нашей системы координат) и координаты (100;0). Он задаётся числом Λ=1+50k, или (1;0;0;50). И мы хотим последовательно поворачивать его на 90 градусов против часовой стрелки, вокруг своей оси. Записываем оператор поворота:



Чтобы осуществить поворот вокруг своей оси, помножаем Λ на Tint СПРАВА:



По виду этого числа не сразу очевидно, что оно выражает. Давайте применим его к вектору i, или (0;1;0;0), выражающего начало координат на нашем "письменном столе". Сначала умножим i справа на число, сопряжённое к Λ1:



Теперь результат умножим слева на Λ1:



Здесь так и подмывает применить формулу сокращённого умножения, (a+b)(a-b)=a2-b2, но нельзя! Ведь оно выводится так:



И затем мы "с чистой совестью" сокращаем ba и ab. Только вот у нас числа некоммутирующие, поэтому, если так сделать - мы придём к ошибочному результату!

Так что будем раскрывать "ручками":











Четыре слагаемых мы выкинули, поскольку j2=k2=jk=kj=0, это ж дуальные числа! Также у нас ушла действительная компонента и компонента при k. И ещё не забываем поделить на 2: это деление мы сейчас временно убрали при выкладках для краткости. Вот результат:



Это соответствует точке на плоскости (100;0), то есть, как мы и хотели, объект остался на том же самом месте. И для полного успокоения совести давайте осуществим движение вектора i+j, или (0;1;1;0), который соответствует точке на плоскости (1;0). Исходя из линейности операций,



Первое слагаемое мы уже нашли, осталось найти второе. Действуем по тому же шаблону, но сейчас выйдет даже проще, т.к j при умножении на j или k будет тут же зануляться! Поехали:





Итак, "вектор" j превратился просто в k, тогда как i превратился в i+100j, поэтому итоговое значение: i+100j+k, или (0;1;100;1), что соответствует точки на плоскости (100;1). Всё верно: центр объекта отобразился в точке (100;0), тогда как точка (1;0), сидящая на объекте, отобразилась в (100;1), что и указывает - объект повернулся на 90° против часовой стрелки вокруг своей оси.

Теперь давайте повернём объект ЕЩЁ ОДИН РАЗ:



И снова преобразуем вектор i. Сначала помножим его справа на сопряжённое:



И слева на Λ2:



Как видим, центр объекта так и остался в точке (100;0), ровно так мы и хотели. И ещё преобразуем вектор j:





Если теперь взять вектор i+j, соответствующий точки на плоскости (1;0), он превращается в (99;0), и это снова вполне ожидаемо: объект теперь развёрнут на 180°, поэтому когда мы сместились В ОСЯХ ОБЪЕКТА на единичку "вправо", в абсолютных координатах это превратилось в сдвиг "влево".

Пока всё работает ровно так, как задумано. А теперь попытаемся то же действие, разворот на 90° против часовой стрелки ВОКРУГ СВОЕЙ ОСИ, изобразить как "внешнее движение", т.е разворот вокруг начала координат со смещением в абсолютных координатах.

Сделаем это "в лоб":



Снова нам не вполне понятно, что за движение выражает это число, поэтому применим его к вектору i:



Итак, точка на плоскости (0;0) переместилась в координаты (100;-100), т.е впридачу к повороту на 90 градусов вокруг начала координат, у нас присутствует параллельный перенос на 100 вправо и вниз.

Это имеет смысл: если мы поворачиваем объект с центром в (100;0) вокруг начала координат против часовой стрелки на 90 градусов, то его центр приобретает новые координаты (0;100). Если же к этому повороту добавить ещё и смещение на 100 вправо и 100 вниз, то мы вернёмся к исходным координатам (100;0)!

Напоследок убедимся в этом, домножив число Λ (исходное положение объекта на плоскости) СЛЕВА на Text:



Как видно, результат такого "внешнего движения" (поворот вокруг начала координат и смещение на 100 вправо, и на 100 вниз) полностью эквивалентен движению "внутреннему" (простое вращение вокруг своей оси), давая тот же самый результат! Сразу напомним: это справедливо лишь для ОДНОГО объекта - именно его можно двигать хоть так, хоть эдак. Если у нас объектов четыре штуки, то одно и то же число, которое опишет, к примеру, их поворот вокруг своей оси на 90 градусов, придётся под каждый из объектов преобразовывать по-своему, и получится ЧЕТЫРЕ РАЗНЫХ ЧИСЛА, которые опишут их движение, только на этот раз "внешнее". То же самое верно и в обратную сторону.

Мы, наконец-то, убедились, что интерполяция "внешними движениями" и "внутренними" - это одно и то же, и рассмотрим, наконец, а как это сделать.

Напомним: у нас есть числа S0 и SN-1, описывающие положение объекта на плоскости на шаге 0 и на шаге N-1, соответственно. Кроме того, мы считаем, что переход от шага к шагу описывается ВНЕШНИМ движением, задаваемым одним и тем же числом ΔT:



Чтобы найти ΔT, запишем эту формулу для n=N-1, где мы знаем результат, помножим обе части справа на (S0)-1, после чего левую и правую часть равенства поменяем местами:



(в кои-то веки мы можем применить операцию ДЕЛЕНИЯ некоммутирующих дуальных комплексных чисел! Когда оно записано как косая черта, то более-менее интуитивно, что умножение на обратную величину производится именно СПРАВА, раз уж она в этом выражении записывается правее! Именно поэтому мы в итоге предпочли "внешнее" движение "внутреннему": в противном случае обратная величина оказалась бы слева.)

Остаётся только извлечь корень (N-1)-й степени, но мы этот корень заменим на экспоненту и логарифм:



Ранее мы выписывали, чему равна экспонента от некоммутирующего дуального комплексного числа, правда, с нулевой действительной частью. Давайте для порядку выпишем самый общий случай:



Отсюда можно сообразить, как нам посчитать логарифм. Обозначим его аргумент: c+si+xj+yk. Такой выбор букв, поскольку первые две компоненты это обычно косинус (c) и синус (s), а последние две компоненты так или иначе выражают параллельный перенос. Сопоставим теперь с буквами выше:









Для начала находим общий множитель, exp(k0):



Теперь выражение можно отнормировать и найти первую компоненту логарифма:











Далее находим мнимую компоненту α:



Это мы находим "главную ветвь", в результате чего наш объект ни в коем случае не "закрутится" более чем на 1 оборот. Всё равно некомм. дуал. компл. числа, как и кватернионы, не могут хранить, сколько оборотов шла закрутка. Максимум, они отличат 360° от 0°, но от закрутки в 720° мы всё же вернёмся в исходное состояние.

И наконец, зная α, можно найти и B:





Мы всё же вводим функцию



Дело в том, что при отсутствии вращения (т.е при α=0) у нас будет получаться ситуация "0/0", которой быть не должно, тут должен сработать замечательный предел и получиться нормальная единичка.

Сейчас мы можем, наконец, громко подумать об "особом случае" α=π. Поскольку наши некомм. дуал. компл. числа оказались некоторой разновидностью кватернионов, и у них углы половинные, то "особый случай" соответствует полному обороту. Здесь у нас просто ОБЯЗАТЕЛЬНО должно быть x=y=0 в аргументе логарифма, иначе у нас получится деление на ноль! Выходит, что если объект совершал полный оборот "маленькими шажками", то он НЕ ИМЕЕТ ПРАВА ещё и куда-то сместиться!

Если рассмотреть "внутреннее движение", то физический смысл этого ограничения становится понятен. Грубо говоря, мы фиксируем у автомобиля руль в отклонённом состоянии, и начинаем ехать. Рано или поздно, сделав полный оборот, мы вернёмся ровно в ту же точку, откуда и стартовали. Диаметр круга, который мы описали, будет существенно разниться в зависимости от поворота руля (чем он "прямее", тем больше диаметр), но вернуться в начало мы попросту обязаны! Если же продолжить движение, мы можем описать и второй круг и снова вернуться в исходную точку, а потом и третий, и четвёртый! Половинные углы наших некоммутирующих дуальных комплексных чисел, в связке с функцией sinc(α), которая выползла в экспоненте, дадут именно такой эффект: если уж мы совершили целое число оборотов, отличное от нуля, значит, мы просто обязаны вернуться в исходную точку! А вот если ни одного оборота не сделано, то получаем вполне нормальное движение по прямой, без каких-либо ограничений.

Напомним: "основные свойства" экспоненты и логарифма у нас здесь, вообще говоря, не выполняются! То есть, экспонента от суммы не обязательно окажется равной произведению отдельных экспонент, равно как и логарифм от произведения не обязательно будет равен сумме логарифмов. Поэтому я предлагаю не использовать здесь запись экспоненты как ex, а исключительно как ФУНЦИЮ exp(x), определённую через ряд. Если используемые числа коммутируют, то можно доказать через бином Ньютона, что exp(x+y)=exp(x)exp(y), в противном случае равенство будет выполняться не всегда. Так что увидев под логарифмом частное от конечного и начального положения, не следует пытаться "упростить" выражение (сделав разность логарифмов), частное надо посчитать "честно", и уже потом брать логарифм, иначе не избежать проблем...

Вот мы и вывели это дело, ещё и показав, что интерполяция "внутренними" и "внешними" движениями оказывается в точности такой же.

Впрочем, в чистом виде такая интерполяция редко когда может пригодиться. В следующей части мы попробуем применить её на автомобиле, увидим, как он перестраивается из ряда в ряд, тупо ДВИГАЯСЬ ВБОК и поймём, что одну степень свободы надо убрать. Вот после этого получится интересный результат.

кватернионы-это просто (том 1), странные девайсы, математика, программки, работа

Previous post Next post
Up