Directions are added, scaled and multiplied like ordinary numbers, and every operation works on a whole list of directions at once. That is the reason a loop over vectors is almost never needed in MTEX.
plottingConvention.default('y↑→x');Building New Directions
Sums and multiples of the specimen axes vector3d.X, vector3d.Y and vector3d.Z are directions again.
v = vector3d.X + 2*vector3d.Yv = vector3d (y↑→x)
x y z
1 2 0 +, -, *, the inner product dot and the cross product cross all behave as in linear algebra.
u = dot(v,vector3d.Y) * vector3d.Y + 2 * cross(v,vector3d.Z)u = vector3d (y↑→x)
x y z
4 0 0Angles
The angle between two directions is a central measurement in texture analysis - for example, how far a lattice-plane normal is tilted away from the sheet normal. The angle between complete crystal orientations is a different operation, introduced in the misorientation chapter.
angle(vector3d.X,vector3d.Y) ./ degreeans =
90The result is in radians, hence the division by degree, and it lies between \(0\) and \(180^\circ\). If the two directions are axes rather than directions the answer is never obtuse, which is the subject of Axes and Antipodal Symmetry.
Length
norm is the length of a direction and normalize divides it out.
norm(u)ans =
4u = normalize(u)u = vector3d (y↑→x)
x y z
1 0 0Normalising changes nothing about where the direction points, so it changes nothing about a spherical plot either. It matters when the numbers themselves are used, for instance because dot of two unit vectors is the cosine of the angle between them.
dot(normalize(v),vector3d.Y)ans =
0.8944The Available Operations
|
angle between two directions |
|
|
inner product |
|
|
cross product |
|
|
length |
|
|
length scaled to one |
|
|
component orthogonal to N |
|
|
a direction orthogonal to all of v |
|
|
sum over the list |
|
|
mean direction of the list |
|
|
the two spherical angles |
|
|
turn by a rotation |
Lists of Directions
Square brackets join directions into one list, and the entries are read back by their index.
w = [v,u];
w(1)ans = vector3d (y↑→x)
x y z
1 2 0Arithmetic on a list is done entry by entry. Adding a single direction to a list of five adds it to each of them, so an operation that looks like it needs a loop usually does not.
w = w + vw = vector3d (y↑→x)
size: 1 × 2
x y z
2 4 0
2 2 0Lists are indexed as numeric arrays are, by position or by a logical condition. Here a file of a thousand directions is loaded and only those with a polar angle below \(60^\circ\) are kept, see Lists and Indexing.
fname = fullfile(mtexDataPath,'vector3d','vectors.txt');
v = vector3d.load(fname,'ColumnNames',{'polar angle','azimuth angle'})v = vector3d (y↑→x)
size: 1000 × 1scatter(v(v.theta < 60*degree),'grid','on')
The outer ring of the projection is empty now. It held the 236 directions that lie more than \(60^\circ\) away from the Z axis.
Averaging a List
mean averages the coordinates entry by entry, so it points into the middle of the list.
mean(v)ans = vector3d (y↑→x)
x y z
-0.137 0.198 0.677Its length says how tightly the list is clustered: unit directions all pointing the same way average to length one, a list spread over the sphere to something much shorter - here 0.72. Directions pointing opposite ways cancel outright. For axes, where v and -v mean the same thing, that cancellation is wrong and the mean has to be taken with the 'antipodal' flag, see Axes and Antipodal Symmetry.
Next
Turning a direction into another one is the job of a rotation, and Density Estimation replaces a long list of directions by a smooth function on the sphere.