-
Notifications
You must be signed in to change notification settings - Fork 1
/
planevec2axes.m
171 lines (135 loc) · 4.38 KB
/
planevec2axes.m
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
function varargout = planevec2axes( s1, v1, s2, v2, O )
%% Rotation matrix from two vectors defining a plane
%
% Form a coordinate system using two vectors and their cross product.
% Vectors are not assumed to be unit vectors, and are normalised to be column-wise.
% The axes are always labeled X, Y, Z with a right-hand orientation, and
% the designation of which vectors (`v1`, `v2`) are which axes is explicit in the
% arguments (`s1`, `s2`) to the function.
%
% Outputs are either a rotation matrix or a set of unit vectors, or a
% transformation matrix if an original is provided:
%
% ------------------------------------------------------------------------
% rotM = planevec2axes( s1, v1, s2, v2)
% [X, Y, Z] = planevec2axes( s1, v1, s2, v2)
% transM = planevec2axes( s1, v1, s2, v2, O)
% ------------------------------------------------------------------------
%
% If the two vectors are orthogonal, the third axis is formed from their
% cross product:
%
% ------------------------------------------------------------------------
% rotM = planevec2axes( 'X', v1, 'Y', v2)
% rotM = planevec2axes( 'X', v1, 'Z', v2)
% rotM = planevec2axes( 'Y', v1, 'X', v2)
% rotM = planevec2axes( 'Y', v1, 'Z', v2)
% rotM = planevec2axes( 'Z', v1, 'X', v2)
% rotM = planevec2axes( 'Z', v1, 'Y', v2)
% ------------------------------------------------------------------------
%
% If the two vectors are not orthogonal, their cross product is used to
% form the second axis, and the third is formed from a subsequent cross
% product:
%
% ------------------------------------------------------------------------
% rotM = planevec2axes( 'X', v1, 'XY', v2)
% rotM = planevec2axes( 'X', v1, 'XZ', v2)
% rotM = planevec2axes( 'Y', v1, 'YX', v2)
% rotM = planevec2axes( 'Y', v1, 'YZ', v2)
% rotM = planevec2axes( 'Z', v1, 'ZX', v2)
% rotM = planevec2axes( 'Z', v1, 'ZY', v2)
% ------------------------------------------------------------------------
%
% In the latter case, the order of the "two letter" second input is not
% important. E.g., 'XY' is the same as 'YX'.
% Validate input:
if numel(s1) == 1 && numel(s2) == 1
assert( abs(dot(v1,v2))<eps , 'Two input vectors must be orthogonal.' )
else
assert( 1-abs(dot(v1,v2))<eps , 'Two input vectors must not be parallel.' )
end
% Ensure column vectors and that s2 is ordered alphabetically:
v1 = v1(:);
v2 = v2(:);
s2 = sort(s2);
% Initialise:
axes = struct('X',[],'Y',[],'Z',[]);
% The main routine:
switch s1
case 'X'
axes.X = v1;
switch s2
case 'Y'
axes.Y = v2;
axes.Z = cross(axes.X,axes.Y);
case 'XY'
axes.Z = cross(axes.X,v2);
axes.Y = cross(axes.Z,axes.X);
case 'Z'
axes.Z = v2;
axes.Y = cross(axes.Z,axes.X);
case 'XZ'
axes.Y = cross(v2,axes.X);
axes.Z = cross(axes.X,axes.Y);
otherwise
error('Unknown option pair "%s"/"%s"',s1,s2)
end
case 'Y'
axes.Y = v1;
switch s2
case 'X'
axes.X = v2;
axes.Z = cross(axes.X,axes.Y);
case 'XY'
axes.Z = cross(v2,axes.Y);
axes.X = cross(axes.Y,axes.Z);
case 'Z'
axes.Z = v2;
axes.X = cross(axes.Y,axes.Z);
case 'YZ'
axes.X = cross(axes.Y,v2);
axes.Z = cross(axes.X,axes.Y);
otherwise
error('Unknown option pair "%s"/"%s"',s1,s2)
end
case 'Z'
axes.Z = v1;
switch s2
case 'X'
axes.X = v2;
axes.Y = cross(axes.Z,axes.X);
case 'XZ'
axes.Y = cross(axes.Z,v2);
axes.X = cross(axes.Y,axes.Z);
case 'Y'
axes.Y = v2;
axes.X = cross(axes.Y,axes.Z);
case 'YZ'
axes.X = cross(v2,axes.Z);
axes.Y = cross(axes.Z,axes.X);
otherwise
error('Unknown option pair "%s"/"%s"',s1,s2)
end
otherwise
error('Unknown first vector option "%s"',s1)
end
% Unit vectors for each axis:
X = axes.X/norm(axes.X);
Y = axes.Y/norm(axes.Y);
Z = axes.Z/norm(axes.Z);
% Outputs:
if nargin == 5
% transformation matrix output:
varargout{1} = [X Y Z O(:); 0 0 0 1];
elseif nargin == 4
if nargout == 1
% rotation matrix output:
varargout{1} = [X Y Z];
elseif nargout == 3
% unit vector axes output:
varargout = {X, Y, Z};
end
end
end
% Licence included in README.