Converting Coordinates

Monkey Forums/Monkey Programming/Converting Coordinates

Tibit(Posted 2011) [#1]
If anyone is kick-ass at matrix stuff,

I have a World-Space and a Camera-Space. The Camera can scroll/rotate/zoom, the World is always the same, however from the viewers angle it looks like the world turns/rotates/sacles.

If that makes sense, here is my problem.

Atm to get what I call is ScreenCoordinates I use Warpy's tip:
Local matrix#[] = GetMatrix()
Local screenX:Float = matrix[0] + matrix[2] + matrix[4]
Local screenY:Float = matrix[1] + matrix[3] + matrix[5]
This is after that object has been rotated and translates and so on, it can in after a long series of pop-push matrices.

This works great, but now I instead want the world-coordniate the object has.

So I figured I'd simply do a GetMatrix() into a Global called WorldMatrix after the Camera Translation/Rotate/Scale, and then go:
Local matrix#[] = WorldMatrix
Local worldX:Float = matrix[0] + matrix[2] + matrix[4]
Local worldY:Float = matrix[1] + matrix[3] + matrix[5]
But this does not seem to work.

Is the logic correct? Am I missing something obvious or should I just keep working on it?


Warpy(Posted 2011) [#2]
Please look at bananas/warpy/transform/transform_mouse.monkey

It does exactly what you want.

Use Transform([pointarray]) instead of that GetMatrix three-liner you've got there.


Tibit(Posted 2011) [#3]
Warpy, thanks!

I'm still having some trouble.

Transform WorldMatrix
Local coords#[] = InvTransform([node.Position.X, node.Position.Y])										
node.WorldPosition.Set( coords[0], coords[1] )

Local matrix#[] = GetMatrix()
node.ScreenPosition.Set matrix[0] + matrix[2] + matrix[4], matrix[1] + matrix[3] + matrix[5]


This is how it looks now. The ScreenPosition is perfectly calculated for all nodes. WorldPosition is not right though.

With world position I mean the position that is independant of zoom, rotation or translation of the camera. In other words if I measure the distance between two points in the world I expect the distance to be constant during camera zoom/rotate, but only change if the object's themselves move.

Also I assumed that the correct place to set the WorldMatrix is before the camera update/translation, and I set it using GetMatrix, is that assumption correct?


Warpy(Posted 2011) [#4]
Why are you using transformation matrices to move things in world co-ordinates? How is node.Position different from node.WorldPosition or node.ScreenPosition?

So, a few things:

1. Transform applied to a float array interprets the array as pairs of 2d co-ordinates and applies the current transformation matrix to them. The version of Transform which takes six float arguments applies the given transformation matrix to the current transformation matrix, which is also not what you want. You want SetMatrix WorldMatrix

2. You've got the formula for applying a transformation matrix to a point wrong - the version you have returns the same numbers for any input co-ordinates, because it doesn't use them! The formula should be
newx = matrix[0]*oldx + matrix[1]*oldy + matrix[4]
newy = matrix[2]*oldx + matrix[3]*oldy + matrix[5]



Tibit(Posted 2011) [#5]
Hi,

Was away last week, sorry for replying so late, awesome help so far :)

I'm getting results in the right direction, now everything works except that the worldPosition I get is only relative to the first layer, unlike screenPosition which is absolute (not related to how many push/pop has been done)

This is how the logic looks like:
Method Render:Void()
 If AttachedList
  For Local node:GraphicsNode = Eachin AttachedList
   PushMatrix()
	graphics.Rotate RotationAngle
	graphics.Scale Size, Size	
	graphics.Translate node.Position.X, node.Position.Y				
			
	Local matrix#[] = GetMatrix()
	node.ScreenPosition.Set matrix[0] + matrix[2] + matrix[4], matrix[1] + matrix[3] + matrix[5]
	
	SetMatrix WorldMatrix
	Local worldMatrix#[] = GetMatrix()
	Local newx:Float = worldMatrix[0]*node.Position.X + worldMatrix[1]*node.Position.Y + worldMatrix[4]
	Local newy:Float = worldMatrix[2]*node.Position.X + worldMatrix[3]*node.Position.Y + worldMatrix[5]
	node.WorldPosition.Set( newx, newy )
	
	SetMatrix matrix

	node.Render() 
   PopMatrix()
  Next
 End


node.Position is the Object's local coordinates. If the object is attached Directly to the world then this is Equal to WorldPosition. ScreenPosition is the actual coordinate, as seen on screen, and when zooming with the camera the ScreenPosition changes, but WorldPosition or Position does not. WorldPosition is meant to be the object location in the world, but I'd prefer to not have to loop all parent objects to figure out the translation of this object, ScreenPosition is calculated is such a beutiful way, I figured I could do the same for WorldPosition?

Insteaf of multiplying with Position I'd like to multiply with WorldPosition, but this creates a paradox in that the world layer must use Position, since before WorldPosition is calcualted it is 0.


Tibit(Posted 2011) [#6]
Or maybe I can use the Screen-Coordinates and Inverse/undo the Camera's matrix?

I just realized, I'm solving an impossible problem.

The only reason the Screen-Coordinates appear correct is that I'm using a camera that has the exact same position and size as the screen.

Obviously, if I had 2 cameras, an object's screen position would be different on each of these cameras. However the world position is the same.

I'm thinking of a method like this:

Method ScreenCoordinates:Vector( camera:Camera )
'Use camera's matrix to calculate the position in screen-space
End


Warpy(Posted 2011) [#7]
Yes, that's correct. Please have another look at my transform_mouse example.


Tibit(Posted 2011) [#8]
Cool, going forwards, but I think I'm a bit stuck again! XD

I have this now:
	Method Screen:Vector( camera:Camera )
		Local screenMatrix#[] = camera.MatrixAfter
		Local newx:Float = screenMatrix[0]*Position.X + screenMatrix[2]*Position.Y + screenMatrix[4]
		Local newy:Float = screenMatrix[1]*Position.X + screenMatrix[3]*Position.Y + screenMatrix[5]		
		ScreenPosition.Set newx,newy
		Return ScreenPosition
	End
	
	Method Map:Vector( camera:Camera )
		Local worldMatrix#[] = camera.Matrix
		Local newx:Float = worldMatrix[0]*Position.X + worldMatrix[2]*Position.Y + worldMatrix[4]
		Local newy:Float = worldMatrix[1]*Position.X + worldMatrix[3]*Position.Y + worldMatrix[5]		
		WorldPosition.Set newx,newy
		Return WorldPosition
	End


It works but it does not take into account what the object is attached to. I'm doing something wrong I guess. I'm quite comfortable with Matrices in math and doing projections, but I have little experience on how to use Matrices in practice in game programming, like in this situation.

EDIT, Update:

I managed to get Screen Coordinates to work using the Parent Matrix, which I by no logic call MyMatrix.

	'Working!
	Method Screen:Vector( camera:Camera )
		Local parentMatrix#[] = MyMatrix
		Local tmx:Float = parentMatrix[0]*Position.X + parentMatrix[2]*Position.Y + parentMatrix[4]
		Local tmy:Float = parentMatrix[1]*Position.X + parentMatrix[3]*Position.Y + parentMatrix[5]	
	
		Local screenMatrix#[] = camera.Matrix
		Local newx:Float = screenMatrix[0]*tmx + screenMatrix[2]*tmy + screenMatrix[4]
		Local newy:Float = screenMatrix[1]*tmx + screenMatrix[3]*tmy + screenMatrix[5]		
		ScreenPosition.Set newx,newy
		Return ScreenPosition
	End
	
	'Not Working on attached objects, so almost working...
	Method Map:Vector( camera:Camera )
		Local parentMatrix#[] = MyMatrix
		Local tmx:Float = Position.X
		Local tmy:Float = Position.Y	
	
		Local worldMatrix#[] = camera.Matrix
		Local newx:Float = worldMatrix[0]*tmx + worldMatrix[2]*tmy + worldMatrix[4]
		Local newy:Float = worldMatrix[1]*tmx + worldMatrix[3]*tmy + worldMatrix[5]		
		WorldPosition.Set newx,newy
		Return WorldPosition
	End


Map, is what I before called World. The world coordinates are calculated correctly, however when I move an Object, that has objects attached to it, the attached objects are un-affected, but of course I expect them to move. I feel I'm not doing a good job explaining my predicament here, but maybe I get across a bit :P

Warpy, any ideas what I'm missing here? :)


Tibit(Posted 2011) [#9]
SOLVED!!

So if anyone has any interest, here is the solution I found that did work. Please comment if there is a better or more optimized way of doing it.

	' Working!
	Method Screen:Vector( camera:Camera )
		Local parentMatrix#[] = MyMatrix
		Local tmx:Float = parentMatrix[0]*Position.X + parentMatrix[2]*Position.Y + parentMatrix[4]
		Local tmy:Float = parentMatrix[1]*Position.X + parentMatrix[3]*Position.Y + parentMatrix[5]	
	
		Local screenMatrix#[] = camera.Matrix
		Local newx:Float = screenMatrix[0]*tmx + screenMatrix[2]*tmy + screenMatrix[4]
		Local newy:Float = screenMatrix[1]*tmx + screenMatrix[3]*tmy + screenMatrix[5]		
		ScreenPosition.Set newx,newy
		Return ScreenPosition
	End
	
	' Working!
	Method World:Vector() Property
		WorldPosition.Set ParentPosition
		WorldPosition.Add Position
		Return WorldPosition
	End
In the update Loop:
PushMatrix()
	
	MyMatrix = GetMatrix()				
	node.ParentPosition.Set( Position.X, Position.Y )
										
	graphics.Rotate RotationAngle
	graphics.Scale Size, Size	
	graphics.Translate node.Position.X, node.Position.Y			
	
	node.Render() 
PopMatrix()


So each frame I set the MyMatrix using GetMatrix() - I hope that's a quick operation. I also calculate this node's Parent's position by saving the Position of the parent, later on I use this (recursivly) to calculate the World Position.

Many Thanks Warpy for your help in nudging me in the right direction, greatly appriciated! :D