MATLAB Answers

0

Why is my Matlab hgtransform matrix invalid?

Asked by Richard Crozier on 22 Feb 2017
Latest activity Commented on by Richard Crozier on 22 Feb 2017
I am attempting to apply a transform matrix by setting the 'Matrix' property of a matlab hgtransform object. The transform matrix is below:
866.0254e-003 500.0000e-003 0.0000e+000 500.0000e-003
500.0000e-003 -866.0254e-003 0.0000e+000 500.0000e-003
0.0000e+000 0.0000e+000 1.0000e+000 0.0000e+000
0.0000e+000 0.0000e+000 0.0000e+000 1.0000e+000
This particular matrix is intended to represent a translation
(0.5, 0.5, 0)
and rotation around the Z axis of pi/6 (although actually I think it results in a rotation of -pi/6, more on this below).
When I try to do this:
% make a unit box
sx = 1;
sy = 1;
sz = 1;
shapeData.Vertices = [ -sx/2, -sy/2, -sz/2;
sx/2, -sy/2, -sz/2;
sx/2, sy/2, -sz/2;
-sx/2, sy/2, -sz/2;
-sx/2, -sy/2, sz/2;
sx/2, -sy/2, sz/2;
sx/2, sy/2, sz/2;
-sx/2, sy/2, sz/2; ];
shapeData.Faces = [ 1, 4, 3, 2;
1, 5, 6, 2;
2, 6, 7, 3;
7, 8, 4, 3;
8, 5, 1, 4;
8, 7, 6, 5 ];
figure;
axes;
transformObject = hgtransform (gca);
patchObject = patch (gca, ...
'Faces', shapeData.Faces, ...
'Vertices', shapeData.Vertices, ...
'FaceColor', 'red', ...
'FaceAlpha', 1.0, ...
'EdgeColor', 'none', ...
'FaceLighting', 'gouraud', ...
'AmbientStrength', 0.15, ...
'Parent', transformObject);
M = [ ...
866.0254e-003 500.0000e-003 0.0000e+000 500.0000e-003; ...
500.0000e-003 -866.0254e-003 0.0000e+000 500.0000e-003; ...
0.0000e+000 0.0000e+000 1.0000e+000 0.0000e+000; ...
0.0000e+000 0.0000e+000 0.0000e+000 1.0000e+000; ...
];
set ( transformObject, 'Matrix', M );
I get the error:
Error using matlab.graphics.primitive.Transform/set
Invalid value for Matrix property
Why?
To generate this transform matrix I used the following class I created which constructs orientation (rotation) matrices in various ways:
classdef orientmat
properties (GetAccess = public, SetAccess = protected)
orientationMatrix;
end
methods
function this = orientmat (spectype, spec)
% orentmat constructor
%
% Syntax
%
% om = orientmat (spectype, spec)
%
% Input
%
%
switch spectype
case 'orientation'
this.orientationMatrix = spec;
case 'euler'
this.orientationMatrix = SpinCalc('EA123toDCM', rad2deg (spec), eps (), 1);
case 'euler123'
this.orientationMatrix = SpinCalc('EA123toDCM', rad2deg (spec), eps (), 1);
case 'euler321'
this.orientationMatrix = SpinCalc('EA321toDCM', rad2deg (spec), eps (), 1);
case 'vector'
% axis and angle (angle in rad = norm of matrix)
wcrs = [ 0 spec(3) -spec(2)
-spec(3) 0 spec(1)
spec(2) -spec(1) 0] ;
this.orientationMatrix = expm (wcrs);
case '2vectors'
% normalise the fisr vector
spec.vec1 = this.unit (spec.vec1);
spec.vec2 = this.unit (spec.vec2);
spec.vec3 = cross (spec.vec1, spec.vec2);
spec.vec2 = this.unit (cross (this.unit (spec.vec3), spec.vec1));
switch spec.vec1axis
case 1
X = spec.vec1;
if spec.vec2axis == 2
Y = spec.vec2;
Z = spec.vec3;
elseif spec.vec2axis == 3
Y = spec.vec3;
Z = spec.vec2;
end
case 2
Y = spec.vec1;
if spec.vec2axis == 1
X = spec.vec2;
Z = spec.vec3;
elseif spec.vec2axis == 3
X = spec.vec3;
Z = spec.vec2;
end
case 3
Z = spec.vec1;
if spec.vec2axis == 2
X = spec.vec2;
Y = spec.vec3;
elseif spec.vec2axis == 3
X = spec.vec3;
Y = spec.vec2;
end
end
this.orientationMatrix = [ X, Y, Z ];
end
end
end
% operator overloading
methods
function om = plus (om1, om2)
om = mbdyn.pre.orientmat ('orientation', om1.orientationMatrix + om2.orientationMatrix);
end
function om = minus (om1, om2)
om = mbdyn.pre.orientmat ('orientation', om1.orientationMatrix - om2.orientationMatrix);
end
function om = times (om1, om2)
om = mbdyn.pre.orientmat ('orientation', om1.orientationMatrix .* om2.orientationMatrix);
end
function om = mtimes (om1, om2)
om = mbdyn.pre.orientmat ('orientation', om1.orientationMatrix * om2.orientationMatrix);
end
function om = double (om1)
om = om1.orientationMatrix;
end
function om = uminus (om1)
om = mbdyn.pre.orientmat ('orientation', -om1.orientationMatrix);
end
function om = uplus (om1)
om = mbdyn.pre.orientmat ('orientation', +om1.orientationMatrix);
end
function om = transpose (om1)
om = mbdyn.pre.orientmat ('orientation', om1.orientationMatrix.');
end
function om = ctranspose (om1)
om = mbdyn.pre.orientmat ('orientation', om1.orientationMatrix');
end
end
methods (Access = private)
function out = unit (self, vec)
out = vec ./ norm (vec);
end
end
end
Then did:
om = orientmat ('2vectors', struct ('vec1axis', 1, 'vec1', [cos(pi/6);sin(pi/6);0], 'vec2axis', 3, 'vec2', [0;0;1]));
M = [ om.orientationMatrix, [0.5; 0.5; 0]; 0, 0, 0, 1 ];
This constructs an orientation matrix from two vectors which define a plane.
Now there may be an issue with the rotation not actually being what I intend (I think the order of the cross products is wrong so the rotation ends up in the wrong direction), but as far as I can see it is still a valid transformation matrix. So why does hgtransform not like it?
EDIT
As explained earlier, there is actually an issue with the transform not doing what I intend (actually produces a rotation in the wrong direction), but the matrix seems valid, for example it produces the same result as hgtransform:
>> M
M =
866.0254e-003 500.0000e-003 0.0000e+000 500.0000e-003
500.0000e-003 -866.0254e-003 0.0000e+000 500.0000e-003
0.0000e+000 0.0000e+000 1.0000e+000 0.0000e+000
0.0000e+000 0.0000e+000 0.0000e+000 1.0000e+000
>> pos = [1,0,0,0]
pos =
1.0000e+000 0.0000e+000 0.0000e+000 0.0000e+000
>> pos * M
ans =
866.0254e-003 500.0000e-003 0.0000e+000 500.0000e-003
>> Mhgt = makehgtform('translate', [0.5 0.5 0], 'zrotate', -pi/6)
Mhgt =
866.0254e-003 500.0000e-003 0.0000e+000 500.0000e-003
-500.0000e-003 866.0254e-003 0.0000e+000 500.0000e-003
0.0000e+000 0.0000e+000 1.0000e+000 0.0000e+000
0.0000e+000 0.0000e+000 0.0000e+000 1.0000e+000
>> pos * Mhgt
ans =
866.0254e-003 500.0000e-003 0.0000e+000 500.0000e-003

  1 Comment

I'm starting to think that the reason is the -ve coefficient on the diagonal of my matrix, as according to Transforms Supported by hgtransform no non-negative scaling terms are allowed. So even though the scaling here is 1 the negative term makes it invalid.

Sign in to comment.

1 Answer

Answer by Walter Roberson
on 22 Feb 2017

You appear to have the wrong sign on one of your coefficients.
M = makehgtform('translate', [0.5 0.5 0], 'zrotate', -pi/6)
or +pi/6 when you figure out which you want.

  3 Comments

Thanks for the fast answer, but yes, as I explain, the rotation is not what I intended (probably because the cross product order is not correct), but the matrix to me still seems like a valid transformation matrix. The question is really why does hgtransform not like what appears to be a valid transformation matrix (irrespective of the fact that it was not what I intended, i.e. gives a rotation in the opposite direction than desired).
I edited the question to show my transform matrix appears to do the same as one generated with makehgtform.
Actually I see that it is probably due to the -ve scaling coefficient (perhaps this is what you meant?) I've added a comment to the question with a link to the relevant matlab doc.

Sign in to comment.