Matrix HELP!!! (needed for MonkeyMax)

Monkey Archive Forums/Monkey Discussion/Matrix HELP!!! (needed for MonkeyMax)

therevills(Posted 2012) [#1]
Whilst testing MonkeyMax ErikT has found an issue (with negitive Scale) with the matrix code and we are a tad stuck on it...

The issue is that rotation affects scale and I can't work out how to extract rotation from the matrix.

This is the BlitzMax code we have current got:
	Method SetMatrix:Int(ix:Float,iy:Float,jx:Float,jy:Float,tx:Float,ty:Float)
		Self.ix = ix ; Self.iy = iy
		Self.jx = jx ; Self.jy = jy
		Self.tx = tx ; Self.ty = ty
		sx = Sqr( (ix*ix) + (jx*jx) )
		sy = Sqr( (iy*iy) + (jy*jy) )
		rot = -Atan2( jx, ix )
		SetTransform( rot, sx, sy )
		Return 0
	EndMethod


So the first problem is that sx and sy will always return positive due to the SquareRoot. So we added this:
if ix < 0 then sx = -sx
if jy < 0 then sy = -sy


But if you scale by a non-uniform amount and rotate it all goes pear shaped...

So any ideas?


ErikT(Posted 2012) [#2]
Just thinking out loud with my limited coder abilities :P Couldn't you tag the gfx in SetMatrix as having a negative scale and then flip the tagged graphics right before it gets drawn, after rotations and other calculations are done with?


Jesse(Posted 2012) [#3]
maybe I can figure it out for you?

what is ix,jx and iy,jy and how are they calculated?


AdamRedwoods(Posted 2012) [#4]
you could normalize the 2x2 matrix (ie find the determinant) and then find the ratios (divide) for i,j.
t is position you don't need to use that to know the scale.

http://en.wikipedia.org/wiki/Determinant
ad-bc = (ix*jy) - (jx*iy) = det
then
det/ix = scale x
det/jy = scale y

if there is shearing (not orthogonal matrix) then you'll have to calculate the other two (jx,iy) as well. (I'm assuming ix,jy are column major, so if the answer looks wrong then its ix,jx)


Floyd(Posted 2012) [#5]
I think you would need to store scale information separately. There is not enough information in the matrix to recover scale and rotation uniquely.

Consider the following two transformations:

(1) Rotate by 180 degrees, scale x and y by +1 ( no scaling )
(2) Rotate by 0 degrees ( no rotation ), scale x and y by -1

To visualize these get a sheet of paper with something written on one side. Hold it upright in front of you. Now turn it 180 degrees, keeping the same side facing you. This is transformation (1), which has turned the page upside down.

Start over with the paper in its original position. Now flip it around a vertical axis. This isn't quite the same as scaling x by -1. To see the result of that just hold the paper up to a light so you can see through to the back. It has been flipped left to right. Now scale y by -1, meaning flip around a horizontal axis. Notice the writing is again facing you and upside down. This is the result of transformation (2) and is exactly the same as transformation (1).

The transformations, being identical, have the same matrix. If you are given that matrix you cannot tell what rotation and scale produced it.


therevills(Posted 2012) [#6]
@ErikT - yeah that would be nice, but we found that the rotation currently doesnt work with non-uniform scale as well as the negative scales

@Jesse - the Matrix is built up in Mojo:

For Scale:
Scale[tx:Float, ty:Float)
   Transform(tx, 0.0, 0.0, ty, 0.0, 0.0)
End

For Rotation:
Rotate(angle:Float)
   Transform(cos(angle),-sin(angle),sin(angle),cos(angle),0.0,0.0)
End

For Translate:
Translate(tx:Float, ty:Float)
   Transform(1.0,0.0,0.0,1.0, tx, ty);
End


And Transform set the internal values which are used in SetMatrix.

In another post Adam kindly provided the Transform values:
Function Transform( ix#, iy#, jx#, jy#, tx#, ty# )

ix = scale * rotation cos(a)
iy = rotation -sin(a) (* scale)
jx = rotation sin(a) (* scale)
jy = scale * rotation cos(a)
tx = translate x
ty = translate y


@Adam - thanks for that I was trying heaps of stuff last from normalizing, dot products, length etc... but not the determinant - which does seem to help with Scale, but not sure about the Rotation.

@Floyed - dont tell me that :( This is all set within Mojo so we can't change the code there :(


AdamRedwoods(Posted 2012) [#7]
Oh yeah, I was wrong, determinants does nothing (but can identify orthonormal matrix). BUT-- normalizing and ratios work just fine:



EXCEPT for signs as noted above. There may be a way to use the determinate and matrix signs to determine correct scale signs...


Samah(Posted 2012) [#8]
All fixed. This is what I ended up with, and it seems to work:
Method SetMatrix:Int(ix:Float,iy:Float,jx:Float,jy:Float,tx:Float,ty:Float)
	Self.ix = ix ; Self.iy = iy
	Self.jx = jx ; Self.jy = jy
	Self.tx = tx ; Self.ty = ty
	sx = Sqr(ix*ix+iy*iy)
	sy = Sqr(jx*jx+jy*jy)
	rot = Atan2( iy, ix )
	If ix < 0 Then
		sx = -sx
		rot :+ 180
	EndIf
	If jy < 0 Then sy = -sy
	SetTransform( rot, sx, sy )
	Return 0
EndMethod

Code is checked in.