floQ.m 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. classdef floQ < quaternion
  2. % floQ is an expansion of quaternion
  3. % Adding many attributes and functions to make ray tracing with
  4. % quaternion easy to compute
  5. properties %
  6. w
  7. x
  8. y
  9. z
  10. end
  11. properties (SetAccess = private)
  12. u
  13. v
  14. end
  15. methods
  16. function obj = floQ(inputMat)
  17. input_size = size(inputMat);
  18. switch class(inputMat)
  19. case "double"
  20. if input_size(end) == 3
  21. Qmat = cat(length(input_size),zeros([input_size(1:end-1),1]),inputMat);
  22. elseif input_size(end) == 4
  23. Qmat = inputMat;
  24. elseif input_size(end) == 2
  25. Qmat = reshape(inputMat,[],2);
  26. [Qmat_x,Qmat_y,Q_mat_z] = sph2cart(Qmat(:,1),Qmat(:,2),ones(size(Qmat(:,1))));
  27. Qmat = [zeros(size(Qmat_x)),Qmat_x,Qmat_y,Q_mat_z];
  28. else
  29. error("the input array should be N-by-4, instead it is N-by-%i",input_size(end))
  30. end
  31. Qmat = reshape(Qmat,[],4);
  32. if length(input_size)>2
  33. Qsize = input_size(1:end-1);
  34. else
  35. Qsize = [input_size(1),1];
  36. end
  37. case "quaternion"
  38. Qmat = inputMat.compact;
  39. Qsize = input_size;
  40. case "floQ"
  41. Qmat = inputMat.compact;
  42. Qsize = input_size;
  43. end
  44. obj@quaternion(Qmat);
  45. obj = reshape(obj,Qsize);
  46. % obj = update_parts(obj);
  47. end
  48. function quat_obj = as_quaternion(obj)
  49. quat_obj = reshape(quaternion(obj.compact),size(obj));
  50. end
  51. function Qmatrix = asMatrix(obj)
  52. Qmatrix = reshape(obj.compact,[size(obj),4]);
  53. end
  54. function obj = set.w(obj,warray)
  55. obj.w = warray;
  56. obj.a = warray;
  57. end
  58. function qw = get.w(obj)
  59. qw = obj.a;
  60. end
  61. function obj = set.x(obj,xarray)
  62. obj.x = xarray;
  63. obj.b = xarray;
  64. end
  65. function qx = get.x(obj)
  66. qx = obj.b;
  67. end
  68. function obj = set.y(obj,yarray)
  69. obj.y = yarray;
  70. obj.c = yarray;
  71. end
  72. function qy = get.y(obj)
  73. qy = obj.c;
  74. end
  75. function obj = set.z(obj,zarray)
  76. obj.z = zarray;
  77. obj.d = zarray;
  78. end
  79. function qz = get.z(obj)
  80. qz = obj.d;
  81. end
  82. function qu = get.u(obj)
  83. qu = atan2(obj.c,obj.b);
  84. end
  85. function qv = get.v(obj)
  86. xynorm = hypot(obj.b,obj.c);
  87. qv = atan2(obj.d,xynorm);
  88. end
  89. function azi = azi(obj)
  90. azi = obj.u;
  91. end
  92. function elv = elv(obj)
  93. elv = obj.v;
  94. end
  95. function qparts = U(obj,unitName)
  96. if strcmp(unitName,'imag')
  97. unitName = 'xyz';
  98. end
  99. qU = cell(1,6);
  100. [qU{1},qU{2},qU{3},qU{4}] = obj.parts;
  101. [qU{5},qU{6}] = cart2sph(qU{2},qU{3},qU{4});
  102. [UindexMat,~] = find(~(unitName-('wxyzuv')'));
  103. qU = qU(UindexMat);
  104. qparts = cat(obj.ndims+1,qU{:});
  105. end
  106. function qparts = qU(obj,unitName)
  107. switch unitName
  108. case 'imag'
  109. unitName = 'xyz';
  110. case 'real'
  111. unitName = 'w';
  112. end
  113. fn = {'w','x','y','z'};
  114. [UindexMat,~] = find(~(unitName-('wxyz')'));
  115. qparts = obj.*0;
  116. for i = UindexMat'
  117. qparts.(fn{i}) = obj.(fn{i});
  118. end
  119. end
  120. function realQobj = real(obj)
  121. realQobj = obj.w;
  122. end
  123. function imagQobj = imag(obj)
  124. imagQobj = obj.U('xyz');
  125. end
  126. function imagQobj = Qimag(obj)
  127. imagQobj = obj;
  128. imagQobj.w = obj.w.*0;
  129. end
  130. function realQobj = Qreal(obj)
  131. realQobj = obj.*0;
  132. realQobj.w = obj.w;
  133. end
  134. function newobj = horzcat(varargin)
  135. Q_array = cellfun(@as_quaternion,varargin,'UniformOutput',false);
  136. newobj = floQ(horzcat(Q_array{:}));
  137. end
  138. function newobj = vertcat(varargin)
  139. Q_array = cellfun(@as_quaternion,varargin,'UniformOutput',false);
  140. newobj = floQ(vertcat(Q_array{:}));
  141. end
  142. function newobj = cat(dim_cat,varargin)
  143. Q_array = cellfun(@as_quaternion,varargin,'UniformOutput',false);
  144. newobj = floQ(cat(dim_cat,Q_array{:}));
  145. end
  146. function obj = T(obj)
  147. nd = ndims(obj);
  148. if nd == 2
  149. obj = permute(obj,[2,1]);
  150. elseif nd > 2
  151. obj = permute(obj,[2,1,3:nd]);
  152. end
  153. end
  154. function obj_sum = sum(obj,varargin)
  155. mat_obj = obj.asMatrix;
  156. sum_mat_obj = sum(mat_obj,varargin{:});
  157. obj_sum = floQ(sum_mat_obj);
  158. end
  159. function obj_mean = mean(obj,varargin)
  160. if numel(obj) > 1
  161. mat_obj = obj.asMatrix;
  162. mean_mat_obj = mean(mat_obj,varargin{:});
  163. obj_mean = floQ(mean_mat_obj);
  164. else
  165. obj_mean = obj;
  166. end
  167. end
  168. function obj_cs = cumsum(obj,varargin)
  169. mat_obj = obj.asMatrix;
  170. sum_mat_obj = cumsum(mat_obj,varargin{:});
  171. obj_cs = floQ(sum_mat_obj);
  172. end
  173. function crossProduct = Qcross(obj,obj2,outputForm) %%%%%%%
  174. if ~exist('outputForm','var')
  175. outputForm = 'floQ';
  176. end
  177. switch outputForm
  178. case 'floQ'
  179. crossProduct = Qimag(obj.*obj2);
  180. case 'matrix'
  181. crossProduct = obj.*obj2;
  182. crossProduct = crossProduct.U('imag');
  183. end
  184. end
  185. function dotProduct = Qdot(obj,obj2,outputForm) %%%%%%%
  186. if ~exist('outputForm','var')
  187. outputForm = 'floQ';
  188. end
  189. switch outputForm
  190. case 'floQ'
  191. dotProduct = -Qreal(obj.*obj2);
  192. case 'matrix'
  193. dotProduct = obj.*obj2;
  194. dotProduct = -dotProduct.w;
  195. end
  196. end
  197. function interAng = Qangle(obj,obj2) %%%%%%%
  198. % Calculate the angle between two vectors
  199. interAng = asin(norm(obj.normalize - obj2.normalize)./2).*2;
  200. end
  201. function lmMat = get_leftMultiplicationMatrix(obj) %%%%%%%
  202. lmMat = [obj.a, obj.b, obj.c, obj.d;...
  203. obj.b,-obj.a, obj.d,-obj.c;...
  204. obj.c,-obj.d,-obj.a, obj.b;...
  205. obj.d, obj.c,-obj.b,-obj.a];
  206. end
  207. function RotVec = asRotVec(obj,rotangle)
  208. RotVec = exp(rotangle/2.*obj.normalize);
  209. end
  210. function rotated = Qrot(obj,point2rot,rotangle)
  211. if ~exist('rotangle','var')
  212. rotated = obj.*point2rot.*obj.conj;
  213. else
  214. obj_rot = obj.asRotVec(rotangle);
  215. rotated = obj_rot.*point2rot.*obj_rot.conj;
  216. end
  217. end
  218. function QrotMat = getRotMat(obj)
  219. if numel(obj) == 1
  220. lmMat = obj.get_leftMultiplicationMatrix;
  221. QrotMat = lmMat*lmMat;
  222. else
  223. QrotMat = [];
  224. end
  225. end
  226. function reflected = Qreflect(obj,points)
  227. reflected = obj.*points.*obj;
  228. end
  229. function QreflectMat = getReflectMat(obj)
  230. if numel(obj) == 1 && norm(get_real(obj))<10^-5
  231. lmMat = obj.get_leftMultiplicationMatrix;
  232. QreflectMat = -lmMat*lmMat;
  233. else
  234. QreflectMat = [];
  235. end
  236. end
  237. function projected = Qproject(obj,points,proj_type)
  238. if ~exist('proj_type','var')
  239. proj_type = 'plane';
  240. end
  241. % n_obj = obj.normalize;
  242. switch proj_type
  243. case 'plane'
  244. projected = (points+obj.*points.*obj)./2;
  245. case 'line'
  246. projected = (points-obj.*points.*obj)./2;
  247. end
  248. end
  249. function plength = project_length(obj,points)
  250. cos_angle = Qangle(obj,points);
  251. plength = norm(points).*cos_angle;
  252. end
  253. function QprojectMat = getProjectMat(obj)
  254. QreflectMat = getReflectMat(obj);
  255. QprojectMat = (eye(4)+QreflectMat)./2;
  256. end
  257. function transVec = rotTo(obj,target)
  258. target = target.normalize;
  259. realpart = Qdot(obj,target);
  260. imagpart = Qcross(obj,target);
  261. realpart = realpart+norm(realpart+imagpart);
  262. transVec = imagpart+realpart;
  263. transVec = normalize(transVec);
  264. end
  265. function [azi,elv,R] = asSphCoord(obj)
  266. cartcoord = obj.Qimag;
  267. [azi,elv,R] = cart2sph(cartcoord.x,cartcoord.y,cartcoord.z);
  268. end
  269. end
  270. end