Is there a way to get current transformation?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
AnRu
Citizen
Posts: 69
Joined: Sun Oct 27, 2013 1:33 pm
Contact:

Is there a way to get current transformation?

Post by AnRu »

I would like to get current position, rotation and scaling values of graphics transform, caused by nested transformations

Code: Select all

function drawObject(object)
	love.graphics.push()
	love.graphics.translate(...)
	love.graphics.rotate(...)
	love.graphics.scale(...)
	
	-- I want to do something like this:
	globalPos, globalRot, globalScale = love.graphics.currentTransformation() 
	
	for k, v in pairs(object.children) do
		drawObject(v)
	end	
	love.graphics.pop()
end
Is there a way to achieve this?
User avatar
Plu
Inner party member
Posts: 722
Joined: Fri Mar 15, 2013 9:36 pm

Re: Is there a way to get current transformation?

Post by Plu »

I asked the same question recently (viewtopic.php?f=4&t=82545&hilit=translation) and the answer seems to be "no". :(
User avatar
4aiman
Party member
Posts: 262
Joined: Sat Jan 16, 2016 10:30 am

Re: Is there a way to get current transformation?

Post by 4aiman »

Uhmm...
When you call translate with some args you should know what args you're using, right?
So use those args and get what you want.
The same goes for "scale" and "rotate".

Or maybe...
You haven't hardcoded the arguments, have you?
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Is there a way to get current transformation?

Post by zorg »

4aiman wrote:Uhmm...
When you call translate with some args you should know what args you're using, right?
So use those args and get what you want.
The same goes for "scale" and "rotate".

Or maybe...
You haven't hardcoded the arguments, have you?
Doesn't matter whether the args are hardcoded or not, what matters is that, as you said, if he wants to use them later, he needs to store them somewhere.

You could monkeypatch the love.graphics coordsys manipulating functions to update a matrix you handle on the lua side, and have a neat function as you wrote, to get back those values, but i don't know why you would want to know this. (Or, i don't know the reason why, but i do believe löve uses such a matrix internally anyway, one could "beg" for a function to return those values... you'll need to work out the separate translation, rotation, scale, skew values yourself... if you need those, i mean.)



Two major paths when drawing stuff:

- You have the unmodified transform state (gettable by l.g.origin), because you want to draw "absolutely", or relative to the window itself.
- You have the modified transform state, because you want to draw "relatively" to that modified system.

Neither need you to get the current transformation, and although there may be other uses, i can't think of one myself.
...Also, only i replied to the other thread as well? I'm sad since graphics isn't exactly my forté either :P
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Is there a way to get current transformation?

Post by pgimeno »

zorg wrote:one could "beg" for a function to return those values...
And set them, please, to not have to deal with dirty tricks such as SVD which very few people even know about.
User avatar
AnRu
Citizen
Posts: 69
Joined: Sun Oct 27, 2013 1:33 pm
Contact:

Re: Is there a way to get current transformation?

Post by AnRu »

The reason i ask that is that i need to get global position of an child object in the tree
I have no problems with storing positions, but what about rotation? If i rotate parent, childs will rotate with it and a have rotated coordinates. How get this changed coords?
User avatar
4aiman
Party member
Posts: 262
Joined: Sat Jan 16, 2016 10:30 am

Re: Is there a way to get current transformation?

Post by 4aiman »

AnRu wrote:The reason i ask that is that i need to get global position of an child object in the tree
I bet the real question should be not "How to get X" but "Why do I need X?"
Chances are you're doing something counter-productive or over-engineering things.
AnRu wrote:but what about rotation? If i rotate parent, childs will rotate with it and a have rotated coordinates.
In the case you're dealing with something most of people haven't heard of, see Wikipedia: https://en.wikipedia.org/wiki/Rotation_(mathematics)
User avatar
airstruck
Party member
Posts: 650
Joined: Thu Jun 04, 2015 7:11 pm
Location: Not being time thief.

Re: Is there a way to get current transformation?

Post by airstruck »

If you don't have control over all transformations that may be happening, the monkeypatching thing zorg mentioned will work. There's an example of that in box2dhelper (I don't remember where exactly, but I'm sure I saw it there).

If you do have control over the transformations (at least the ones you care about), it should be pretty easy to reverse them to convert between world and screen coordinates. There's an example of that here.
User avatar
AnRu
Citizen
Posts: 69
Joined: Sun Oct 27, 2013 1:33 pm
Contact:

Re: Is there a way to get current transformation?

Post by AnRu »

Thank you all for replies :)
I\ll try to write own transform system
User avatar
pgimeno
Party member
Posts: 3550
Joined: Sun Oct 18, 2015 2:58 pm

Re: Is there a way to get current transformation?

Post by pgimeno »

You can always use a wrapper that keeps track of the matrix.

Code: Select all

local lgorigin = love.graphics.origin
local lgscale = love.graphics.scale
local lgrotate = love.graphics.rotate
local lgshear = love.graphics.shear
local lgtranslate = love.graphics.translate

-- The implicit third row is always 0, 0, 1
local matrix = {1,0,0,
                0,1,0}

local function getMatrix(t)
  if t == nil then
    -- Return a copy
    return {matrix[ 1], matrix[ 2], matrix[ 3],
            matrix[ 4], matrix[ 5], matrix[ 6]}
  end
  -- Assign the elements (enables reusing tables)
  -- (unrolled loop)
  t[1] = matrix[1]; t[2] = matrix[2]; t[3] = matrix[3]
  t[4] = matrix[4]; t[5] = matrix[5]; t[6] = matrix[6]
  return t
end

local function origin()
  matrix[1] = 1  matrix[2] = 0  matrix[3] = 0
  matrix[4] = 0  matrix[5] = 1  matrix[6] = 0
  lgorigin()
end

local function scale(x, y)
  matrix[1] = matrix[1] * x; matrix[2] = matrix[2] * y
  matrix[4] = matrix[4] * x; matrix[5] = matrix[5] * y
  lgscale(x, y)
end

local function rotate(a)
  local c, s = math.cos(a), math.sin(a)
  matrix[1], matrix[2] = matrix[1]*c + matrix[2]*s, matrix[1]*-s + matrix[2]*c
  matrix[4], matrix[5] = matrix[4]*c + matrix[5]*s, matrix[4]*-s + matrix[5]*c
  lgrotate(a)
end

local function shear(x, y)
  matrix[1], matrix[2] = matrix[1] + matrix[2]*y, matrix[1]*x + matrix[2]
  matrix[4], matrix[5] = matrix[4] + matrix[5]*y, matrix[4]*x + matrix[5]
  lgshear(x, y)
end

local function translate(x, y)
  matrix[3] = matrix[3] + matrix[1]*x + matrix[2]*y
  matrix[6] = matrix[6] + matrix[4]*x + matrix[5]*y
  lgtranslate(x, y)
end

local function xform(matrix, x, y)
  return matrix[1]*x + matrix[2]*y + matrix[3], matrix[4]*x + matrix[5]*y + matrix[6]
end

local function xformBack(matrix, x, y)
  x, y = x - matrix[3], y - matrix[6]
  local det = matrix[1] * matrix[5] - matrix[2] * matrix[4]
  if det ~= 0 then
    return (matrix[5] * x - matrix[2] * y) / det,
           (matrix[1] * y - matrix[4] * x) / det
  end
  -- The transform is 1D or 0D
  return x, y
end

return {getMatrix=getMatrix, xform = xform, xformBack = xformBack, origin=origin,
        scale=scale, rotate=rotate, shear=shear, translate=translate}
Inverting the matrix is left as an exercise to the reader ;)

Removed the unnecessary generic matrix calculations from the above, leaving only the strictly necessary part, and used a 2D matrix to add the backward transform, now called xformBack.

Example:

Code: Select all

local xform = require('xform')
local matrix

function love.draw()
  xform.origin()
  love.graphics.setColor(255,255,255)
  xform.translate(400,300)
  xform.rotate(0.3)
  xform.scale(0.7, 1.1)
  xform.translate(42, 86)
  xform.rotate(0.5)
  xform.shear(1.7, 1.3)
  matrix = xform.getMatrix()
  love.graphics.rectangle("fill", 5, 9, 53, 31)

  xform.origin()
  love.graphics.setColor(255,0,0)
  local x, y = xform.xform(matrix, 5, 9)
  love.graphics.rectangle("fill", x-1, y-1, 3, 3)
  x, y = xform.xform(matrix, 5+52, 9)
  love.graphics.rectangle("fill", x-1, y-1, 3, 3)
  x, y = xform.xform(matrix, 5, 9+30)
  love.graphics.rectangle("fill", x-1, y-1, 3, 3)
  x, y = xform.xform(matrix, 5+52, 9+30)
  love.graphics.rectangle("fill", x-1, y-1, 3, 3)

  x, y = xform.xformBack(matrix, xform.xform(matrix, 5, 3))
  love.graphics.print(string.format("%.17g\t%.17g\t%s", x, y, "<- should be 5, 3"))
end
Remember to always call xform.origin() at the beginning of love.draw() to reset the matrix, because the default love.run calls love.graphics.origin() internally right before calling love.draw().

Edit: Modified so you can also do this hack if you want:

Code: Select all

local xform = require 'xform'

do
  local lg = love.graphics
  lg.translate = xform.translate
  lg.rotate = xform.rotate
  lg.scale = xform.scale
  lg.shear = xform.shear
  lg.origin = xform.origin
end
so that your program can access any transformation function transparently, and you don't need to call xform.origin() manually at the start.

Edit2: Simplified and added backwards transform.
Last edited by pgimeno on Mon Oct 17, 2016 11:41 pm, edited 1 time in total.
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 214 guests