Bezier curve path to IPO

Hi there,
Well, i’m new to python coding, and have been trying to find a script and failed, that will convert a bezier curve path into a set of Ipo Curves with the name of the Ipo set of curves named the same as the curve object.

I thought this would be a standard within Blender to create Ipo Curves when the Bezier curve is turned into a path.

So i’m having a go now, small steps
current plan, print in the console window, and to a log file if possible all the points in the entire curve and their handles, 1 line for knot/handle on its axis in 3d space, confused, I am :slight_smile:

Once thats done, it should be a simple matter of assigning those points to their corresponding 2D Ipo graphs

what I have so far is
Curve2IPO


#!BPY

# A script to convert a curve to an IPO curve which can be used by an object to simulate the path it is flying

# Specifically designed to help with GoW_PyPrp plugin
"""
Name: 'Curve2IPO'
Blender: 246
Group: 'Wizards'
Tooltip: 'Make IPO curves from path'
"""
import Blender

try:
    scn = Scene.GetCurrent()
    Blender.Curve.data.getFlag(3) == true #  Is "CurvePath" flag set.
except:
    Blender.Draw.PupMenu("Curve is not a Path")

myCurve = Blender.Object.GetSelected()[0]     # Assign what is the currently selected curve
#myCurveName = myCurveName.getName()
myCurveName = myCurve.getName()
myCurveBez = Blender.Object.Get(myCurve)    # Get data of curve 
myCurveData = Blender.Curve.Get()[0]
myIPOCurveSet =  myCurve.getName() 
myCurvePoints = n = 0
myPathLength = myCurveData.getPathLen()
myPathIter = myCurrentPathLen = myPathLength
#myIPOCurves = myIPOCurves.LOC[x]
myIPOCurveSet = Blender.Ipo.New('Object', myCurveName) # Attmpting  to get the Curve name same as IPO curve set
#myIPOCurves = Blender.IpoCurve.New(myIPOCurveSet)
handleTypes = (Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE)
myCurveData = myCurve.data
# Old way -> myCurvePoints = myCurveData.__getitem__(myCurvePoints)
myCurvePoints = myCurveData[myCurvePoints] 
myNumberOfPoints = 0
for iNumberOfPoints in myCurvePoints:
    myNumberOfPoints = myNumberOfPoints + 1
myPathIter = myPathLength / myNumberOfPoints
    
print "
##############################################"
print "Curve name: %s " % myCurveName
print "Curve data: %s " % myCurveData
print "Ipo curves: %s " % myIPOCurveSet
print "Ipo length: %s " % myPathLength
print "Path iteration constant: %s" % myPathIter
print "##############################################
"
# Create LocX, LocY, and LocZ Ipo curves in our new Curve Object
# and store them so we can access them later
myIPOCurveSet_X = myIPOCurveSet.addCurve('dLocX')
myIPOCurveSet_Y = myIPOCurveSet.addCurve('dLocY')
myIPOCurveSet_Z = myIPOCurveSet.addCurve('dLocZ')
myBezPointNumber = 0
for nCurvePoints in myCurvePoints:
    myBezPointNumber = myBezPointNumber + 1
    myCurrentPathLen = myPathIter * myBezPointNumber
    
    #myIPOCurves = Blender.Ipo.New(Blender.Ipo.OB_LOCX, 'Ipo1a')
    # Create an new Ipo Curve of name myIpo and type Object
    #myIPOCurves = bpy.data.ipos.new(myCurveName, 'Object')
    
 

    #print"%s" %s myCurvePoints
    # Apparently  BezTriple outputs 9 floats for each handle/knot in 3D space
    # so print out each float value
    print"
##############################################"
    print"Bezier point number: %s" % myBezPointNumber
    print"Out of a total: %s" % myNumberOfPoints
    print"Current iteration at frame: %s
" %  myCurrentPathLen
    print"H1x: %s " % nCurvePoints.vec[0][0] 
    print"H1y: %s " % nCurvePoints.vec[0][1]
    print"H1z: %s " % nCurvePoints.vec[0][2]
    print"
"
    print"Px: %s " % nCurvePoints.vec[1][0] 
    print"Py: %s " % nCurvePoints.vec[1][1] 
    print"Pz: %s " % nCurvePoints.vec[1][2]
    print"
"
    print"H2x: %s " % nCurvePoints.vec[2][0] 
    print"H2y: %s " % nCurvePoints.vec[2][1]
    print"H2z: %s " % nCurvePoints.vec[2][2] 
    print"##############################################
"
    
    # Here set the current frame
    # myIpo = myCurveIPO.__setitem__ (myCurrentPathLen, nCurvePoints)
    # Here Append current frame with BezTriple nCurvePoints
    # myIPOCurves = myIPOCurveSet.IpoCurve.
    # myIPOCurves = myIPOCurveSet.__setitem__(myCurrentPathLen, nCurvePoints)
    #myIPOCurves = Blender.Ipo.addCurve([Blender.Ipo.OB_LOCX])  # retrieves an Ipo object
    #ipo.name = 'ipo1'                              # change the Ipo's name
    #icu = ipo[Blender.Ipo.OB_LOCX] # request X Location Ipo curve object
    #if icu != None and len(icu.bezierPoints) > 0: # if curve exists and has BezTriple points
    #    val = icu[2.5]              # get the curve's value at time 2.5

    # Append to the Ipo curve at location frame, with the value ipoValue_x
    # Note that we should pass the append function a tuple or a BezTriple
     myIPOCurveSet_X.append((myCurrentPathLen, nCurvePoints.vec[1][0]))
    
    # Similar to above
    myIPOCurveSet_Y.append((myCurrentPathLen, nCurvePoints.vec[1][1]))
    myIPOCurveSet_Z.append((myCurrentPathLen, nCurvePoints.vec[1][2]))

Can someone please help, python is sending me bonkers

Create free online surveys and forms with http://surveylover.com

ok deep breaths…

in the following line,

H1x,H1y,H1z,Px,Py.Pz,H2x,H2y,H2z = myCurvePoints

what are you expecting the full stop to do?

I’m trying to declare the variables that the compiler complains doesn’t exist, which also have to be initialised


print "
##############################################
"
print "Curve is: %s 
" % myCurve
print "Curve name: %s 
" % myCurveName
print "Ipo curves: %s 
" % myCurveIPO
print "Ipo length: %s 
" % myPathLength
print "##############################################
"

H1x = myCurvePoints
H1y = myCurvePoints
H1z = myCurvePoints
Px = myCurvePoints
Py = myCurvePoints
Pz = myCurvePoints
H2x = myCurvePoints
H2y = myCurvePoints
H2z = myCurvePoints

for myCurvePoints in myCurvePoints:
    # Apparently  BezTriple outputs 9 floats for each handle/knot in 3D space
    # so print out each float value
    print"
##############################################"
    print"Bezier point number: %s 
" % myCurvePoints
    print"H1x: %s 
" % H1x 
    print"H1y: %s 
" % H1y 
    print"H1z: %s 
" % H1z 
    print"
"
    print"Px: %s 
" % Px 
    print"Py: %s 
" % Py 
    print"Pz: %s 
" % Pz 
    print"
"
    print"H2x: %s 
" % H2x 
    print"H2y: %s 
" % H2y 
    print"H2z: %s 
" % H2z 
    print"##############################################
"

I did this, but its only a temporary fix, I still can’t figure out how to assign to those variables from the BezTriple.
The documents say that getitem returns the nth point as well as the BezTriple for it.
Ideally i’d use the function getTriple() but that is no longer maintaine.

I’ve got it, now it prints out each BezTriple float item
Still working on getting the count right eg
Bezier Point Number: 1
Bezier Point Number: 2
Bezier Point Number: 3
And report nothing when the try:
Blender.Curve.data.getFlag(3) == true # Is “CurvePath” flag set.
Relating to the button “CurvePath” in the editing buttons “F9” under “Curve and Surface” is toggled


#!BPY

# A script to convert a curve to an IPO curve which can be used by an object to simulate the path it is flying

# Specifically designed to help with GoW_PyPrp plugin
"""
Name: 'Curve2IPO'
Blender: 246
Group: 'Wizards'
Tooltip: 'Make IPO curves from path'
"""
import Blender

try:
    scn = Scene.GetCurrent()
    Blender.Curve.data.getFlag(3) == true #  Is "CurvePath" flag set.
except:
    Blender.Draw.PupMenu("Curve is not a Path")

myCurve = Blender.Object.GetSelected()[0]     # Assign what is the currently selected curve
myCurveData = Blender.Object.Get(myCurve)    # Get data of curve 
myCurveName = Blender.Curve.Get()[0]        # Assign myCurveName string as the name of the object
myCurvePoints = n = 0

myPathLength = myCurveName.getPathLen()
myCurvedName = myCurveName.getName()
myCurveIPO = Blender.Ipo.New('Object', 'myCurve') # Attmpting  to get the Curve name same as IPO curve set

myCurveData = myCurve.data
myCurvePoints = myCurveData.__getitem__(myCurvePoints)

handleTypes= (Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE)

print "
##############################################
"
print "Curve is: %s 
" % myCurve
print "Curve name: %s 
" % myCurveName
print "Ipo curves: %s 
" % myCurveIPO
print "Ipo length: %s 
" % myPathLength
print "##############################################
"


for nCurvePoints in myCurvePoints:
    # Apparently  BezTriple outputs 9 floats for each handle/knot in 3D space
    # so print out each float value
    print"
##############################################"
    print"Bezier point number: %s 
" % nCurvePoints
    print"H1x: %s 
" % nCurvePoints.vec[0][0] 
    print"H1y: %s 
" % nCurvePoints.vec[0][1]
    print"H1z: %s 
" % nCurvePoints.vec[0][2]
    print"
"
    print"Px: %s 
" % nCurvePoints.vec[1][0] 
    print"Py: %s 
" % nCurvePoints.vec[1][1] 
    print"Pz: %s 
" % nCurvePoints.vec[1][2]
    print"
"
    print"H2x: %s 
" % nCurvePoints.vec[2][0] 
    print"H2y: %s 
" % nCurvePoints.vec[2][1]
    print"H2z: %s 
" % nCurvePoints.vec[2][2] 
    print"##############################################
"

Its getting there, slowly

I got it, gosh I do feel dumb
Got rid of that whole segment of code and added the end of the print statement
nCurvePoints.vec[][], been trying to figure out how to use that for about a week now
As well as printing out in the console window the current number of the bezier point in the iteration
So its now onto getting rid of the popup when the “CurvePath” flag is set

I have also updated the first post with what I currently have as the latest code

Can someone please give me an example of how to use the append function in the IpoCurve class

Thanks

check out my “Midi_Import_X” script in my sig… this makes ipo curves from midi tracks and uses said append calls. Just search for “append” in it until you see lots of IPO words :wink:

Argh,
I’m not getting very far.

I’ve tried reading and applying the same approach, its not working, and I have noticed a couple of other problems

I need to set a BezTriple to a specific time frame, still trying to find the API reference for that. Will have to a bit more digging to see if I can
How to set the name of IPO curves as the name of the bezier curve. Following your way and the compiler complains saying its expecting 2 strings, 1 strings is straight characters and the other string is a call from a function. I’ll figure this one out soon I hope

Then i’m back onto figuring out how to append to that frame the BezTriple

I know that I understand python poorly.

Could you please explain to me how to append an IPO curve or set of IPO curves

I’ve nearly figured out how to get to the next frame using the setitem in the ipocurve class, though I still need a clearer example of appending curves with a beztriple at a frame x while taking the handles from the curve path and appending those he possible so that the Ipo curves match the bezier curve path

Finally found something that I can use, and its a good clear example for applying IPO curves from an object.

http://blenderartists.org/forum/showthread.php?t=122768

I’ve had a quite a milestone today, found at last an example of appending a beztriple to an IPO curve
http://blenderartists.org/forum/showthread.php?t=122768

still got errors but thats ok, for now.

Problems solved are

  • Managed to pass the name of the bezier curve path and set it as the name of the IPO curve set

Still left to fix or do

  • Pass the beztriple of the bezier path and set each knot and set each (tuple?) to its respective IPO block
  • Remove the dialog box that pops up, this is a bug where it cannot resolve the logic condition properly
  • Add more parameters to check for before proceeding with the script
  • Change the pop up dialog box to that of an error message dialog box.
  • Find the functions for getting the tilt and bank of the curve, which should be the rotation of the object centre or knot
  • Some other stuff that I can’t recall to do http://forum.guildofwriters.com/images/smilies/icon_mrgreen.gif

I hope that the tuples of the handles will pass automatically after the knots have been resolved, otherwise i’ll have another problem to solve

At this stage, why does it give an error on this line?
myIPOCurveSet_X.append((myCurrentPathLen, nCurvePoints))

I’ve got the script partially working now.

Now i’m looking at how on earth to pass the handles of the bezier curve to the IPO curve bezier handles

Anyone?
This is the last big thing I need to fix to get the script working properly


for nCurvePoints in myCurvePoints:
    #print"%s" %s myCurvePoints
    # Apparently  BezTriple outputs 9 floats for each handle/knot in 3D space
    # so print out each float value
    print"
##############################################"
    print"Bezier point number: %s" % myBezPointNumber
    print"Out of a total: %s" % myNumberOfPoints
    print"Current iteration at frame: %s
" %  myCurrentPathLen
    print"H1x: %s " % nCurvePoints.vec[0][0] 
    print"H1y: %s " % nCurvePoints.vec[0][1]
    print"H1z: %s " % nCurvePoints.vec[0][2]
    print"
"
    print"Px: %s " % nCurvePoints.vec[1][0] 
    print"Py: %s " % nCurvePoints.vec[1][1] 
    print"Pz: %s " % nCurvePoints.vec[1][2]
    print"
"
    print"H2x: %s " % nCurvePoints.vec[2][0] 
    print"H2y: %s " % nCurvePoints.vec[2][1]
    print"H2z: %s " % nCurvePoints.vec[2][2] 
    print"##############################################
"
    
    

    # Append to the Ipo curve at location frame, with the value ipoValue_x
    # Note that we should pass the append function a tuple or a BezTriple
     myIPOCurveSet_X.append((myCurrentPathLen, nCurvePoints.vec[1][0]))
    
    # Similar to above
    myIPOCurveSet_Y.append((myCurrentPathLen, nCurvePoints.vec[1][1]))
    myIPOCurveSet_Z.append((myCurrentPathLen, nCurvePoints.vec[1][2]))

Well i’ve done quite a bit since last time, and figured out, no thanks to the documentation, how to get the curve from the Ipo widow.

Still have the current problem

How do I feed back to the Ipo Window the new set of of handle points?

I’m certain that if I use the append function that it will screw everything up, and the only clue is in the docs which say look at the BezTriple API, which doesn’t say much to help.

Please someone?

I think I have narrowed down to using the .pt variable, but have no idea how this will alter the Ipo Curve in question.

hi Grogyan, go to camera-jitter.py for a working example of IPO API.
For more help: post here the current version of your script or better a link to your test blend file.
migius

Sure, the code is here, all of it

Note that i’m commenting a lot, this is basically for me and other newbies to python and blender scripting, it helps to know why you do what you did.


#!BPY

# A script to convert a curve to an IPO curve which can be used by an object to simulate the path it is flying

# Specifically designed to help with GoW_PyPrp plugin
"""
Name: 'Curve2IPO'
Blender: 246
Group: 'Wizards'
Tooltip: 'Make IPO curves from path'
"""
# ==============================================
#
#            ToDo
#
#    1) Move the else statement 
#       to the end so that that section is skipped 
#       when the condition isn't true 
#       -> DONE
#
#    2) Put in a check object type in before the 
#       first if statement, the else goes at the end
#       -> DONE
#
#    3) Put in a check for if its cyclic or not,
#       if it is true then save copy of the first 
#       BezTriple and apply it after the for loop
#
#    4) Apply the BezTriple of locations to the IPO
#       window
#
#    5) Add to the IPO window the folowing blocks
#       dRotX, dRotY, dRotZ and Time where time is 
#       the slow down or speed up at certain sections
#       though this is probably redundant and just 
#       maintain a constand speed
#    
#    6) Work out an algorithm for the above
#       by 10, eg 90 degres becomes 9 degrees
#       but test it out first.
#       but don't for get that rotation is divided 
#
#    7) Set the curves' datablock name as the 
#       objects'
#       -> DONE
#
# ==============================================

import Blender

print"


#################################################"
print"    Attempting to run script"
print"##############################################
"

# Get the currently selected object
myCurve = Blender.Object.GetSelected()[0] 

# Create variable and get the type of object   
myObjectType = myCurve.getType()

if myObjectType == 'Curve':
    print"    -> Object is a %s" % myObjectType
        
    myCurveData = Blender.Curve.Get()[0]
    myCurveFlag1 = myCurveData.getFlag()

    # Standard bit mask for bit 3
    if myCurveFlag1 and 0x08: #  Is "CurvePath" flag set
        print"    -> Curve flag bit 3 at 0x00001000 is set, value is: %x " % (myCurveFlag1 and 0x08)

        # Get the object name of the curve
        myCurveName = myCurve.getName()
        #myCurveBez = Blender.Object.Get(myCurve)    # Get data of curve 
        
        # Initialize what will be the name of the IPO's
        myIPOCurveSet =  myCurve.getName() 
        
        # Get the length of the curve in frames
        myPathLength = myCurveData.getPathLen()
        
        # Create variables myPathIter, myCurrentPathLen
        # and initialize them to a known value
        myPathIter = myCurrentPathLen = myPathLength
        
        #myIPOCurves = myIPOCurves.LOC[x]
        myIPOCurveSet = Blender.Ipo.New('Object', myCurveName) # Attmpting  to get the Curve name same as IPO curve set
        
        #####################################
        #handleTypes = (Blender.BezTriple.HandleTypes.FREE, Blender.BezTriple.HandleTypes.FREE)
        #####################################
        
        # Get the name of the data block 
        myCurveData = myCurve.data
        
        myCyclicTest = myCurveData.isCyclic()
        if myCyclicTest == True:
            print"    -> Curve is cyclic"
        else:
            print"    -> Curve is not cyclic"
        
        # Set the name of the data block as the
        # objects' name
        myCurveData.setName(myCurveName)
        
        # Create the variable and intialize it to 0
        myCurvePoints = 0
        # Old way -> myCurvePoints = myCurveData.__getitem__(myCurvePoints)
        myCurvePoints = myCurveData[myCurvePoints]     

        # can't be bothered how to figure out how
        # use get curve length function in the API
        # its just as easy to write a loop to calculate it
        myNumberOfPoints = 0
        for iNumberOfPoints in myCurvePoints:
            myNumberOfPoints = myNumberOfPoints + 1
        myNumberOfPoints = myNumberOfPoints - 1
        myPathIter = myPathLength / myNumberOfPoints
            
        print "
##############################################"
        print "Curve name: %s " % myCurveName
        print "Curve data: %s " % myCurveData
        print "Ipo curves: %s " % myIPOCurveSet
        print "Ipo length: %s " % myPathLength
        print "Path iteration constant: %s" % myPathIter
        print "##############################################
"    

        # Create LocX, LocY, and LocZ Ipo curves in our new Curve Object
        # and store them so we can access them later
        myIPOCurve_X = myIPOCurveSet.addCurve('dLocX')
        myIPOCurve_Y = myIPOCurveSet.addCurve('dLocY')
        myIPOCurve_Z = myIPOCurveSet.addCurve('dLocZ')
        myIPOCurveRot_X = myIPOCurveSet.addCurve('dRotX')
        myIPOCurveRot_Y = myIPOCurveSet.addCurve('dRotY')
        myIPOCurveRot_Z = myIPOCurveSet.addCurve('dRotZ')
        #myIPOCurveSpeed = myIPOCurveSet.addCurve('Time')
            
        myBezPointNumber = 0
        myCurrentPathLen = 1
        for nCurvePoints in myCurvePoints:
            
            # Copy the first set of co-ordinates
            # ready for a isCyclic condtion
            if myBezPointNumber == 0:
                myFirstCoods = nCurvePoints
            
            # Apparently  BezTriple outputs 9 floats for each handle/knot in 3D space
            # so print out each float value
            print"
##############################################"
            print"Bezier point number: %s" % myBezPointNumber
            print"Out of a total: %s" % myNumberOfPoints
            print"Current iteration at frame: %s
" %  myCurrentPathLen
            print"H1x: %s " % nCurvePoints.vec[0][0]
            print"H1y: %s " % nCurvePoints.vec[0][1]
            print"H1z: %s " % nCurvePoints.vec[0][2]
            print"
"
            print"Px: %s " % nCurvePoints.vec[1][0] 
            print"Py: %s " % nCurvePoints.vec[1][1] 
            print"Pz: %s " % nCurvePoints.vec[1][2]
            print"
"
            print"H2x: %s " % nCurvePoints.vec[2][0] 
            print"H2y: %s " % nCurvePoints.vec[2][1]
            print"H2z: %s " % nCurvePoints.vec[2][2] 
            print"##############################################
"
    
            # Store all bezier points
            H1_X = nCurvePoints.vec[0][0]
            H1_Y = nCurvePoints.vec[0][0]
            H1_Z = nCurvePoints.vec[0][2]
            P_X = nCurvePoints.vec[1][0]
            P_Y = nCurvePoints.vec[1][1]
            P_Z = nCurvePoints.vec[1][2]
            H2_X = nCurvePoints.vec[2][0] 
            H2_Y = nCurvePoints.vec[2][1]
            H2_Z = nCurvePoints.vec[2][2]
        
            # make 3 BezTriples, and mke sure their handles are FREE
            # pass eacch of these 3 new BezTriples for X, Y and Z
            # to theirrelevant IPO's
            myIPOCurveX = ((H1_X, 0, 0, P_X, 0, 0, H2_X, 0, 0)) # currently redundant
            myIPOCurveY = ((0, H1_Y, 0, 0, P_Y, 0, 0, H2_Y, 0)) # currently redundant
            myIPOCurveZ = ((0, 0, H1_Z, 0, 0, P_Z, 0, 0, H2_Z)) # currently redundant
            
            # ============================================================
            #
            # L{IpoCurve.bezierPoints<IpoCurve.IpoCurve.bezierPoints>} to get a 
            # BezTriple point, then use the 
            # L{BezTriple} API to set the point's attributes
            #
            # ============================================================ 
    
            # Append to the Ipo curve at location frame, with the value ipoValue_x
            # Note that we should pass the append function a tuple or a BezTriple
             myIPOCurve_X.append((myCurrentPathLen, nCurvePoints.vec[1][0]))
            myIPOCurve_Y.append((myCurrentPathLen, nCurvePoints.vec[1][1]))
            myIPOCurve_Z.append((myCurrentPathLen, nCurvePoints.vec[1][2]))
            
            #myIPOCurveSpeed.append((myCurrentPathLen, 30))
            # Must be done last in the for loop
            myBezPointNumber = myBezPointNumber + 1
            myCurrentPathLen = myPathIter * myBezPointNumber
    
            
    
            myIPOCurve_X.recalc()
            myIPOCurve_Y.recalc()
            myIPOCurve_Z.recalc()
    
    else:
        Blender.Draw.PupMenu("Curve is not a Path")
        print"    -> Curve flag bit 3 at 0x00001000 is NOT set, value is: %x " % (myCurveFlag1 and 0x08)         

else:
    Blender.Draw.PupMenu("Object is not a curve")
    print"    -> Object is a %s" % myObjectType

Hiya Grogyan :slight_smile:

Just been googling for some info about this, and found your thread here for the first time. Don’t know why it didn’t come up earlier :confused:.

I’ve been looking at the IPO plot, and it doesn’t currently seem to take into account the directions of the handles on the control points… I kinda got scared when I found this, and ran off, but there really doesn’t seem to be any alternative on the entire net… Gonna check it out.

I’ve been thinking that the path length could be used to set the resolution of the keys that are placed into the IPO curves, and then using the speed IPO to control the length of the action. What do you think?

Edit:

Been having a look around, and I’m thinking that the last link I gave might be a dead end, though it is very interesting. It says near the end:

This program takes an exponential number of function calls (an exercise) to compute Fibonacci(n). Therefore, the above recursive version of de Casteljau’s algorithm is not suitable for direct implementation, although it looks simple and elegant!

I have, however, found a nice mathematical analysis of Bezier curves on the page Reverse Engineering Bezier Curves.

I’ve noticed that each section of the Bezier curve is controlled by 4 points. The start, end, and the two “arms” that extend from these end points towards the curve section. These 4 points are the control points referred to in the article, and can be found relatively easily (as you have already done :)).

The implementation seems to be a lot more simple than the approach in the first link that I posted.

Vincent Tan calculates a series of 4 points that lie on the curve based on the location of the control points. 2 of these points are the start and end control points, the others lie between them.

I’m going to play with this a little and see if I can get anywhere with it, starting with 4 points on the line that can be turned into IPO keys and moving on to an arbitrary number of points based on the path length. This could give an arbitrary accuracy to the curve depending on how the user sets the path length. I get the feeling that the path length will need to be an exact multiple of the number of points that form the curve, but since it’s possible to set the path length, the script could check this and change the path length accordingly. If it comes down to it, the number of points that are calculated can be set to 4 per curve section and the algorithm used pretty much as it is ;).

Edit 2:

After a big of head-mashing and bug-chasing, I’ve finally managed to get the right information in a usable format to the CalculateIPOPoints() function :D.

Now I need to apply the mysterious, magical function to the data and plot it in an IPO curve.

The cubic Bezier equation is:


 [P] = ((1-u)*(1-u)*(1-u)*[P0]) + (3*(1-u)*(1-u)*u*[P1]) + (3*(1-u)*u*u*[P2]) + (u*u*u*[P3])

u is the distance along the curve between the 2 points that control the curve, a number between 0 and 1
[P] Is the 3 dimensional point in space of the curve at distance u
[P0] is the 3d coordinate of the first point (curve passes through this)
[P1] is the 3d coordinate of the handle connected to the first point (curve is deflected by this)
[P2] is the 3d coordinate of the handle connected to the second point (curve is deflected by this)
[P3] is the 3d coordinate of the second point (curve passes through this)

x, y and z coordinates of the guiding points need to be plugged in to the above equation in turn to give the x, y, z coordinates of the curve at distance u along the arc between the 2 points.

My code is below. The output from the console window should be pretty self-explanatory but is a bit verbose… (Magic formula not implemented yet ;))


#!BPY
# A script to convert a curve to an IPO curve which can be applied to an object
"""
Name: 'MyIPOScript'
Blender: 246
Group: 'Wizards'
Tooltip: 'Make IPO curves from path'
"""
import Blender
#ok... here's an idea... select the objects that you want to follow the curve then select the curve
#activate the script, and the objects have the IPO created for them.
def AnalyseCurve(currentCurve):
 curveName = currentCurve.getName()
 print "Curve name =", curveName
 curveData = currentCurve.data
 print "curveData =", curveData
 curveDataName = curveData.getName()
 print "curveDataName =", curveDataName
 bitFlag = curveData.getFlag()
 print "Flag =", bitFlag
 if bitFlag & 0x08:  #check 4th bit (true is curve path, false is not curve path)
  print "Curve path is set"
 else:
  print "Curve path not set"
  Blender.Draw.PupMenu("Curve not set to Curve Path")
  return
 numberOfCurves = curveData.getNumCurves()
 print "Number of curves =", numberOfCurves
 pathLength = curveData.getPathLen()
 print "Path length =", pathLength
 for curve in range(0, numberOfCurves):
  numberOfPoints = len(curveData[curve])
  print ""
  print "**********"
  print "Curve number =", curve
  print "Number of points =", numberOfPoints
  print "****"
  print ""
  for point in range(0, numberOfPoints):
   print "Point number", point, "=", curveData[curve][point]
 else:
  print "****"
 FindPoints(curveData)
def FindPoints(curveData):
 #################################
 #from http://polymathprogrammer.com/2007/06/27/reverse-engineering-bezier-curves/
 #by Vincent Tan
 #for each point P distance 0<u<1 between  controllers start point [P0], and point [P3], 
 #intermediate controlling points [P1], [P2]
 #P = (((1-u)^3)*[P0]) + ((3*(1-u)^2)*(u*[P1])) + ((3*(1-u)*(u^2))*[P2]) + ((u^3)*[P3])
 #################################
 print ""
 print "***************"
 print "START OF CURVE POINTS PROCESSING"
 print ""
 
 for curve in range(0,curveData.getNumCurves()):
  print ""
  print "************"
  if curveData.isCyclic(curve):
   print "Curve",curve,"is cyclic"
   numSegments = len(curveData[curve])
   print "numSegments =", numSegments
  else:
   print "Curve", curve, "is NOT cyclic"
   numSegments = len(curveData[curve])-1
   print "numSegments =", numSegments
   print ""
  for segment in range(0,numSegments):
   print "****"
   print "Segment",segment
   print "Point", segment
   currentPoint = curveData[curve][segment]
   P1_x = currentPoint.vec[1][0]
   P1_y = currentPoint.vec[1][1]
   P1_z = currentPoint.vec[1][2]
   H1_x = currentPoint.vec[2][0]
   H1_y = currentPoint.vec[2][1]
   H1_z = currentPoint.vec[2][2]
   print "P1_x =",P1_x
   print "P1_y =",P1_y
   print "P1_z =",P1_z
   print "H1_x =",H1_x
   print "H1_y =",H1_y
   print "H1_z =",H1_z
   print "****"
   #Check for final point. Needed to prevent errors if cyclic and re-using first point
   if segment+1 > len(curveData[curve])-1:
    currentPoint = curveData[curve][0]
    print "Point", 0
   else:
    currentPoint = curveData[curve][segment+1]
    print "Point", segment+1
 
   H2_x = currentPoint.vec[0][0]
   H2_y = currentPoint.vec[0][1]
   H2_z = currentPoint.vec[0][2]
   P2_x = currentPoint.vec[1][0]
   P2_y = currentPoint.vec[1][1]
   P2_z = currentPoint.vec[1][2]
   print "H2_x =",H2_x
   print "H2_y =",H2_y
   print "H2_z =",H2_z
   print "P2_x =",P2_x
   print "P2_y =",P2_y
   print "P2_z =",P2_z
   print "****"
   CalculateIPOPoints(P1_x, P1_y, P1_z, H1_x, H1_y, H1_z, \
    H2_x, H2_y, H2_z, P2_x, P2_y, P2_z)
def CalculateIPOPoints(P1_x, P1_y, P1_z, H1_x, H1_y, H1_z, \
   H2_x, H2_y, H2_z, P2_x, P2_y, P2_z):
 print ""
 print "******"
 print "START OF IPO POINTS CALCULATION"
 print ""
 print "P1_x =",P1_x
 print "P1_y =",P1_y
 print "P1_z =",P1_z
 print "H1_x =",H1_x
 print "H1_y =",H1_y
 print "H1_z =",H1_z
 print "H2_x =",H2_x
 print "H2_y =",H2_y
 print "H2_z =",H2_z
 print "P2_x =",P2_x
 print "P2_y =",P2_y
 print "P2_z =",P2_z
 print "******"
def main():
 print ""
 print "*************************"
 print "NEW SCRIPT RUN"
 print "*************************"
 print ""
 scn = Blender.Scene.GetCurrent()
 selectedObjects =  Blender.Object.GetSelected()
 print "Selected objects =", selectedObjects
 try:
  ob = selectedObjects[0]
 except:
  Blender.Draw.PupMenu("Please select a curve.")
  return
 
 if ob.type == "Curve":
  currentCurve = ob
  Blender.Draw.PupMenu("Hooray!! A curve!!")
  AnalyseCurve(currentCurve)
 else:
  Blender.Draw.PupMenu("Active object is not a curve")
  return
 
main()

Great to see you got your script to work, even though your tackling the problem different to myself.

I’m still trying to change the values in the handles to get the curve in the IPO in as few control points as possible (on the IPO window).

I’m sure that I will have to apply an algorithm of sorts to get the time base for each handle, not sure how i’m gonna do that, but seeing as you found the cubic algorithm works i’ll see if I can use it to get the time base.
That is of course AFTER I can manually change the handle data

PS this thread is the main thread i’m watching but here is another one
http://www.blender.org/forum/viewtopic.php?t=13427

And while my brain has faltered i’m looking at algorithms I can use for the dRotX, dRotY, dRotZ, and i’m thinking this thread has the answer

http://blenderartists.org/forum/showthread.php?t=130908
http://blenderartists.org/forum/showthread.php?t=128540

After re reading your post FunkyWrym, I see you found the same docs I did, all supporting the 4 control points or 1 control point and 1 handle, 2 needed for 1 segment hence the 4 points they mention.
In our case we have 1 control point and 2 handles, 2 needed for the 6 points for Blender to create a a basic curve.

The BezTriple API does support changing the values in the handles, but I havn’t yet got it working, it should be
<Your IPO curve on axis>.vec[<0 or 2>], I dunno why they don’t mention this on the API reference, grr.

But I think, if ya don’t mind, use your script as a basis for doing the rotation curves?

I need a math Professor and a Blender Scripting Pro to help me understand this.

PS, notice that i’m not using functions, good reason for this, I suck at Python! And I have enough on my head to keep the wall bloody