Important: Please read the Qt Code of Conduct -

Arrow label positioning code, label shoots off into hyperspace, has anyone done this before?

  • Here is some explanation behind the theoretical math.

    Here is the relevant code, short and sweet:

        def updateTextPosition(self):
            from geom_tools import mag2D
            from PyQt5.QtGui import QTransform
            src = self.sourcePoint()
            tar = self.targetPoint()
            if src and tar:
                dx = src.posDelta()
                dy = tar.posDelta()
                #c = self.pointCenter()
                x = src.pos() #- c
                y = tar.pos() # - c
                #dc = c - self.lastPointCenter()
                if x != y:
                    x0 = x - dx 
                    y0 = y - dy
                    magx = mag2D(x0)
                    magy = mag2D(y0)
                    T = QTransform(x.x(), y.x(), x.y(), y.y(), 0, 0) #dc.x(), dc.y())
                    for label in self.allLabels():
                        p = label.pos() #- c
                        u = QPointF.dotProduct(x0, p)
                        v = QPointF.dotProduct(y0, p)
                        if abs(magx) > 0:
                            u /= magx
                        if abs(magy) > 0:
                            v /= magy
                        p = QPointF(u, v)

    As you can see I've also tried keeping the positioning relative to the arrow's control-point center.

    self.sourcePoint() returns the controlpoint that touches the node at the source end of the arrow and likewise for self.targetPoint().

    So all I'm trying to do is do a properly proportioned transform of each labels text.

    Before I did it by storing text-positioning info for each of the labels, very inelegant and that is now buggy, so I'm coming up with a simpler solution.

    Both the labels and the control points are parented by self (Arrow).

    "Hyperspace" is a good description and it whitesout the QGraphicsScene.

        def updateTextPosition(self):
            line = self.labelPosLine()
            line0 = self.lastLabelPosLine()
            p = line.p1()
            q = line.p2()
            p0 = line0.p1()
            q0 = line0.p2()
            dv = ((p-p0) + (q - q0))/2
            for label in self.allLabels():
                label.setPos(label.pos() + dv)

    Averaging looks okay but is not quite right! The arrow will sometimes swap sides when you rotate an arrow around one of its ends 180 degrees.

  • Yeah, I know I'm doing it wrong. Just now discovered. I will post a solution to this.

Log in to reply