TextNode and center

I sometimes notice inexplicable panda behavior that I don’t understand.

For example, create the following code:

from panda3d.core import NodePath, TextNode

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)

        font = loader.loadFont('arial.ttf')

        label = TextNode('')
        label.set_font(font)
        label.set_text("Bags")
        label.set_text_color((1, 0, 0, 1))
        label.setAlign(TextNode.ACenter)
        
        node_label = NodePath(label.generate())
        node_label.reparentTo(aspect2d, 1)

app = MyApp()
app.run()

And you will see that the text is offset from the center. To verify this add node_label.showBounds ()

from panda3d.core import NodePath, TextNode

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)

        font = loader.loadFont('arial.ttf')

        label = TextNode('')
        label.set_font(font)
        label.set_text("Bags")
        label.set_text_color((1, 0, 0, 1))
        label.setAlign(TextNode.ACenter)
        
        node_label = NodePath(label.generate())
        node_label.showBounds()

        node_label.reparentTo(aspect2d, 1)

app = MyApp()
app.run()

Now we can clearly see the center of the sphere and the text, however, where does the offset on the render aspect2d node come from? To solve this problem, I make such a fix.

from panda3d.core import NodePath, TextNode

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)

        font = loader.loadFont('arial.ttf')

        label = TextNode('')
        label.set_font(font)
        label.set_text("Bags")
        label.set_text_color((1, 0, 0, 1))
        label.setAlign(TextNode.ACenter)
        
        node_label = NodePath(label.generate())
        node_label.showBounds()
        
        size = node_label.getBounds()
        center = size.getCenter()
        node_label.set_pos(-center)
        
        node_label.reparentTo(aspect2d, 1)

app = MyApp()
app.run()

Accordingly, the question arises, why does the panda move the text from the center? After all, it is more logical by default that the text should be centered. But it is strange that no one pays attention to it, it seems that this is one of the problems for me only.

I think that Panda defaults to having the origin of a TextNode be at the baseline of its text, not its centre. Thus placing a TextNode at (0, 0, 0) places its baseline at the origin.

I suspect that this is fairly standard behaviour with regards to placing text, which may be why it’s seldom commented on.

Notice that I used vertical center alignment.

label.setAlign(TextNode.ACenter)

However, the center is not found correctly:

from panda3d.core import NodePath, TextNode, Vec4
from direct.directtools.DirectGeometry import LineNodePath

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)

        font = loader.loadFont('arial.ttf')

        label = TextNode('')
        label.set_font(font)
        label.set_text("Bags")
        label.set_text_color((1, 0, 0, 1))
        label.setAlign(TextNode.ACenter)
        
        node_label = NodePath(label.generate())
        node_label.showBounds()
        
        #size = node_label.getBounds()
        #center = size.getCenter()
        #node_label.set_pos(-center)
        
        node_label.reparentTo(aspect2d, 1)
        
        lines = LineNodePath(render, colorVec = Vec4(0, 0, 1, 1))
        lines.drawLines([((0, 0, -0.25),(0, 0, 0.25)),
                         ((0.25, 0, 0),(-0.25, 0, 0))
                        ])
        lines.create()
        lines.reparentTo(aspect2d, 2)

app = MyApp()
app.run()

I’m pretty sure that “setAlign” sets the horizontal alignment, not the vertical–it’s the reason that your text there has its origin at its horizontal centre, rather than at its left or right.

How can horizontal alignment have concepts left and right?

TextNode.ALeft 
TextNode.ACenter
TextNode.ARight

I think that perhaps we mean different things when we speak of “horizontal” and “vertical” alignment.

What I mean is that “setAlign” determines the object’s origin on the horizontal axis–that is, whether it’s placed relative to its left-most end, its right-most end, or its centre.

Thus it doesn’t affect where the vertical centre of the object is–that is, how far up or down the screen the object is placed when positioned at (0, 0, 0)–which is what I thought you were referring to. Was I mistaken in that?

To illustrate:

I am talking about axles. Accordingly, they have a common center.
For vertical there are left and right.
For horizontal, there is a top and bottom

For the horizontal, I did not indicate the side.

Okay, I see what you mean now, I believe.

(We were indeed using “vertical alignment” and “horizontal alignment” differently; to my mind, “left/centre/right alignment” is horizontal, since it involves placement on the horizontal axis.

But that’s not important now; the important thing is that the miscommunication has been cleared up, I feel!)

Now, as to the actual topic:

The placement of the “top and bottom” alignment is, I think, correct to common usage: it places the text according to its baseline, rather than its centre-point.

(One might argue that it’s slightly off of that point, since it appears to be slightly above the base of the characters, but I’m not sure of exactly how the baseline is defined, or whether the font or text-scaling might affect it.)

The placement of the “left and right” alignment does, however, look wrong; it looks like the origin on that axis is a little offset. There might be some good reason for this that I’m not seeing–but it may also be a bug in Panda.

But note that the offset occurs along a parallel axis, and the distance cannot be accurately determined. In order to accurately set the distance, you need to move relative to the perpendicular, that is, measure the distance to the vertical axis.

Which is simply its coordinate on the horizontal axis. :stuck_out_tongue:

But yeah, it’s just a difference of terminology, the question of whether it call it “horizontal alignment” or “vertical alignment”.

But the question is how to determine where the object is: left or right. If you determine, then in relation to what. The horizontal axis is not suitable for this.

The horizontal axis is exactly what you would likely use–if you were to get coordinates, you’d likely end up looking at the object’s x-axis value, which is the horizontal axis.

That said, if you specify left-alignment, then the object’s origin on the x-axis should be at the left-hand side of the text. If you specify right-alignment, then the object’s origin on the x-axis should be at the right-hand side of the text. And if you specify centre-alignment, then the object’s origin on the x-axis should be halfway between its left- and right- sides, I would expect.

And it does look as thought that last mode–centre-alignment–is more or less correct, but perhaps slightly offset for some reason.

Yes, it seems that contrary to the world concept, I have developed my own point of view. On alignment, I don’t remember where I got this wrong definition from. I just count from the perpendicular axis. And not along the axis.

In any case, I need to try other fonts for experimentation.

Yup–and try text at different font-sizes, not just scaled up, too, in case that affects things. And do report back, please, as this may indeed be a Panda bug!

I checked three fonts, and they are all centered with an offset, the X axis is somewhere around with an error of 0.05.

This, given the horizontal alignment of label.setAlign (TextNode.ACenter), the offset is obtained for the X axis of 0.05. For vertical alignment, I do not know the method.

I think that maybe there may be a default indent or border, and so on, maybe I need to clear it.

I think there is a fact that alignment does not work correctly. This is understandable in connection with the limitation of volume in the form of a sphere. Correctly displayed relative to the text, i.e. the center match.

However, I found methods that help align text, I don’t know if this is correct, but it seems possible to customize it for myself as needed.

from panda3d.core import NodePath, TextNode, Vec4
from direct.directtools.DirectGeometry import LineNodePath

from direct.showbase.ShowBase import ShowBase

class MyApp(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)

        font3 = loader.loadFont('cmr12.egg')
        
        label = TextNode('')
        label.set_font(font3)
        label.set_text("Panda3D")
        label.setGlyphScale(0.3)
        label.setGlyphShift(0.03)
        node_label = NodePath(label.generate())
        node_label.reparentTo(aspect2d, 1)

        vertical = LineNodePath(render, colorVec = Vec4(0, 1, 0, 1))
        vertical.setThickness(2)
        vertical.drawLines([((0, 0, -0.25),(0, 0, 0.25))])
        vertical.create()
        vertical.reparentTo(aspect2d, 2)
        
        horizontal = LineNodePath(render, colorVec = Vec4(0, 0, 1, 1))
        horizontal.setThickness(2)
        horizontal.drawLines([((0.25, 0, 0),(-0.25, 0, 0))])
        horizontal.create()
        horizontal.reparentTo(aspect2d, 3)
        
app = MyApp()
app.run()