classdef quaternion < handle
% 四元数 qa qx qy qz
properties
data = zeros(4, 1);%列向量
end
methods %普通函数块--开始
function obj = quaternion(varargin)
% 构造函数,支持“4x1向量” 、“1x4向量”、“4个单变量axyz”进行构造
% q=[qa qx qy qz]
if 1 == nargin
arg = varargin{1};
obj.data(1) = arg(1);
obj.data(2) = arg(2);
obj.data(3) = arg(3);
obj.data(4) = arg(4);
elseif 4 == nargin
obj.data(1) = varargin{1};
obj.data(2) = varargin{2};
obj.data(3) = varargin{3};
obj.data(4) = varargin{4};
else
%error('quaternion类 仅支持“4x1向量” 、“1x4向量”、“4个单变量axyz”进行构造');%注意,转C语言时,不要出现打印语句
end
end
function [] = setValue(obj, in4x1)
%赋值
obj.data = in4x1;
end
function [] = set.data(obj, in4x1)
%赋值,当写出q.data = xxxx;语句时,该函数会被自动调用,一般可用于右值合法检测
obj.data = in4x1;
%disp('quaternion set.data is called');
end
function [] = normalize(obj)
%把本四元数归一化
obj.data = obj.data / norm(obj.data);
end
function res = mtimes(q1, q2)
% 乘法*运算符重载
p = [ q1.data(1) -q1.data(2) -q1.data(3) -q1.data(4);
q1.data(2) q1.data(1) -q1.data(4) q1.data(3);
q1.data(3) q1.data(4) q1.data(1) -q1.data(2);
q1.data(4) -q1.data(3) q1.data(2) q1.data(1)] ...
* [ q2.data(1) q2.data(2) q2.data(3) q2.data(4)]';
res = quaternion(p(1), p(2), p(3), p(4));
end
function [ret] = rotateVec(obj, vec)
%四元数对三维向量进行旋转,注意,请保证输入的q为单位四元数
%形参:默认本类的对象q,要被旋转的三维向量vec(行列均可)
%返回三维列向量
qv = quaternion(0, vec(1), vec(2), vec(3)); %[0 vec(1) vec(2) vec(3)]';
qi = conjugate(obj);
qvqi = obj * qv * qi;
ret = [qvqi.data(2) qvqi.data(3) qvqi.data(4)]';
end
end %普通函数块--结束
methods(Static) %静态函数块---开始
%这里写静态函数
end %静态函数块---结束
end %类定义结束
以上给出了简单的几个示例,挨个说明:
1、类声明与继承
声明形如 classdef quaternion < handle,其中<代表继承handle类,
若继承多个类,可写成形如:classdef quaternion < base1 & base2 &base3
这里继承的handle需要强调一下,matlab有两个超类,handle和value,关于这两者的区别,请看我这一篇文章《matlab handle类和value类的区别》,一般我们自己写的类都要继承者这两者中的一个。
2、构造函数
构造函数与类名同名,必须有一个返回值,返回值的名称必须是obj,由于matlab不支持函数重载,因此只能有一个构造函数,不过我们可以通过可变参数表变相近似实现以下构造函数的重载,varargin这是matlab内置的形参,代表输入的参数数目是可变的,在函数内部可通过nargin来判断实参的数目(number of argument input),来区别不同的实参。这一技巧也可用在普通的函数中。
3、成员变量
如例子所示,被 properties xxxxx end标签包裹的部分为成员变量。
在成员函数中访问成员变量,必须要加obj.前缀(需要注意的是,这个前缀并不固定是obj,这取决于成员函数第一参的命名),示例代码中的很多成员函数已经展示了如何读写成员变量。
4、无参成员函数
无参函数指的是在调用时无参,一般声明和定义函数时,matlab默认把第一参数当做this指针,所以,几乎的成员函数都至少带有一个形参。第一参数的名字可随意取,一般惯例是取做obj,但不是绝对的,例如例子中重载的乘法运算符,我把第一参取名为q1,也是可以的。
上例中,normalize函数有一个形参obj,但在调用时是无参的:
q= quaternion([1 2 3 4]');
q.normalize();
disp(q.data');%结果为: 0.1826 0.3651 0.5477 0.7303
5、有参成员函数
真正的参数是从第二个参数开始的,例如例子中的rotateVec函数,声明时他有两个参数,但在调用时,只有一个参数,因为真正的第一参被隐式用作this指针了。
q= quaternion([0.1826 0.3651 0.5477 0.7303]');
q.rotateVec([1 2 3]);