Draw Bezier is confusing!



  • On 13/05/2015 at 17:41, xxxxxxxx wrote:

    I've managed to draw complex bezier curves despite the completely confusing docs:

    GeUserArea.DrawBezier(sx, sy, p, closed, filled)

    • sx  (float) – X coordinate of the upper left corner of the drawn curve.
    • sy  (float) – Y coordinate of the upper left corner of the drawn curve.
    • p  (array of float) –
      An array with the bezier curves points.
      The following values ease the initialization of the points array:
      DRAWBEZIER_BX| X coordinate of the second curve point.
      ---|---
      DRAWBEZIER_BY| Y coordinate of the second curve point.
      DRAWBEZIER_CX| X coordinate of the third curve point.
      DRAWBEZIER_CY| Y coordinate of the third curve point.
      DRAWBEZIER_DX| X coordinate of the fourth curve point.
      DRAWBEZIER_DY| Y coordinate of the fourth curve point.

    _<_t_>_



  • On 13/05/2015 at 17:44, xxxxxxxx wrote:

    Here are my notes that make it more understandable.
    Where is says 'point' in the docs, it isn't always a curve point.  Some of them are tangent handles.

      
    # Drawing beziers on a user area differs from creating splines in the 3D view.
    # The start coords (sx, sy) are the first knot.
    # A point array is then passed with 6 entries (3 x,y positions); These are: previous knot out-tan, next knot in-tan, next knot.
      
                        
    # Format:
    # points[c4d.DRAWBEZIER_BX+0] = Out-tangent x
    # points[c4d.DRAWBEZIER_BY+0] = Out-tangent y
    # points[c4d.DRAWBEZIER_CX+0] = Next Knot In-Tangent x
    # points[c4d.DRAWBEZIER_CY+0] = Next Knot In-Tangent y
    # points[c4d.DRAWBEZIER_DX+0] = Next Knot x
    # points[c4d.DRAWBEZIER_DY+0] = Next Knot y
    

    If you try try to pass an array with a number of entries that are not a multiple of 6, you get a warning that it must be a multiple of 6.  That sounds like you are allowed to set up arrays with more than 6 entries to draw multiple curve segments.  But, when I try to pass more than 6, the point after the first 6 goes shooting off the UserArea in a straight line.

    I've only managed to draw complex shapes by repeatedly calling the function with sx, sy, and a 6 entry array.

    This obviously makes it impossible to draw a filled complex shape.

    Am I doing something wrong with trying to pass an array with more than 6 entries?
    How do you draw a filled shape with lots of points?

    Thanks,

    Chris



  • On 13/05/2015 at 18:22, xxxxxxxx wrote:

    Could someone post an example drawing a circle, 4 points with 2 tangent handles each, in a single array?

    Thanks



  • On 15/05/2015 at 04:12, xxxxxxxx wrote:

    Hi Chris,

    The documentation for GeUserArea.DrawBezier() isn't accurate but your notes are exact 🙂.

    There seem to have an issue passing an array for multiple splines. It only works as expected passing an array for one spline only.
    So we can currently only draw one spline at a time (start/ending points + in/out control points/tangents).

    To draw an approximation of a circle with bezier splines the best solution is to draw 4 bezier splines and use magic numbers 0.55228475 or 0.551784 to calculate the influence points.

    Here's the code to use inside GeUserArea.DrawMsg():

    width = x2
    height = y2
      
    diameter = height-1
      
    # Create an array for 6 float values (3 points with x+y coordinates each)
    points = array.array('f', xrange(6))
      
    # Calculate 4 points for circle bezier spline approximation
    p0 = c4d.Vector(diameter/2.0, diameter, 0.0)
    p1 = c4d.Vector(diameter, diameter/2.0, 0.0)
    p2 = c4d.Vector(diameter/2.0, 0.0, 0.0)
    p3 = c4d.Vector(0.0, diameter/2.0, 0.0)
      
    # Draw lower right bezier spline
    points[c4d.DRAWBEZIER_BX] = p0.x + (p0.x * 0.551784)
    points[c4d.DRAWBEZIER_BY] = p0.y
    points[c4d.DRAWBEZIER_CX] = p1.x
    points[c4d.DRAWBEZIER_CY] = p1.y + (p1.y * 0.551784)
    points[c4d.DRAWBEZIER_DX] = p1.x
    points[c4d.DRAWBEZIER_DY] = p1.y
    self.DrawBezier(p0.x, p0.y, points, False, False)
      
    # Draw upper right bezier spline
    points[c4d.DRAWBEZIER_BX] = p1.x
    points[c4d.DRAWBEZIER_BY] = p1.y - (p1.y * 0.551784)
    points[c4d.DRAWBEZIER_CX] = p2.x + (p2.x * 0.551784)
    points[c4d.DRAWBEZIER_CY] = p2.y
    points[c4d.DRAWBEZIER_DX] = p2.x
    points[c4d.DRAWBEZIER_DY] = p2.y
    self.DrawBezier(p1.x, p1.y, points, False, False)
      
    # Draw upper left bezier spline
    points[c4d.DRAWBEZIER_BX] = p2.x - (p2.x * 0.551784)
    points[c4d.DRAWBEZIER_BY] = p2.y
    points[c4d.DRAWBEZIER_CX] = p3.x
    points[c4d.DRAWBEZIER_CY] = p3.y - (p3.y * 0.551784)
    points[c4d.DRAWBEZIER_DX] = p3.x
    points[c4d.DRAWBEZIER_DY] = p3.y
    self.DrawBezier(p2.x, p2.y, points, False, False)
      
    # Draw lower left bezier spline
    points[c4d.DRAWBEZIER_BX] = p3.x
    points[c4d.DRAWBEZIER_BY] = p3.y + (p3.y * 0.551784)
    points[c4d.DRAWBEZIER_CX] = p0.x - (p0.x * 0.551784)
    points[c4d.DRAWBEZIER_CY] = p0.y
    points[c4d.DRAWBEZIER_DX] = p0.x
    points[c4d.DRAWBEZIER_DY] = p0.y
    self.DrawBezier(p3.x, p3.y, points, False, False)
    

    See this paper for the surprisingly simple maths behind this code and magic numbers  0.55228475  or  0.551784.



  • On 15/05/2015 at 19:22, xxxxxxxx wrote:

    Yannick,

    Thanks for taking a look.
    I thought there must be something wrong, I spent hours trying to make it draw correctly while passing multiples of 6 in the array.

    So there is no way to draw a filled shape with multiple segments then?

    If not, if I report this as a bug, will they fix it?
    This has been here since R14.


Log in to reply