Форум программистов, компьютерный форум, киберфорум
Python
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.93/40: Рейтинг темы: голосов - 40, средняя оценка - 4.93
7 / 7 / 0
Регистрация: 05.04.2016
Сообщений: 410

Поворот вектора по кватерниону

04.01.2018, 02:16. Показов 8124. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
судя по гуглу - заезженная тема, но.. но я убил грёбанных полтора дня, перепробовал n методов:
http://www.gamedev.ru/code/art... 215&page=2
https://habrahabr.ru/post/255005/
http://gamesetup.ru/topic/621.html
(тут же можно ссылки кидать?)
уже пробовал вплоть до дословного переписывания кода (только с интерпретацией под питон, естественно) - всё равно у них написано в конце что то вроде "есть такой кватернион, такой вектор, поворачиваем вектор кватернионом и получаем такой вектор", но сколько я не бьюсь, у меня всё время в результате вектор получается нулевой, не могу понять где ошибка, если всё перепробовал уже с разных источников и вплоть до дословного кода.
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
class Vector3f:
    x = 0.0;
    y = 0.0;
    z = 0.0;
    def __init__(self, x = 0.0, y = 0.0, z = 0.0):
        self.x = x;
        self.y = y;
        self.z = z;
    def __add__(self, other):
        if (isinstance(other, Vector3f)):
            return Vector3f(self.x + other.x, self.y + other.y, self.z + other.z);
        else:
            raise TypeError("Oops!");
    def __sub__(self, other):
        if (isinstance(other, Vector3f)):
            return Vector3f(self.x - other.x, self.y - other.y, self.z - other.z);
        else:
            raise TypeError("Oops!");
    def __mul__(self, other):
        if (isinstance(other, Vector3f)):
            return self.x * other.x + self.y * other.y + self.z * other.z;
        elif (isinstance(other, int) or isinstance(other, float)):
            return Vector3f(self.x * other, self.y * other, self.z * other);
        else:
            raise TypeError("Oops!");
    def __rmul__(self, other):
        if (isinstance(other, Vector3f)):
            return self.x * other.x + self.y * other.y + self.z * other.z;
        elif (isinstance(other, int) or isinstance(other, float)):
            return Vector3f(self.x * other, self.y * other, self.z * other);
        else:
            raise TypeError("Oops!");
    def __truediv__(self, other):
        if (isinstance(other, int) or isinstance(other, float)):
            return Vector3f(self.x / other, self.y / other, self.z / other);
        else:
            raise TypeError("Oops!");
    def __iadd__(self, other):
        if (isinstance(other, Vector3f)):
            return Vector3f(self.x + other.x, self.y + other.y, self.z + other.z);
        else:
            raise TypeError("Oops!");
    def __isub__(self, other):
        if (isinstance(other, Vector3f)):
            return Vector3f(self.x - other.x, self.y - other.y, self.z - other.z);
        else:
            raise TypeError("Oops!");
    def __imul__(self, other):
        if (isinstance(other, Vector3f)):
            return self.x * other.x + self.y * other.y + self.z * other.z;
        elif (isinstance(other, int) or isinstance(other, float)):
            return Vector3f(self.x * other, self.y * other, self.z * other);
        else:
            raise TypeError("Oops!");
    def __itruediv__(self, other):
        if (isinstance(other, int) or isinstance(other, float)):
            return Vector3f(self.x / other, self.y / other, self.z / other);
        else:
            raise TypeError("Oops!");
    def __eq__(self, other):
        if (not isinstance(other, Vector3f)):
            raise TypeError("Oops!");
        if ((self.x == other.x) and (self.y == other.y) and (self.z == other.z)):
            return True;
        else:
            return False;
    def __ne__(self, other):
        if (not isinstance(other, Vector3f)):
            raise TypeError("Oops!");
        if ((self.x != other.x) or (self.y != other.y) or (self.z != other.z)):
            return True;
        else:
            return False;
    def __str__(self):
 
        return '(' + str(self.x) + ', ' + str(self.y) + ', ' + str(self.z) + ')';
    def length(self):
 
        return sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
    def normilize(self):
        length = self.length();
        if (length == 0):
            return;
        res = self / length;
        self.x = res.x;
        self.y = res.y;
        self.z = res.z;
    def isCollinearTo(self, other):
        if (not isinstance(other, Vector3f)):
            raise TypeError("Oops!");
        if ((self.x / other.x == self.y / other.y) and (self.y / other.y == self.z / other.z)):
            return True;
        else:
            return False;
    def normilized(self):
        length = self.length();
        if (length == 0):
            return self;
        return self / length;
    def vecMul(self, other):
        if (isinstance(other, Vector3f)):
            return Vector3f(self.y * other.z - self.z * other.y, self.x * other.z - self.z * other.x, self.x * other.y - self.y * other.x);
        else:
            raise TypeError("Oops!");
    def asTuple(self):
 
        return (self.x, self.y, self.z);
 
class Quaternion:
    x = 0.0;
    y = 0.0;
    z = 0.0;
    w = 1.0;
    def __init__(self, w = 1.0, x = 0.0, y = 0.0, z = 0.0):
        self.w = w;
        self.x = x;
        self.y = y;
        self.z = z;
    def __mul__(self, other):
        if (isinstance(other, Quaternion)):
            return Quaternion(self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z,
                              self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
                              self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x,
                              self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w);
        elif (isinstance(other, Vector3f)):
            return Quaternion(- self.x * other.x - self.y * other.y - self.z * other.z,
                              self.w * other.x + self.y * other.z - self.z * other.y,
                              self.w * other.y - self.x * other.z + self.z * other.x,
                              self.w * other.z + self.x * other.y - self.y * other.x);
        elif (isinstance(other, float) or isinstance(other, int)):
            return Quaternion(self.w * other, self.x * other, self.y * other, self.z * other);
        else:
            raise TypeError("Oops!");
    def __truediv__(self, other):
        if (not (isinstance(other, float) or isinstance(other, int))):
            raise TypeError("Oops!");
        return Quaternion(self.w / other, self.x / other, self.y / other, self.z / other);
    def norm(self):
 
        return self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w;
    def magnitude(self):
 
        return sqrt(self.norm());
    def inverted(self):
        quat = Quaternion(self.w, -self.x, -self.y, -self.z);
        quat.normilize();
        return quat;
    def normilize(self):
        len = self.magnitude();
        self.x /= len;
        self.y /= len;
        self.z /= len;
        self.w /= len;
 
    @staticmethod
    def fromAxisAndAngle(axis, angle):
        if (not isinstance(axis, Vector3f)):
            raise TypeError("Oops!");
        if (not (isinstance(angle, float) or isinstance(angle, int))):
            raise TypeError("Oops!");
        axis = axis.normilized();
        sin_a = sin(angle / 2);
        cos_a = cos(angle / 2);
        quat = Quaternion(cos_a, axis.x * sin_a, axis.y * sin_a, axis.z * sin_a);
        return quat;
 
    def rotateVector(self, vec): # тут вся магия, отсюда лучше, наверное, древо функций просматривать
        if (not isinstance(vec, Vector3f)):
            raise TypeError("Oops!");
        quat = self * vec;
        #quat = quat * (quat.inverted() / quat.norm());
        quat = quat * quat.inverted();
        return Vector3f(quat.x, quat.y, quat.z);
и, собственно, место "поворота":
Python
1
2
3
4
5
quat = Quaternion.fromAxisAndAngle(Vector3f(0, 0, 1), 180 / 180 * pi);
print(str(quat.w) + " " + str(quat.x) + " " + str(quat.y) + " " + str(quat.z));
vec = Vector3f(1, 0, 0);
vec = quat.rotateVector(vec);
print("vec = " + str(vec));
(в питоне недавно, пришёл после семи лет C# (строго типизированного), так что не кидайтесь кирпичами, мне легче когда немного типизации всё же имеется в функциях и я знаю где что должно быть)

Добавлено через 1 минуту
P.S.: разбирал все формулы в голове, прогонял через debug (юзаю Visual Studio 2017), действительно в итоге получается нулевой вектор, но вот на сайтах, откуда взята информация, должен быть не нулевой.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.01.2018, 02:16
Ответы с готовыми решениями:

Как задать кватерниону поворот трансформа ?
ребята, всем привет ! подскажите, есть такой код: Vector3 spawnRandomPosition = spawnPoints.transform.localPosition; ...

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

Поворот вектора
Всем доброго времени суток! Есть тело в пространстве с определенной нормалью (нормальный вектор), и есть вектор, до которого тело нужно...

6
1741 / 913 / 480
Регистрация: 05.12.2013
Сообщений: 3,074
04.01.2018, 06:01
Что-то вы там неправильно напереписывали

Вот я попробовал прямо переписать код из статьи с хабра по вашей ссылке, в результате получается, то указано в статье

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import math
 
class Vector3f:
    def __init__(self, x = 0.0, y = 0.0, z = 0.0):
        self.x = x;
        self.y = y;
        self.z = z;
 
    def __str__(self):
     return "Vector = " + str(self.x) + " " + str(self.y) + " " + str(self.z);
 
class Quaternion:
    def __init__(self, w = 1.0, x = 0.0, y = 0.0, z = 0.0):
        self.w = w;
        self.x = x;
        self.y = y;
        self.z = z;
 
    def __str__(self):
     return "Quaternion = " + str(self.w) + " " + str(self.x) + " " + str(self.y) + " " + str(self.z);
 
 
def normal(v):
    normal = Vector3f()
    length = (v.x ** 2 + v.y ** 2 + v.z ** 2) ** 0.5    
    normal.x = v.x / length
    normal.y = v.y / length
    normal.z = v.z / length
    return normal
 
def create_quat(rotate_vector, rotate_angle):
    quat = Quaternion()
    rotate_vector = normal(rotate_vector)
    quat.w = math.cos(rotate_angle / 2)
    quat.x = rotate_vector.x * math.sin(rotate_angle / 2)
    quat.y = rotate_vector.y * math.sin(rotate_angle / 2)
    quat.z = rotate_vector.z * math.sin(rotate_angle / 2)
    return quat
 
def quat_scale(q, val):
    q.w = q.w * val
    q.x = q.x * val
    q.y = q.y * val
    q.z = q.z * val
    return q
 
def quat_length(q):
    quat_length = (q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z) ** 0.5
    return quat_length
 
def quat_normalize(q):
    n = quat_length(q)
    return quat_scale(q, 1 / n)
 
def quat_invert(q):
    res = Quaternion()
    res.w = q.w
    res.x = -q.x
    res.y = -q.y
    res.z = -q.z
    return quat_normalize(res)
 
def quat_mul_quat(a, b):
    res = Quaternion()
    res.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
    res.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y
    res.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x
    res.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w
    return res
 
def quat_mul_vector(a, b):
    res = Quaternion()
    res.w = -a.x * b.x - a.y * b.y - a.z * b.z
    res.x = a.w * b.x + a.y * b.z - a.z * b.y
    res.y = a.w * b.y - a.x * b.z + a.z * b.x
    res.z = a.w * b.z + a.x * b.y - a.y * b.x
    return res
 
def quat_transform_vector(q, v):
    t = Quaternion()
    t = quat_mul_vector(q, v)
    t = quat_mul_quat(t, quat_invert(q))
    ret = Vector3f()
    ret.x = t.x
    ret.y = t.y
    ret.z = t.z
    return ret
 
qua = create_quat(Vector3f(0,1,0), math.pi/2)
vec = Vector3f(0,0,1)
print(quat_transform_vector(qua, vec))
0
Эксперт Python
 Аватар для dondublon
4653 / 2073 / 366
Регистрация: 17.03.2012
Сообщений: 10,183
Записей в блоге: 6
04.01.2018, 12:09
Цитата Сообщение от Nordicus666 Посмотреть сообщение
class Vector3f: x = 0.0; y = 0.0; z = 0.0;
Для начала - не надо так делать. Это атрибуты уровня класса (а не объекта, то бишь экземпляра), вполне возможно, что где-то будет коллизия имён.

Добавлено через 3 минуты
Цитата Сообщение от Nordicus666 Посмотреть сообщение
180 / 180 * pi
А смысл?

Добавлено через 1 минуту
Цитата Сообщение от Nordicus666 Посмотреть сообщение
P.S.: разбирал все формулы в голове, прогонял через debug (юзаю Visual Studio 2017), действительно в итоге получается нулевой вектор, но вот на сайтах, откуда взята информация, должен быть не нулевой.
Советую проверить все числа и привести к float. У вас в параметрах я вижу int.

Ну и заюзать numpy, конечно.

Добавлено через 5 минут
Кстати, для ленивых.
http://kieranwynn.github.io/pyquaternion/
https://github.com/moble/quaternion
0
7 / 7 / 0
Регистрация: 05.04.2016
Сообщений: 410
04.01.2018, 12:26  [ТС]
Цитата Сообщение от ТабуретY Посмотреть сообщение
Что-то вы там неправильно напереписывали
Вот я попробовал прямо переписать код из статьи с хабра по вашей ссылке, в результате получается, то указано в статье
не могу понять, честно, в нашем коде разница разве что в том, что у вас методы вынесены из класса Quaternion, но проверил. действительно ваш код работает, почему - не понимаю (серьёзно, я в полном недоумении), попробую эти методы по одному вносить в класс кватерниона и проверять работоспособность

Цитата Сообщение от dondublon Посмотреть сообщение
class Vector3f: x = 0.0; y = 0.0; z = 0.0;
Для начала - не надо так делать. Это атрибуты уровня класса (а не объекта, то бишь экземпляра), вполне возможно, что где-то будет коллизия имён.
понял о чём вы.. но как тогда,если я хочу точно знать (т.е. что б в одном месте где то были описаны поля класса) какие есть поля у моего объекта уж наверняка, как это описать?

Цитата Сообщение от dondublon Посмотреть сообщение
180 / 180 * pi
А смысл?
просто для удобства, первое число - угол в градусах, писать туда любой можно, а далее просто перевод в радианы, с которыми работают тригонометрические функции

Цитата Сообщение от dondublon Посмотреть сообщение
P.S.: разбирал все формулы в голове, прогонял через debug (юзаю Visual Studio 2017), действительно в итоге получается нулевой вектор, но вот на сайтах, откуда взята информация, должен быть не нулевой.
Советую проверить все числа и привести к float. У вас в параметрах я вижу int.
разве питон при надобности не приводит инт к флоату?

Цитата Сообщение от dondublon Посмотреть сообщение
у меня задача самостоятельно написать их, не юзать готовые
0
Эксперт Python
 Аватар для dondublon
4653 / 2073 / 366
Регистрация: 17.03.2012
Сообщений: 10,183
Записей в блоге: 6
04.01.2018, 12:42
Цитата Сообщение от Nordicus666 Посмотреть сообщение
понял о чём вы.. но как тогда,если я хочу точно знать (т.е. что б в одном месте где то были описаны поля класса) какие есть поля у моего объекта уж наверняка, как это описать?
У вас всё описано в __init__, этого достаточно.

Цитата Сообщение от Nordicus666 Посмотреть сообщение
разве питон при надобности не приводит инт к флоату?
При присваивании - нет. Это компилируемые языки всё за нас делают
0
7 / 7 / 0
Регистрация: 05.04.2016
Сообщений: 410
04.01.2018, 18:12  [ТС]
В общем решил с нуля ещё раз переписать свой код, заработало.. не знаю почему, но заработало
что ж, всем спасибо за помощь)
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
04.01.2018, 19:09
Цитата Сообщение от Nordicus666 Посмотреть сообщение
в питоне недавно, пришёл после семи лет C# (строго типизированного), так что не кидайтесь кирпичами, мне легче когда немного типизации всё же имеется в функциях и я знаю где что должно быть
Так используй аннотации типов и наслаждайся всеми прелестями динамической типизации.

И ещё, не нужно ставить точки с запятой, это мусор, который в коде не нужен совершенно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
04.01.2018, 19:09
Помогаю со студенческими работами здесь

Поворот вектора
известны начальные и конечные координаты вектора...необходимо направить его в противоположную сторону относительно начальной...

Поворот 3D вектора
Подскажите пожалуйста, как исправить можно? Входные данные: 1. 3D - координаты вектора. 2. Угол поворота в радианах. ...

Поворот вектора
Всем доброго времени суток. Есть кубик. При нажатии на него и дальнейшем свайпе происходит расчёт вектора на экране (координата коннца...

Поворот вектора
Здравствуйте. Есть вектор A{x,y,z} и вектор А'=M*A, где М - матрица поворота вокруг оси ОХ на 30 градусов (см. рис). Вопрос: как...

Поворот вокруг вектора.
Поделитесь исходником функции поворота точки вокруг вектора. Написал так по книжке "Д.Роджерс, Дж.Адамс Математические основы машинной...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
Программный отбор значения справочника
Maks 21.03.2026
Процедура ВодителиНачалоВыбора(Элемент, ДанныеВыбора, ВыборДобавлением, СтандартнаяОбработка) / / Отключаем стандартную обработку (стандартное открытие формы выбора без фильтров) . . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru