simplify IPO curve

hi,

subj should be impliment in blender, i wonder why it still not realized.

so, for now i did fast and dirty simplification script, it works ok, but far from perfection, cause utilize polyline Douglas-Peucker simplification algorithm, taken from http://emergent.unpy.net/

hope blender developers will make normal simplify function (which any vector-editor contain, inkscape, so on…) and improve working with curves also in 3d.

so, here blend
http://eggnot.com/virt/blender/del-keyframes.blend

and here code:


# small script you can simplify IPO - curves
#
# aleksey grishchenko (http://eggnot.com/) 2006
#
# keep in mind simplifycation algorithm
# based on Douglas-Peucker POLYLINE simp. procedure,
# so curved IPO's will never will be better,
# but it can be ok for cleaning after Game Physics IPO recording
# or Motion Capture or so...

# once executed, script rebuild all curves of fist IPO
# for selected object and create new IPO name old_name+"simply"
# for next execution it creating IPO's old_name+"simply."+NNN
# so you can try different TOLERANCE value for best result


TOLERANCE = 0.1

#press ALT+P to continue!

###############################################################
# dist_lseg and douglas was taken from http://emergent.unpy.net
# without any changes
###############################################################
def dist_lseg(l1, l2, p):
    x0, y0, z0 = l1
    xa, ya, za = l2
    xi, yi, zi = p

    dx = xa-x0
    dy = ya-y0
    dz = za-z0 
    d2 = dx*dx + dy*dy + dz*dz
    
    if d2 == 0: return 0

    t = (dx * (xi-x0) + dy * (yi-y0) + dz * (zi-z0)) / d2
    if t < 0: t = 0
    if t > 1: t = 1
    dist2 = (xi - x0 - t * dx) ** 2 + (yi - y0 - t * dy) ** 2 + (zi - z0 - t * dz) ** 2

    return dist2 ** .5

def douglas(st, tolerance=.01, first=True):

    if len(st) == 1:
        yield st[0]
        return

    l1 = st[0]
    l2 = st[-1]
    
    worst_dist = 0
    worst = 0
    
    for i, p in enumerate(st): 
        if p is l1 or p is l2: continue
        dist = dist_lseg(l1, l2, p)
        if dist > worst_dist:
            worst = i
            worst_dist = dist
            
    if first: yield st[0]
    if worst_dist > tolerance:
        for i in douglas(st[:worst+1], tolerance, False):
            yield i
        yield st[worst]
        for i in douglas(st[worst:], tolerance, False):
            yield i
    if first: yield st[-1]
########################################################33


from Blender import Object, Ipo

ob = Object.GetSelected()[0]
ipo = ob.getIpo()

newIpo = Ipo.New("Object",ipo.getName()+"-simply")

for curve in ipo.getCurves():
	
	print "->", curve

	poly = []

	for beZier in curve.getPoints():
		polyx = beZier.vec[1][0]
		#print beZier.getPoints() # deprecated???
		poly.append([polyx,curve[polyx],0])
		#print polyx
		#curve.delBezier(polyx) #deprecated???
	
	#ipo.delCurve(curve.name)
	
	newCurve = newIpo.addCurve(curve.name)
	
	for x,y,z in douglas(poly, TOLERANCE):
		newCurve.addBezier((x,y))
		print "new point x,y:", x, y
			
	newCurve.recalc()

i think for future improve it possible to use this: http://www.simdesign.nl/bezier.html

CVS (pre 2.43) has both “clean IPO curves” and “smooth IPO functions”.

I haven’t used either yet, but I’ll try them right now and compare the results to your script

Mike

this one http://www.graphicall.org/builds/builds/showbuild.php?action=show&id=336

is quite crash-happy with new ipo optimizers. Which doesn’t mean that the final version will be …

seems it using the same linear simplification. where the power of beziers? %)