-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcross2.m
123 lines (113 loc) · 4.52 KB
/
cross2.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
function c = cross2(a, b, idA, idB)
%CROSS2 Vector cross product.
% This function exploits the BAXFUN engine (MATLAB Central, file #23084),
% which enables multiple products and array expansion (AX).
%
% When A and B are 3-element vectors (e.g. 3×1, 1×3, or 1×1×3 arrays):
%
% C = CROSS2(A, B) returns their cross product. That is, C = A x B.
% If NDIMS(A) == 2 and NDIMS(B) == 2, CROSS2(A, B) is equivalent to
% CROSS(A, B).
%
% More generally, when A and B are arrays of any size containing one or
% more 3-element vectors:
%
% C = CROSS2(A, B) is equivalent to C = CROSS2(A, B, IDA, IDB), where
% IDA and IDB are the first dimensions of A and B whose length is 3.
%
% C = CROSS2(A, B, DIM) is equivalent to C = CROSS2(A, B, IDA, IDB),
% where IDA = IDB = DIM. If A and B have the same size, it is also
% equivalent to C = CROSS(A, B, DIM).
%
% C = CROSS2(A, B, IDA, IDB) returns the cross products between the
% vectors contained in A along dimension IDA and those contained in B
% along dimension IDB. These vectors must have 3 elements. A and B
% are viewed as "block arrays". IDA and IDB are referred to as their
% "internal dimensions" (IDs). For instance, a 3×6×2 array may be
% viewed as an array containing twelve 3-element blocks. In this
% case, its size is denoted by (3)×6×2, and its ID is 1. Since AX is
% enabled, A and B may have different size, and IDA may not coincide
% with IDB (see MULTIPROD).
%
% Input and output format:
% Array Block size Internal dimension
% ---------------------------------------------------------------
% A 3 (1-D) IDA
% B 3 (1-D) IDB
% C 3 (1-D) MAX(IDA, IDB)
% ---------------------------------------------------------------
% If SIZE(A)==SIZE(B) and IDA==IDB, then SIZE(C)=SIZE(A)=SIZE(B).
%
% Examples:
% If A and B are both (3)×6×2 arrays of vectors,
% C = CROSS2(A, B) is a (3)×6×2 array of vectors.
%
% A single vector B multiplies thirty vectors contained in A:
% If A is ................ a 5×6×(3) array of 30 vectors,
% and B is ................ a (3)×1 vector,
% C = CROSS2(A, B, 3, 1) is a 5×6×(3) array of 30 vectors.
%
% See also DOT2, CROSS, CROSSDIV, OUTER, MAGN, UNIT, PROJECTION,
% REJECTION, TESTCROSS2.
% $ Version: 2.0 $
% CODE by: Paolo de Leva (IUSM, Rome, IT) 2009 Feb 2
% optimized by: Code author 2009 Feb 12
% COMMENTS by: Code author 2009 Feb 26
% OUTPUT tested by: Code author 2009 Feb 26
% -------------------------------------------------------------------------
% Allow 2 to 4 input arguments
error( nargchk(2, 4, nargin) );
% Setting IDA and/or IDB
sizeA = size(a);
sizeB = size(b);
switch nargin
case 2
idA = find(sizeA==3, 1, 'first'); % First dim. of length 3
idB = find(sizeB==3, 1, 'first');
if isempty(idA) || isempty(idB)
error('CROSS2:InvalidSize',...
'A and B must have at least one dimension of length 3.');
end
case 3
idB = idA;
end
% Check block size
if (sizeA(idA)~=3) || (sizeB(idB)~=3),
error('CROSS2:InvalidBlockSize',...
['A and B must be of length 3 in the dimensions\n'...
'in which the cross product is taken.'])
end
% Dimension shift (first step of array expansion)
% NOTE: The BAXFUN engine is implemented here without calling
% BAXFUN, to avoid repeated shift of A and B
diff = idB - idA;
if diff >= 0
id = idB;
sizeA = [ones(1, diff) sizeA];
a = reshape(a, sizeA);
else
id = idA;
sizeB = [ones(1,-diff) sizeB];
b = reshape(b, sizeB);
end
% Vectorized indices to rearrange A and B
idxA = ivector(sizeA);
idxB = ivector(sizeB);
% Calculate cross product
% c = [a(2,:).*b(3,:) - a(3,:).*b(2,:)
% a(3,:).*b(1,:) - a(1,:).*b(3,:)
% a(1,:).*b(2,:) - a(2,:).*b(1,:)];
idxA{id} = [2 3 1];
idxB{id} = [3 1 2];
c = bsxfun( @times, a(idxA{:}), b(idxB{:}) );
idxA{id} = [3 1 2];
idxB{id} = [2 3 1];
c = c - bsxfun( @times, a(idxA{:}), b(idxB{:}) );
%--------------------------------------------------------------------------
function indices = ivector(sizeA)
%IVECTOR Vectorizing the indices of an array.
Ndims = length(sizeA);
indices = cell(1,Ndims); % preallocating
for d = 1 : Ndims
indices{d} = 1:sizeA(d);
end