Length of a Bezier curve in 2.5?

Is it possible to find the length of a Bezier curve in Blender 2.5.6a? I’m sure in 2.4x you could see how long a Bezier was on one of the panels. I am animating a length of hose uncurling, but I want to make sure its length stays approximatley “true”, and doesn’t appear to stretch as I move the control points of the Bezier curve that controls its shape.

yes, in blender-2.49 there was this little “print length” button in the curve-window - it did calculate the length of the curve. Looks like i have to dive into the spline-length calculation …
and i wonder … i have seen something about it in the python -section - somenone who did already calc. the length with pyhton.
Anyone some hints what this was?
I have tried to find it with the forum-search fuction … but without success.
keywords… are? spline… bezier… curve … ??

For this situation you could use some reference object and apply a curve modifier to it, as you are editing the curve the object will deform but remain the same length.

If only I knew some Python I think it must be easy… Pressing Alt+C converts a Bezier to a mesh - a set of vector edges - using the U resolution of the Bezier to determine the number of segments. If a Python script could “do an Alt+C” in code using a high U resolution (say 1000) and then sum the segment lengths, you would get quite an accurate approximation of the Bezier curve length.

@litero: It’s not quite as simple as it seems, I must use a Bezier for this and other purposes too.

Hmm I thought liero was spot on so i did a little test file. Plane is a single vertex object is applied to a curve with the modifier… at x=13.37 in the direction of the modifier it is at the end of the curve… however, Plane.001 a two vertex mesh given an array modifier set to fit the curve has a length of 26.7 when array is applied… and the curve modifier turned off. The unmodified (unit) length of Plane.001 is 0.1… it could be scaled to fit the accuracy required.

Firstly the fit curve array modifier suggests that the curves length is being used in this calculation and is therefore a property that should be available…without having to apply the modifier or convert to mesh or any other tricks… and any thoughts why the curve modifier for the single vertex object indicates it’s half that length… I tried it with bending and flexing and scaling and straightening the curve and always comes out the same …pretty much half.

The applied array fit curve line should solve your hose probs… by leaving on the curve modifier you can see if it is longer or shorter than the “hose”… or use it as the hose as liero suggests… just twigged.

. also the other way with the single vert mesh there is a sphere copying it’s location so you can see where it is… i keyframed it to traverse the hose… it’s at one end at frame 1 and the other at 250… modify the hose and you want the sphere to stay pretty much on the tip… (at frame 250 in the example that is) I use the curve modifier approach to animate objects along curves and thought it was pretty much a 1:1 relationship … this points to it being a 2:1…

EDIT: I did a try with Reaction’s suggested approach, momentarily convert to mesh and sum the length of all edges.
It seems to work fine, it is a tab in properties panel, press N to see it.
Should work on any kind of curve now.

http://img401.imageshack.us/img401/7269/length.jpg


import bpy, mathutils
from mathutils import Vector
le = 'get length of a curve'

class PANEL(bpy.types.Panel):
    bl_label = "Curve length"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    def draw(self, context):
        layout = self.layout
        layout.operator("boton.le")
        box = layout.box()
        box.label(text="Length: " + str(le))
   
class BOTON(bpy.types.Operator):
    bl_idname = "boton.le"
    bl_label = "Calculate"
    def execute(self, context):
        ob = context.active_object
        if ob and ob.select and ob.type == 'CURVE':
            em = (ob.mode == 'EDIT')
            bpy.ops.object.mode_set()
            bpy.ops.object.convert(target='MESH', keep_original=False)
            ve = ob.data.vertices
            global le
            dd = le = 0
            for i in ob.data.edges:
                dd = ve[i.vertices[0]].co - ve[i.vertices[1]].co
                le += dd.length
            le = round(le,4)
            bpy.ops.ed.undo()
            if em: bpy.ops.object.mode_set(mode='EDIT', toggle=False)
        else:
            le = 'not a curve object'
        return{'FINISHED'}

Thanks for this little script

but i tough there was a way in 2.49 to use the values from the Curve itself to calculate the lenght of curves!

i mean this is used in several place in blender and it has to be possible to evaluate this lenght on the curve!

may be you have to first convert to a Poly type may be then use the points to calculate the lenght of each segment !

understand that with the control poinst from bezier the calculated lenght might be a lillte shorted cause you don’t see all the other points in between which add to the lenght!

Thanks

You’re welcome :slight_smile:
I think the accuracy depends of the preview resolution of the curve… when converted to mesh it creates lots of segments betwen control points. There may be an easier way that I couldn’t find, but this was a little python exercise.

Hi, thought I’d have a go at using the array modifier approach for length of curve as a learning excersize too… lifted liero’s script n came up with this. The script creates a single edged object the length of the accuracy prop and applies the fit curve array modifier to it…

import bpy, mathutils
from mathutils import Vector
le = 'get length of a curve'


def initSceneProperties(scn):


    bpy.types.Scene.Accuracy = bpy.props.FloatProperty(
        name="Accuracy", 
        default = 0.01,
        min = 0.0001,
        max = 1)
    scn['Accuracy'] = 0.01

initSceneProperties(bpy.context.scene)

class UIPanel(bpy.types.Panel):
    bl_label = "Curve length"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    def draw(self, context):
        layout = self.layout
        layout.prop(context.scene, "Accuracy")

        #layout.prop(dx)
        layout.operator("object.LengthButton")
        box = layout.box()
        box.label(text="Length: " + str(le))
   
class OBJECT_OT_LengthButton(bpy.types.Operator):
    bl_idname = "OBJECT_OT_LengthButton"
    bl_label = "Calculate"
    def execute(self, context):
        ob = context.active_object
        if ob and ob.select == True and ob.type == 'CURVE':
            dx = context.scene.Accuracy
            verts = []
            edges = [(0,1)]
            #add a small mesh
            mesh = bpy.data.meshes.new("mesh")
            verts.append(Vector((0,0,0)))
            verts.append(Vector((dx,0,0)))
            mesh.from_pydata(verts,edges,[])
            lo = bpy.data.objects.new("lengthfinder",mesh)
            mod = lo.modifiers.new("length","ARRAY")
            mod.fit_type = "FIT_CURVE"
            mod.curve = ob
            base = bpy.context.scene.objects.link(lo)
            global le
            bpy.context.scene.update()
            le = lo.dimensions[0]
            #clean up
            bpy.context.scene.objects.unlink(lo)
            bpy.data.objects.remove(lo)
        return{'FINISHED'}
    

A couple of questions… rather than have the UI there and test whether it’s a curve … is there a way to only have the UI if the context is a curve…

PS… any thoughts on post 5 as to why the curve modifier travels 2:1???

would like to see the equivalent of the first script in 2.5
i could learn from that one too how to play with edges vertices ect…!

you added it into the N panel i know that usually you an find values there
but i’m so use seeing things in tool prop i’ll probablymoce it there !LOL

i have to look how this second srcipt works
i mean can you use the array modif to calculate the lenght ?
are you taking let say a specific lenght and ttryng to see how many fit up to the end of fthe curve?

THanks happy 2.5

Yes and no check out the fit-curve property of the array modifier … does it for you.

does it always work ok or do you have to Ctrl-A the 2 objects before to be certain it will calculate the real lenght and not a fake value ?

happy 2.5

If you remove or comment out the 2 lines after the # clean up comment it leaves the array modified line with the x dimension being the length of the curve after running the script. Seems there is no need to apply the modifier… which is handy as its one of those things i’m not sure how to do without context.

Also I concur with your comment re curve length is used in several places in blender … fit_curve being one of them.

If you add a curve modifier to it you will see its a pretty good copy of the curve… the smaller the bits the more accurate.

i already did post this part in another thread (about the bvh-workflow and anim. bvh-parts along a curve)


#calculate length of bezierline with iteration=3 - accurate enough?
def bezier1(p, depth=0): #recursive for iteration-depth for the 2 bezier-points + their handles
    l = 0
    if depth == 0:
        pass #return
    if depth > 3:
        #set_line(p[0], p[3])
        #print(p[0], p[3])
        return( (p[3]-p[0]).length )
    else:
        depth += 1
        p01   = 0.5*(p[0]+p[1])
        p12   = 0.5*(p[1]+p[2])
        p012  = 0.5*(p01+p12)
        p23   = 0.5*(p[2]+p[3])
        p123  = 0.5*(p12+p23)
        p0123 = 0.5*(p012+p123)
        
        l += bezier1( [p[0],p01,p012,p0123], depth)
        l += bezier1( [p0123,p123,p23,p[3]], depth)
        return(l)

def bezierlength(beziercurvename): #calculate length of beziercurve and return length and duration
    l = 0
    b = get_object(beziercurvename)
    if b == None: return(0) #error if not found!
    if b.type != "CURVE": return(0) #i should print some error
    if len(b.data.splines) == 0: return(0)
    bzp = b.data.splines[0].bezier_points #is the first the only one?
    if len(bzp) == 0: return(0) #how to calculate other lines with spline-points?
    for i in range( len(bzp)-1 ):
        l += bezier1( [bzp[i].co, bzp[i].handle_right, bzp[i+1].handle_left, bzp[i+1].co] )
    return(l, b.data.path_duration)

it only works for BezierCurves - not for bsplines … i have not tried to check whats the big difference (the bsplines have bezierpoints =0 in their object-structure and i am not shure if it is a cubic-line according to the spline-points … - if someone knows, it should be possible to extend the script to use the cubic-calc.-routine if the curve does not use bezierpoints)

@test-dr nice one, still not that accurate and do not work on closed curves as it is now
@batFINGER your script relies on the way Blender internally calculates the array length from a curve, mine in the way it interpolates it to create some mesh, so in both cases the accuracy only depends on the curve preview resolution, test that with a circle… the convert to mesh algorithm seems more reliable, I rounded the results to 4 decimals cause this are all aproximations

@liero: for closed curves there is the need to calculate an edititional bezier-part (last point to first one, thats why bezierpoints have 2 handles, left - right , even if the outer-space-handles not used for not-closed beziercurves) - and for accurracy there one might set the same iteration-level as for the default blender-beziercurve (it seems to be 12 … could be tweaked in the curve-options … and if you go down to 2 … you end at straight lines … connecting the points …).
One could use the mathutils-function:
mathutils.geometry.interpolate_bezier( …
and run this over the bezierpoints of the curve-object.
The iteration 3 (i used) was only for a prove of concept and the result was enough for the patched animation …
What i miss, there should be a routine in the c-source-code of blender, that does this (calculating the length according to the different settings of the curve-properties) - and shure … i did not find any docs about it … its (blender) a real development in action :wink:

edit: i did say, there are needs to check for the other curve-special-settings … “closed-curve” is only one … iteration seems to be the little parts visible in edit-mode of the curve…

ok, and this is (might be ) real SPAM

why i did write down the algo for bezier-parts,
there is
this joke…
about a mathematican, physics and engineer -
everyone is trapped in a room with time-code-door,
that opens only in 2 weeks.
They have enough water, but only one tin-can-box of SPAM.
(thats the meat … spam-mails got their name …)
And they have no tin-can opener.
After 2 weeks the time-code-door opens and
the survivor was:
the physicist
(maybe the joke is wrong at this part …)
On the wall of the dead mathematica was written down
the prove, that the tin-can with spam could be opened
and the meat would help to survive the time till the door
opens again.
On the wall of the engineer were a lot of deep impacts.
The tin-can was still closed and was only very dented
but still closed.
On the wall of the physicist was writen down a calculation
how to throw the tin-can against the wall to hit the week
corners and make it splash …

and btw. … most times i do use “trial and error” …

@liero

Yeah that prop needs a better name than accuracy… its just the size of bits that make up the whole to approximate the length… on investigation with the circle 0.001 is a good value to use. The convert to mesh is more accurate but the array mod is a dang bit quicker on my machine… anyway when can we use that internal calculation directly from a property on the curve object.

PS: looks like both our scripts need to copy original curve and apply scale to work.

@test-dr I’ve heard that the term spam comes from the monty python skitt about the “meat” known as spam

the last script for bezier curves only
is this for 2.5 ?

do you havea complete script like first one so we can test this

would be good to include all these little script inot one script with a menu may be

anyone knows how to make a test on a curve to determine if it is a bezier poly or spline one?
that would be interesting

hope there was not much API changes for curves lately!
and i wont’ laugh on that one cause it’s not a joke anymore more like a pain in the neck!

happy 2.5

<deleted double post> self posted???.. think this baby has to go down for a while.