scale an object relative to it's leftmost point?

Hi. I’m trying to scale nodes relative to their bottom, left, right, or top. I thought I could get the points from their bounding boxes, create a node in that position and scale them relative to that node’s space, but I’m doing something wrong.

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *

cm = CardMaker('')
cm.setFrame(-0.4,0.4,-0.1,0.1)
card = aspect2d.attachNewNode(cm.generate())

cardleft = aspect2d.attachNewNode('cardleft')
cardleft.setX(card.getTightBounds()[0][0])

def myFunction(t):
	card.setSx(cardleft, t)
 
i = LerpFunc(myFunction,
	fromData=0.0,
	toData=1.0,
	duration=2.0,
	blendType='noBlend')
i2 = LerpFunc(myFunction,
	fromData=1.0,
	toData=0.0,
	duration=2.0,
	blendType='noBlend')
sequence = Sequence(i, i2)
sequence.loop()

run()

This doesn’t seem to work, the card is scaled relative to it’s center, not “leftmost point”.

It’d be easier to reparent the card to cardleft, position it relative to its parent once, and then scale cardleft instead.

Or, you could adjust the center point permanently by calling setX on the card, then calling flattenLight, and then scaling it.

Of course, it’d be even easier to just adjust the CardMaker frame to use coordinates ranging from 0 to 0.5.

The thing is the size and positions of the cards are stored in a file and the positions are absolute (relative to aspect2d). So I can’t really repositionthe cards.

I’m not sure why you say it’d be easier, I mean does this method even work for you?

setScale() always scales a node around its origin point, (0, 0, 0). You can’t change that behavior. But what you can do is create an intervening node as rdb suggests that effectively moves the origin to wherever you want the scale center to be, and scale that node. Or you can change the origin of the node, which amounts to the same thing.

There’s no reason that having fixed coordinates relative to render2d should interfere with this approach. This is simply the way that you achieve scaling about an arbitrary origin. It requires two nodes, but otherwise works the way you imagine it should.

David

I’m a bit confused on how to do this.

If I have the positions of the nodes stored relative to aspect2d, then I can’t reparent the node to another one which is positioned to the node’s left side and still use the absolute positions to position the node, right?

BTW, wrtReparentTo seems to change the position for some reason.

from pandac.PandaModules import *
import direct.directbase.DirectStart
from direct.interval.IntervalGlobal import *

cm = CardMaker('')
cm.setFrame(-0.4,0.4,-0.1,0.1)
card = NodePath(cm.generate())

cardleft = aspect2d.attachNewNode('cardleft')
cardleft.setX(card.getTightBounds()[0][0])
card.wrtReparentTo(cardleft)

def myFunction(t):
	cardleft.setSx(t)
 
i = LerpFunc(myFunction,
	fromData=0.0,
	toData=1.0,
	duration=2.0,
	blendType='noBlend')
i2 = LerpFunc(myFunction,
	fromData=1.0,
	toData=0.0,
	duration=2.0,
	blendType='noBlend')
sequence = Sequence(i, i2)
sequence.loop()

run()

replace it with :
card = aspect2d.attachNewNode(cm.generate())

wrtReparentTo() is changing the node’s apparent position because it’s not starting out under aspect2d, which is where you had positioned the coordinates for. Try going back to:

card = aspect2d.attachNewNode(cm.generate())

then when you do:

card.wrtReparentTo(cardleft)

it won’t change the position.

Edit: ynjh_jo beat me to it. :slight_smile:

David

Now it seems wrtReparentTo() is scaling my card along the x axis (makes it longer). This is pretty weird, I’ll try to recreate the problem in an example script if this isn’t enough to understand what I’m doing wrong.

EDIT: When I print card.getScale(), I get (1.333, 1, 1)
And if I rescale it to (1,1,1) after, it won’t be in it’s correct position (lower along the x axis). Very weird.

You’re picking up the scale from aspect2d. This means that you are either wrtReparenting from a parent that is not under aspect2d to a parent that is, or vice-versa.

If your card is under aspect2d before you call wrtReparentTo(), and it is still (indirectly) under aspect2d after you call wrtReparentTo(), then the wrtReparent operation won’t change the scale.

Since it is changing the scale, it means that either (a) your card is not initially under aspect2d, or (b) cardleft is not under aspect2d.

Note that wrtReparentTo() is supposed to change the scale if you cross into or out of aspect2d, because of the way it works.

David

Thanks.