Search code examples
python-2.7qtpyqtpyqt4

QPainterPath percentage/t value for Element


I have a QPainterPath that has two Elements, both of which are cubic Bezier curves, like this:

If I want to find a particular point along the path, I can use the pointAtPercent method. The documentation states that

When curves are present the percentage argument is mapped to the t parameter of the Bezier equations.

enter image description here

When I get the percentage, it's from 0 to 1 along the length of the entire path. That middle control point, for example, is at t = 0.46, when actually it's the end of the left Element (t = 1.0) and the start of the next (t = 0). So in my image if I get the percentage at the green circle, it'll be around 0.75. What I'd like is to get something like 0.5 for the green circle, i.e. the percentage of just the second Bezier.

So my question is, is there a way in Qt to determine the percentage value of a given Element instead of relative to the entire path length? In my example I happen to know the percentage value for the middle control point, but in general I won't know it, so I can't just scale the percentages or assume even distribution.

I'm using PyQt4 (Qt 4.8) if that matters. Thanks!


Solution

  • t scales along the total length(), but you can also know the length of individual segments, and thus adjust t accordingly. The path's element is a rather specific term: there are 3 elements per each cubicTo, assuming no intervening position changes. An arbitrary path like yours with consist of a MoveToElement, CurveToElement, two CurveToDataElements, another CurveToElement, another two CurveToDataElements. You have to iterate the elements and extract the length of the first cubic, to adjust the t.

    A function extracting the first cubic, determining its length, and then using that to compute t2 from t would look similar to (untested):

    def t2(path, t):
       if path.elementCount() != 7:
          raise ValueError('invalid path element count')
       path1 = QPainterPath()
       path1.moveTo(path.elementAt(0))
       path1.cubicTo(path.elementAt(2), path.elementAt(3), path.elementAt(1))
       l = path.length()
       l1 = path1.length()
       l2 = l - l1
       t2 =  (t*l - l1)/l2
       return t2